14fc5923d739a85f51d9c339c1449ea87cd4fcd0
[occt.git] / src / OpenGl / OpenGl_ShaderManager.cxx
1 // Created on: 2013-09-26
2 // Created by: Denis BOGOLEPOV
3 // Copyright (c) 2013-2014 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15
16 #include <typeinfo>
17
18 #include <OpenGl_AspectFace.hxx>
19 #include <OpenGl_AspectLine.hxx>
20 #include <OpenGl_AspectMarker.hxx>
21 #include <OpenGl_AspectText.hxx>
22 #include <OpenGl_Clipping.hxx>
23 #include <OpenGl_Context.hxx>
24 #include <OpenGl_ShaderManager.hxx>
25 #include <OpenGl_ShaderProgram.hxx>
26 #include <OpenGl_Workspace.hxx>
27
28 IMPLEMENT_STANDARD_HANDLE (OpenGl_SetOfShaderPrograms, Standard_Transient)
29 IMPLEMENT_STANDARD_RTTIEXT(OpenGl_SetOfShaderPrograms, Standard_Transient)
30
31 IMPLEMENT_STANDARD_HANDLE (OpenGl_ShaderManager, Standard_Transient)
32 IMPLEMENT_STANDARD_RTTIEXT(OpenGl_ShaderManager, Standard_Transient)
33
34 namespace
35 {
36
37 #define EOL "\n"
38
39 //! Definition of VertColor varying.
40 const char THE_VARY_VertColor[] =
41   EOL"varying vec4 VertColor;";
42
43 const char THE_VARY_TexCoord[] =
44   EOL"varying vec2 TexCoord;";
45
46 //! Auxiliary function to transform normal
47 const char THE_FUNC_transformNormal[] =
48   EOL"vec3 transformNormal (in vec3 theNormal)"
49   EOL"{"
50   EOL"  vec4 aResult = occWorldViewMatrixInverseTranspose"
51   EOL"               * occModelWorldMatrixInverseTranspose"
52   EOL"               * vec4 (theNormal, 0.0);"
53   EOL"  return normalize (aResult.xyz);"
54   EOL"}";
55
56 //! Global shader variable for color definition with lighting enabled.
57 const char THE_FUNC_lightDef[] =
58   EOL"vec3 Ambient;"   //!< Ambient  contribution of light sources
59   EOL"vec3 Diffuse;"   //!< Diffuse  contribution of light sources
60   EOL"vec3 Specular;"; //!< Specular contribution of light sources
61
62 //! Function computes contribution of isotropic point light source
63 const char THE_FUNC_pointLight[] =
64   EOL"void pointLight (in int  theId,"
65   EOL"                 in vec3 theNormal,"
66   EOL"                 in vec3 theView,"
67   EOL"                 in vec3 thePoint,"
68   EOL"                 in bool theIsFront)"
69   EOL"{"
70   EOL"  vec3 aLight = occLight_Position (theId).xyz;"
71   EOL"  if (occLight_IsHeadlight (theId) == 0)"
72   EOL"  {"
73   EOL"    aLight = vec3 (occWorldViewMatrix * occModelWorldMatrix * vec4 (aLight, 1.0));"
74   EOL"  }"
75   EOL"  aLight -= thePoint;"
76   EOL
77   EOL"  float aDist = length (aLight);"
78   EOL"  aLight = aLight * (1.0 / aDist);"
79   EOL
80   EOL"  float anAtten = 1.0 / (occLight_ConstAttenuation  (theId)"
81   EOL"                       + occLight_LinearAttenuation (theId) * aDist);"
82   EOL
83   EOL"  vec3 aHalf = normalize (aLight + theView);"
84   EOL
85   EOL"  vec3  aFaceSideNormal = theIsFront ? theNormal : -theNormal;"
86   EOL"  float aNdotL = max (0.0, dot (aFaceSideNormal, aLight));"
87   EOL"  float aNdotH = max (0.0, dot (aFaceSideNormal, aHalf ));"
88   EOL
89   EOL"  float aSpecl = 0.0;"
90   EOL"  if (aNdotL > 0.0)"
91   EOL"  {"
92   EOL"    aSpecl = pow (aNdotH, theIsFront ? occFrontMaterial_Shininess() : occBackMaterial_Shininess());"
93   EOL"  }"
94   EOL
95   EOL"Diffuse  += occLight_Diffuse  (theId).rgb * aNdotL * anAtten;"
96   EOL"Specular += occLight_Specular (theId).rgb * aSpecl * anAtten;"
97   EOL"}";
98
99 //! Function computes contribution of spotlight source
100 const char THE_FUNC_spotLight[] =
101   EOL"void spotLight (in int  theId,"
102   EOL"                in vec3 theNormal,"
103   EOL"                in vec3 theView,"
104   EOL"                in vec3 thePoint,"
105   EOL"                in bool theIsFront)"
106   EOL"{"
107   EOL"  vec3 aLight   = occLight_Position      (theId).xyz;"
108   EOL"  vec3 aSpotDir = occLight_SpotDirection (theId).xyz;"
109   EOL"  if (occLight_IsHeadlight (theId) == 0)"
110   EOL"  {"
111   EOL"    aLight   = vec3 (occWorldViewMatrix * occModelWorldMatrix * vec4 (aLight,   1.0));"
112   EOL"    aSpotDir = vec3 (occWorldViewMatrix * occModelWorldMatrix * vec4 (aSpotDir, 0.0));"
113   EOL"  }"
114   EOL"  aLight -= thePoint;"
115   EOL
116   EOL"  float aDist = length (aLight);"
117   EOL"  aLight = aLight * (1.0 / aDist);"
118   EOL
119   EOL"  aSpotDir = normalize (aSpotDir);"
120   // light cone
121   EOL"  float aCosA = dot (aSpotDir, -aLight);"
122   EOL"  if (aCosA >= 1.0 || aCosA < cos (occLight_SpotCutOff (theId)))"
123   EOL"  {"
124   EOL"    return;"
125   EOL"  }"
126   EOL
127   EOL"  float anExponent = occLight_SpotExponent (theId);"
128   EOL"  float anAtten    = 1.0 / (occLight_ConstAttenuation  (theId)"
129   EOL"                          + occLight_LinearAttenuation (theId) * aDist);"
130   EOL"  if (anExponent > 0.0)"
131   EOL"  {"
132   EOL"    anAtten *= pow (aCosA, anExponent * 128.0);"
133   EOL"  }"
134   EOL
135   EOL"  vec3 aHalf = normalize (aLight + theView);"
136   EOL
137   EOL"  vec3  aFaceSideNormal = theIsFront ? theNormal : -theNormal;"
138   EOL"  float aNdotL = max (0.0, dot (aFaceSideNormal, aLight));"
139   EOL"  float aNdotH = max (0.0, dot (aFaceSideNormal, aHalf ));"
140   EOL
141   EOL"  float aSpecl = 0.0;"
142   EOL"  if (aNdotL > 0.0)"
143   EOL"  {"
144   EOL"    aSpecl = pow (aNdotH, theIsFront ? occFrontMaterial_Shininess() : occBackMaterial_Shininess());"
145   EOL"  }"
146   EOL
147   EOL"  Diffuse  += occLight_Diffuse  (theId).rgb * aNdotL * anAtten;"
148   EOL"  Specular += occLight_Specular (theId).rgb * aSpecl * anAtten;"
149   EOL"}";
150
151 //! Function computes contribution of directional light source
152 const char THE_FUNC_directionalLight[] =
153   EOL"void directionalLight (in int  theId,"
154   EOL"                       in vec3 theNormal,"
155   EOL"                       in vec3 theView,"
156   EOL"                       in bool theIsFront)"
157   EOL"{"
158   EOL"  vec3 aLight = normalize (occLight_Position (theId).xyz);"
159   EOL"  if (occLight_IsHeadlight (theId) == 0)"
160   EOL"  {"
161   EOL"    aLight = vec3 (occWorldViewMatrix * occModelWorldMatrix * vec4 (aLight, 0.0));"
162   EOL"  }"
163   EOL
164   EOL"  vec3 aHalf = normalize (aLight + theView);"
165   EOL
166   EOL"  vec3  aFaceSideNormal = theIsFront ? theNormal : -theNormal;"
167   EOL"  float aNdotL = max (0.0, dot (aFaceSideNormal, aLight));"
168   EOL"  float aNdotH = max (0.0, dot (aFaceSideNormal, aHalf ));"
169   EOL
170   EOL"  float aSpecl = 0.0;"
171   EOL"  if (aNdotL > 0.0)"
172   EOL"  {"
173   EOL"    aSpecl = pow (aNdotH, theIsFront ? occFrontMaterial_Shininess() : occBackMaterial_Shininess());"
174   EOL"  }"
175   EOL
176   EOL"  Diffuse  += occLight_Diffuse  (theId).rgb * aNdotL;"
177   EOL"  Specular += occLight_Specular (theId).rgb * aSpecl;"
178   EOL"}";
179
180 //! Process clipping planes in Fragment Shader.
181 //! Should be added at the beginning of the main() function.
182 const char THE_FRAG_CLIP_PLANES[] =
183   EOL"  for (int aPlaneIter = 0; aPlaneIter < occClipPlaneCount; ++aPlaneIter)"
184   EOL"  {"
185   EOL"    vec4 aClipEquation = occClipPlaneEquations[aPlaneIter];"
186   EOL"    int  aClipSpace    = occClipPlaneSpaces[aPlaneIter];"
187   EOL"    if (aClipSpace == OccEquationCoords_World)"
188   EOL"    {"
189   EOL"      if (dot (aClipEquation.xyz, PositionWorld.xyz) + aClipEquation.w < 0.0)"
190   EOL"      {"
191   EOL"        discard;"
192   EOL"      }"
193   EOL"    }"
194   EOL"    else if (aClipSpace == OccEquationCoords_View)"
195   EOL"    {"
196   EOL"      if (dot (aClipEquation.xyz, Position.xyz) + aClipEquation.w < 0.0)"
197   EOL"      {"
198   EOL"        discard;"
199   EOL"      }"
200   EOL"    }"
201   EOL"  }";
202
203 }
204
205 // =======================================================================
206 // function : OpenGl_ShaderManager
207 // purpose  : Creates new empty shader manager
208 // =======================================================================
209 OpenGl_ShaderManager::OpenGl_ShaderManager (OpenGl_Context* theContext)
210 : myShadingModel (Visual3d_TOM_VERTEX),
211   myContext  (theContext),
212   myLastView (NULL)
213 {
214   //
215 }
216
217 // =======================================================================
218 // function : ~OpenGl_ShaderManager
219 // purpose  : Releases resources of shader manager
220 // =======================================================================
221 OpenGl_ShaderManager::~OpenGl_ShaderManager()
222 {
223   myProgramList.Clear();
224 }
225
226 // =======================================================================
227 // function : clear
228 // purpose  :
229 // =======================================================================
230 void OpenGl_ShaderManager::clear()
231 {
232   myProgramList.Clear();
233   myLightPrograms.Nullify();
234   myFlatPrograms = OpenGl_SetOfShaderPrograms();
235   myMapOfLightPrograms.Clear();
236   myFontProgram.Nullify();
237   switchLightPrograms();
238 }
239
240 // =======================================================================
241 // function : Create
242 // purpose  : Creates new shader program
243 // =======================================================================
244 Standard_Boolean OpenGl_ShaderManager::Create (const Handle(Graphic3d_ShaderProgram)& theProxy,
245                                                TCollection_AsciiString&               theShareKey,
246                                                Handle(OpenGl_ShaderProgram)&          theProgram)
247 {
248   theProgram.Nullify();
249   if (theProxy.IsNull())
250   {
251     return Standard_False;
252   }
253
254   theShareKey = theProxy->GetId();
255   if (myContext->GetResource<Handle(OpenGl_ShaderProgram)> (theShareKey, theProgram))
256   {
257     if (theProgram->Share())
258     {
259       myProgramList.Append (theProgram);
260     }
261     return Standard_True;
262   }
263
264   theProgram = new OpenGl_ShaderProgram (theProxy);
265   if (!theProgram->Initialize (myContext, theProxy->ShaderObjects()))
266   {
267     theProgram->Release (myContext);
268     theShareKey.Clear();
269     theProgram.Nullify();
270     return Standard_False;
271   }
272
273   myProgramList.Append (theProgram);
274   myContext->ShareResource (theShareKey, theProgram);
275   return Standard_True;
276 }
277
278 // =======================================================================
279 // function : Unregister
280 // purpose  : Removes specified shader program from the manager
281 // =======================================================================
282 void OpenGl_ShaderManager::Unregister (TCollection_AsciiString&      theShareKey,
283                                        Handle(OpenGl_ShaderProgram)& theProgram)
284 {
285   for (OpenGl_ShaderProgramList::Iterator anIt (myProgramList); anIt.More(); anIt.Next())
286   {
287     if (anIt.Value() == theProgram)
288     {
289       if (!theProgram->UnShare())
290       {
291         theShareKey.Clear();
292         theProgram.Nullify();
293         return;
294       }
295
296       myProgramList.Remove (anIt);
297       myMaterialStates.UnBind (theProgram);
298       break;
299     }
300   }
301
302   const TCollection_AsciiString anID = theProgram->myProxy->GetId();
303   if (anID.IsEmpty())
304   {
305     myContext->DelayedRelease (theProgram);
306     theProgram.Nullify();
307   }
308   else
309   {
310     theProgram.Nullify();
311     myContext->ReleaseResource (anID, Standard_True);
312   }
313 }
314
315 // =======================================================================
316 // function : ShaderPrograms
317 // purpose  : Returns list of registered shader programs
318 // =======================================================================
319 const OpenGl_ShaderProgramList& OpenGl_ShaderManager::ShaderPrograms() const
320 {
321   return myProgramList;
322 }
323
324 // =======================================================================
325 // function : Empty
326 // purpose  : Returns true if no program objects are attached
327 // =======================================================================
328 Standard_Boolean OpenGl_ShaderManager::IsEmpty() const
329 {
330   return myProgramList.IsEmpty();
331 }
332
333 // =======================================================================
334 // function : switchLightPrograms
335 // purpose  :
336 // =======================================================================
337 void OpenGl_ShaderManager::switchLightPrograms()
338 {
339   TCollection_AsciiString aKey (myShadingModel == Visual3d_TOM_FRAGMENT ? "p_" : "g_");
340   const OpenGl_ListOfLight* aLights = myLightSourceState.LightSources();
341   if (aLights != NULL)
342   {
343     for (OpenGl_ListOfLight::Iterator aLightIter (*aLights); aLightIter.More(); aLightIter.Next())
344     {
345       switch (aLightIter.Value().Type)
346       {
347         case Visual3d_TOLS_AMBIENT:
348           break; // skip ambient
349         case Visual3d_TOLS_DIRECTIONAL:
350           aKey += "d";
351           break;
352         case Visual3d_TOLS_POSITIONAL:
353           aKey += "p";
354           break;
355         case Visual3d_TOLS_SPOT:
356           aKey += "s";
357           break;
358       }
359     }
360   }
361
362   if (!myMapOfLightPrograms.Find (aKey, myLightPrograms))
363   {
364     myLightPrograms = new OpenGl_SetOfShaderPrograms();
365     myMapOfLightPrograms.Bind (aKey, myLightPrograms);
366   }
367 }
368
369 // =======================================================================
370 // function : UpdateLightSourceStateTo
371 // purpose  : Updates state of OCCT light sources
372 // =======================================================================
373 void OpenGl_ShaderManager::UpdateLightSourceStateTo (const OpenGl_ListOfLight* theLights)
374 {
375   myLightSourceState.Set (theLights);
376   myLightSourceState.Update();
377   switchLightPrograms();
378 }
379
380 // =======================================================================
381 // function : SetShadingModel
382 // purpose  :
383 // =======================================================================
384 void OpenGl_ShaderManager::SetShadingModel (const Visual3d_TypeOfModel theModel)
385 {
386   myShadingModel = theModel;
387   switchLightPrograms();
388 }
389
390 // =======================================================================
391 // function : SetProjectionState
392 // purpose  : Sets new state of OCCT projection transform
393 // =======================================================================
394 void OpenGl_ShaderManager::UpdateProjectionStateTo (const OpenGl_Mat4& theProjectionMatrix)
395 {
396   myProjectionState.Set (theProjectionMatrix);
397   myProjectionState.Update();
398 }
399
400 // =======================================================================
401 // function : SetModelWorldState
402 // purpose  : Sets new state of OCCT model-world transform
403 // =======================================================================
404 void OpenGl_ShaderManager::UpdateModelWorldStateTo (const OpenGl_Mat4& theModelWorldMatrix)
405 {
406   myModelWorldState.Set (theModelWorldMatrix);
407   myModelWorldState.Update();
408 }
409
410 // =======================================================================
411 // function : SetWorldViewState
412 // purpose  : Sets new state of OCCT world-view transform
413 // =======================================================================
414 void OpenGl_ShaderManager::UpdateWorldViewStateTo (const OpenGl_Mat4& theWorldViewMatrix)
415 {
416   myWorldViewState.Set (theWorldViewMatrix);
417   myWorldViewState.Update();
418 }
419
420 // =======================================================================
421 // function : LightSourceState
422 // purpose  : Returns current state of OCCT light sources
423 // =======================================================================
424 const OpenGl_LightSourceState& OpenGl_ShaderManager::LightSourceState() const
425 {
426   return myLightSourceState;
427 }
428
429 // =======================================================================
430 // function : ProjectionState
431 // purpose  : Returns current state of OCCT projection transform
432 // =======================================================================
433 const OpenGl_ProjectionState& OpenGl_ShaderManager::ProjectionState() const
434 {
435   return myProjectionState;
436 }
437
438 // =======================================================================
439 // function : ModelWorldState
440 // purpose  : Returns current state of OCCT model-world transform
441 // =======================================================================
442 const OpenGl_ModelWorldState& OpenGl_ShaderManager::ModelWorldState() const
443 {
444   return myModelWorldState;
445 }
446
447 // =======================================================================
448 // function : WorldViewState
449 // purpose  : Returns current state of OCCT world-view transform
450 // =======================================================================
451 const OpenGl_WorldViewState& OpenGl_ShaderManager::WorldViewState() const
452 {
453   return myWorldViewState;
454 }
455
456 //! Packed properties of light source
457 class OpenGl_ShaderLightParameters
458 {
459 public:
460
461   OpenGl_Vec4 Color;
462   OpenGl_Vec4 Position;
463   OpenGl_Vec4 Direction;
464   OpenGl_Vec4 Parameters;
465
466   //! Returns packed (serialized) representation of light source properties
467   const OpenGl_Vec4* Packed() const { return reinterpret_cast<const OpenGl_Vec4*> (this); }
468   static Standard_Integer NbOfVec4() { return 4; }
469
470 };
471
472 //! Packed light source type information
473 class OpenGl_ShaderLightType
474 {
475 public:
476
477   Standard_Integer Type;
478   Standard_Integer IsHeadlight;
479
480   //! Returns packed (serialized) representation of light source type
481   const OpenGl_Vec2i* Packed() const { return reinterpret_cast<const OpenGl_Vec2i*> (this); }
482   static Standard_Integer NbOfVec2i() { return 1; }
483
484 };
485
486 // =======================================================================
487 // function : PushLightSourceState
488 // purpose  : Pushes state of OCCT light sources to the program
489 // =======================================================================
490 void OpenGl_ShaderManager::PushLightSourceState (const Handle(OpenGl_ShaderProgram)& theProgram) const
491 {
492   if (myLightSourceState.Index() == theProgram->ActiveState (OpenGl_LIGHT_SOURCES_STATE)
493    || !theProgram->IsValid())
494   {
495     return;
496   }
497
498   OpenGl_ShaderLightType* aLightTypeArray = new OpenGl_ShaderLightType[OpenGLMaxLights];
499   for (Standard_Integer aLightIt = 0; aLightIt < OpenGLMaxLights; ++aLightIt)
500   {
501     aLightTypeArray[aLightIt].Type = -1;
502   }
503
504   const Standard_Integer aLightsDefNb = Min (myLightSourceState.LightSources()->Size(), OpenGLMaxLights);
505   if (aLightsDefNb < 1)
506   {
507     theProgram->SetUniform (myContext,
508                             theProgram->GetStateLocation (OpenGl_OCC_LIGHT_SOURCE_COUNT),
509                             0);
510     theProgram->SetUniform (myContext,
511                             theProgram->GetStateLocation (OpenGl_OCC_LIGHT_AMBIENT),
512                             OpenGl_Vec4 (0.0f, 0.0f, 0.0f, 0.0f));
513     theProgram->SetUniform (myContext,
514                             theProgram->GetStateLocation (OpenGl_OCC_LIGHT_SOURCE_TYPES),
515                             OpenGLMaxLights * OpenGl_ShaderLightType::NbOfVec2i(),
516                             aLightTypeArray[0].Packed());
517     theProgram->UpdateState (OpenGl_LIGHT_SOURCES_STATE, myLightSourceState.Index());
518     delete[] aLightTypeArray;
519     return;
520   }
521
522   OpenGl_ShaderLightParameters* aLightParamsArray = new OpenGl_ShaderLightParameters[aLightsDefNb];
523
524   OpenGl_Vec4 anAmbient (0.0f, 0.0f, 0.0f, 0.0f);
525   Standard_Integer aLightsNb = 0;
526   for (OpenGl_ListOfLight::Iterator anIter (*myLightSourceState.LightSources()); anIter.More(); anIter.Next())
527   {
528     const OpenGl_Light& aLight = anIter.Value();
529     if (aLight.Type == Visual3d_TOLS_AMBIENT)
530     {
531       anAmbient += aLight.Color;
532       continue;
533     }
534     else if (aLightsNb >= OpenGLMaxLights)
535     {
536       continue;
537     }
538
539     OpenGl_ShaderLightType& aLightType = aLightTypeArray[aLightsNb];
540     aLightType.Type        = aLight.Type;
541     aLightType.IsHeadlight = aLight.IsHeadlight;
542
543     OpenGl_ShaderLightParameters& aLightParams = aLightParamsArray[aLightsNb];
544     aLightParams.Color    = aLight.Color;
545     aLightParams.Position = aLight.Type == Visual3d_TOLS_DIRECTIONAL
546                          ? -aLight.Direction
547                          :  aLight.Position;
548     if (aLight.Type == Visual3d_TOLS_SPOT)
549     {
550       aLightParams.Direction = aLight.Direction;
551     }
552     aLightParams.Parameters = aLight.Params;
553     ++aLightsNb;
554   }
555
556   theProgram->SetUniform (myContext,
557                           theProgram->GetStateLocation (OpenGl_OCC_LIGHT_SOURCE_COUNT),
558                           aLightsNb);
559   theProgram->SetUniform (myContext,
560                           theProgram->GetStateLocation (OpenGl_OCC_LIGHT_AMBIENT),
561                           anAmbient);
562   theProgram->SetUniform (myContext,
563                           theProgram->GetStateLocation (OpenGl_OCC_LIGHT_SOURCE_TYPES),
564                           OpenGLMaxLights * OpenGl_ShaderLightType::NbOfVec2i(),
565                           aLightTypeArray[0].Packed());
566   if (aLightsNb > 0)
567   {
568     theProgram->SetUniform (myContext,
569                             theProgram->GetStateLocation (OpenGl_OCC_LIGHT_SOURCE_PARAMS),
570                             aLightsNb * OpenGl_ShaderLightParameters::NbOfVec4(),
571                             aLightParamsArray[0].Packed());
572   }
573   delete[] aLightParamsArray;
574   delete[] aLightTypeArray;
575
576   theProgram->UpdateState (OpenGl_LIGHT_SOURCES_STATE, myLightSourceState.Index());
577 }
578
579 // =======================================================================
580 // function : PushProjectionState
581 // purpose  : Pushes state of OCCT projection transform to the program
582 // =======================================================================
583 void OpenGl_ShaderManager::PushProjectionState (const Handle(OpenGl_ShaderProgram)& theProgram) const
584 {
585   if (myProjectionState.Index() == theProgram->ActiveState (OpenGl_PROJECTION_STATE))
586   {
587     return;
588   }
589
590   theProgram->SetUniform (myContext,
591                           theProgram->GetStateLocation (OpenGl_OCC_PROJECTION_MATRIX),
592                           myProjectionState.ProjectionMatrix());
593
594   GLint aLocation = theProgram->GetStateLocation (OpenGl_OCC_PROJECTION_MATRIX_INVERSE);
595   if (aLocation != OpenGl_ShaderProgram::INVALID_LOCATION)
596   {
597     theProgram->SetUniform (myContext, aLocation, myProjectionState.ProjectionMatrixInverse());
598   }
599
600   theProgram->SetUniform (myContext,
601                           theProgram->GetStateLocation (OpenGl_OCC_PROJECTION_MATRIX_TRANSPOSE),
602                           myProjectionState.ProjectionMatrix(), true);
603
604   aLocation = theProgram->GetStateLocation (OpenGl_OCC_PROJECTION_MATRIX_INVERSE_TRANSPOSE);
605   if (aLocation != OpenGl_ShaderProgram::INVALID_LOCATION)
606   {
607     theProgram->SetUniform (myContext, aLocation, myProjectionState.ProjectionMatrixInverse(), true);
608   }
609
610   theProgram->UpdateState (OpenGl_PROJECTION_STATE, myProjectionState.Index());
611 }
612
613 // =======================================================================
614 // function : PushModelWorldState
615 // purpose  : Pushes state of OCCT model-world transform to the program
616 // =======================================================================
617 void OpenGl_ShaderManager::PushModelWorldState (const Handle(OpenGl_ShaderProgram)& theProgram) const
618 {
619   if (myModelWorldState.Index() == theProgram->ActiveState (OpenGl_MODEL_WORLD_STATE))
620   {
621     return;
622   }
623
624   theProgram->SetUniform (myContext,
625                           theProgram->GetStateLocation (OpenGl_OCC_MODEL_WORLD_MATRIX),
626                           myModelWorldState.ModelWorldMatrix());
627
628   GLint aLocation = theProgram->GetStateLocation (OpenGl_OCC_MODEL_WORLD_MATRIX_INVERSE);
629   if (aLocation != OpenGl_ShaderProgram::INVALID_LOCATION)
630   {
631     theProgram->SetUniform (myContext, aLocation, myModelWorldState.ModelWorldMatrixInverse());
632   }
633
634   theProgram->SetUniform (myContext,
635                           theProgram->GetStateLocation (OpenGl_OCC_MODEL_WORLD_MATRIX_TRANSPOSE),
636                           myModelWorldState.ModelWorldMatrix(), true);
637
638   aLocation = theProgram->GetStateLocation (OpenGl_OCC_MODEL_WORLD_MATRIX_INVERSE_TRANSPOSE);
639   if (aLocation != OpenGl_ShaderProgram::INVALID_LOCATION)
640   {
641     theProgram->SetUniform (myContext, aLocation, myModelWorldState.ModelWorldMatrixInverse(), true);
642   }
643
644   theProgram->UpdateState (OpenGl_MODEL_WORLD_STATE, myModelWorldState.Index());
645 }
646
647 // =======================================================================
648 // function : PushWorldViewState
649 // purpose  : Pushes state of OCCT world-view transform to the program
650 // =======================================================================
651 void OpenGl_ShaderManager::PushWorldViewState (const Handle(OpenGl_ShaderProgram)& theProgram) const
652 {
653   if (myWorldViewState.Index() == theProgram->ActiveState (OpenGl_WORLD_VIEW_STATE))
654   {
655     return;
656   }
657
658   theProgram->SetUniform (myContext,
659                           theProgram->GetStateLocation (OpenGl_OCC_WORLD_VIEW_MATRIX),
660                           myWorldViewState.WorldViewMatrix());
661
662   GLint aLocation = theProgram->GetStateLocation (OpenGl_OCC_WORLD_VIEW_MATRIX_INVERSE);
663   if (aLocation != OpenGl_ShaderProgram::INVALID_LOCATION)
664   {
665     theProgram->SetUniform (myContext, aLocation, myWorldViewState.WorldViewMatrixInverse());
666   }
667
668   theProgram->SetUniform (myContext,
669                           theProgram->GetStateLocation (OpenGl_OCC_WORLD_VIEW_MATRIX_TRANSPOSE),
670                           myWorldViewState.WorldViewMatrix(), true);
671
672   aLocation = theProgram->GetStateLocation (OpenGl_OCC_WORLD_VIEW_MATRIX_INVERSE_TRANSPOSE);
673   if (aLocation != OpenGl_ShaderProgram::INVALID_LOCATION)
674   {
675     theProgram->SetUniform (myContext, aLocation, myWorldViewState.WorldViewMatrixInverse(), true);
676   }
677
678   theProgram->UpdateState (OpenGl_WORLD_VIEW_STATE, myWorldViewState.Index());
679 }
680
681 // =======================================================================
682 // function : UpdateClippingState
683 // purpose  : Updates state of OCCT clipping planes
684 // =======================================================================
685 void OpenGl_ShaderManager::UpdateClippingState()
686 {
687   myClippingState.Update();
688 }
689
690 // =======================================================================
691 // function : RevertClippingState
692 // purpose  : Reverts state of OCCT clipping planes
693 // =======================================================================
694 void OpenGl_ShaderManager::RevertClippingState()
695 {
696   myClippingState.Revert();
697 }
698
699 // =======================================================================
700 // function : PushClippingState
701 // purpose  : Pushes state of OCCT clipping planes to the program
702 // =======================================================================
703 void OpenGl_ShaderManager::PushClippingState (const Handle(OpenGl_ShaderProgram)& theProgram) const
704 {
705   if (myClippingState.Index() == theProgram->ActiveState (OpenGl_CLIP_PLANES_STATE))
706   {
707     return;
708   }
709
710   theProgram->UpdateState (OpenGl_CLIP_PLANES_STATE, myClippingState.Index());
711   const GLint aLocEquations = theProgram->GetStateLocation (OpenGl_OCC_CLIP_PLANE_EQUATIONS);
712   const GLint aLocSpaces    = theProgram->GetStateLocation (OpenGl_OCC_CLIP_PLANE_SPACES);
713   if (aLocEquations == OpenGl_ShaderProgram::INVALID_LOCATION
714    && aLocSpaces    == OpenGl_ShaderProgram::INVALID_LOCATION)
715   {
716     return;
717   }
718
719   GLint aPlanesNb = 0;
720   for (Graphic3d_SequenceOfHClipPlane::Iterator anIter (myContext->Clipping().Planes());
721        anIter.More(); anIter.Next())
722   {
723     const Handle(Graphic3d_ClipPlane)& aPlane = anIter.Value();
724     if (!myContext->Clipping().IsEnabled (aPlane))
725     {
726       continue;
727     }
728
729     ++aPlanesNb;
730   }
731   if (aPlanesNb < 1)
732   {
733     return;
734   }
735
736   const Standard_Size MAX_CLIP_PLANES = 8;
737   OpenGl_Vec4* anEquations = new OpenGl_Vec4[MAX_CLIP_PLANES];
738   GLint*       aSpaces     = new GLint      [MAX_CLIP_PLANES];
739   GLuint aPlaneId = 0;
740   for (Graphic3d_SequenceOfHClipPlane::Iterator anIter (myContext->Clipping().Planes());
741        anIter.More(); anIter.Next())
742   {
743     const Handle(Graphic3d_ClipPlane)& aPlane = anIter.Value();
744     if (!myContext->Clipping().IsEnabled (aPlane))
745     {
746       continue;
747     }
748
749     const Graphic3d_ClipPlane::Equation& anEquation = aPlane->GetEquation();
750     anEquations[aPlaneId] = OpenGl_Vec4 ((float) anEquation.x(),
751                                          (float) anEquation.y(),
752                                          (float) anEquation.z(),
753                                          (float) anEquation.w());
754     aSpaces[aPlaneId] = myContext->Clipping().GetEquationSpace (aPlane);
755     ++aPlaneId;
756   }
757
758   theProgram->SetUniform (myContext,
759                           theProgram->GetStateLocation (OpenGl_OCC_CLIP_PLANE_COUNT),
760                           aPlanesNb);
761   theProgram->SetUniform (myContext, aLocEquations, MAX_CLIP_PLANES, anEquations);
762   theProgram->SetUniform (myContext, aLocSpaces,    MAX_CLIP_PLANES, aSpaces);
763
764   delete[] anEquations;
765   delete[] aSpaces;
766 }
767
768 // =======================================================================
769 // function : UpdateMaterialStateTo
770 // purpose  : Updates state of OCCT material for specified program
771 // =======================================================================
772 void OpenGl_ShaderManager::UpdateMaterialStateTo (const Handle(OpenGl_ShaderProgram)& theProgram,
773                                                   const OpenGl_Element*               theAspect)
774 {
775   if (myMaterialStates.IsBound (theProgram))
776   {
777     OpenGl_MaterialState& aState = myMaterialStates.ChangeFind (theProgram);
778     aState.Set (theAspect);
779     aState.Update();
780   }
781   else
782   {
783     myMaterialStates.Bind       (theProgram, OpenGl_MaterialState (theAspect));
784     myMaterialStates.ChangeFind (theProgram).Update();
785   }
786 }
787
788 // =======================================================================
789 // function : ResetMaterialStates
790 // purpose  : Resets state of OCCT material for all programs
791 // =======================================================================
792 void OpenGl_ShaderManager::ResetMaterialStates()
793 {
794   for (OpenGl_ShaderProgramList::Iterator anIt (myProgramList); anIt.More(); anIt.Next())
795   {
796     anIt.Value()->UpdateState (OpenGl_MATERIALS_STATE, 0);
797   }
798 }
799
800 // =======================================================================
801 // function : MaterialState
802 // purpose  : Returns state of OCCT material for specified program
803 // =======================================================================
804 const OpenGl_MaterialState* OpenGl_ShaderManager::MaterialState (const Handle(OpenGl_ShaderProgram)& theProgram) const
805 {
806   if (!myMaterialStates.IsBound (theProgram))
807     return NULL;
808
809   return &myMaterialStates.Find (theProgram);
810 }
811
812 namespace
813 {
814
815 static const OpenGl_Vec4 THE_COLOR_BLACK_VEC4 (0.0f, 0.0f, 0.0f, 0.0f);
816
817 // =======================================================================
818 // function : PushAspectFace
819 // purpose  :
820 // =======================================================================
821 static void PushAspectFace (const Handle(OpenGl_Context)&       theCtx,
822                             const Handle(OpenGl_ShaderProgram)& theProgram,
823                             const OpenGl_AspectFace*            theAspect)
824 {
825   theProgram->SetUniform (theCtx,
826                           theProgram->GetStateLocation (OpenGl_OCCT_TEXTURE_ENABLE),
827                           theAspect->DoTextureMap());
828   theProgram->SetUniform (theCtx,
829                           theProgram->GetStateLocation (OpenGl_OCCT_ACTIVE_SAMPLER),
830                           0 /* GL_TEXTURE0 */);
831   theProgram->SetUniform (theCtx,
832                           theProgram->GetStateLocation (OpenGl_OCCT_DISTINGUISH_MODE),
833                           theAspect->DistinguishingMode());
834
835   OpenGl_Material aParams;
836   for (Standard_Integer anIndex = 0; anIndex < 2; ++anIndex)
837   {
838     const GLint aLoc = theProgram->GetStateLocation (anIndex == 0
839                                                    ? OpenGl_OCCT_FRONT_MATERIAL
840                                                    : OpenGl_OCCT_BACK_MATERIAL);
841     if (aLoc == OpenGl_ShaderProgram::INVALID_LOCATION)
842     {
843       continue;
844     }
845
846     aParams.Init (anIndex == 0 ? theAspect->IntFront() : theAspect->IntBack());
847     theProgram->SetUniform (theCtx, aLoc, OpenGl_Material::NbOfVec4(),
848                             aParams.Packed());
849   }
850 }
851
852 // =======================================================================
853 // function : PushAspectLine
854 // purpose  :
855 // =======================================================================
856 static void PushAspectLine (const Handle(OpenGl_Context)&       theCtx,
857                             const Handle(OpenGl_ShaderProgram)& theProgram,
858                             const OpenGl_AspectLine*            theAspect)
859 {
860   theProgram->SetUniform (theCtx, theProgram->GetStateLocation (OpenGl_OCCT_TEXTURE_ENABLE),   TOff);
861   theProgram->SetUniform (theCtx, theProgram->GetStateLocation (OpenGl_OCCT_DISTINGUISH_MODE), TOff);
862
863   const OpenGl_Vec4 aDiffuse (theAspect->Color().rgb[0],
864                               theAspect->Color().rgb[1],
865                               theAspect->Color().rgb[2],
866                               theAspect->Color().rgb[3]);
867   OpenGl_Vec4 aParams[5];
868   aParams[0] = THE_COLOR_BLACK_VEC4;
869   aParams[1] = THE_COLOR_BLACK_VEC4;
870   aParams[2] = aDiffuse;
871   aParams[3] = THE_COLOR_BLACK_VEC4;
872   aParams[4].x() = 0.0f; // shininess
873   aParams[4].y() = 0.0f; // transparency
874   theProgram->SetUniform (theCtx, theProgram->GetStateLocation (OpenGl_OCCT_FRONT_MATERIAL),
875                           5, aParams);
876 }
877
878 // =======================================================================
879 // function : PushAspectText
880 // purpose  :
881 // =======================================================================
882 static void PushAspectText (const Handle(OpenGl_Context)&       theCtx,
883                             const Handle(OpenGl_ShaderProgram)& theProgram,
884                             const OpenGl_AspectText*            theAspect)
885 {
886   theProgram->SetUniform (theCtx, theProgram->GetStateLocation (OpenGl_OCCT_TEXTURE_ENABLE),   TOn);
887   theProgram->SetUniform (theCtx, theProgram->GetStateLocation (OpenGl_OCCT_DISTINGUISH_MODE), TOff);
888   theProgram->SetUniform (theCtx, theProgram->GetStateLocation (OpenGl_OCCT_ACTIVE_SAMPLER),   0 /* GL_TEXTURE0 */);
889
890   OpenGl_Vec4 aDiffuse (theAspect->Color().rgb[0],
891                         theAspect->Color().rgb[1],
892                         theAspect->Color().rgb[2],
893                         theAspect->Color().rgb[3]);
894   if (theAspect->DisplayType() == Aspect_TODT_DEKALE
895    || theAspect->DisplayType() == Aspect_TODT_SUBTITLE)
896   {
897     aDiffuse = OpenGl_Vec4 (theAspect->SubtitleColor().rgb[0],
898                             theAspect->SubtitleColor().rgb[1],
899                             theAspect->SubtitleColor().rgb[2],
900                             theAspect->SubtitleColor().rgb[3]);
901   }
902
903   OpenGl_Vec4 aParams[5];
904   aParams[0] = THE_COLOR_BLACK_VEC4;
905   aParams[1] = THE_COLOR_BLACK_VEC4;
906   aParams[2] = aDiffuse;
907   aParams[3] = THE_COLOR_BLACK_VEC4;
908   aParams[4].x() = 0.0f; // shininess
909   aParams[4].y() = 0.0f; // transparency
910   theProgram->SetUniform (theCtx, theProgram->GetStateLocation (OpenGl_OCCT_FRONT_MATERIAL),
911                           5, aParams);
912 }
913
914 // =======================================================================
915 // function : PushAspectMarker
916 // purpose  :
917 // =======================================================================
918 static void PushAspectMarker (const Handle(OpenGl_Context)&       theCtx,
919                               const Handle(OpenGl_ShaderProgram)& theProgram,
920                               const OpenGl_AspectMarker*          theAspect)
921 {
922   theProgram->SetUniform (theCtx, theProgram->GetStateLocation (OpenGl_OCCT_TEXTURE_ENABLE),   TOn);
923   theProgram->SetUniform (theCtx, theProgram->GetStateLocation (OpenGl_OCCT_DISTINGUISH_MODE), TOff);
924   theProgram->SetUniform (theCtx, theProgram->GetStateLocation (OpenGl_OCCT_ACTIVE_SAMPLER),   0 /* GL_TEXTURE0 */);
925
926   const OpenGl_Vec4 aDiffuse (theAspect->Color().rgb[0],
927                               theAspect->Color().rgb[1],
928                               theAspect->Color().rgb[2],
929                               theAspect->Color().rgb[3]);
930   OpenGl_Vec4 aParams[5];
931   aParams[0] = THE_COLOR_BLACK_VEC4;
932   aParams[1] = THE_COLOR_BLACK_VEC4;
933   aParams[2] = aDiffuse;
934   aParams[3] = THE_COLOR_BLACK_VEC4;
935   aParams[4].x() = 0.0f; // shininess
936   aParams[4].y() = 0.0f; // transparency
937   theProgram->SetUniform (theCtx, theProgram->GetStateLocation (OpenGl_OCCT_FRONT_MATERIAL),
938                           5, aParams);
939 }
940
941 }; // nameless namespace
942
943 // =======================================================================
944 // function : PushMaterialState
945 // purpose  : Pushes current state of OCCT material to the program
946 // =======================================================================
947 void OpenGl_ShaderManager::PushMaterialState (const Handle(OpenGl_ShaderProgram)& theProgram) const
948 {
949   if (!myMaterialStates.IsBound (theProgram))
950   {
951     return;
952   }
953
954   const OpenGl_MaterialState& aState = myMaterialStates.Find (theProgram);
955   if (aState.Index() == theProgram->ActiveState (OpenGl_MATERIALS_STATE))
956   {
957     return;
958   }
959
960   if (typeid (*aState.Aspect()) == typeid (OpenGl_AspectFace))
961   {
962     PushAspectFace   (myContext, theProgram, dynamic_cast<const OpenGl_AspectFace*> (aState.Aspect()));
963   }
964   else if (typeid (*aState.Aspect()) == typeid (OpenGl_AspectLine))
965   {
966     PushAspectLine   (myContext, theProgram, dynamic_cast<const OpenGl_AspectLine*> (aState.Aspect()));
967   }
968   else if (typeid (*aState.Aspect()) == typeid (OpenGl_AspectText))
969   {
970     PushAspectText   (myContext, theProgram, dynamic_cast<const OpenGl_AspectText*> (aState.Aspect()));
971   }
972   else if (typeid (*aState.Aspect()) == typeid (OpenGl_AspectMarker))
973   {
974     PushAspectMarker (myContext, theProgram, dynamic_cast<const OpenGl_AspectMarker*> (aState.Aspect()));
975   }
976
977   theProgram->UpdateState (OpenGl_MATERIALS_STATE, aState.Index());
978 }
979
980 // =======================================================================
981 // function : PushWorldViewState
982 // purpose  : Pushes state of OCCT graphics parameters to the program
983 // =======================================================================
984 void OpenGl_ShaderManager::PushState (const Handle(OpenGl_ShaderProgram)& theProgram) const
985 {
986   PushClippingState    (theProgram);
987   PushMaterialState    (theProgram);
988   PushWorldViewState   (theProgram);
989   PushModelWorldState  (theProgram);
990   PushProjectionState  (theProgram);
991   PushLightSourceState (theProgram);
992 }
993
994 // =======================================================================
995 // function : prepareStdProgramFont
996 // purpose  :
997 // =======================================================================
998 Standard_Boolean OpenGl_ShaderManager::prepareStdProgramFont()
999 {
1000   Handle(Graphic3d_ShaderProgram) aProgramSrc = new Graphic3d_ShaderProgram();
1001   TCollection_AsciiString aSrcVert = TCollection_AsciiString()
1002      + THE_VARY_TexCoord
1003      + EOL"void main()"
1004        EOL"{"
1005        EOL"  TexCoord = occTexCoord.st;"
1006        EOL"  gl_Position = occProjectionMatrix * occWorldViewMatrix * occModelWorldMatrix * occVertex;"
1007        EOL"}";
1008
1009   TCollection_AsciiString aSrcFrag = TCollection_AsciiString() +
1010      + THE_VARY_TexCoord
1011      + EOL"float getAlpha(void) { return texture2D(occActiveSampler, TexCoord.st).a; }"
1012        EOL"void main()"
1013        EOL"{"
1014        EOL"  vec4 aColor = occColor;"
1015        EOL"  aColor.a *= getAlpha();"
1016        EOL"  if (aColor.a <= 0.285) discard;"
1017        EOL"  gl_FragColor = aColor;"
1018        EOL"}";
1019
1020   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_VERTEX,   aSrcVert));
1021   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_FRAGMENT, aSrcFrag));
1022   TCollection_AsciiString aKey;
1023   if (!Create (aProgramSrc, aKey, myFontProgram))
1024   {
1025     myFontProgram = new OpenGl_ShaderProgram(); // just mark as invalid
1026     return Standard_False;
1027   }
1028   return Standard_True;
1029 }
1030
1031 // =======================================================================
1032 // function : prepareStdProgramFlat
1033 // purpose  :
1034 // =======================================================================
1035 Standard_Boolean OpenGl_ShaderManager::prepareStdProgramFlat (Handle(OpenGl_ShaderProgram)& theProgram,
1036                                                               const Standard_Integer        theBits)
1037 {
1038   Handle(Graphic3d_ShaderProgram) aProgramSrc = new Graphic3d_ShaderProgram();
1039   TCollection_AsciiString aSrcVert, aSrcVertExtraOut, aSrcVertExtraMain, aSrcFrag, aSrcFragExtraOut, aSrcFragExtraMain;
1040   TCollection_AsciiString aSrcFragGetColor     = EOL"vec4 getColor(void) { return occColor; }";
1041   TCollection_AsciiString aSrcFragMainGetColor = EOL"  gl_FragColor = getColor();";
1042   if ((theBits & OpenGl_PO_Point) != 0)
1043   {
1044   #if defined(GL_ES_VERSION_2_0)
1045     aSrcVertExtraMain += EOL"  gl_PointSize = occPointSize;";
1046   #endif
1047     if ((theBits & OpenGl_PO_TextureA) != 0)
1048     {
1049       aSrcFragGetColor =
1050         EOL"float getAlpha(void) { return texture2D(occActiveSampler, gl_PointCoord).a; }"
1051         EOL"vec4  getColor(void)"
1052         EOL"{"
1053         EOL"  vec4 aColor = occColor;"
1054         EOL"  aColor.a *= getAlpha();"
1055         EOL"  return aColor;"
1056         EOL"}";
1057
1058       aSrcFragMainGetColor =
1059         EOL"  vec4 aColor = getColor();"
1060         EOL"  if (aColor.a <= 0.1) discard;"
1061         EOL"  gl_FragColor = aColor;";
1062     }
1063     else if ((theBits & OpenGl_PO_TextureRGB) != 0)
1064     {
1065       aSrcFragGetColor =
1066         EOL"vec4 getColor(void) { return texture2D(occActiveSampler, gl_PointCoord); }";
1067       aSrcFragMainGetColor =
1068         EOL"  vec4 aColor = getColor();"
1069         EOL"  if (aColor.a <= 0.1) discard;"
1070         EOL"  gl_FragColor = aColor;";
1071     }
1072   }
1073   else
1074   {
1075     if ((theBits & OpenGl_PO_TextureRGB) != 0)
1076     {
1077       aSrcVertExtraOut  += THE_VARY_TexCoord;
1078       aSrcFragExtraOut  += THE_VARY_TexCoord;
1079       aSrcVertExtraMain +=
1080         EOL"  TexCoord = occTexCoord.st;";
1081
1082       aSrcFragGetColor =
1083         EOL"vec4 getColor(void) { return texture2D(occActiveSampler, TexCoord.st); }";
1084     }
1085   }
1086   if ((theBits & OpenGl_PO_VertColor) != 0)
1087   {
1088     aSrcVertExtraOut  += THE_VARY_VertColor;
1089     aSrcVertExtraMain += EOL"  VertColor = occVertColor;";
1090     aSrcFragExtraOut  += THE_VARY_VertColor;
1091     aSrcFragGetColor  =  EOL"vec4 getColor(void) { return VertColor; }";
1092   }
1093   if ((theBits & OpenGl_PO_ClipPlanes) != 0)
1094   {
1095     const char THE_POS_VARY[] =
1096       EOL"varying vec4 PositionWorld;"
1097       EOL"varying vec4 Position;";
1098
1099     aSrcVertExtraOut  += THE_POS_VARY;
1100     aSrcFragExtraOut  += THE_POS_VARY;
1101     aSrcVertExtraMain +=
1102       EOL"  PositionWorld = occModelWorldMatrix * occVertex;"
1103       EOL"  Position      = occWorldViewMatrix * PositionWorld;";
1104     aSrcFragExtraMain += THE_FRAG_CLIP_PLANES;
1105   }
1106
1107   aSrcVert =
1108       aSrcVertExtraOut
1109     + EOL"void main()"
1110       EOL"{"
1111     + aSrcVertExtraMain
1112     + EOL"  gl_Position = occProjectionMatrix * occWorldViewMatrix * occModelWorldMatrix * occVertex;"
1113       EOL"}";
1114
1115   aSrcFrag =
1116       aSrcFragExtraOut
1117     + aSrcFragGetColor
1118     + EOL"void main()"
1119       EOL"{"
1120     + aSrcFragExtraMain
1121     + aSrcFragMainGetColor
1122     + EOL"}";
1123
1124   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_VERTEX,   aSrcVert));
1125   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_FRAGMENT, aSrcFrag));
1126
1127   TCollection_AsciiString aKey;
1128   if (!Create (aProgramSrc, aKey, theProgram))
1129   {
1130     theProgram = new OpenGl_ShaderProgram(); // just mark as invalid
1131     return Standard_False;
1132   }
1133   return Standard_True;
1134 }
1135
1136 // =======================================================================
1137 // function : stdComputeLighting
1138 // purpose  :
1139 // =======================================================================
1140 TCollection_AsciiString OpenGl_ShaderManager::stdComputeLighting (const Standard_Boolean theHasVertColor)
1141 {
1142   bool aLightsMap[Visual3d_TOLS_SPOT + 1] = { false, false, false, false };
1143   TCollection_AsciiString aLightsFunc, aLightsLoop;
1144   const OpenGl_ListOfLight* aLights = myLightSourceState.LightSources();
1145   if (aLights != NULL)
1146   {
1147     Standard_Integer anIndex = 0;
1148     for (OpenGl_ListOfLight::Iterator aLightIter (*aLights); aLightIter.More(); aLightIter.Next(), ++anIndex)
1149     {
1150       switch (aLightIter.Value().Type)
1151       {
1152         case Visual3d_TOLS_AMBIENT:
1153           --anIndex;
1154           break; // skip ambient
1155         case Visual3d_TOLS_DIRECTIONAL:
1156           aLightsLoop = aLightsLoop + EOL"    directionalLight (" + anIndex + ", theNormal, theView, theIsFront);";
1157           break;
1158         case Visual3d_TOLS_POSITIONAL:
1159           aLightsLoop = aLightsLoop + EOL"    pointLight (" + anIndex + ", theNormal, theView, aPoint, theIsFront);";
1160           break;
1161         case Visual3d_TOLS_SPOT:
1162           aLightsLoop = aLightsLoop + EOL"    spotLight (" + anIndex + ", theNormal, theView, aPoint, theIsFront);";
1163           break;
1164       }
1165
1166       bool& aTypeBit = aLightsMap[aLightIter.Value().Type];
1167       if (aTypeBit)
1168       {
1169         continue;
1170       }
1171
1172       aTypeBit = true;
1173       switch (aLightIter.Value().Type)
1174       {
1175         case Visual3d_TOLS_AMBIENT:     break;
1176         case Visual3d_TOLS_DIRECTIONAL: aLightsFunc += THE_FUNC_directionalLight; break;
1177         case Visual3d_TOLS_POSITIONAL:  aLightsFunc += THE_FUNC_pointLight;       break;
1178         case Visual3d_TOLS_SPOT:        aLightsFunc += THE_FUNC_spotLight;        break;
1179       }
1180     }
1181   }
1182
1183   TCollection_AsciiString aGetMatAmbient = "theIsFront ? occFrontMaterial_Ambient()  : occBackMaterial_Ambient();";
1184   TCollection_AsciiString aGetMatDiffuse = "theIsFront ? occFrontMaterial_Diffuse()  : occBackMaterial_Diffuse();";
1185   if (theHasVertColor)
1186   {
1187     aGetMatAmbient = "getVertColor();";
1188     aGetMatDiffuse = "getVertColor();";
1189   }
1190
1191   return TCollection_AsciiString()
1192     + THE_FUNC_lightDef
1193     + aLightsFunc
1194     + EOL
1195       EOL"vec4 computeLighting (in vec3 theNormal,"
1196       EOL"                      in vec3 theView,"
1197       EOL"                      in vec4 thePoint,"
1198       EOL"                      in bool theIsFront)"
1199       EOL"{"
1200       EOL"  Ambient  = occLightAmbient.rgb;"
1201       EOL"  Diffuse  = vec3 (0.0);"
1202       EOL"  Specular = vec3 (0.0);"
1203       EOL"  vec3 aPoint = thePoint.xyz / thePoint.w;"
1204     + aLightsLoop
1205     + EOL"  vec4 aMaterialAmbient  = " + aGetMatAmbient
1206     + EOL"  vec4 aMaterialDiffuse  = " + aGetMatDiffuse
1207     + EOL"  vec4 aMaterialSpecular = theIsFront ? occFrontMaterial_Specular() : occBackMaterial_Specular();"
1208       EOL"  vec4 aMaterialEmission = theIsFront ? occFrontMaterial_Emission() : occBackMaterial_Emission();"
1209       EOL"  return vec4 (Ambient,  1.0) * aMaterialAmbient"
1210       EOL"       + vec4 (Diffuse,  1.0) * aMaterialDiffuse"
1211       EOL"       + vec4 (Specular, 1.0) * aMaterialSpecular"
1212       EOL"                              + aMaterialEmission;"
1213       EOL"}";
1214 }
1215
1216 // =======================================================================
1217 // function : prepareStdProgramGouraud
1218 // purpose  :
1219 // =======================================================================
1220 Standard_Boolean OpenGl_ShaderManager::prepareStdProgramGouraud (Handle(OpenGl_ShaderProgram)& theProgram,
1221                                                                  const Standard_Integer        theBits)
1222 {
1223   Handle(Graphic3d_ShaderProgram) aProgramSrc = new Graphic3d_ShaderProgram();
1224   TCollection_AsciiString aSrcVert, aSrcVertColor, aSrcVertExtraOut, aSrcVertExtraMain, aSrcFrag, aSrcFragExtraOut, aSrcFragExtraMain;
1225   TCollection_AsciiString aSrcFragGetColor = EOL"vec4 getColor(void) { return gl_FrontFacing ? FrontColor : BackColor; }";
1226   if ((theBits & OpenGl_PO_Point) != 0)
1227   {
1228   #if defined(GL_ES_VERSION_2_0)
1229     aSrcVertExtraMain += EOL"  gl_PointSize = occPointSize;";
1230   #endif
1231   }
1232   if ((theBits & OpenGl_PO_VertColor) != 0)
1233   {
1234     aSrcVertColor = EOL"vec4 getVertColor(void) { return occVertColor; }";
1235   }
1236   if ((theBits & OpenGl_PO_Point) != 0)
1237   {
1238     if ((theBits & OpenGl_PO_TextureRGB) != 0)
1239     {
1240       aSrcFragGetColor =
1241         EOL"vec4 getColor(void)"
1242         EOL"{"
1243         EOL"  vec4 aColor = gl_FrontFacing ? FrontColor : BackColor;"
1244         EOL"  return texture2D(occActiveSampler, gl_PointCoord) * aColor;"
1245         EOL"}";
1246     }
1247   }
1248   else
1249   {
1250     if ((theBits & OpenGl_PO_TextureRGB) != 0)
1251     {
1252       aSrcVertExtraOut  += THE_VARY_TexCoord;
1253       aSrcFragExtraOut  += THE_VARY_TexCoord;
1254       aSrcVertExtraMain +=
1255         EOL"  TexCoord = occTexCoord.st;";
1256
1257       aSrcFragGetColor =
1258         EOL"vec4 getColor(void)"
1259         EOL"{"
1260         EOL"  vec4 aColor = gl_FrontFacing ? FrontColor : BackColor;"
1261         EOL"  return texture2D(occActiveSampler, TexCoord.st) * aColor;"
1262         EOL"}";
1263     }
1264   }
1265   if ((theBits & OpenGl_PO_ClipPlanes) != 0)
1266   {
1267     const char THE_POS_VARY[] =
1268       EOL"varying vec4 PositionWorld;"
1269       EOL"varying vec4 Position;";
1270
1271     aSrcVertExtraOut  += THE_POS_VARY;
1272     aSrcFragExtraOut  += THE_POS_VARY;
1273     aSrcVertExtraMain +=
1274       EOL"  PositionWorld = aPositionWorld;"
1275       EOL"  Position      = aPosition;";
1276     aSrcFragExtraMain += THE_FRAG_CLIP_PLANES;
1277   }
1278
1279   const TCollection_AsciiString aLights = stdComputeLighting ((theBits & OpenGl_PO_VertColor) != 0);
1280   aSrcVert = TCollection_AsciiString()
1281     + THE_FUNC_transformNormal
1282     + EOL
1283     + aSrcVertColor
1284     + aLights
1285     + EOL
1286       EOL"varying vec4 FrontColor;"
1287       EOL"varying vec4 BackColor;"
1288       EOL
1289     + aSrcVertExtraOut
1290     + EOL"void main()"
1291       EOL"{"
1292       EOL"  vec4 aPositionWorld = occModelWorldMatrix * occVertex;"
1293       EOL"  vec4 aPosition      = occWorldViewMatrix * aPositionWorld;"
1294       EOL"  vec3 aNormal        = transformNormal (occNormal);"
1295       EOL"  vec3 aView          = vec3 (0.0, 0.0, 1.0);"
1296       EOL"  FrontColor  = computeLighting (normalize (aNormal), normalize (aView), aPosition, true);"
1297       EOL"  BackColor   = computeLighting (normalize (aNormal), normalize (aView), aPosition, false);"
1298     + aSrcVertExtraMain
1299     + EOL"  gl_Position = occProjectionMatrix * occWorldViewMatrix * occModelWorldMatrix * occVertex;"
1300       EOL"}";
1301
1302   aSrcFrag = TCollection_AsciiString()
1303     + EOL"varying vec4 FrontColor;"
1304       EOL"varying vec4 BackColor;"
1305     + aSrcFragExtraOut
1306     + aSrcFragGetColor
1307     + EOL"void main()"
1308       EOL"{"
1309     + aSrcFragExtraMain
1310     + EOL"  gl_FragColor = getColor();"
1311       EOL"}";
1312
1313   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_VERTEX,   aSrcVert));
1314   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_FRAGMENT, aSrcFrag));
1315   TCollection_AsciiString aKey;
1316   if (!Create (aProgramSrc, aKey, theProgram))
1317   {
1318     theProgram = new OpenGl_ShaderProgram(); // just mark as invalid
1319     return Standard_False;
1320   }
1321   return Standard_True;
1322 }
1323
1324 // =======================================================================
1325 // function : prepareStdProgramPhong
1326 // purpose  :
1327 // =======================================================================
1328 Standard_Boolean OpenGl_ShaderManager::prepareStdProgramPhong (Handle(OpenGl_ShaderProgram)& theProgram,
1329                                                                const Standard_Integer        theBits)
1330 {
1331   #define thePhongCompLight "computeLighting (normalize (Normal), normalize (View), Position, gl_FrontFacing)"
1332
1333   Handle(Graphic3d_ShaderProgram) aProgramSrc = new Graphic3d_ShaderProgram();
1334   TCollection_AsciiString aSrcVert, aSrcVertExtraOut, aSrcVertExtraMain, aSrcFrag, aSrcFragExtraOut, aSrcFragGetVertColor, aSrcFragExtraMain;
1335   TCollection_AsciiString aSrcFragGetColor = EOL"vec4 getColor(void) { return " thePhongCompLight "; }";
1336   if ((theBits & OpenGl_PO_Point) != 0)
1337   {
1338   #if defined(GL_ES_VERSION_2_0)
1339     aSrcVertExtraMain += EOL"  gl_PointSize = occPointSize;";
1340   #endif
1341   }
1342   if ((theBits & OpenGl_PO_VertColor) != 0)
1343   {
1344     aSrcVertExtraOut  += THE_VARY_VertColor;
1345     aSrcVertExtraMain += EOL"  VertColor = occVertColor;";
1346     aSrcFragGetColor   = EOL"varying vec4 VertColor;"
1347                          EOL"vec4 getVertColor(void) { return VertColor; }";
1348   }
1349
1350   if ((theBits & OpenGl_PO_Point) != 0)
1351   {
1352     if ((theBits & OpenGl_PO_TextureRGB) != 0)
1353     {
1354       aSrcFragGetColor =
1355         EOL"vec4 getColor(void)"
1356         EOL"{"
1357         EOL"  vec4 aColor = " thePhongCompLight ";"
1358         EOL"  return texture2D(occActiveSampler, gl_PointCoord) * aColor;"
1359         EOL"}";
1360     }
1361   }
1362   else
1363   {
1364     if ((theBits & OpenGl_PO_TextureRGB) != 0)
1365     {
1366       aSrcVertExtraOut  += THE_VARY_TexCoord;
1367       aSrcFragExtraOut  += THE_VARY_TexCoord;
1368       aSrcVertExtraMain +=
1369         EOL"  TexCoord = occTexCoord.st;";
1370
1371       aSrcFragGetColor =
1372         EOL"vec4 getColor(void)"
1373         EOL"{"
1374         EOL"  vec4 aColor = " thePhongCompLight ";"
1375         EOL"  return texture2D(occActiveSampler, TexCoord.st) * aColor;"
1376         EOL"}";
1377     }
1378   }
1379
1380   if ((theBits & OpenGl_PO_ClipPlanes) != 0)
1381   {
1382     aSrcFragExtraMain += THE_FRAG_CLIP_PLANES;
1383   }
1384
1385   aSrcVert = TCollection_AsciiString()
1386     + THE_FUNC_transformNormal
1387     + EOL
1388       EOL"varying vec4 PositionWorld;"
1389       EOL"varying vec4 Position;"
1390       EOL"varying vec3 Normal;"
1391       EOL"varying vec3 View;"
1392       EOL
1393     + aSrcVertExtraOut
1394     + EOL"void main()"
1395       EOL"{"
1396       EOL"  PositionWorld = occModelWorldMatrix * occVertex;"
1397       EOL"  Position      = occWorldViewMatrix * PositionWorld;"
1398       EOL"  Normal        = transformNormal (occNormal);"
1399       EOL"  View          = vec3 (0.0, 0.0, 1.0);"
1400     + aSrcVertExtraMain
1401     + EOL"  gl_Position = occProjectionMatrix * occWorldViewMatrix * occModelWorldMatrix * occVertex;"
1402       EOL"}";
1403
1404   const TCollection_AsciiString aLights = stdComputeLighting ((theBits & OpenGl_PO_VertColor) != 0);
1405   aSrcFrag = TCollection_AsciiString()
1406     + EOL"varying vec4 PositionWorld;"
1407       EOL"varying vec4 Position;"
1408       EOL"varying vec3 Normal;"
1409       EOL"varying vec3 View;"
1410     + EOL
1411     + aSrcFragExtraOut
1412     + aSrcFragGetVertColor
1413     + aLights
1414     + aSrcFragGetColor
1415     + EOL
1416       EOL"void main()"
1417       EOL"{"
1418     + aSrcFragExtraMain
1419     + EOL"  gl_FragColor = getColor();"
1420       EOL"}";
1421
1422   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_VERTEX,   aSrcVert));
1423   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_FRAGMENT, aSrcFrag));
1424   TCollection_AsciiString aKey;
1425   if (!Create (aProgramSrc, aKey, theProgram))
1426   {
1427     theProgram = new OpenGl_ShaderProgram(); // just mark as invalid
1428     return Standard_False;
1429   }
1430   return Standard_True;
1431 }
1432
1433 // =======================================================================
1434 // function : bindProgramWithState
1435 // purpose  :
1436 // =======================================================================
1437 Standard_Boolean OpenGl_ShaderManager::bindProgramWithState (const Handle(OpenGl_ShaderProgram)& theProgram,
1438                                                              const OpenGl_Element*               theAspect)
1439 {
1440   if (!myContext->BindProgram (theProgram))
1441   {
1442     return Standard_False;
1443   }
1444   theProgram->ApplyVariables (myContext);
1445
1446   const OpenGl_MaterialState* aMaterialState = MaterialState (theProgram);
1447   if (aMaterialState == NULL || aMaterialState->Aspect() != theAspect)
1448   {
1449     UpdateMaterialStateTo (theProgram, theAspect);
1450   }
1451
1452   PushState (theProgram);
1453   return Standard_True;
1454 }