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