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