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