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