0029517: Visualization - introduce AlphaMode property defining alpha value handling...
[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 <Graphic3d_TextureParams.hxx>
19 #include <OpenGl_AspectFace.hxx>
20 #include <OpenGl_AspectLine.hxx>
21 #include <OpenGl_AspectMarker.hxx>
22 #include <OpenGl_AspectText.hxx>
23 #include <OpenGl_Clipping.hxx>
24 #include <OpenGl_Context.hxx>
25 #include <OpenGl_ShaderManager.hxx>
26 #include <OpenGl_ShaderProgram.hxx>
27 #include <OpenGl_Workspace.hxx>
28
29 #include <TCollection_ExtendedString.hxx>
30
31 IMPLEMENT_STANDARD_RTTIEXT(OpenGl_ShaderManager,Standard_Transient)
32
33 namespace
34 {
35   //! Number specifying maximum number of light sources to prepare a GLSL program with unrolled loop.
36   const Standard_Integer THE_NB_UNROLLED_LIGHTS_MAX = 32;
37
38   //! Compute the size of array storing holding light sources definition.
39   static Standard_Integer roundUpMaxLightSources (Standard_Integer theNbLights)
40   {
41     Standard_Integer aMaxLimit = THE_NB_UNROLLED_LIGHTS_MAX;
42     for (; aMaxLimit < theNbLights; aMaxLimit *= 2) {}
43     return aMaxLimit;
44   }
45
46 #define EOL "\n"
47
48 //! Definition of TexCoord varying.
49 const char THE_VARY_TexCoord_OUT[] =
50   EOL"THE_SHADER_OUT vec4 TexCoord;";
51 const char THE_VARY_TexCoord_IN[] =
52   EOL"THE_SHADER_IN  vec4 TexCoord;";
53 //! Compute TexCoord value in Vertex Shader
54 const char THE_VARY_TexCoord_Trsf[] =
55   EOL"  float aRotSin = occTextureTrsf_RotationSin();"
56   EOL"  float aRotCos = occTextureTrsf_RotationCos();"
57   EOL"  vec2  aTex2   = (occTexCoord.xy + occTextureTrsf_Translation()) * occTextureTrsf_Scale();"
58   EOL"  vec2  aCopy   = aTex2;"
59   EOL"  aTex2.x = aCopy.x * aRotCos - aCopy.y * aRotSin;"
60   EOL"  aTex2.y = aCopy.x * aRotSin + aCopy.y * aRotCos;"
61   EOL"  TexCoord = vec4(aTex2, occTexCoord.zw);";
62
63 //! Auxiliary function to flip gl_PointCoord vertically
64 #define THE_VEC2_glPointCoord "vec2 (gl_PointCoord.x, 1.0 - gl_PointCoord.y)"
65
66 //! Auxiliary function to transform normal
67 const char THE_FUNC_transformNormal[] =
68   EOL"vec3 transformNormal (in vec3 theNormal)"
69   EOL"{"
70   EOL"  vec4 aResult = occWorldViewMatrixInverseTranspose"
71   EOL"               * occModelWorldMatrixInverseTranspose"
72   EOL"               * vec4 (theNormal, 0.0);"
73   EOL"  return normalize (aResult.xyz);"
74   EOL"}";
75
76 //! Global shader variable for color definition with lighting enabled.
77 const char THE_FUNC_lightDef[] =
78   EOL"vec3 Ambient;"   //!< Ambient  contribution of light sources
79   EOL"vec3 Diffuse;"   //!< Diffuse  contribution of light sources
80   EOL"vec3 Specular;"; //!< Specular contribution of light sources
81
82 //! Function computes contribution of isotropic point light source
83 const char THE_FUNC_pointLight[] =
84   EOL"void pointLight (in int  theId,"
85   EOL"                 in vec3 theNormal,"
86   EOL"                 in vec3 theView,"
87   EOL"                 in vec3 thePoint,"
88   EOL"                 in bool theIsFront)"
89   EOL"{"
90   EOL"  vec3 aLight = occLight_Position (theId).xyz;"
91   EOL"  if (occLight_IsHeadlight (theId) == 0)"
92   EOL"  {"
93   EOL"    aLight = vec3 (occWorldViewMatrix * vec4 (aLight, 1.0));"
94   EOL"  }"
95   EOL"  aLight -= thePoint;"
96   EOL
97   EOL"  float aDist = length (aLight);"
98   EOL"  aLight = aLight * (1.0 / aDist);"
99   EOL
100   EOL"  float anAtten = 1.0 / (occLight_ConstAttenuation  (theId)"
101   EOL"                       + occLight_LinearAttenuation (theId) * aDist);"
102   EOL
103   EOL"  vec3 aHalf = normalize (aLight + theView);"
104   EOL
105   EOL"  vec3  aFaceSideNormal = theIsFront ? theNormal : -theNormal;"
106   EOL"  float aNdotL = max (0.0, dot (aFaceSideNormal, aLight));"
107   EOL"  float aNdotH = max (0.0, dot (aFaceSideNormal, aHalf ));"
108   EOL
109   EOL"  float aSpecl = 0.0;"
110   EOL"  if (aNdotL > 0.0)"
111   EOL"  {"
112   EOL"    aSpecl = pow (aNdotH, theIsFront ? occFrontMaterial_Shininess() : occBackMaterial_Shininess());"
113   EOL"  }"
114   EOL
115   EOL"Diffuse  += occLight_Diffuse  (theId).rgb * aNdotL * anAtten;"
116   EOL"Specular += occLight_Specular (theId).rgb * aSpecl * anAtten;"
117   EOL"}";
118
119 //! Function computes contribution of spotlight source
120 const char THE_FUNC_spotLight[] =
121   EOL"void spotLight (in int  theId,"
122   EOL"                in vec3 theNormal,"
123   EOL"                in vec3 theView,"
124   EOL"                in vec3 thePoint,"
125   EOL"                in bool theIsFront)"
126   EOL"{"
127   EOL"  vec3 aLight   = occLight_Position      (theId).xyz;"
128   EOL"  vec3 aSpotDir = occLight_SpotDirection (theId).xyz;"
129   EOL"  if (occLight_IsHeadlight (theId) == 0)"
130   EOL"  {"
131   EOL"    aLight   = vec3 (occWorldViewMatrix * vec4 (aLight,   1.0));"
132   EOL"    aSpotDir = vec3 (occWorldViewMatrix * vec4 (aSpotDir, 0.0));"
133   EOL"  }"
134   EOL"  aLight -= thePoint;"
135   EOL
136   EOL"  float aDist = length (aLight);"
137   EOL"  aLight = aLight * (1.0 / aDist);"
138   EOL
139   EOL"  aSpotDir = normalize (aSpotDir);"
140   // light cone
141   EOL"  float aCosA = dot (aSpotDir, -aLight);"
142   EOL"  if (aCosA >= 1.0 || aCosA < cos (occLight_SpotCutOff (theId)))"
143   EOL"  {"
144   EOL"    return;"
145   EOL"  }"
146   EOL
147   EOL"  float anExponent = occLight_SpotExponent (theId);"
148   EOL"  float anAtten    = 1.0 / (occLight_ConstAttenuation  (theId)"
149   EOL"                          + occLight_LinearAttenuation (theId) * aDist);"
150   EOL"  if (anExponent > 0.0)"
151   EOL"  {"
152   EOL"    anAtten *= pow (aCosA, anExponent * 128.0);"
153   EOL"  }"
154   EOL
155   EOL"  vec3 aHalf = normalize (aLight + theView);"
156   EOL
157   EOL"  vec3  aFaceSideNormal = theIsFront ? theNormal : -theNormal;"
158   EOL"  float aNdotL = max (0.0, dot (aFaceSideNormal, aLight));"
159   EOL"  float aNdotH = max (0.0, dot (aFaceSideNormal, aHalf ));"
160   EOL
161   EOL"  float aSpecl = 0.0;"
162   EOL"  if (aNdotL > 0.0)"
163   EOL"  {"
164   EOL"    aSpecl = pow (aNdotH, theIsFront ? occFrontMaterial_Shininess() : occBackMaterial_Shininess());"
165   EOL"  }"
166   EOL
167   EOL"  Diffuse  += occLight_Diffuse  (theId).rgb * aNdotL * anAtten;"
168   EOL"  Specular += occLight_Specular (theId).rgb * aSpecl * anAtten;"
169   EOL"}";
170
171 //! Function computes contribution of directional light source
172 const char THE_FUNC_directionalLight[] =
173   EOL"void directionalLight (in int  theId,"
174   EOL"                       in vec3 theNormal,"
175   EOL"                       in vec3 theView,"
176   EOL"                       in bool theIsFront)"
177   EOL"{"
178   EOL"  vec3 aLight = normalize (occLight_Position (theId).xyz);"
179   EOL"  if (occLight_IsHeadlight (theId) == 0)"
180   EOL"  {"
181   EOL"    aLight = vec3 (occWorldViewMatrix * vec4 (aLight, 0.0));"
182   EOL"  }"
183   EOL
184   EOL"  vec3 aHalf = normalize (aLight + theView);"
185   EOL
186   EOL"  vec3  aFaceSideNormal = theIsFront ? theNormal : -theNormal;"
187   EOL"  float aNdotL = max (0.0, dot (aFaceSideNormal, aLight));"
188   EOL"  float aNdotH = max (0.0, dot (aFaceSideNormal, aHalf ));"
189   EOL
190   EOL"  float aSpecl = 0.0;"
191   EOL"  if (aNdotL > 0.0)"
192   EOL"  {"
193   EOL"    aSpecl = pow (aNdotH, theIsFront ? occFrontMaterial_Shininess() : occBackMaterial_Shininess());"
194   EOL"  }"
195   EOL
196   EOL"  Diffuse  += occLight_Diffuse  (theId).rgb * aNdotL;"
197   EOL"  Specular += occLight_Specular (theId).rgb * aSpecl;"
198   EOL"}";
199
200 //! The same as THE_FUNC_directionalLight but for the light with zero index
201 //! (avoids limitations on some mobile devices).
202 const char THE_FUNC_directionalLightFirst[] =
203   EOL"void directionalLightFirst (in vec3 theNormal,"
204   EOL"                            in vec3 theView,"
205   EOL"                            in bool theIsFront)"
206   EOL"{"
207   EOL"  vec3 aLight = normalize (occLightSources[1].xyz);"
208   EOL"  if (occLight_IsHeadlight (0) == 0)"
209   EOL"  {"
210   EOL"    aLight = vec3 (occWorldViewMatrix * vec4 (aLight, 0.0));"
211   EOL"  }"
212   EOL
213   EOL"  vec3 aHalf = normalize (aLight + theView);"
214   EOL
215   EOL"  vec3  aFaceSideNormal = theIsFront ? theNormal : -theNormal;"
216   EOL"  float aNdotL = max (0.0, dot (aFaceSideNormal, aLight));"
217   EOL"  float aNdotH = max (0.0, dot (aFaceSideNormal, aHalf ));"
218   EOL
219   EOL"  float aSpecl = 0.0;"
220   EOL"  if (aNdotL > 0.0)"
221   EOL"  {"
222   EOL"    aSpecl = pow (aNdotH, theIsFront ? occFrontMaterial_Shininess() : occBackMaterial_Shininess());"
223   EOL"  }"
224   EOL
225   EOL"  Diffuse  += occLightSources[0].rgb * aNdotL;"
226   EOL"  Specular += occLightSources[0].rgb * aSpecl;"
227   EOL"}";
228
229 //! Process clipping planes in Fragment Shader.
230 //! Should be added at the beginning of the main() function.
231 const char THE_FRAG_CLIP_PLANES_N[] =
232   EOL"  for (int aPlaneIter = 0; aPlaneIter < occClipPlaneCount; ++aPlaneIter)"
233   EOL"  {"
234   EOL"    vec4 aClipEquation = occClipPlaneEquations[aPlaneIter];"
235   EOL"    if (dot (aClipEquation.xyz, PositionWorld.xyz / PositionWorld.w) + aClipEquation.w < 0.0)"
236   EOL"    {"
237   EOL"      discard;"
238   EOL"    }"
239   EOL"  }";
240
241 //! Process 1 clipping plane in Fragment Shader.
242 const char THE_FRAG_CLIP_PLANES_1[] =
243   EOL"  vec4 aClipEquation0 = occClipPlaneEquations[0];"
244   EOL"  if (dot (aClipEquation0.xyz, PositionWorld.xyz / PositionWorld.w) + aClipEquation0.w < 0.0)"
245   EOL"  {"
246   EOL"    discard;"
247   EOL"  }";
248
249 //! Process 2 clipping planes in Fragment Shader.
250 const char THE_FRAG_CLIP_PLANES_2[] =
251   EOL"  vec4 aClipEquation0 = occClipPlaneEquations[0];"
252   EOL"  vec4 aClipEquation1 = occClipPlaneEquations[1];"
253   EOL"  if (dot (aClipEquation0.xyz, PositionWorld.xyz / PositionWorld.w) + aClipEquation0.w < 0.0"
254   EOL"   || dot (aClipEquation1.xyz, PositionWorld.xyz / PositionWorld.w) + aClipEquation1.w < 0.0)"
255   EOL"  {"
256   EOL"    discard;"
257   EOL"  }";
258
259 #if !defined(GL_ES_VERSION_2_0)
260
261   static const GLfloat THE_DEFAULT_AMBIENT[4]    = { 0.0f, 0.0f, 0.0f, 1.0f };
262   static const GLfloat THE_DEFAULT_SPOT_DIR[3]   = { 0.0f, 0.0f, -1.0f };
263   static const GLfloat THE_DEFAULT_SPOT_EXPONENT = 0.0f;
264   static const GLfloat THE_DEFAULT_SPOT_CUTOFF   = 180.0f;
265
266   //! Bind FFP light source.
267   static void bindLight (const Graphic3d_CLight& theLight,
268                          const GLenum        theLightGlId,
269                          const OpenGl_Mat4&  theModelView,
270                          OpenGl_Context*     theCtx)
271   {
272     // the light is a headlight?
273     if (theLight.IsHeadlight())
274     {
275       theCtx->core11->glMatrixMode (GL_MODELVIEW);
276       theCtx->core11->glLoadIdentity();
277     }
278
279     // setup light type
280     const Graphic3d_Vec4& aLightColor = theLight.PackedColor();
281     switch (theLight.Type())
282     {
283       case Graphic3d_TOLS_AMBIENT    : break; // handled by separate if-clause at beginning of method
284       case Graphic3d_TOLS_DIRECTIONAL:
285       {
286         // if the last parameter of GL_POSITION, is zero, the corresponding light source is a Directional one
287         const OpenGl_Vec4 anInfDir = -theLight.PackedDirection();
288
289         // to create a realistic effect,  set the GL_SPECULAR parameter to the same value as the GL_DIFFUSE.
290         theCtx->core11->glLightfv (theLightGlId, GL_AMBIENT,               THE_DEFAULT_AMBIENT);
291         theCtx->core11->glLightfv (theLightGlId, GL_DIFFUSE,               aLightColor.GetData());
292         theCtx->core11->glLightfv (theLightGlId, GL_SPECULAR,              aLightColor.GetData());
293         theCtx->core11->glLightfv (theLightGlId, GL_POSITION,              anInfDir.GetData());
294         theCtx->core11->glLightfv (theLightGlId, GL_SPOT_DIRECTION,        THE_DEFAULT_SPOT_DIR);
295         theCtx->core11->glLightf  (theLightGlId, GL_SPOT_EXPONENT,         THE_DEFAULT_SPOT_EXPONENT);
296         theCtx->core11->glLightf  (theLightGlId, GL_SPOT_CUTOFF,           THE_DEFAULT_SPOT_CUTOFF);
297         break;
298       }
299       case Graphic3d_TOLS_POSITIONAL:
300       {
301         // to create a realistic effect, set the GL_SPECULAR parameter to the same value as the GL_DIFFUSE
302         const OpenGl_Vec4 aPosition (static_cast<float>(theLight.Position().X()), static_cast<float>(theLight.Position().Y()), static_cast<float>(theLight.Position().Z()), 1.0f);
303         theCtx->core11->glLightfv (theLightGlId, GL_AMBIENT,               THE_DEFAULT_AMBIENT);
304         theCtx->core11->glLightfv (theLightGlId, GL_DIFFUSE,               aLightColor.GetData());
305         theCtx->core11->glLightfv (theLightGlId, GL_SPECULAR,              aLightColor.GetData());
306         theCtx->core11->glLightfv (theLightGlId, GL_POSITION,              aPosition.GetData());
307         theCtx->core11->glLightfv (theLightGlId, GL_SPOT_DIRECTION,        THE_DEFAULT_SPOT_DIR);
308         theCtx->core11->glLightf  (theLightGlId, GL_SPOT_EXPONENT,         THE_DEFAULT_SPOT_EXPONENT);
309         theCtx->core11->glLightf  (theLightGlId, GL_SPOT_CUTOFF,           THE_DEFAULT_SPOT_CUTOFF);
310         theCtx->core11->glLightf  (theLightGlId, GL_CONSTANT_ATTENUATION,  theLight.ConstAttenuation());
311         theCtx->core11->glLightf  (theLightGlId, GL_LINEAR_ATTENUATION,    theLight.LinearAttenuation());
312         theCtx->core11->glLightf  (theLightGlId, GL_QUADRATIC_ATTENUATION, 0.0);
313         break;
314       }
315       case Graphic3d_TOLS_SPOT:
316       {
317         const OpenGl_Vec4 aPosition (static_cast<float>(theLight.Position().X()), static_cast<float>(theLight.Position().Y()), static_cast<float>(theLight.Position().Z()), 1.0f);
318         theCtx->core11->glLightfv (theLightGlId, GL_AMBIENT,               THE_DEFAULT_AMBIENT);
319         theCtx->core11->glLightfv (theLightGlId, GL_DIFFUSE,               aLightColor.GetData());
320         theCtx->core11->glLightfv (theLightGlId, GL_SPECULAR,              aLightColor.GetData());
321         theCtx->core11->glLightfv (theLightGlId, GL_POSITION,              aPosition.GetData());
322         theCtx->core11->glLightfv (theLightGlId, GL_SPOT_DIRECTION,        theLight.PackedDirection().GetData());
323         theCtx->core11->glLightf  (theLightGlId, GL_SPOT_EXPONENT,         theLight.Concentration() * 128.0f);
324         theCtx->core11->glLightf  (theLightGlId, GL_SPOT_CUTOFF,          (theLight.Angle() * 180.0f) / GLfloat(M_PI));
325         theCtx->core11->glLightf  (theLightGlId, GL_CONSTANT_ATTENUATION,  theLight.ConstAttenuation());
326         theCtx->core11->glLightf  (theLightGlId, GL_LINEAR_ATTENUATION,    theLight.LinearAttenuation());
327         theCtx->core11->glLightf  (theLightGlId, GL_QUADRATIC_ATTENUATION, 0.0f);
328         break;
329       }
330     }
331
332     // restore matrix in case of headlight
333     if (theLight.IsHeadlight())
334     {
335       theCtx->core11->glLoadMatrixf (theModelView.GetData());
336     }
337
338     glEnable (theLightGlId);
339   }
340 #endif
341
342 }
343
344 // =======================================================================
345 // function : OpenGl_ShaderManager
346 // purpose  : Creates new empty shader manager
347 // =======================================================================
348 OpenGl_ShaderManager::OpenGl_ShaderManager (OpenGl_Context* theContext)
349 : myFfpProgram (new OpenGl_ShaderProgramFFP()),
350   myShadingModel (Graphic3d_TOSM_VERTEX),
351   myUnlitPrograms (new OpenGl_SetOfShaderPrograms()),
352   myContext  (theContext),
353   myHasLocalOrigin (Standard_False),
354   myLastView (NULL)
355 {
356   //
357 }
358
359 // =======================================================================
360 // function : ~OpenGl_ShaderManager
361 // purpose  : Releases resources of shader manager
362 // =======================================================================
363 OpenGl_ShaderManager::~OpenGl_ShaderManager()
364 {
365   myProgramList.Clear();
366 }
367
368 // =======================================================================
369 // function : clear
370 // purpose  :
371 // =======================================================================
372 void OpenGl_ShaderManager::clear()
373 {
374   myProgramList.Clear();
375   myLightPrograms.Nullify();
376   myUnlitPrograms = new OpenGl_SetOfShaderPrograms();
377   myMapOfLightPrograms.Clear();
378   myFontProgram.Nullify();
379   myBlitProgram.Nullify();
380   for (Standard_Integer aModeIter = 0; aModeIter < Graphic3d_StereoMode_NB; ++aModeIter)
381   {
382     myStereoPrograms[aModeIter].Nullify();
383   }
384   switchLightPrograms();
385 }
386
387 // =======================================================================
388 // function : Create
389 // purpose  : Creates new shader program
390 // =======================================================================
391 Standard_Boolean OpenGl_ShaderManager::Create (const Handle(Graphic3d_ShaderProgram)& theProxy,
392                                                TCollection_AsciiString&               theShareKey,
393                                                Handle(OpenGl_ShaderProgram)&          theProgram)
394 {
395   theProgram.Nullify();
396   if (theProxy.IsNull())
397   {
398     return Standard_False;
399   }
400
401   theShareKey = theProxy->GetId();
402   if (myContext->GetResource<Handle(OpenGl_ShaderProgram)> (theShareKey, theProgram))
403   {
404     if (theProgram->Share())
405     {
406       myProgramList.Append (theProgram);
407     }
408     return Standard_True;
409   }
410
411   theProgram = new OpenGl_ShaderProgram (theProxy);
412   if (!theProgram->Initialize (myContext, theProxy->ShaderObjects()))
413   {
414     theProgram->Release (myContext);
415     theShareKey.Clear();
416     theProgram.Nullify();
417     return Standard_False;
418   }
419
420   myProgramList.Append (theProgram);
421   myContext->ShareResource (theShareKey, theProgram);
422   return Standard_True;
423 }
424
425 // =======================================================================
426 // function : Unregister
427 // purpose  : Removes specified shader program from the manager
428 // =======================================================================
429 void OpenGl_ShaderManager::Unregister (TCollection_AsciiString&      theShareKey,
430                                        Handle(OpenGl_ShaderProgram)& theProgram)
431 {
432   for (OpenGl_ShaderProgramList::Iterator anIt (myProgramList); anIt.More(); anIt.Next())
433   {
434     if (anIt.Value() == theProgram)
435     {
436       if (!theProgram->UnShare())
437       {
438         theShareKey.Clear();
439         theProgram.Nullify();
440         return;
441       }
442
443       myProgramList.Remove (anIt);
444       break;
445     }
446   }
447
448   const TCollection_AsciiString anID = theProgram->myProxy->GetId();
449   if (anID.IsEmpty())
450   {
451     myContext->DelayedRelease (theProgram);
452     theProgram.Nullify();
453   }
454   else
455   {
456     theProgram.Nullify();
457     myContext->ReleaseResource (anID, Standard_True);
458   }
459 }
460
461 // =======================================================================
462 // function : ShaderPrograms
463 // purpose  : Returns list of registered shader programs
464 // =======================================================================
465 const OpenGl_ShaderProgramList& OpenGl_ShaderManager::ShaderPrograms() const
466 {
467   return myProgramList;
468 }
469
470 // =======================================================================
471 // function : Empty
472 // purpose  : Returns true if no program objects are attached
473 // =======================================================================
474 Standard_Boolean OpenGl_ShaderManager::IsEmpty() const
475 {
476   return myProgramList.IsEmpty();
477 }
478
479 // =======================================================================
480 // function : switchLightPrograms
481 // purpose  :
482 // =======================================================================
483 void OpenGl_ShaderManager::switchLightPrograms()
484 {
485   const Handle(Graphic3d_LightSet)& aLights = myLightSourceState.LightSources();
486   if (aLights.IsNull())
487   {
488     myLightPrograms = myUnlitPrograms;
489     return;
490   }
491
492   TCollection_AsciiString aKey ("l_");
493   if (aLights->NbEnabled() <= THE_NB_UNROLLED_LIGHTS_MAX)
494   {
495     aKey += aLights->KeyEnabledLong();
496   }
497   else
498   {
499     const Standard_Integer aMaxLimit = roundUpMaxLightSources (aLights->NbEnabled());
500     aKey += aLights->KeyEnabledShort();
501     aKey += aMaxLimit;
502   }
503
504   if (!myMapOfLightPrograms.Find (aKey, myLightPrograms))
505   {
506     myLightPrograms = new OpenGl_SetOfShaderPrograms();
507     myMapOfLightPrograms.Bind (aKey, myLightPrograms);
508   }
509 }
510
511 // =======================================================================
512 // function : UpdateLightSourceStateTo
513 // purpose  : Updates state of OCCT light sources
514 // =======================================================================
515 void OpenGl_ShaderManager::UpdateLightSourceStateTo (const Handle(Graphic3d_LightSet)& theLights)
516 {
517   myLightSourceState.Set (theLights);
518   myLightSourceState.Update();
519   switchLightPrograms();
520 }
521
522 // =======================================================================
523 // function : UpdateLightSourceState
524 // purpose  :
525 // =======================================================================
526 void OpenGl_ShaderManager::UpdateLightSourceState()
527 {
528   myLightSourceState.Update();
529 }
530
531 // =======================================================================
532 // function : SetShadingModel
533 // purpose  :
534 // =======================================================================
535 void OpenGl_ShaderManager::SetShadingModel (const Graphic3d_TypeOfShadingModel theModel)
536 {
537   if (theModel == Graphic3d_TOSM_DEFAULT)
538   {
539     throw Standard_ProgramError ("OpenGl_ShaderManager::SetShadingModel() - attempt to set invalid Shading Model!");
540   }
541
542   myShadingModel = theModel;
543   switchLightPrograms();
544 }
545
546 // =======================================================================
547 // function : SetProjectionState
548 // purpose  : Sets new state of OCCT projection transform
549 // =======================================================================
550 void OpenGl_ShaderManager::UpdateProjectionStateTo (const OpenGl_Mat4& theProjectionMatrix)
551 {
552   myProjectionState.Set (theProjectionMatrix);
553   myProjectionState.Update();
554 }
555
556 // =======================================================================
557 // function : SetModelWorldState
558 // purpose  : Sets new state of OCCT model-world transform
559 // =======================================================================
560 void OpenGl_ShaderManager::UpdateModelWorldStateTo (const OpenGl_Mat4& theModelWorldMatrix)
561 {
562   myModelWorldState.Set (theModelWorldMatrix);
563   myModelWorldState.Update();
564 }
565
566 // =======================================================================
567 // function : SetWorldViewState
568 // purpose  : Sets new state of OCCT world-view transform
569 // =======================================================================
570 void OpenGl_ShaderManager::UpdateWorldViewStateTo (const OpenGl_Mat4& theWorldViewMatrix)
571 {
572   myWorldViewState.Set (theWorldViewMatrix);
573   myWorldViewState.Update();
574 }
575
576 // =======================================================================
577 // function : PushLightSourceState
578 // purpose  : Pushes state of OCCT light sources to the program
579 // =======================================================================
580 void OpenGl_ShaderManager::PushLightSourceState (const Handle(OpenGl_ShaderProgram)& theProgram) const
581 {
582   if (myLightSourceState.Index() == theProgram->ActiveState (OpenGl_LIGHT_SOURCES_STATE))
583   {
584     return;
585   }
586
587   theProgram->UpdateState (OpenGl_LIGHT_SOURCES_STATE, myLightSourceState.Index());
588   if (theProgram == myFfpProgram)
589   {
590   #if !defined(GL_ES_VERSION_2_0)
591     if (myContext->core11 == NULL)
592     {
593       return;
594     }
595
596     GLenum aLightGlId = GL_LIGHT0;
597     const OpenGl_Mat4 aModelView = myWorldViewState.WorldViewMatrix() * myModelWorldState.ModelWorldMatrix();
598     for (Graphic3d_LightSet::Iterator aLightIt (myLightSourceState.LightSources(), Graphic3d_LightSet::IterationFilter_ExcludeDisabledAndAmbient);
599          aLightIt.More(); aLightIt.Next())
600     {
601       if (aLightGlId > GL_LIGHT7) // only 8 lights in FFP...
602       {
603         myContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_MEDIUM,
604                                 "Warning: light sources limit (8) has been exceeded within Fixed-function pipeline.");
605         continue;
606       }
607
608       bindLight (*aLightIt.Value(), aLightGlId, aModelView, myContext);
609       ++aLightGlId;
610     }
611
612     // apply accumulated ambient color
613     const Graphic3d_Vec4 anAmbient = !myLightSourceState.LightSources().IsNull()
614                                     ? myLightSourceState.LightSources()->AmbientColor()
615                                     : Graphic3d_Vec4 (0.0f, 0.0f, 0.0f, 1.0f);
616     myContext->core11->glLightModelfv (GL_LIGHT_MODEL_AMBIENT, anAmbient.GetData());
617
618     // GL_LIGHTING is managed by drawers to switch between shaded / no lighting output,
619     // therefore managing the state here does not have any effect - do it just for consistency.
620     if (aLightGlId != GL_LIGHT0)
621     {
622       ::glEnable (GL_LIGHTING);
623     }
624     else
625     {
626       ::glDisable (GL_LIGHTING);
627     }
628     // switch off unused lights
629     for (; aLightGlId <= GL_LIGHT7; ++aLightGlId)
630     {
631       ::glDisable (aLightGlId);
632     }
633   #endif
634     return;
635   }
636
637   const Standard_Integer aNbLightsMax = theProgram->NbLightsMax();
638   const GLint anAmbientLoc = theProgram->GetStateLocation (OpenGl_OCC_LIGHT_AMBIENT);
639   if (aNbLightsMax == 0
640    && anAmbientLoc == OpenGl_ShaderProgram::INVALID_LOCATION)
641   {
642     return;
643   }
644
645   if (myLightTypeArray.Size() < aNbLightsMax)
646   {
647     myLightTypeArray  .Resize (0, aNbLightsMax - 1, false);
648     myLightParamsArray.Resize (0, aNbLightsMax - 1, false);
649   }
650   for (Standard_Integer aLightIt = 0; aLightIt < aNbLightsMax; ++aLightIt)
651   {
652     myLightTypeArray.ChangeValue (aLightIt).Type = -1;
653   }
654
655   if (myLightSourceState.LightSources().IsNull()
656    || myLightSourceState.LightSources()->IsEmpty())
657   {
658     theProgram->SetUniform (myContext,
659                             theProgram->GetStateLocation (OpenGl_OCC_LIGHT_SOURCE_COUNT),
660                             0);
661     theProgram->SetUniform (myContext,
662                             anAmbientLoc,
663                             OpenGl_Vec4 (0.0f, 0.0f, 0.0f, 0.0f));
664     theProgram->SetUniform (myContext,
665                             theProgram->GetStateLocation (OpenGl_OCC_LIGHT_SOURCE_TYPES),
666                             aNbLightsMax * OpenGl_ShaderLightType::NbOfVec2i(),
667                             myLightTypeArray.First().Packed());
668     return;
669   }
670
671   Standard_Integer aLightsNb = 0;
672   for (Graphic3d_LightSet::Iterator anIter (myLightSourceState.LightSources(), Graphic3d_LightSet::IterationFilter_ExcludeDisabledAndAmbient);
673        anIter.More(); anIter.Next())
674   {
675     const Graphic3d_CLight& aLight = *anIter.Value();
676     if (aLightsNb >= aNbLightsMax)
677     {
678       if (aNbLightsMax != 0)
679       {
680         myContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_MEDIUM,
681                                 TCollection_AsciiString("Warning: light sources limit (") + aNbLightsMax + ") has been exceeded.");
682       }
683       continue;
684     }
685
686     OpenGl_ShaderLightType&       aLightType   = myLightTypeArray.ChangeValue (aLightsNb);
687     OpenGl_ShaderLightParameters& aLightParams = myLightParamsArray.ChangeValue (aLightsNb);
688     if (!aLight.IsEnabled()) // has no affect with Graphic3d_LightSet::IterationFilter_ExcludeDisabled - here just for consistency
689     {
690       // if it is desired to keep disabled light in the same order - we can replace it with a black light so that it will have no influence on result
691       aLightType.Type        = -1; // Graphic3d_TOLS_AMBIENT can be used instead
692       aLightType.IsHeadlight = false;
693       aLightParams.Color     = OpenGl_Vec4 (0.0f, 0.0f, 0.0f, 0.0f);
694       ++aLightsNb;
695       continue;
696     }
697
698     aLightType.Type        = aLight.Type();
699     aLightType.IsHeadlight = aLight.IsHeadlight();
700     aLightParams.Color     = aLight.PackedColor();
701     if (aLight.Type() == Graphic3d_TOLS_DIRECTIONAL)
702     {
703       aLightParams.Position = -aLight.PackedDirection();
704     }
705     else if (!aLight.IsHeadlight())
706     {
707       aLightParams.Position.x() = static_cast<float>(aLight.Position().X() - myLocalOrigin.X());
708       aLightParams.Position.y() = static_cast<float>(aLight.Position().Y() - myLocalOrigin.Y());
709       aLightParams.Position.z() = static_cast<float>(aLight.Position().Z() - myLocalOrigin.Z());
710       aLightParams.Position.w() = 1.0f;
711     }
712     else
713     {
714       aLightParams.Position.x() = static_cast<float>(aLight.Position().X());
715       aLightParams.Position.y() = static_cast<float>(aLight.Position().Y());
716       aLightParams.Position.z() = static_cast<float>(aLight.Position().Z());
717       aLightParams.Position.w() = 1.0f;
718     }
719
720     if (aLight.Type() == Graphic3d_TOLS_SPOT)
721     {
722       aLightParams.Direction = aLight.PackedDirection();
723     }
724     aLightParams.Parameters = aLight.PackedParams();
725     ++aLightsNb;
726   }
727
728   const Graphic3d_Vec4& anAmbient = myLightSourceState.LightSources()->AmbientColor();
729   theProgram->SetUniform (myContext,
730                           theProgram->GetStateLocation (OpenGl_OCC_LIGHT_SOURCE_COUNT),
731                           aLightsNb);
732   theProgram->SetUniform (myContext,
733                           anAmbientLoc,
734                           anAmbient);
735   theProgram->SetUniform (myContext,
736                           theProgram->GetStateLocation (OpenGl_OCC_LIGHT_SOURCE_TYPES),
737                           aNbLightsMax * OpenGl_ShaderLightType::NbOfVec2i(),
738                           myLightTypeArray.First().Packed());
739   if (aLightsNb > 0)
740   {
741     theProgram->SetUniform (myContext,
742                             theProgram->GetStateLocation (OpenGl_OCC_LIGHT_SOURCE_PARAMS),
743                             aLightsNb * OpenGl_ShaderLightParameters::NbOfVec4(),
744                             myLightParamsArray.First().Packed());
745   }
746 }
747
748 // =======================================================================
749 // function : PushProjectionState
750 // purpose  : Pushes state of OCCT projection transform to the program
751 // =======================================================================
752 void OpenGl_ShaderManager::PushProjectionState (const Handle(OpenGl_ShaderProgram)& theProgram) const
753 {
754   if (myProjectionState.Index() == theProgram->ActiveState (OpenGl_PROJECTION_STATE))
755   {
756     return;
757   }
758
759   theProgram->UpdateState (OpenGl_PROJECTION_STATE, myProjectionState.Index());
760   if (theProgram == myFfpProgram)
761   {
762   #if !defined(GL_ES_VERSION_2_0)
763     if (myContext->core11 != NULL)
764     {
765       myContext->core11->glMatrixMode (GL_PROJECTION);
766       myContext->core11->glLoadMatrixf (myProjectionState.ProjectionMatrix());
767     }
768   #endif
769     return;
770   }
771
772   theProgram->SetUniform (myContext,
773                           theProgram->GetStateLocation (OpenGl_OCC_PROJECTION_MATRIX),
774                           myProjectionState.ProjectionMatrix());
775
776   GLint aLocation = theProgram->GetStateLocation (OpenGl_OCC_PROJECTION_MATRIX_INVERSE);
777   if (aLocation != OpenGl_ShaderProgram::INVALID_LOCATION)
778   {
779     theProgram->SetUniform (myContext, aLocation, myProjectionState.ProjectionMatrixInverse());
780   }
781
782   theProgram->SetUniform (myContext,
783                           theProgram->GetStateLocation (OpenGl_OCC_PROJECTION_MATRIX_TRANSPOSE),
784                           myProjectionState.ProjectionMatrix(), true);
785
786   aLocation = theProgram->GetStateLocation (OpenGl_OCC_PROJECTION_MATRIX_INVERSE_TRANSPOSE);
787   if (aLocation != OpenGl_ShaderProgram::INVALID_LOCATION)
788   {
789     theProgram->SetUniform (myContext, aLocation, myProjectionState.ProjectionMatrixInverse(), true);
790   }
791 }
792
793 // =======================================================================
794 // function : PushModelWorldState
795 // purpose  : Pushes state of OCCT model-world transform to the program
796 // =======================================================================
797 void OpenGl_ShaderManager::PushModelWorldState (const Handle(OpenGl_ShaderProgram)& theProgram) const
798 {
799   if (myModelWorldState.Index() == theProgram->ActiveState (OpenGl_MODEL_WORLD_STATE))
800   {
801     return;
802   }
803
804   theProgram->UpdateState (OpenGl_MODEL_WORLD_STATE, myModelWorldState.Index());
805   if (theProgram == myFfpProgram)
806   {
807   #if !defined(GL_ES_VERSION_2_0)
808     if (myContext->core11 != NULL)
809     {
810       const OpenGl_Mat4 aModelView = myWorldViewState.WorldViewMatrix() * myModelWorldState.ModelWorldMatrix();
811       myContext->core11->glMatrixMode (GL_MODELVIEW);
812       myContext->core11->glLoadMatrixf (aModelView.GetData());
813       theProgram->UpdateState (OpenGl_WORLD_VIEW_STATE, myWorldViewState.Index());
814     }
815   #endif
816     return;
817   }
818
819   theProgram->SetUniform (myContext,
820                           theProgram->GetStateLocation (OpenGl_OCC_MODEL_WORLD_MATRIX),
821                           myModelWorldState.ModelWorldMatrix());
822
823   GLint aLocation = theProgram->GetStateLocation (OpenGl_OCC_MODEL_WORLD_MATRIX_INVERSE);
824   if (aLocation != OpenGl_ShaderProgram::INVALID_LOCATION)
825   {
826     theProgram->SetUniform (myContext, aLocation, myModelWorldState.ModelWorldMatrixInverse());
827   }
828
829   theProgram->SetUniform (myContext,
830                           theProgram->GetStateLocation (OpenGl_OCC_MODEL_WORLD_MATRIX_TRANSPOSE),
831                           myModelWorldState.ModelWorldMatrix(), true);
832
833   aLocation = theProgram->GetStateLocation (OpenGl_OCC_MODEL_WORLD_MATRIX_INVERSE_TRANSPOSE);
834   if (aLocation != OpenGl_ShaderProgram::INVALID_LOCATION)
835   {
836     theProgram->SetUniform (myContext, aLocation, myModelWorldState.ModelWorldMatrixInverse(), true);
837   }
838 }
839
840 // =======================================================================
841 // function : PushWorldViewState
842 // purpose  : Pushes state of OCCT world-view transform to the program
843 // =======================================================================
844 void OpenGl_ShaderManager::PushWorldViewState (const Handle(OpenGl_ShaderProgram)& theProgram) const
845 {
846   if (myWorldViewState.Index() == theProgram->ActiveState (OpenGl_WORLD_VIEW_STATE))
847   {
848     return;
849   }
850
851   theProgram->UpdateState (OpenGl_WORLD_VIEW_STATE, myWorldViewState.Index());
852   if (theProgram == myFfpProgram)
853   {
854   #if !defined(GL_ES_VERSION_2_0)
855     if (myContext->core11 != NULL)
856     {
857       const OpenGl_Mat4 aModelView = myWorldViewState.WorldViewMatrix() * myModelWorldState.ModelWorldMatrix();
858       myContext->core11->glMatrixMode (GL_MODELVIEW);
859       myContext->core11->glLoadMatrixf (aModelView.GetData());
860       theProgram->UpdateState (OpenGl_MODEL_WORLD_STATE, myModelWorldState.Index());
861     }
862   #endif
863     return;
864   }
865
866   theProgram->SetUniform (myContext,
867                           theProgram->GetStateLocation (OpenGl_OCC_WORLD_VIEW_MATRIX),
868                           myWorldViewState.WorldViewMatrix());
869
870   GLint aLocation = theProgram->GetStateLocation (OpenGl_OCC_WORLD_VIEW_MATRIX_INVERSE);
871   if (aLocation != OpenGl_ShaderProgram::INVALID_LOCATION)
872   {
873     theProgram->SetUniform (myContext, aLocation, myWorldViewState.WorldViewMatrixInverse());
874   }
875
876   theProgram->SetUniform (myContext,
877                           theProgram->GetStateLocation (OpenGl_OCC_WORLD_VIEW_MATRIX_TRANSPOSE),
878                           myWorldViewState.WorldViewMatrix(), true);
879
880   aLocation = theProgram->GetStateLocation (OpenGl_OCC_WORLD_VIEW_MATRIX_INVERSE_TRANSPOSE);
881   if (aLocation != OpenGl_ShaderProgram::INVALID_LOCATION)
882   {
883     theProgram->SetUniform (myContext, aLocation, myWorldViewState.WorldViewMatrixInverse(), true);
884   }
885 }
886
887 // =======================================================================
888 // function : UpdateClippingState
889 // purpose  : Updates state of OCCT clipping planes
890 // =======================================================================
891 void OpenGl_ShaderManager::UpdateClippingState()
892 {
893   myClippingState.Update();
894 }
895
896 // =======================================================================
897 // function : RevertClippingState
898 // purpose  : Reverts state of OCCT clipping planes
899 // =======================================================================
900 void OpenGl_ShaderManager::RevertClippingState()
901 {
902   myClippingState.Revert();
903 }
904
905 // =======================================================================
906 // function : PushClippingState
907 // purpose  : Pushes state of OCCT clipping planes to the program
908 // =======================================================================
909 void OpenGl_ShaderManager::PushClippingState (const Handle(OpenGl_ShaderProgram)& theProgram) const
910 {
911   if (myClippingState.Index() == theProgram->ActiveState (OpenGl_CLIP_PLANES_STATE))
912   {
913     return;
914   }
915
916   theProgram->UpdateState (OpenGl_CLIP_PLANES_STATE, myClippingState.Index());
917   if (theProgram == myFfpProgram)
918   {
919   #if !defined(GL_ES_VERSION_2_0)
920     if (myContext->core11 == NULL)
921     {
922       return;
923     }
924
925     const Standard_Integer aNbMaxPlanes = myContext->MaxClipPlanes();
926     if (myClipPlaneArrayFfp.Size() < aNbMaxPlanes)
927     {
928       myClipPlaneArrayFfp.Resize (0, aNbMaxPlanes - 1, false);
929     }
930
931     Standard_Integer aPlaneId = 0;
932     Standard_Boolean toRestoreModelView = Standard_False;
933     for (OpenGl_ClippingIterator aPlaneIter (myContext->Clipping()); aPlaneIter.More(); aPlaneIter.Next())
934     {
935       const Handle(Graphic3d_ClipPlane)& aPlane = aPlaneIter.Value();
936       if (aPlaneIter.IsDisabled())
937       {
938         continue;
939       }
940       else if (aPlaneId >= aNbMaxPlanes)
941       {
942         myContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_MEDIUM,
943                                 TCollection_ExtendedString("Warning: clipping planes limit (") + aNbMaxPlanes + ") has been exceeded.");
944         break;
945       }
946
947       const Graphic3d_ClipPlane::Equation& anEquation = aPlane->GetEquation();
948       OpenGl_Vec4d& aPlaneEq = myClipPlaneArrayFfp.ChangeValue (aPlaneId);
949       aPlaneEq.x() = anEquation.x();
950       aPlaneEq.y() = anEquation.y();
951       aPlaneEq.z() = anEquation.z();
952       aPlaneEq.w() = anEquation.w();
953       if (myHasLocalOrigin)
954       {
955         const gp_XYZ        aPos = aPlane->ToPlane().Position().Location().XYZ() - myLocalOrigin;
956         const Standard_Real aD   = -(anEquation.x() * aPos.X() + anEquation.y() * aPos.Y() + anEquation.z() * aPos.Z());
957         aPlaneEq.w() = aD;
958       }
959
960       const GLenum anFfpPlaneID = GL_CLIP_PLANE0 + aPlaneId;
961       if (anFfpPlaneID == GL_CLIP_PLANE0)
962       {
963         // set either identity or pure view matrix
964         toRestoreModelView = Standard_True;
965         myContext->core11->glMatrixMode (GL_MODELVIEW);
966         myContext->core11->glLoadMatrixf (myWorldViewState.WorldViewMatrix().GetData());
967       }
968
969       ::glEnable (anFfpPlaneID);
970       myContext->core11->glClipPlane (anFfpPlaneID, aPlaneEq);
971
972       ++aPlaneId;
973     }
974
975     // switch off unused lights
976     for (; aPlaneId < aNbMaxPlanes; ++aPlaneId)
977     {
978       ::glDisable (GL_CLIP_PLANE0 + aPlaneId);
979     }
980
981     // restore combined model-view matrix
982     if (toRestoreModelView)
983     {
984       const OpenGl_Mat4 aModelView = myWorldViewState.WorldViewMatrix() * myModelWorldState.ModelWorldMatrix();
985       myContext->core11->glLoadMatrixf (aModelView.GetData());
986     }
987   #endif
988     return;
989   }
990
991   const GLint aLocEquations = theProgram->GetStateLocation (OpenGl_OCC_CLIP_PLANE_EQUATIONS);
992   if (aLocEquations == OpenGl_ShaderProgram::INVALID_LOCATION)
993   {
994     return;
995   }
996
997   const Standard_Integer aNbClipPlanesMax = theProgram->NbClipPlanesMax();
998   const GLint aNbPlanes = Min (myContext->Clipping().NbClippingOrCappingOn(), aNbClipPlanesMax);
999   theProgram->SetUniform (myContext,
1000                           theProgram->GetStateLocation (OpenGl_OCC_CLIP_PLANE_COUNT),
1001                           aNbPlanes);
1002   if (aNbPlanes < 1)
1003   {
1004     return;
1005   }
1006
1007   if (myClipPlaneArray.Size() < aNbClipPlanesMax)
1008   {
1009     myClipPlaneArray.Resize (0, aNbClipPlanesMax - 1, false);
1010   }
1011
1012   Standard_Integer aPlaneId = 0;
1013   for (OpenGl_ClippingIterator aPlaneIter (myContext->Clipping()); aPlaneIter.More(); aPlaneIter.Next())
1014   {
1015     const Handle(Graphic3d_ClipPlane)& aPlane = aPlaneIter.Value();
1016     if (aPlaneIter.IsDisabled())
1017     {
1018       continue;
1019     }
1020     else if (aPlaneId >= aNbClipPlanesMax)
1021     {
1022       myContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_MEDIUM,
1023                               TCollection_AsciiString("Warning: clipping planes limit (") + aNbClipPlanesMax + ") has been exceeded.");
1024       break;
1025     }
1026
1027     const Graphic3d_ClipPlane::Equation& anEquation = aPlane->GetEquation();
1028     OpenGl_Vec4& aPlaneEq = myClipPlaneArray.ChangeValue (aPlaneId);
1029     aPlaneEq.x() = float(anEquation.x());
1030     aPlaneEq.y() = float(anEquation.y());
1031     aPlaneEq.z() = float(anEquation.z());
1032     aPlaneEq.w() = float(anEquation.w());
1033     if (myHasLocalOrigin)
1034     {
1035       const gp_XYZ        aPos = aPlane->ToPlane().Position().Location().XYZ() - myLocalOrigin;
1036       const Standard_Real aD   = -(anEquation.x() * aPos.X() + anEquation.y() * aPos.Y() + anEquation.z() * aPos.Z());
1037       aPlaneEq.w() = float(aD);
1038     }
1039     ++aPlaneId;
1040   }
1041
1042   theProgram->SetUniform (myContext, aLocEquations, aNbClipPlanesMax, &myClipPlaneArray.First());
1043 }
1044
1045 // =======================================================================
1046 // function : PushMaterialState
1047 // purpose  :
1048 // =======================================================================
1049 void OpenGl_ShaderManager::PushMaterialState (const Handle(OpenGl_ShaderProgram)& theProgram) const
1050 {
1051   if (myMaterialState.Index() == theProgram->ActiveState (OpenGl_MATERIAL_STATE))
1052   {
1053     return;
1054   }
1055
1056   const OpenGl_Material& aFrontMat = myMaterialState.FrontMaterial();
1057   const OpenGl_Material& aBackMat  = myMaterialState.BackMaterial();
1058   theProgram->UpdateState (OpenGl_MATERIAL_STATE, myMaterialState.Index());
1059   if (theProgram == myFfpProgram)
1060   {
1061   #if !defined(GL_ES_VERSION_2_0)
1062     if (myContext->core11 == NULL)
1063     {
1064       return;
1065     }
1066
1067     if (myMaterialState.AlphaCutoff() < ShortRealLast())
1068     {
1069       glAlphaFunc (GL_GEQUAL, myMaterialState.AlphaCutoff());
1070       glEnable (GL_ALPHA_TEST);
1071     }
1072     else
1073     {
1074       glDisable (GL_ALPHA_TEST);
1075     }
1076
1077     const GLenum aFrontFace = myMaterialState.ToDistinguish() ? GL_FRONT : GL_FRONT_AND_BACK;
1078     myContext->core11->glMaterialfv(aFrontFace, GL_AMBIENT,   aFrontMat.Ambient.GetData());
1079     myContext->core11->glMaterialfv(aFrontFace, GL_DIFFUSE,   aFrontMat.Diffuse.GetData());
1080     myContext->core11->glMaterialfv(aFrontFace, GL_SPECULAR,  aFrontMat.Specular.GetData());
1081     myContext->core11->glMaterialfv(aFrontFace, GL_EMISSION,  aFrontMat.Emission.GetData());
1082     myContext->core11->glMaterialf (aFrontFace, GL_SHININESS, aFrontMat.Shine());
1083     if (myMaterialState.ToDistinguish())
1084     {
1085       myContext->core11->glMaterialfv(GL_BACK, GL_AMBIENT,   aBackMat.Ambient.GetData());
1086       myContext->core11->glMaterialfv(GL_BACK, GL_DIFFUSE,   aBackMat.Diffuse.GetData());
1087       myContext->core11->glMaterialfv(GL_BACK, GL_SPECULAR,  aBackMat.Specular.GetData());
1088       myContext->core11->glMaterialfv(GL_BACK, GL_EMISSION,  aBackMat.Emission.GetData());
1089       myContext->core11->glMaterialf (GL_BACK, GL_SHININESS, aBackMat.Shine());
1090     }
1091   #endif
1092     return;
1093   }
1094
1095   theProgram->SetUniform (myContext,
1096                           theProgram->GetStateLocation (OpenGl_OCCT_ALPHA_CUTOFF),
1097                           myMaterialState.AlphaCutoff());
1098   theProgram->SetUniform (myContext,
1099                           theProgram->GetStateLocation (OpenGl_OCCT_TEXTURE_ENABLE),
1100                           myMaterialState.ToMapTexture()  ? 1 : 0);
1101   theProgram->SetUniform (myContext,
1102                           theProgram->GetStateLocation (OpenGl_OCCT_DISTINGUISH_MODE),
1103                           myMaterialState.ToDistinguish() ? 1 : 0);
1104
1105   const GLint aLocFront = theProgram->GetStateLocation (OpenGl_OCCT_FRONT_MATERIAL);
1106   if (aLocFront != OpenGl_ShaderProgram::INVALID_LOCATION)
1107   {
1108     theProgram->SetUniform (myContext, aLocFront, OpenGl_Material::NbOfVec4(),
1109                             aFrontMat.Packed());
1110   }
1111
1112   const GLint aLocBack = theProgram->GetStateLocation (OpenGl_OCCT_BACK_MATERIAL);
1113   if (aLocBack != OpenGl_ShaderProgram::INVALID_LOCATION)
1114   {
1115     theProgram->SetUniform (myContext, aLocBack,  OpenGl_Material::NbOfVec4(),
1116                             aBackMat.Packed());
1117   }
1118 }
1119
1120 // =======================================================================
1121 // function : PushOitState
1122 // purpose  : Pushes state of OIT uniforms to the specified program
1123 // =======================================================================
1124 void OpenGl_ShaderManager::PushOitState (const Handle(OpenGl_ShaderProgram)& theProgram) const
1125 {
1126   if (!theProgram->IsValid())
1127   {
1128     return;
1129   }
1130
1131   if (myOitState.Index() == theProgram->ActiveState (OpenGL_OIT_STATE))
1132   {
1133     return;
1134   }
1135
1136   const GLint aLocOutput = theProgram->GetStateLocation (OpenGl_OCCT_OIT_OUTPUT);
1137   if (aLocOutput != OpenGl_ShaderProgram::INVALID_LOCATION)
1138   {
1139     theProgram->SetUniform (myContext, aLocOutput, myOitState.ToEnableWrite());
1140   }
1141
1142   const GLint aLocDepthFactor = theProgram->GetStateLocation (OpenGl_OCCT_OIT_DEPTH_FACTOR);
1143   if (aLocDepthFactor != OpenGl_ShaderProgram::INVALID_LOCATION)
1144   {
1145     theProgram->SetUniform (myContext, aLocDepthFactor, myOitState.DepthFactor());
1146   }
1147 }
1148
1149 // =======================================================================
1150 // function : PushState
1151 // purpose  : Pushes state of OCCT graphics parameters to the program
1152 // =======================================================================
1153 void OpenGl_ShaderManager::PushState (const Handle(OpenGl_ShaderProgram)& theProgram) const
1154 {
1155   const Handle(OpenGl_ShaderProgram)& aProgram = !theProgram.IsNull() ? theProgram : myFfpProgram;
1156   PushClippingState    (aProgram);
1157   PushWorldViewState   (aProgram);
1158   PushModelWorldState  (aProgram);
1159   PushProjectionState  (aProgram);
1160   PushLightSourceState (aProgram);
1161   PushMaterialState    (aProgram);
1162   PushOitState         (aProgram);
1163 }
1164
1165 // =======================================================================
1166 // function : prepareStdProgramFont
1167 // purpose  :
1168 // =======================================================================
1169 Standard_Boolean OpenGl_ShaderManager::prepareStdProgramFont()
1170 {
1171   Handle(Graphic3d_ShaderProgram) aProgramSrc = new Graphic3d_ShaderProgram();
1172   TCollection_AsciiString aSrcVert = TCollection_AsciiString()
1173      + EOL"THE_SHADER_OUT vec2 TexCoord;"
1174        EOL"void main()"
1175        EOL"{"
1176        EOL"  TexCoord = occTexCoord.st;"
1177        EOL"  gl_Position = occProjectionMatrix * occWorldViewMatrix * occModelWorldMatrix * occVertex;"
1178        EOL"}";
1179
1180   TCollection_AsciiString
1181     aSrcGetAlpha = EOL"float getAlpha(void) { return occTexture2D(occSamplerBaseColor, TexCoord.st).a; }";
1182 #if !defined(GL_ES_VERSION_2_0)
1183   if (myContext->core11 == NULL)
1184   {
1185     aSrcGetAlpha = EOL"float getAlpha(void) { return occTexture2D(occSamplerBaseColor, TexCoord.st).r; }";
1186   }
1187 #endif
1188
1189   TCollection_AsciiString aSrcFrag = TCollection_AsciiString() +
1190      + EOL"THE_SHADER_IN vec2 TexCoord;"
1191      + aSrcGetAlpha
1192      + EOL"void main()"
1193        EOL"{"
1194        EOL"  vec4 aColor = occColor;"
1195        EOL"  aColor.a *= getAlpha();"
1196        EOL"  if (aColor.a <= 0.285) discard;"
1197        EOL"  occSetFragColor (aColor);"
1198        EOL"}";
1199
1200 #if !defined(GL_ES_VERSION_2_0)
1201   if (myContext->core32 != NULL)
1202   {
1203     aProgramSrc->SetHeader ("#version 150");
1204   }
1205 #else
1206   if (myContext->IsGlGreaterEqual (3, 1))
1207   {
1208     // prefer "100 es" on OpenGL ES 3.0 devices
1209     // and    "300 es" on newer devices (3.1+)
1210     aProgramSrc->SetHeader ("#version 300 es");
1211   }
1212 #endif
1213   aProgramSrc->SetNbLightsMax (0);
1214   aProgramSrc->SetNbClipPlanesMax (0);
1215   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_VERTEX,   aSrcVert));
1216   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_FRAGMENT, aSrcFrag));
1217   TCollection_AsciiString aKey;
1218   if (!Create (aProgramSrc, aKey, myFontProgram))
1219   {
1220     myFontProgram = new OpenGl_ShaderProgram(); // just mark as invalid
1221     return Standard_False;
1222   }
1223   return Standard_True;
1224 }
1225
1226 // =======================================================================
1227 // function : prepareStdProgramFboBlit
1228 // purpose  :
1229 // =======================================================================
1230 Standard_Boolean OpenGl_ShaderManager::prepareStdProgramFboBlit()
1231 {
1232   Handle(Graphic3d_ShaderProgram) aProgramSrc = new Graphic3d_ShaderProgram();
1233   TCollection_AsciiString aSrcVert =
1234       EOL"THE_SHADER_OUT vec2 TexCoord;"
1235       EOL"void main()"
1236       EOL"{"
1237       EOL"  TexCoord    = occVertex.zw;"
1238       EOL"  gl_Position = vec4(occVertex.x, occVertex.y, 0.0, 1.0);"
1239       EOL"}";
1240
1241   TCollection_AsciiString aSrcFrag =
1242       EOL"uniform sampler2D uColorSampler;"
1243       EOL"uniform sampler2D uDepthSampler;"
1244       EOL
1245       EOL"THE_SHADER_IN vec2 TexCoord;"
1246       EOL
1247       EOL"void main()"
1248       EOL"{"
1249       EOL"  gl_FragDepth = occTexture2D (uDepthSampler, TexCoord).r;"
1250       EOL"  occSetFragColor (occTexture2D (uColorSampler, TexCoord));"
1251       EOL"}";
1252
1253 #if defined(GL_ES_VERSION_2_0)
1254   if (myContext->IsGlGreaterEqual (3, 0))
1255   {
1256     aProgramSrc->SetHeader ("#version 300 es");
1257   }
1258   else if (myContext->extFragDepth)
1259   {
1260     aProgramSrc->SetHeader ("#extension GL_EXT_frag_depth : enable"
1261                          EOL"#define gl_FragDepth gl_FragDepthEXT");
1262   }
1263   else
1264   {
1265     // there is no way to draw into depth buffer
1266     aSrcFrag =
1267       EOL"uniform sampler2D uColorSampler;"
1268       EOL
1269       EOL"THE_SHADER_IN vec2 TexCoord;"
1270       EOL
1271       EOL"void main()"
1272       EOL"{"
1273       EOL"  occSetFragColor (occTexture2D (uColorSampler, TexCoord));"
1274       EOL"}";
1275   }
1276 #else
1277   if (myContext->core32 != NULL)
1278   {
1279     aProgramSrc->SetHeader ("#version 150");
1280   }
1281 #endif
1282   aProgramSrc->SetNbLightsMax (0);
1283   aProgramSrc->SetNbClipPlanesMax (0);
1284   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_VERTEX,   aSrcVert));
1285   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_FRAGMENT, aSrcFrag));
1286   TCollection_AsciiString aKey;
1287   if (!Create (aProgramSrc, aKey, myBlitProgram))
1288   {
1289     myBlitProgram = new OpenGl_ShaderProgram(); // just mark as invalid
1290     return Standard_False;
1291   }
1292
1293   myContext->BindProgram (myBlitProgram);
1294   myBlitProgram->SetSampler (myContext, "uColorSampler", Graphic3d_TextureUnit_0);
1295   myBlitProgram->SetSampler (myContext, "uDepthSampler", Graphic3d_TextureUnit_1);
1296   myContext->BindProgram (NULL);
1297   return Standard_True;
1298 }
1299
1300 // =======================================================================
1301 // function : prepareStdProgramOitCompositing
1302 // purpose  :
1303 // =======================================================================
1304 Standard_Boolean OpenGl_ShaderManager::prepareStdProgramOitCompositing (const Standard_Boolean theMsaa)
1305 {
1306   Handle(OpenGl_ShaderProgram)& aProgram = myOitCompositingProgram[theMsaa ? 1 : 0];
1307   Handle(Graphic3d_ShaderProgram) aProgramSrc = new Graphic3d_ShaderProgram();
1308   TCollection_AsciiString aSrcVert, aSrcFrag;
1309
1310   aSrcVert =
1311     EOL"THE_SHADER_OUT vec2 TexCoord;"
1312     EOL"void main()"
1313     EOL"{"
1314     EOL"  TexCoord    = occVertex.zw;"
1315     EOL"  gl_Position = vec4 (occVertex.x, occVertex.y, 0.0, 1.0);"
1316     EOL"}";
1317
1318   if (!theMsaa)
1319   {
1320     aSrcFrag =
1321       EOL"uniform sampler2D uAccumTexture;"
1322       EOL"uniform sampler2D uWeightTexture;"
1323       EOL
1324       EOL"THE_SHADER_IN vec2 TexCoord;"
1325       EOL
1326       EOL"void main()"
1327       EOL"{"
1328       EOL"  vec4 aAccum   = occTexture2D (uAccumTexture,  TexCoord);"
1329       EOL"  float aWeight = occTexture2D (uWeightTexture, TexCoord).r;"
1330       EOL"  occSetFragColor (vec4 (aAccum.rgb / max (aWeight, 0.00001), aAccum.a));"
1331       EOL"}";
1332   #if !defined(GL_ES_VERSION_2_0)
1333     if (myContext->IsGlGreaterEqual (3, 2))
1334     {
1335       aProgramSrc->SetHeader ("#version 150");
1336     }
1337   #else
1338     if (myContext->IsGlGreaterEqual (3, 0))
1339     {
1340       aProgramSrc->SetHeader ("#version 300 es");
1341     }
1342   #endif
1343   }
1344   else
1345   {
1346     aSrcFrag =
1347       EOL"uniform sampler2DMS uAccumTexture;"
1348       EOL"uniform sampler2DMS uWeightTexture;"
1349       EOL
1350       EOL"THE_SHADER_IN vec2 TexCoord;"
1351       EOL
1352       EOL"void main()"
1353       EOL"{"
1354       EOL"  ivec2 aTexel  = ivec2 (vec2 (textureSize (uAccumTexture)) * TexCoord);"
1355       EOL"  vec4 aAccum   = texelFetch (uAccumTexture,  aTexel, gl_SampleID);"
1356       EOL"  float aWeight = texelFetch (uWeightTexture, aTexel, gl_SampleID).r;"
1357       EOL"  occSetFragColor (vec4 (aAccum.rgb / max (aWeight, 0.00001), aAccum.a));"
1358       EOL"}";
1359   #if !defined(GL_ES_VERSION_2_0)
1360     if (myContext->IsGlGreaterEqual (4, 0))
1361     {
1362       aProgramSrc->SetHeader ("#version 400");
1363     }
1364   #else
1365     if (myContext->IsGlGreaterEqual (3, 2))
1366     {
1367       aProgramSrc->SetHeader ("#version 320 es");
1368     }
1369     else if (myContext->IsGlGreaterEqual (3, 0))
1370     {
1371       aProgramSrc->SetHeader ("#version 300 es"); // with GL_OES_sample_variables extension
1372     }
1373   #endif
1374   }
1375
1376   aProgramSrc->SetNbLightsMax (0);
1377   aProgramSrc->SetNbClipPlanesMax (0);
1378   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_VERTEX,   aSrcVert));
1379   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_FRAGMENT, aSrcFrag));
1380   TCollection_AsciiString aKey;
1381   if (!Create (aProgramSrc, aKey, aProgram))
1382   {
1383     aProgram = new OpenGl_ShaderProgram(); // just mark as invalid
1384     return Standard_False;
1385   }
1386
1387   myContext->BindProgram (aProgram);
1388   aProgram->SetSampler (myContext, "uAccumTexture",  Graphic3d_TextureUnit_0);
1389   aProgram->SetSampler (myContext, "uWeightTexture", Graphic3d_TextureUnit_1);
1390   myContext->BindProgram (Handle(OpenGl_ShaderProgram)());
1391   return Standard_True;
1392 }
1393
1394 // =======================================================================
1395 // function : pointSpriteAlphaSrc
1396 // purpose  :
1397 // =======================================================================
1398 TCollection_AsciiString OpenGl_ShaderManager::pointSpriteAlphaSrc (const Standard_Integer theBits)
1399 {
1400   TCollection_AsciiString aSrcGetAlpha = EOL"float getAlpha(void) { return occTexture2D(occSamplerBaseColor, " THE_VEC2_glPointCoord ").a; }";
1401 #if !defined(GL_ES_VERSION_2_0)
1402   if (myContext->core11 == NULL
1403    && (theBits & OpenGl_PO_TextureA) != 0)
1404   {
1405     aSrcGetAlpha = EOL"float getAlpha(void) { return occTexture2D(occSamplerBaseColor, " THE_VEC2_glPointCoord ").r; }";
1406   }
1407 #else
1408   (void )theBits;
1409 #endif
1410   return aSrcGetAlpha;
1411 }
1412
1413 namespace
1414 {
1415
1416   // =======================================================================
1417   // function : textureUsed
1418   // purpose  :
1419   // =======================================================================
1420   static bool textureUsed (const Standard_Integer theBits)
1421   {
1422     return (theBits & OpenGl_PO_TextureA) != 0 || (theBits & OpenGl_PO_TextureRGB) != 0;
1423   }
1424
1425 }
1426
1427 // =======================================================================
1428 // function : prepareStdProgramUnlit
1429 // purpose  :
1430 // =======================================================================
1431 Standard_Boolean OpenGl_ShaderManager::prepareStdProgramUnlit (Handle(OpenGl_ShaderProgram)& theProgram,
1432                                                                const Standard_Integer        theBits)
1433 {
1434   Handle(Graphic3d_ShaderProgram) aProgramSrc = new Graphic3d_ShaderProgram();
1435   TCollection_AsciiString aSrcVert, aSrcVertExtraOut, aSrcVertExtraMain, aSrcVertExtraFunc, aSrcGetAlpha;
1436   TCollection_AsciiString aSrcFrag, aSrcFragExtraOut, aSrcFragExtraMain, aSrcFragWriteOit;
1437   TCollection_AsciiString aSrcFragGetColor     = EOL"vec4 getColor(void) { return occColor; }";
1438   TCollection_AsciiString aSrcFragMainGetColor = EOL"  occSetFragColor (getColor());";
1439   if ((theBits & OpenGl_PO_Point) != 0)
1440   {
1441   #if defined(GL_ES_VERSION_2_0)
1442     aSrcVertExtraMain += EOL"  gl_PointSize = occPointSize;";
1443   #endif
1444
1445     if ((theBits & OpenGl_PO_TextureRGB) != 0)
1446     {
1447       aSrcFragGetColor =
1448         EOL"vec4 getColor(void) { return occTexture2D(occSamplerBaseColor, " THE_VEC2_glPointCoord "); }";
1449     }
1450
1451     if (textureUsed (theBits))
1452     {
1453       aSrcGetAlpha = pointSpriteAlphaSrc (theBits);
1454
1455     #if !defined(GL_ES_VERSION_2_0)
1456       if (myContext->core11 != NULL
1457         && myContext->IsGlGreaterEqual (2, 1))
1458       {
1459         aProgramSrc->SetHeader ("#version 120"); // gl_PointCoord has been added since GLSL 1.2
1460       }
1461     #endif
1462
1463       aSrcFragMainGetColor =
1464         EOL"  vec4 aColor = getColor();"
1465         EOL"  aColor.a = getAlpha();"
1466         EOL"  if (aColor.a <= 0.1) discard;"
1467         EOL"  occSetFragColor (aColor);";
1468     }
1469     else
1470     {
1471       aSrcFragMainGetColor =
1472         EOL"  vec4 aColor = getColor();"
1473         EOL"  if (aColor.a <= 0.1) discard;"
1474         EOL"  occSetFragColor (aColor);";
1475     }
1476   }
1477   else
1478   {
1479     if ((theBits & OpenGl_PO_TextureRGB) != 0)
1480     {
1481       aSrcVertExtraOut  += THE_VARY_TexCoord_OUT;
1482       aSrcFragExtraOut  += THE_VARY_TexCoord_IN;
1483       aSrcVertExtraMain += THE_VARY_TexCoord_Trsf;
1484
1485       aSrcFragGetColor =
1486         EOL"vec4 getColor(void) { return occTexture2D(occSamplerBaseColor, TexCoord.st / TexCoord.w); }";
1487     }
1488     else if ((theBits & OpenGl_PO_TextureEnv) != 0)
1489     {
1490       aSrcVertExtraOut += THE_VARY_TexCoord_OUT;
1491       aSrcFragExtraOut += THE_VARY_TexCoord_IN;
1492
1493       aSrcVertExtraFunc = THE_FUNC_transformNormal;
1494
1495       aSrcVertExtraMain +=
1496         EOL"  vec4 aPosition = occWorldViewMatrix * occModelWorldMatrix * occVertex;"
1497         EOL"  vec3 aNormal   = transformNormal (occNormal);"
1498         EOL"  vec3 aReflect  = reflect (normalize (aPosition.xyz), aNormal);"
1499         EOL"  aReflect.z += 1.0;"
1500         EOL"  TexCoord = vec4(aReflect.xy * inversesqrt (dot (aReflect, aReflect)) * 0.5 + vec2 (0.5), 0.0, 1.0);";
1501
1502       aSrcFragGetColor =
1503         EOL"vec4 getColor(void) { return occTexture2D (occSamplerBaseColor, TexCoord.st); }";
1504     }
1505   }
1506   if ((theBits & OpenGl_PO_VertColor) != 0)
1507   {
1508     aSrcVertExtraOut  += EOL"THE_SHADER_OUT vec4 VertColor;";
1509     aSrcVertExtraMain += EOL"  VertColor = occVertColor;";
1510     aSrcFragExtraOut  += EOL"THE_SHADER_IN  vec4 VertColor;";
1511     aSrcFragGetColor  =  EOL"vec4 getColor(void) { return VertColor; }";
1512   }
1513
1514   int aNbClipPlanes = 0;
1515   if ((theBits & OpenGl_PO_ClipPlanesN) != 0)
1516   {
1517     aSrcVertExtraOut +=
1518       EOL"THE_SHADER_OUT vec4 PositionWorld;"
1519       EOL"THE_SHADER_OUT vec4 Position;";
1520     aSrcFragExtraOut +=
1521       EOL"THE_SHADER_IN  vec4 PositionWorld;"
1522       EOL"THE_SHADER_IN  vec4 Position;";
1523     aSrcVertExtraMain +=
1524       EOL"  PositionWorld = occModelWorldMatrix * occVertex;"
1525       EOL"  Position      = occWorldViewMatrix * PositionWorld;";
1526
1527     if ((theBits & OpenGl_PO_ClipPlanes1) != 0)
1528     {
1529       aNbClipPlanes = 1;
1530       aSrcFragExtraMain += THE_FRAG_CLIP_PLANES_1;
1531     }
1532     else if ((theBits & OpenGl_PO_ClipPlanes2) != 0)
1533     {
1534       aNbClipPlanes = 2;
1535       aSrcFragExtraMain += THE_FRAG_CLIP_PLANES_2;
1536     }
1537     else
1538     {
1539       aNbClipPlanes = Graphic3d_ShaderProgram::THE_MAX_CLIP_PLANES_DEFAULT;
1540       aSrcFragExtraMain += THE_FRAG_CLIP_PLANES_N;
1541     }
1542   }
1543   if ((theBits & OpenGl_PO_WriteOit) != 0)
1544   {
1545     aProgramSrc->SetNbFragmentOutputs (2);
1546     aProgramSrc->SetWeightOitOutput (true);
1547   #if defined(GL_ES_VERSION_2_0)
1548     if (myContext->IsGlGreaterEqual (3, 0))
1549     {
1550       aProgramSrc->SetHeader ("#version 300 es");
1551     }
1552   #endif
1553   }
1554
1555   TCollection_AsciiString aSrcVertEndMain;
1556   if ((theBits & OpenGl_PO_StippleLine) != 0)
1557   {
1558     bool hasGlslBitOps = false;
1559   #if defined(GL_ES_VERSION_2_0)
1560     if (myContext->IsGlGreaterEqual (3, 0))
1561     {
1562       aProgramSrc->SetHeader ("#version 300 es");
1563       hasGlslBitOps = true;
1564     }
1565   #else
1566     if (myContext->IsGlGreaterEqual (3, 0))
1567     {
1568       aProgramSrc->SetHeader ("#version 130");
1569       hasGlslBitOps = true;
1570     }
1571     else if(myContext->CheckExtension("GL_EXT_gpu_shader4"))
1572     {
1573       aProgramSrc->SetHeader ("#extension GL_EXT_gpu_shader4 : enable");
1574       hasGlslBitOps = true;
1575     }
1576   #endif
1577
1578     if (hasGlslBitOps)
1579     {
1580       aSrcVertExtraOut +=
1581         EOL"THE_SHADER_OUT vec2 ScreenSpaceCoord;";
1582       aSrcFragExtraOut +=
1583         EOL"THE_SHADER_IN  vec2 ScreenSpaceCoord;"
1584         EOL"uniform int   uPattern;"
1585         EOL"uniform float uFactor;";
1586       aSrcVertEndMain =
1587         EOL"  ScreenSpaceCoord = gl_Position.xy / gl_Position.w;";
1588       aSrcFragMainGetColor =
1589         EOL"  float anAngle      = atan (dFdx (ScreenSpaceCoord.x), dFdy (ScreenSpaceCoord.y));"
1590         EOL"  float aRotatePoint = gl_FragCoord.x * sin (anAngle) + gl_FragCoord.y * cos (anAngle);"
1591         EOL"  uint  aBit         = uint (floor (aRotatePoint / uFactor + 0.5)) & 15U;"
1592         EOL"  if ((uint (uPattern) & (1U << aBit)) == 0U) discard;"
1593         EOL"  vec4 aColor = getColor();"
1594         EOL"  if (aColor.a <= 0.1) discard;"
1595         EOL"  occSetFragColor (aColor);";
1596     }
1597     else
1598     {
1599       const TCollection_ExtendedString aWarnMessage =
1600         "Warning: stipple lines in GLSL will be ignored.";
1601       myContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION,
1602         GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_HIGH, aWarnMessage);
1603     }
1604   }
1605
1606   aSrcVert =
1607       aSrcVertExtraFunc
1608     + aSrcVertExtraOut
1609     + EOL"void main()"
1610       EOL"{"
1611     + aSrcVertExtraMain
1612     + EOL"  gl_Position = occProjectionMatrix * occWorldViewMatrix * occModelWorldMatrix * occVertex;"
1613     + aSrcVertEndMain
1614     + EOL"}";
1615
1616   aSrcFrag =
1617       aSrcFragExtraOut
1618     + aSrcFragGetColor
1619     + aSrcGetAlpha
1620     + EOL"void main()"
1621       EOL"{"
1622     + aSrcFragExtraMain
1623     + aSrcFragMainGetColor
1624     + aSrcFragWriteOit
1625     + EOL"}";
1626
1627 #if !defined(GL_ES_VERSION_2_0)
1628   if (myContext->core32 != NULL)
1629   {
1630     aProgramSrc->SetHeader ("#version 150");
1631   }
1632 #else
1633   if (myContext->IsGlGreaterEqual (3, 1))
1634   {
1635     // prefer "100 es" on OpenGL ES 3.0 devices
1636     // and    "300 es" on newer devices (3.1+)
1637     aProgramSrc->SetHeader ("#version 300 es");
1638   }
1639 #endif
1640   aProgramSrc->SetNbLightsMax (0);
1641   aProgramSrc->SetNbClipPlanesMax (aNbClipPlanes);
1642   aProgramSrc->SetAlphaTest ((theBits & OpenGl_PO_AlphaTest) != 0);
1643   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_VERTEX,   aSrcVert));
1644   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_FRAGMENT, aSrcFrag));
1645
1646   TCollection_AsciiString aKey;
1647   if (!Create (aProgramSrc, aKey, theProgram))
1648   {
1649     theProgram = new OpenGl_ShaderProgram(); // just mark as invalid
1650     return Standard_False;
1651   }
1652   return Standard_True;
1653 }
1654
1655 // =======================================================================
1656 // function : pointSpriteShadingSrc
1657 // purpose  :
1658 // =======================================================================
1659 TCollection_AsciiString OpenGl_ShaderManager::pointSpriteShadingSrc (const TCollection_AsciiString theBaseColorSrc,
1660                                                                      const Standard_Integer theBits)
1661 {
1662   TCollection_AsciiString aSrcFragGetColor;
1663   if ((theBits & OpenGl_PO_TextureA) != 0)
1664   {
1665     aSrcFragGetColor = pointSpriteAlphaSrc (theBits) +
1666       EOL"vec4 getColor(void)"
1667       EOL"{"
1668       EOL"  vec4 aColor = " + theBaseColorSrc + ";"
1669       EOL"  aColor.a = getAlpha();"
1670       EOL"  if (aColor.a <= 0.1) discard;"
1671       EOL"  return aColor;"
1672       EOL"}";
1673   }
1674   else if ((theBits & OpenGl_PO_TextureRGB) != 0)
1675   {
1676     aSrcFragGetColor = TCollection_AsciiString() +
1677       EOL"vec4 getColor(void)"
1678       EOL"{"
1679       EOL"  vec4 aColor = " + theBaseColorSrc + ";"
1680       EOL"  aColor = occTexture2D(occSamplerBaseColor, " THE_VEC2_glPointCoord ") * aColor;"
1681       EOL"  if (aColor.a <= 0.1) discard;"
1682       EOL"  return aColor;"
1683       EOL"}";
1684   }
1685
1686   return aSrcFragGetColor;
1687 }
1688
1689 // =======================================================================
1690 // function : stdComputeLighting
1691 // purpose  :
1692 // =======================================================================
1693 TCollection_AsciiString OpenGl_ShaderManager::stdComputeLighting (Standard_Integer& theNbLights,
1694                                                                   Standard_Boolean  theHasVertColor)
1695 {
1696   TCollection_AsciiString aLightsFunc, aLightsLoop;
1697   theNbLights = 0;
1698   const Handle(Graphic3d_LightSet)& aLights = myLightSourceState.LightSources();
1699   if (!aLights.IsNull())
1700   {
1701     theNbLights = aLights->NbEnabled();
1702     if (theNbLights <= THE_NB_UNROLLED_LIGHTS_MAX)
1703     {
1704       Standard_Integer anIndex = 0;
1705       for (Graphic3d_LightSet::Iterator aLightIter (aLights, Graphic3d_LightSet::IterationFilter_ExcludeDisabledAndAmbient);
1706            aLightIter.More(); aLightIter.Next(), ++anIndex)
1707       {
1708         switch (aLightIter.Value()->Type())
1709         {
1710           case Graphic3d_TOLS_AMBIENT:
1711             --anIndex;
1712             break; // skip ambient
1713           case Graphic3d_TOLS_DIRECTIONAL:
1714             aLightsLoop = aLightsLoop + EOL"    directionalLight (" + anIndex + ", theNormal, theView, theIsFront);";
1715             break;
1716           case Graphic3d_TOLS_POSITIONAL:
1717             aLightsLoop = aLightsLoop + EOL"    pointLight (" + anIndex + ", theNormal, theView, aPoint, theIsFront);";
1718             break;
1719           case Graphic3d_TOLS_SPOT:
1720             aLightsLoop = aLightsLoop + EOL"    spotLight (" + anIndex + ", theNormal, theView, aPoint, theIsFront);";
1721             break;
1722         }
1723       }
1724     }
1725     else
1726     {
1727       theNbLights = roundUpMaxLightSources (theNbLights);
1728       bool isFirstInLoop = true;
1729       aLightsLoop = aLightsLoop +
1730         EOL"    for (int anIndex = 0; anIndex < occLightSourcesCount; ++anIndex)"
1731         EOL"    {"
1732         EOL"      int aType = occLight_Type (anIndex);";
1733       if (aLights->NbEnabledLightsOfType (Graphic3d_TOLS_DIRECTIONAL) > 0)
1734       {
1735         isFirstInLoop = false;
1736         aLightsLoop +=
1737           EOL"      if (aType == OccLightType_Direct)"
1738           EOL"      {"
1739           EOL"        directionalLight (anIndex, theNormal, theView, theIsFront);"
1740           EOL"      }";
1741       }
1742       if (aLights->NbEnabledLightsOfType (Graphic3d_TOLS_POSITIONAL) > 0)
1743       {
1744         if (!isFirstInLoop)
1745         {
1746           aLightsLoop += EOL"      else ";
1747         }
1748         isFirstInLoop = false;
1749         aLightsLoop +=
1750           EOL"      if (aType == OccLightType_Point)"
1751           EOL"      {"
1752           EOL"        pointLight (anIndex, theNormal, theView, aPoint, theIsFront);"
1753           EOL"      }";
1754       }
1755       if (aLights->NbEnabledLightsOfType (Graphic3d_TOLS_SPOT) > 0)
1756       {
1757         if (!isFirstInLoop)
1758         {
1759           aLightsLoop += EOL"      else ";
1760         }
1761         isFirstInLoop = false;
1762         aLightsLoop +=
1763           EOL"      if (aType == OccLightType_Spot)"
1764           EOL"      {"
1765           EOL"        spotLight (anIndex, theNormal, theView, aPoint, theIsFront);"
1766           EOL"      }";
1767       }
1768       aLightsLoop += EOL"    }";
1769     }
1770     if (aLights->NbEnabledLightsOfType (Graphic3d_TOLS_DIRECTIONAL) == 1
1771      && theNbLights == 1)
1772     {
1773       // use the version with hard-coded first index
1774       aLightsLoop = EOL"    directionalLightFirst(theNormal, theView, theIsFront);";
1775       aLightsFunc += THE_FUNC_directionalLightFirst;
1776     }
1777     else if (aLights->NbEnabledLightsOfType (Graphic3d_TOLS_DIRECTIONAL) > 0)
1778     {
1779       aLightsFunc += THE_FUNC_directionalLight;
1780     }
1781     if (aLights->NbEnabledLightsOfType (Graphic3d_TOLS_POSITIONAL) > 0)
1782     {
1783       aLightsFunc += THE_FUNC_pointLight;
1784     }
1785     if (aLights->NbEnabledLightsOfType (Graphic3d_TOLS_SPOT) > 0)
1786     {
1787       aLightsFunc += THE_FUNC_spotLight;
1788     }
1789   }
1790
1791   TCollection_AsciiString aGetMatAmbient = "theIsFront ? occFrontMaterial_Ambient()  : occBackMaterial_Ambient();";
1792   TCollection_AsciiString aGetMatDiffuse = "theIsFront ? occFrontMaterial_Diffuse()  : occBackMaterial_Diffuse();";
1793   if (theHasVertColor)
1794   {
1795     aGetMatAmbient = "getVertColor();";
1796     aGetMatDiffuse = "getVertColor();";
1797   }
1798
1799   return TCollection_AsciiString()
1800     + THE_FUNC_lightDef
1801     + aLightsFunc
1802     + EOL
1803       EOL"vec4 computeLighting (in vec3 theNormal,"
1804       EOL"                      in vec3 theView,"
1805       EOL"                      in vec4 thePoint,"
1806       EOL"                      in bool theIsFront)"
1807       EOL"{"
1808       EOL"  Ambient  = occLightAmbient.rgb;"
1809       EOL"  Diffuse  = vec3 (0.0);"
1810       EOL"  Specular = vec3 (0.0);"
1811       EOL"  vec3 aPoint = thePoint.xyz / thePoint.w;"
1812     + aLightsLoop
1813     + EOL"  vec4 aMatAmbient  = " + aGetMatAmbient
1814     + EOL"  vec4 aMatDiffuse  = " + aGetMatDiffuse
1815     + EOL"  vec4 aMatSpecular = theIsFront ? occFrontMaterial_Specular() : occBackMaterial_Specular();"
1816       EOL"  vec4 aMatEmission = theIsFront ? occFrontMaterial_Emission() : occBackMaterial_Emission();"
1817       EOL"  vec3 aColor = Ambient  * aMatAmbient.rgb"
1818       EOL"              + Diffuse  * aMatDiffuse.rgb"
1819       EOL"              + Specular * aMatSpecular.rgb"
1820       EOL"                         + aMatEmission.rgb;"
1821       EOL"  return vec4 (aColor, aMatDiffuse.a);"
1822       EOL"}";
1823 }
1824
1825 // =======================================================================
1826 // function : prepareStdProgramGouraud
1827 // purpose  :
1828 // =======================================================================
1829 Standard_Boolean OpenGl_ShaderManager::prepareStdProgramGouraud (Handle(OpenGl_ShaderProgram)& theProgram,
1830                                                                  const Standard_Integer        theBits)
1831 {
1832   Handle(Graphic3d_ShaderProgram) aProgramSrc = new Graphic3d_ShaderProgram();
1833   TCollection_AsciiString aSrcVert, aSrcVertColor, aSrcVertExtraOut, aSrcVertExtraMain;
1834   TCollection_AsciiString aSrcFrag, aSrcFragExtraOut, aSrcFragExtraMain, aSrcFragWriteOit;
1835   TCollection_AsciiString aSrcFragGetColor = EOL"vec4 getColor(void) { return gl_FrontFacing ? FrontColor : BackColor; }";
1836   if ((theBits & OpenGl_PO_Point) != 0)
1837   {
1838   #if defined(GL_ES_VERSION_2_0)
1839     aSrcVertExtraMain += EOL"  gl_PointSize = occPointSize;";
1840   #endif
1841
1842     if (textureUsed (theBits))
1843     {
1844       #if !defined(GL_ES_VERSION_2_0)
1845         if (myContext->core11 != NULL
1846          && myContext->IsGlGreaterEqual (2, 1))
1847         {
1848           aProgramSrc->SetHeader ("#version 120"); // gl_PointCoord has been added since GLSL 1.2
1849         }
1850       #endif
1851
1852       aSrcFragGetColor = pointSpriteShadingSrc ("gl_FrontFacing ? FrontColor : BackColor", theBits);
1853     }
1854   }
1855   else
1856   {
1857     if ((theBits & OpenGl_PO_TextureRGB) != 0)
1858     {
1859       aSrcVertExtraOut  += THE_VARY_TexCoord_OUT;
1860       aSrcFragExtraOut  += THE_VARY_TexCoord_IN;
1861       aSrcVertExtraMain += THE_VARY_TexCoord_Trsf;
1862
1863       aSrcFragGetColor =
1864         EOL"vec4 getColor(void)"
1865         EOL"{"
1866         EOL"  vec4 aColor = gl_FrontFacing ? FrontColor : BackColor;"
1867         EOL"  return occTexture2D(occSamplerBaseColor, TexCoord.st / TexCoord.w) * aColor;"
1868         EOL"}";
1869     }
1870   }
1871
1872   if ((theBits & OpenGl_PO_VertColor) != 0)
1873   {
1874     aSrcVertColor = EOL"vec4 getVertColor(void) { return occVertColor; }";
1875   }
1876
1877   int aNbClipPlanes = 0;
1878   if ((theBits & OpenGl_PO_ClipPlanesN) != 0)
1879   {
1880     aSrcVertExtraOut +=
1881       EOL"THE_SHADER_OUT vec4 PositionWorld;"
1882       EOL"THE_SHADER_OUT vec4 Position;";
1883     aSrcFragExtraOut +=
1884       EOL"THE_SHADER_IN  vec4 PositionWorld;"
1885       EOL"THE_SHADER_IN  vec4 Position;";
1886     aSrcVertExtraMain +=
1887       EOL"  PositionWorld = aPositionWorld;"
1888       EOL"  Position      = aPosition;";
1889
1890     if ((theBits & OpenGl_PO_ClipPlanes1) != 0)
1891     {
1892       aNbClipPlanes = 1;
1893       aSrcFragExtraMain += THE_FRAG_CLIP_PLANES_1;
1894     }
1895     else if ((theBits & OpenGl_PO_ClipPlanes2) != 0)
1896     {
1897       aNbClipPlanes = 2;
1898       aSrcFragExtraMain += THE_FRAG_CLIP_PLANES_2;
1899     }
1900     else
1901     {
1902       aNbClipPlanes = Graphic3d_ShaderProgram::THE_MAX_CLIP_PLANES_DEFAULT;
1903       aSrcFragExtraMain += THE_FRAG_CLIP_PLANES_N;
1904     }
1905   }
1906   if ((theBits & OpenGl_PO_WriteOit) != 0)
1907   {
1908     aProgramSrc->SetNbFragmentOutputs (2);
1909     aProgramSrc->SetWeightOitOutput (true);
1910   #if defined(GL_ES_VERSION_2_0)
1911     if (myContext->IsGlGreaterEqual (3, 0))
1912     {
1913       aProgramSrc->SetHeader ("#version 300 es");
1914     }
1915   #endif
1916   }
1917
1918   Standard_Integer aNbLights = 0;
1919   const TCollection_AsciiString aLights = stdComputeLighting (aNbLights, (theBits & OpenGl_PO_VertColor) != 0);
1920   aSrcVert = TCollection_AsciiString()
1921     + THE_FUNC_transformNormal
1922     + EOL
1923     + aSrcVertColor
1924     + aLights
1925     + EOL
1926       EOL"THE_SHADER_OUT vec4 FrontColor;"
1927       EOL"THE_SHADER_OUT vec4 BackColor;"
1928       EOL
1929     + aSrcVertExtraOut
1930     + EOL"void main()"
1931       EOL"{"
1932       EOL"  vec4 aPositionWorld = occModelWorldMatrix * occVertex;"
1933       EOL"  vec4 aPosition      = occWorldViewMatrix * aPositionWorld;"
1934       EOL"  vec3 aNormal        = transformNormal (occNormal);"
1935       EOL"  vec3 aView          = vec3 (0.0, 0.0, 1.0);"
1936       EOL"  FrontColor  = computeLighting (normalize (aNormal), normalize (aView), aPosition, true);"
1937       EOL"  BackColor   = computeLighting (normalize (aNormal), normalize (aView), aPosition, false);"
1938     + aSrcVertExtraMain
1939     + EOL"  gl_Position = occProjectionMatrix * occWorldViewMatrix * occModelWorldMatrix * occVertex;"
1940       EOL"}";
1941
1942   aSrcFrag = TCollection_AsciiString()
1943     + EOL"THE_SHADER_IN vec4 FrontColor;"
1944       EOL"THE_SHADER_IN vec4 BackColor;"
1945     + aSrcFragExtraOut
1946     + aSrcFragGetColor
1947     + EOL"void main()"
1948       EOL"{"
1949     + aSrcFragExtraMain
1950     + EOL"  occSetFragColor (getColor());"
1951     + aSrcFragWriteOit
1952     + EOL"}";
1953
1954 #if !defined(GL_ES_VERSION_2_0)
1955   if (myContext->core32 != NULL)
1956   {
1957     aProgramSrc->SetHeader ("#version 150");
1958   }
1959 #else
1960   if (myContext->IsGlGreaterEqual (3, 1))
1961   {
1962     // prefer "100 es" on OpenGL ES 3.0 devices
1963     // and    "300 es" on newer devices (3.1+)
1964     aProgramSrc->SetHeader ("#version 300 es");
1965   }
1966 #endif
1967   aProgramSrc->SetNbLightsMax (aNbLights);
1968   aProgramSrc->SetNbClipPlanesMax (aNbClipPlanes);
1969   aProgramSrc->SetAlphaTest ((theBits & OpenGl_PO_AlphaTest) != 0);
1970   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_VERTEX,   aSrcVert));
1971   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_FRAGMENT, aSrcFrag));
1972   TCollection_AsciiString aKey;
1973   if (!Create (aProgramSrc, aKey, theProgram))
1974   {
1975     theProgram = new OpenGl_ShaderProgram(); // just mark as invalid
1976     return Standard_False;
1977   }
1978   return Standard_True;
1979 }
1980
1981 // =======================================================================
1982 // function : prepareStdProgramPhong
1983 // purpose  :
1984 // =======================================================================
1985 Standard_Boolean OpenGl_ShaderManager::prepareStdProgramPhong (Handle(OpenGl_ShaderProgram)& theProgram,
1986                                                                const Standard_Integer        theBits,
1987                                                                const Standard_Boolean        theIsFlatNormal)
1988 {
1989   #define thePhongCompLight "computeLighting (normalize (Normal), normalize (View), Position, gl_FrontFacing)"
1990 #if defined(GL_ES_VERSION_2_0)
1991   const bool isFlatNormal = theIsFlatNormal
1992                          && (myContext->IsGlGreaterEqual (3, 0)
1993                           || myContext->oesStdDerivatives);
1994 #else
1995   const bool isFlatNormal = theIsFlatNormal;
1996 #endif
1997
1998   Handle(Graphic3d_ShaderProgram) aProgramSrc = new Graphic3d_ShaderProgram();
1999   TCollection_AsciiString aSrcVert, aSrcVertExtraOut, aSrcVertExtraMain;
2000   TCollection_AsciiString aSrcFrag, aSrcFragExtraOut, aSrcFragGetVertColor, aSrcFragExtraMain, aSrcFragWriteOit;
2001   TCollection_AsciiString aSrcFragGetColor = EOL"vec4 getColor(void) { return " thePhongCompLight "; }";
2002   if ((theBits & OpenGl_PO_Point) != 0)
2003   {
2004   #if defined(GL_ES_VERSION_2_0)
2005     aSrcVertExtraMain += EOL"  gl_PointSize = occPointSize;";
2006   #endif
2007
2008     if (textureUsed (theBits))
2009     {
2010       #if !defined(GL_ES_VERSION_2_0)
2011         if (myContext->core11 != NULL
2012          && myContext->IsGlGreaterEqual (2, 1))
2013         {
2014           aProgramSrc->SetHeader ("#version 120"); // gl_PointCoord has been added since GLSL 1.2
2015         }
2016       #endif
2017
2018       aSrcFragGetColor = pointSpriteShadingSrc (thePhongCompLight, theBits);
2019     }
2020   }
2021   else
2022   {
2023     if ((theBits & OpenGl_PO_TextureRGB) != 0)
2024     {
2025       aSrcVertExtraOut  += THE_VARY_TexCoord_OUT;
2026       aSrcFragExtraOut  += THE_VARY_TexCoord_IN;
2027       aSrcVertExtraMain += THE_VARY_TexCoord_Trsf;
2028
2029       aSrcFragGetColor =
2030         EOL"vec4 getColor(void)"
2031         EOL"{"
2032         EOL"  vec4 aColor = " thePhongCompLight ";"
2033         EOL"  return occTexture2D(occSamplerBaseColor, TexCoord.st / TexCoord.w) * aColor;"
2034         EOL"}";
2035     }
2036   }
2037
2038   if ((theBits & OpenGl_PO_VertColor) != 0)
2039   {
2040     aSrcVertExtraOut    += EOL"THE_SHADER_OUT vec4 VertColor;";
2041     aSrcVertExtraMain   += EOL"  VertColor = occVertColor;";
2042     aSrcFragGetVertColor = EOL"THE_SHADER_IN  vec4 VertColor;"
2043                            EOL"vec4 getVertColor(void) { return VertColor; }";
2044   }
2045
2046   int aNbClipPlanes = 0;
2047   if ((theBits & OpenGl_PO_ClipPlanesN) != 0)
2048   {
2049     if ((theBits & OpenGl_PO_ClipPlanes1) != 0)
2050     {
2051       aNbClipPlanes = 1;
2052       aSrcFragExtraMain += THE_FRAG_CLIP_PLANES_1;
2053     }
2054     else if ((theBits & OpenGl_PO_ClipPlanes2) != 0)
2055     {
2056       aNbClipPlanes = 2;
2057       aSrcFragExtraMain += THE_FRAG_CLIP_PLANES_2;
2058     }
2059     else
2060     {
2061       aNbClipPlanes = Graphic3d_ShaderProgram::THE_MAX_CLIP_PLANES_DEFAULT;
2062       aSrcFragExtraMain += THE_FRAG_CLIP_PLANES_N;
2063     }
2064   }
2065   if ((theBits & OpenGl_PO_WriteOit) != 0)
2066   {
2067     aProgramSrc->SetNbFragmentOutputs (2);
2068     aProgramSrc->SetWeightOitOutput (true);
2069   }
2070
2071   aSrcVert = TCollection_AsciiString()
2072     + (isFlatNormal ? "" : THE_FUNC_transformNormal)
2073     + EOL
2074       EOL"THE_SHADER_OUT vec4 PositionWorld;"
2075       EOL"THE_SHADER_OUT vec4 Position;"
2076       EOL"THE_SHADER_OUT vec3 View;"
2077     + (isFlatNormal ? ""
2078     : EOL"THE_SHADER_OUT vec3 Normal;")
2079     + EOL
2080     + aSrcVertExtraOut
2081     + EOL"void main()"
2082       EOL"{"
2083       EOL"  PositionWorld = occModelWorldMatrix * occVertex;"
2084       EOL"  Position      = occWorldViewMatrix * PositionWorld;"
2085     + (isFlatNormal ? ""
2086     : EOL"  Normal        = transformNormal (occNormal);")
2087     + EOL"  View          = vec3 (0.0, 0.0, 1.0);"
2088     + aSrcVertExtraMain
2089     + EOL"  gl_Position = occProjectionMatrix * occWorldViewMatrix * occModelWorldMatrix * occVertex;"
2090       EOL"}";
2091
2092   Standard_Integer aNbLights = 0;
2093   const TCollection_AsciiString aLights = stdComputeLighting (aNbLights, (theBits & OpenGl_PO_VertColor) != 0);
2094   aSrcFrag = TCollection_AsciiString()
2095     + EOL"THE_SHADER_IN vec4 PositionWorld;"
2096       EOL"THE_SHADER_IN vec4 Position;"
2097       EOL"THE_SHADER_IN vec3 View;"
2098     + (isFlatNormal
2099     ? EOL"vec3 Normal;"
2100     : EOL"THE_SHADER_IN vec3 Normal;")
2101     + EOL
2102     + aSrcFragExtraOut
2103     + aSrcFragGetVertColor
2104     + aLights
2105     + aSrcFragGetColor
2106     + EOL
2107       EOL"void main()"
2108       EOL"{"
2109     + aSrcFragExtraMain
2110     + (isFlatNormal
2111     ? EOL"  Normal = normalize (cross (dFdx (Position.xyz / Position.w), dFdy (Position.xyz / Position.w)));"
2112     : "")
2113     + EOL"  occSetFragColor (getColor());"
2114     + aSrcFragWriteOit
2115     + EOL"}";
2116
2117 #if !defined(GL_ES_VERSION_2_0)
2118   if (myContext->core32 != NULL)
2119   {
2120     aProgramSrc->SetHeader ("#version 150");
2121   }
2122 #else
2123   if (myContext->IsGlGreaterEqual (3, 1))
2124   {
2125     // prefer "100 es" on OpenGL ES 3.0 devices
2126     // and    "300 es" on newer devices (3.1+)
2127     aProgramSrc->SetHeader ("#version 300 es");
2128   }
2129   else if (isFlatNormal)
2130   {
2131     if (myContext->IsGlGreaterEqual (3, 0))
2132     {
2133       aProgramSrc->SetHeader ("#version 300 es");
2134     }
2135     else if (myContext->oesStdDerivatives)
2136     {
2137       aProgramSrc->SetHeader ("#extension GL_OES_standard_derivatives : enable");
2138     }
2139     else
2140     {
2141       myContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION,
2142                               GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_MEDIUM,
2143                               "Warning: flat shading requires OpenGL ES 3.0+ or GL_OES_standard_derivatives extension.");
2144     }
2145   }
2146 #endif
2147   aProgramSrc->SetNbLightsMax (aNbLights);
2148   aProgramSrc->SetNbClipPlanesMax (aNbClipPlanes);
2149   aProgramSrc->SetAlphaTest ((theBits & OpenGl_PO_AlphaTest) != 0);
2150   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_VERTEX,   aSrcVert));
2151   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_FRAGMENT, aSrcFrag));
2152   TCollection_AsciiString aKey;
2153   if (!Create (aProgramSrc, aKey, theProgram))
2154   {
2155     theProgram = new OpenGl_ShaderProgram(); // just mark as invalid
2156     return Standard_False;
2157   }
2158   return Standard_True;
2159 }
2160
2161 // =======================================================================
2162 // function : prepareStdProgramStereo
2163 // purpose  :
2164 // =======================================================================
2165 Standard_Boolean OpenGl_ShaderManager::prepareStdProgramStereo (Handle(OpenGl_ShaderProgram)& theProgram,
2166                                                                 const Graphic3d_StereoMode    theStereoMode)
2167 {
2168   Handle(Graphic3d_ShaderProgram) aProgramSrc = new Graphic3d_ShaderProgram();
2169   TCollection_AsciiString aSrcVert =
2170       EOL"THE_SHADER_OUT vec2 TexCoord;"
2171       EOL"void main()"
2172       EOL"{"
2173       EOL"  TexCoord    = occVertex.zw;"
2174       EOL"  gl_Position = vec4(occVertex.x, occVertex.y, 0.0, 1.0);"
2175       EOL"}";
2176
2177   TCollection_AsciiString aSrcFrag;
2178   switch (theStereoMode)
2179   {
2180     case Graphic3d_StereoMode_Anaglyph:
2181     {
2182       aSrcFrag =
2183           EOL"uniform sampler2D uLeftSampler;"
2184           EOL"uniform sampler2D uRightSampler;"
2185           EOL
2186           EOL"uniform mat4 uMultL;"
2187           EOL"uniform mat4 uMultR;"
2188           EOL
2189           EOL"const vec4 THE_POW_UP   =       vec4 (2.2, 2.2, 2.2, 1.0);"
2190           EOL"const vec4 THE_POW_DOWN = 1.0 / vec4 (2.2, 2.2, 2.2, 1.0);"
2191           EOL
2192           EOL"THE_SHADER_IN vec2 TexCoord;"
2193           EOL
2194           EOL"void main()"
2195           EOL"{"
2196           EOL"  vec4 aColorL = occTexture2D (uLeftSampler,  TexCoord);"
2197           EOL"  vec4 aColorR = occTexture2D (uRightSampler, TexCoord);"
2198           EOL"  aColorL = pow (aColorL, THE_POW_UP);" // normalize
2199           EOL"  aColorR = pow (aColorR, THE_POW_UP);"
2200           EOL"  vec4 aColor = uMultR * aColorR + uMultL * aColorL;"
2201           EOL"  occSetFragColor (pow (aColor, THE_POW_DOWN));"
2202           EOL"}";
2203       break;
2204     }
2205     case Graphic3d_StereoMode_RowInterlaced:
2206     {
2207       aSrcFrag =
2208           EOL"uniform sampler2D uLeftSampler;"
2209           EOL"uniform sampler2D uRightSampler;"
2210           EOL
2211           EOL"THE_SHADER_IN vec2 TexCoord;"
2212           EOL
2213           EOL"void main()"
2214           EOL"{"
2215           EOL"  vec4 aColorL = occTexture2D (uLeftSampler,  TexCoord);"
2216           EOL"  vec4 aColorR = occTexture2D (uRightSampler, TexCoord);"
2217           EOL"  if (int (mod (gl_FragCoord.y - 1023.5, 2.0)) != 1)"
2218           EOL"  {"
2219           EOL"    occSetFragColor (aColorL);"
2220           EOL"  }"
2221           EOL"  else"
2222           EOL"  {"
2223           EOL"    occSetFragColor (aColorR);"
2224           EOL"  }"
2225           EOL"}";
2226       break;
2227     }
2228     case Graphic3d_StereoMode_ColumnInterlaced:
2229     {
2230       aSrcFrag =
2231           EOL"uniform sampler2D uLeftSampler;"
2232           EOL"uniform sampler2D uRightSampler;"
2233           EOL
2234           EOL"THE_SHADER_IN vec2 TexCoord;"
2235           EOL
2236           EOL"void main()"
2237           EOL"{"
2238           EOL"  vec4 aColorL = occTexture2D (uLeftSampler,  TexCoord);"
2239           EOL"  vec4 aColorR = occTexture2D (uRightSampler, TexCoord);"
2240           EOL"  if (int (mod (gl_FragCoord.x - 1023.5, 2.0)) == 1)"
2241           EOL"  {"
2242           EOL"    occSetFragColor (aColorL);"
2243           EOL"  }"
2244           EOL"  else"
2245           EOL"  {"
2246           EOL"    occSetFragColor (aColorR);"
2247           EOL"  }"
2248           EOL"}";
2249       break;
2250     }
2251     case Graphic3d_StereoMode_ChessBoard:
2252     {
2253       aSrcFrag =
2254           EOL"uniform sampler2D uLeftSampler;"
2255           EOL"uniform sampler2D uRightSampler;"
2256           EOL
2257           EOL"THE_SHADER_IN vec2 TexCoord;"
2258           EOL
2259           EOL"void main()"
2260           EOL"{"
2261           EOL"  vec4 aColorL = occTexture2D (uLeftSampler,  TexCoord);"
2262           EOL"  vec4 aColorR = occTexture2D (uRightSampler, TexCoord);"
2263           EOL"  bool isEvenX = int(mod(floor(gl_FragCoord.x - 1023.5), 2.0)) != 1;"
2264           EOL"  bool isEvenY = int(mod(floor(gl_FragCoord.y - 1023.5), 2.0)) == 1;"
2265           EOL"  if ((isEvenX && isEvenY) || (!isEvenX && !isEvenY))"
2266           EOL"  {"
2267           EOL"    occSetFragColor (aColorL);"
2268           EOL"  }"
2269           EOL"  else"
2270           EOL"  {"
2271           EOL"    occSetFragColor (aColorR);"
2272           EOL"  }"
2273           EOL"}";
2274       break;
2275     }
2276     case Graphic3d_StereoMode_SideBySide:
2277     {
2278       aSrcFrag =
2279           EOL"uniform sampler2D uLeftSampler;"
2280           EOL"uniform sampler2D uRightSampler;"
2281           EOL
2282           EOL"THE_SHADER_IN vec2 TexCoord;"
2283           EOL
2284           EOL"void main()"
2285           EOL"{"
2286           EOL"  vec2 aTexCoord = vec2 (TexCoord.x * 2.0, TexCoord.y);"
2287           EOL"  if (TexCoord.x > 0.5)"
2288           EOL"  {"
2289           EOL"    aTexCoord.x -= 1.0;"
2290           EOL"  }"
2291           EOL"  vec4 aColorL = occTexture2D (uLeftSampler,  aTexCoord);"
2292           EOL"  vec4 aColorR = occTexture2D (uRightSampler, aTexCoord);"
2293           EOL"  if (TexCoord.x <= 0.5)"
2294           EOL"  {"
2295           EOL"    occSetFragColor (aColorL);"
2296           EOL"  }"
2297           EOL"  else"
2298           EOL"  {"
2299           EOL"    occSetFragColor (aColorR);"
2300           EOL"  }"
2301           EOL"}";
2302       break;
2303     }
2304     case Graphic3d_StereoMode_OverUnder:
2305     {
2306       aSrcFrag =
2307           EOL"uniform sampler2D uLeftSampler;"
2308           EOL"uniform sampler2D uRightSampler;"
2309           EOL
2310           EOL"THE_SHADER_IN vec2 TexCoord;"
2311           EOL
2312           EOL"void main()"
2313           EOL"{"
2314           EOL"  vec2 aTexCoord = vec2 (TexCoord.x, TexCoord.y * 2.0);"
2315           EOL"  if (TexCoord.y > 0.5)"
2316           EOL"  {"
2317           EOL"    aTexCoord.y -= 1.0;"
2318           EOL"  }"
2319           EOL"  vec4 aColorL = occTexture2D (uLeftSampler,  aTexCoord);"
2320           EOL"  vec4 aColorR = occTexture2D (uRightSampler, aTexCoord);"
2321           EOL"  if (TexCoord.y <= 0.5)"
2322           EOL"  {"
2323           EOL"    occSetFragColor (aColorL);"
2324           EOL"  }"
2325           EOL"  else"
2326           EOL"  {"
2327           EOL"    occSetFragColor (aColorR);"
2328           EOL"  }"
2329           EOL"}";
2330       break;
2331     }
2332     case Graphic3d_StereoMode_QuadBuffer:
2333     case Graphic3d_StereoMode_SoftPageFlip:
2334     default:
2335     {
2336       /*const Handle(OpenGl_ShaderProgram)& aProgram = myStereoPrograms[Graphic3d_StereoMode_QuadBuffer];
2337       if (!aProgram.IsNull())
2338       {
2339         return aProgram->IsValid();
2340       }*/
2341       aSrcFrag =
2342           EOL"uniform sampler2D uLeftSampler;"
2343           EOL"uniform sampler2D uRightSampler;"
2344           EOL
2345           EOL"THE_SHADER_IN vec2 TexCoord;"
2346           EOL
2347           EOL"void main()"
2348           EOL"{"
2349           EOL"  vec4 aColorL = occTexture2D (uLeftSampler,  TexCoord);"
2350           EOL"  vec4 aColorR = occTexture2D (uRightSampler, TexCoord);"
2351           EOL"  aColorL.b = 0.0;"
2352           EOL"  aColorL.g = 0.0;"
2353           EOL"  aColorR.r = 0.0;"
2354           EOL"  occSetFragColor (aColorL + aColorR);"
2355           EOL"}";
2356       break;
2357     }
2358   }
2359
2360 #if !defined(GL_ES_VERSION_2_0)
2361   if (myContext->core32 != NULL)
2362   {
2363     aProgramSrc->SetHeader ("#version 150");
2364   }
2365 #else
2366   if (myContext->IsGlGreaterEqual (3, 1))
2367   {
2368     // prefer "100 es" on OpenGL ES 3.0 devices
2369     // and    "300 es" on newer devices (3.1+)
2370     aProgramSrc->SetHeader ("#version 300 es");
2371   }
2372 #endif
2373
2374   aProgramSrc->SetNbLightsMax (0);
2375   aProgramSrc->SetNbClipPlanesMax (0);
2376   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_VERTEX,   aSrcVert));
2377   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_FRAGMENT, aSrcFrag));
2378   TCollection_AsciiString aKey;
2379   if (!Create (aProgramSrc, aKey, theProgram))
2380   {
2381     theProgram = new OpenGl_ShaderProgram(); // just mark as invalid
2382     return Standard_False;
2383   }
2384
2385   myContext->BindProgram (theProgram);
2386   theProgram->SetSampler (myContext, "uLeftSampler",  Graphic3d_TextureUnit_0);
2387   theProgram->SetSampler (myContext, "uRightSampler", Graphic3d_TextureUnit_1);
2388   myContext->BindProgram (NULL);
2389   return Standard_True;
2390 }
2391
2392 // =======================================================================
2393 // function : bindProgramWithState
2394 // purpose  :
2395 // =======================================================================
2396 Standard_Boolean OpenGl_ShaderManager::bindProgramWithState (const Handle(OpenGl_ShaderProgram)& theProgram)
2397 {
2398   const Standard_Boolean isBound = myContext->BindProgram (theProgram);
2399   if (isBound
2400   && !theProgram.IsNull())
2401   {
2402     theProgram->ApplyVariables (myContext);
2403   }
2404   PushState (theProgram);
2405   return isBound;
2406 }