b2f4ea940a1dee2520a6c858dd47d17dd9d47051
[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   //! Generate map key for light sources configuration.
381   static TCollection_AsciiString genLightKey (const Handle(Graphic3d_LightSet)& theLights)
382   {
383     if (theLights->NbEnabled() <= THE_NB_UNROLLED_LIGHTS_MAX)
384     {
385       return TCollection_AsciiString ("l_") + theLights->KeyEnabledLong();
386     }
387
388     const Standard_Integer aMaxLimit = roundUpMaxLightSources (theLights->NbEnabled());
389     return TCollection_AsciiString ("l_") + theLights->KeyEnabledShort() + aMaxLimit;
390   }
391 }
392
393 // =======================================================================
394 // function : OpenGl_ShaderManager
395 // purpose  : Creates new empty shader manager
396 // =======================================================================
397 OpenGl_ShaderManager::OpenGl_ShaderManager (OpenGl_Context* theContext)
398 : myFfpProgram (new OpenGl_ShaderProgramFFP()),
399   myShadingModel (Graphic3d_TOSM_VERTEX),
400   myUnlitPrograms (new OpenGl_SetOfShaderPrograms()),
401   myContext  (theContext),
402   myHasLocalOrigin (Standard_False),
403   myLastView (NULL)
404 {
405   //
406 }
407
408 // =======================================================================
409 // function : ~OpenGl_ShaderManager
410 // purpose  : Releases resources of shader manager
411 // =======================================================================
412 OpenGl_ShaderManager::~OpenGl_ShaderManager()
413 {
414   myProgramList.Clear();
415 }
416
417 // =======================================================================
418 // function : clear
419 // purpose  :
420 // =======================================================================
421 void OpenGl_ShaderManager::clear()
422 {
423   myProgramList.Clear();
424   myLightPrograms.Nullify();
425   myUnlitPrograms = new OpenGl_SetOfShaderPrograms();
426   myMapOfLightPrograms.Clear();
427   myFontProgram.Nullify();
428   myBlitProgram.Nullify();
429   myBoundBoxProgram.Nullify();
430   myBoundBoxVertBuffer.Nullify();
431   for (Standard_Integer aModeIter = 0; aModeIter < Graphic3d_StereoMode_NB; ++aModeIter)
432   {
433     myStereoPrograms[aModeIter].Nullify();
434   }
435   switchLightPrograms();
436 }
437
438 // =======================================================================
439 // function : Create
440 // purpose  : Creates new shader program
441 // =======================================================================
442 Standard_Boolean OpenGl_ShaderManager::Create (const Handle(Graphic3d_ShaderProgram)& theProxy,
443                                                TCollection_AsciiString&               theShareKey,
444                                                Handle(OpenGl_ShaderProgram)&          theProgram)
445 {
446   theProgram.Nullify();
447   if (theProxy.IsNull())
448   {
449     return Standard_False;
450   }
451
452   theShareKey = theProxy->GetId();
453   if (myContext->GetResource<Handle(OpenGl_ShaderProgram)> (theShareKey, theProgram))
454   {
455     if (theProgram->Share())
456     {
457       myProgramList.Append (theProgram);
458     }
459     return Standard_True;
460   }
461
462   theProgram = new OpenGl_ShaderProgram (theProxy);
463   if (!theProgram->Initialize (myContext, theProxy->ShaderObjects()))
464   {
465     theProgram->Release (myContext);
466     theShareKey.Clear();
467     theProgram.Nullify();
468     return Standard_False;
469   }
470
471   myProgramList.Append (theProgram);
472   myContext->ShareResource (theShareKey, theProgram);
473   return Standard_True;
474 }
475
476 // =======================================================================
477 // function : Unregister
478 // purpose  : Removes specified shader program from the manager
479 // =======================================================================
480 void OpenGl_ShaderManager::Unregister (TCollection_AsciiString&      theShareKey,
481                                        Handle(OpenGl_ShaderProgram)& theProgram)
482 {
483   for (OpenGl_ShaderProgramList::Iterator anIt (myProgramList); anIt.More(); anIt.Next())
484   {
485     if (anIt.Value() == theProgram)
486     {
487       if (!theProgram->UnShare())
488       {
489         theShareKey.Clear();
490         theProgram.Nullify();
491         return;
492       }
493
494       myProgramList.Remove (anIt);
495       break;
496     }
497   }
498
499   const TCollection_AsciiString anID = theProgram->myProxy->GetId();
500   if (anID.IsEmpty())
501   {
502     myContext->DelayedRelease (theProgram);
503     theProgram.Nullify();
504   }
505   else
506   {
507     theProgram.Nullify();
508     myContext->ReleaseResource (anID, Standard_True);
509   }
510 }
511
512 // =======================================================================
513 // function : ShaderPrograms
514 // purpose  : Returns list of registered shader programs
515 // =======================================================================
516 const OpenGl_ShaderProgramList& OpenGl_ShaderManager::ShaderPrograms() const
517 {
518   return myProgramList;
519 }
520
521 // =======================================================================
522 // function : Empty
523 // purpose  : Returns true if no program objects are attached
524 // =======================================================================
525 Standard_Boolean OpenGl_ShaderManager::IsEmpty() const
526 {
527   return myProgramList.IsEmpty();
528 }
529
530 // =======================================================================
531 // function : switchLightPrograms
532 // purpose  :
533 // =======================================================================
534 void OpenGl_ShaderManager::switchLightPrograms()
535 {
536   const Handle(Graphic3d_LightSet)& aLights = myLightSourceState.LightSources();
537   if (aLights.IsNull())
538   {
539     myLightPrograms = myUnlitPrograms;
540     return;
541   }
542
543   const TCollection_AsciiString aKey = genLightKey (aLights);
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, "font", 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->SetId ("occt_blit");
1384   aProgramSrc->SetNbLightsMax (0);
1385   aProgramSrc->SetNbClipPlanesMax (0);
1386   aProgramSrc->AttachShader (OpenGl_ShaderObject::CreateFromSource (aSrcVert, Graphic3d_TOS_VERTEX,   aUniforms, aStageInOuts));
1387   aProgramSrc->AttachShader (OpenGl_ShaderObject::CreateFromSource (aSrcFrag, Graphic3d_TOS_FRAGMENT, aUniforms, aStageInOuts));
1388   TCollection_AsciiString aKey;
1389   if (!Create (aProgramSrc, aKey, myBlitProgram))
1390   {
1391     myBlitProgram = new OpenGl_ShaderProgram(); // just mark as invalid
1392     return Standard_False;
1393   }
1394
1395   myContext->BindProgram (myBlitProgram);
1396   myBlitProgram->SetSampler (myContext, "uColorSampler", Graphic3d_TextureUnit_0);
1397   myBlitProgram->SetSampler (myContext, "uDepthSampler", Graphic3d_TextureUnit_1);
1398   myContext->BindProgram (NULL);
1399   return Standard_True;
1400 }
1401
1402 // =======================================================================
1403 // function : prepareStdProgramOitCompositing
1404 // purpose  :
1405 // =======================================================================
1406 Standard_Boolean OpenGl_ShaderManager::prepareStdProgramOitCompositing (const Standard_Boolean theMsaa)
1407 {
1408   Handle(OpenGl_ShaderProgram)& aProgram = myOitCompositingProgram[theMsaa ? 1 : 0];
1409   Handle(Graphic3d_ShaderProgram) aProgramSrc = new Graphic3d_ShaderProgram();
1410   TCollection_AsciiString aSrcVert, aSrcFrag;
1411
1412   OpenGl_ShaderObject::ShaderVariableList aUniforms, aStageInOuts;
1413   aStageInOuts.Append (OpenGl_ShaderObject::ShaderVariable ("vec2 TexCoord", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
1414
1415   aSrcVert =
1416     EOL"void main()"
1417     EOL"{"
1418     EOL"  TexCoord    = occVertex.zw;"
1419     EOL"  gl_Position = vec4 (occVertex.x, occVertex.y, 0.0, 1.0);"
1420     EOL"}";
1421
1422   if (!theMsaa)
1423   {
1424     aUniforms.Append (OpenGl_ShaderObject::ShaderVariable ("sampler2D uAccumTexture",  Graphic3d_TOS_FRAGMENT));
1425     aUniforms.Append (OpenGl_ShaderObject::ShaderVariable ("sampler2D uWeightTexture", Graphic3d_TOS_FRAGMENT));
1426     aSrcFrag =
1427       EOL"void main()"
1428       EOL"{"
1429       EOL"  vec4 aAccum   = occTexture2D (uAccumTexture,  TexCoord);"
1430       EOL"  float aWeight = occTexture2D (uWeightTexture, TexCoord).r;"
1431       EOL"  occSetFragColor (vec4 (aAccum.rgb / max (aWeight, 0.00001), aAccum.a));"
1432       EOL"}";
1433   #if !defined(GL_ES_VERSION_2_0)
1434     if (myContext->IsGlGreaterEqual (3, 2))
1435     {
1436       aProgramSrc->SetHeader ("#version 150");
1437     }
1438   #else
1439     if (myContext->IsGlGreaterEqual (3, 0))
1440     {
1441       aProgramSrc->SetHeader ("#version 300 es");
1442     }
1443   #endif
1444   }
1445   else
1446   {
1447     aUniforms.Append (OpenGl_ShaderObject::ShaderVariable ("sampler2DMS uAccumTexture",  Graphic3d_TOS_FRAGMENT));
1448     aUniforms.Append (OpenGl_ShaderObject::ShaderVariable ("sampler2DMS uWeightTexture", Graphic3d_TOS_FRAGMENT));
1449     aSrcFrag =
1450       EOL"void main()"
1451       EOL"{"
1452       EOL"  ivec2 aTexel  = ivec2 (vec2 (textureSize (uAccumTexture)) * TexCoord);"
1453       EOL"  vec4 aAccum   = texelFetch (uAccumTexture,  aTexel, gl_SampleID);"
1454       EOL"  float aWeight = texelFetch (uWeightTexture, aTexel, gl_SampleID).r;"
1455       EOL"  occSetFragColor (vec4 (aAccum.rgb / max (aWeight, 0.00001), aAccum.a));"
1456       EOL"}";
1457   #if !defined(GL_ES_VERSION_2_0)
1458     if (myContext->IsGlGreaterEqual (4, 0))
1459     {
1460       aProgramSrc->SetHeader ("#version 400");
1461     }
1462   #else
1463     if (myContext->IsGlGreaterEqual (3, 2))
1464     {
1465       aProgramSrc->SetHeader ("#version 320 es");
1466     }
1467     else if (myContext->IsGlGreaterEqual (3, 0))
1468     {
1469       aProgramSrc->SetHeader ("#version 300 es"); // with GL_OES_sample_variables extension
1470     }
1471   #endif
1472   }
1473
1474   aProgramSrc->SetId (theMsaa ? "occt_weight-oit-msaa" : "occt_weight-oit");
1475   aProgramSrc->SetNbLightsMax (0);
1476   aProgramSrc->SetNbClipPlanesMax (0);
1477   aProgramSrc->AttachShader (OpenGl_ShaderObject::CreateFromSource (aSrcVert, Graphic3d_TOS_VERTEX,   aUniforms, aStageInOuts));
1478   aProgramSrc->AttachShader (OpenGl_ShaderObject::CreateFromSource (aSrcFrag, Graphic3d_TOS_FRAGMENT, aUniforms, aStageInOuts));
1479   TCollection_AsciiString aKey;
1480   if (!Create (aProgramSrc, aKey, aProgram))
1481   {
1482     aProgram = new OpenGl_ShaderProgram(); // just mark as invalid
1483     return Standard_False;
1484   }
1485
1486   myContext->BindProgram (aProgram);
1487   aProgram->SetSampler (myContext, "uAccumTexture",  Graphic3d_TextureUnit_0);
1488   aProgram->SetSampler (myContext, "uWeightTexture", Graphic3d_TextureUnit_1);
1489   myContext->BindProgram (Handle(OpenGl_ShaderProgram)());
1490   return Standard_True;
1491 }
1492
1493 // =======================================================================
1494 // function : pointSpriteAlphaSrc
1495 // purpose  :
1496 // =======================================================================
1497 TCollection_AsciiString OpenGl_ShaderManager::pointSpriteAlphaSrc (const Standard_Integer theBits)
1498 {
1499   TCollection_AsciiString aSrcGetAlpha = EOL"float getAlpha(void) { return occTexture2D(occSamplerBaseColor, " THE_VEC2_glPointCoord ").a; }";
1500 #if !defined(GL_ES_VERSION_2_0)
1501   if (myContext->core11 == NULL
1502    && (theBits & OpenGl_PO_TextureA) != 0)
1503   {
1504     aSrcGetAlpha = EOL"float getAlpha(void) { return occTexture2D(occSamplerBaseColor, " THE_VEC2_glPointCoord ").r; }";
1505   }
1506 #else
1507   (void )theBits;
1508 #endif
1509   return aSrcGetAlpha;
1510 }
1511
1512 namespace
1513 {
1514
1515   // =======================================================================
1516   // function : textureUsed
1517   // purpose  :
1518   // =======================================================================
1519   static bool textureUsed (const Standard_Integer theBits)
1520   {
1521     return (theBits & OpenGl_PO_TextureA) != 0 || (theBits & OpenGl_PO_TextureRGB) != 0;
1522   }
1523
1524 }
1525
1526 // =======================================================================
1527 // function : defaultGlslVersion
1528 // purpose  :
1529 // =======================================================================
1530 int OpenGl_ShaderManager::defaultGlslVersion (const Handle(Graphic3d_ShaderProgram)& theProgram,
1531                                               const TCollection_AsciiString& theName,
1532                                               int theBits,
1533                                               bool theUsesDerivates) const
1534 {
1535   int aBits = theBits;
1536 #if !defined(GL_ES_VERSION_2_0)
1537   if (myContext->core32 != NULL)
1538   {
1539     theProgram->SetHeader ("#version 150");
1540   }
1541   else
1542   {
1543     if ((theBits & OpenGl_PO_StippleLine) != 0)
1544     {
1545       if (myContext->IsGlGreaterEqual (3, 0))
1546       {
1547         theProgram->SetHeader ("#version 130");
1548       }
1549       else if (myContext->CheckExtension ("GL_EXT_gpu_shader4"))
1550       {
1551         theProgram->SetHeader ("#extension GL_EXT_gpu_shader4 : enable");
1552       }
1553       else
1554       {
1555         aBits = aBits & ~OpenGl_PO_StippleLine;
1556       }
1557     }
1558   }
1559   (void )theUsesDerivates;
1560 #else
1561   // prefer "100 es" on OpenGL ES 3.0- devices (save the features unavailable before "300 es")
1562   // and    "300 es" on OpenGL ES 3.1+ devices
1563   if (myContext->IsGlGreaterEqual (3, 1))
1564   {
1565     if ((theBits & OpenGl_PO_NeedsGeomShader) != 0)
1566     {
1567       theProgram->SetHeader (myContext->hasGeometryStage != OpenGl_FeatureInExtensions ? "#version 320 es" : "#version 310 es");
1568     }
1569     else
1570     {
1571       theProgram->SetHeader ("#version 300 es");
1572     }
1573   }
1574   else
1575   {
1576     if ((theBits & OpenGl_PO_WriteOit) != 0
1577      || (theBits & OpenGl_PO_StippleLine) != 0)
1578     {
1579       if (myContext->IsGlGreaterEqual (3, 0))
1580       {
1581         theProgram->SetHeader ("#version 300 es");
1582       }
1583       else
1584       {
1585         aBits = aBits & ~OpenGl_PO_WriteOit;
1586         aBits = aBits & ~OpenGl_PO_StippleLine;
1587       }
1588     }
1589     if (theUsesDerivates)
1590     {
1591       if (myContext->IsGlGreaterEqual (3, 0))
1592       {
1593         theProgram->SetHeader ("#version 300 es");
1594       }
1595       else if (myContext->oesStdDerivatives)
1596       {
1597         theProgram->SetHeader ("#extension GL_OES_standard_derivatives : enable");
1598       }
1599     }
1600   }
1601 #endif
1602
1603   // should fit OpenGl_PO_NB
1604   char aBitsStr[64];
1605   Sprintf (aBitsStr, "%04x", aBits);
1606   theProgram->SetId (TCollection_AsciiString ("occt_") + theName + aBitsStr);
1607   return aBits;
1608 }
1609
1610 // =======================================================================
1611 // function : prepareGeomMainSrc
1612 // purpose  :
1613 // =======================================================================
1614 TCollection_AsciiString OpenGl_ShaderManager::prepareGeomMainSrc (OpenGl_ShaderObject::ShaderVariableList& theUnifoms,
1615                                                                   OpenGl_ShaderObject::ShaderVariableList& theStageInOuts,
1616                                                                   Standard_Integer theBits)
1617 {
1618   if ((theBits & OpenGl_PO_NeedsGeomShader) == 0)
1619   {
1620     return TCollection_AsciiString();
1621   }
1622
1623   TCollection_AsciiString aSrcMainGeom =
1624     EOL"void main()"
1625     EOL"{";
1626
1627   if ((theBits & OpenGl_PO_MeshEdges) != 0)
1628   {
1629     theUnifoms.Append    (OpenGl_ShaderObject::ShaderVariable ("vec4 occViewport",       Graphic3d_TOS_GEOMETRY));
1630     theUnifoms.Append    (OpenGl_ShaderObject::ShaderVariable ("bool occIsQuadMode",     Graphic3d_TOS_GEOMETRY));
1631     theUnifoms.Append    (OpenGl_ShaderObject::ShaderVariable ("float occLineWidth",     Graphic3d_TOS_GEOMETRY));
1632     theUnifoms.Append    (OpenGl_ShaderObject::ShaderVariable ("float occLineWidth",     Graphic3d_TOS_FRAGMENT));
1633     theUnifoms.Append    (OpenGl_ShaderObject::ShaderVariable ("float occLineFeather",   Graphic3d_TOS_FRAGMENT));
1634     theUnifoms.Append    (OpenGl_ShaderObject::ShaderVariable ("vec4 occWireframeColor", Graphic3d_TOS_FRAGMENT));
1635     theStageInOuts.Append(OpenGl_ShaderObject::ShaderVariable ("vec3 EdgeDistance",      Graphic3d_TOS_GEOMETRY | Graphic3d_TOS_FRAGMENT));
1636
1637     aSrcMainGeom = TCollection_AsciiString()
1638     + EOL"vec3 ViewPortTransform (vec4 theVec)"
1639       EOL"{"
1640       EOL"  vec3 aWinCoord = theVec.xyz / theVec.w;"
1641       EOL"  aWinCoord    = aWinCoord * 0.5 + 0.5;"
1642       EOL"  aWinCoord.xy = aWinCoord.xy * occViewport.zw + occViewport.xy;"
1643       EOL"  return aWinCoord;"
1644       EOL"}"
1645     + aSrcMainGeom
1646     + EOL"  vec3 aSideA = ViewPortTransform (gl_in[2].gl_Position) - ViewPortTransform (gl_in[1].gl_Position);"
1647       EOL"  vec3 aSideB = ViewPortTransform (gl_in[2].gl_Position) - ViewPortTransform (gl_in[0].gl_Position);"
1648       EOL"  vec3 aSideC = ViewPortTransform (gl_in[1].gl_Position) - ViewPortTransform (gl_in[0].gl_Position);"
1649       EOL"  float aQuadArea = abs (aSideB.x * aSideC.y - aSideB.y * aSideC.x);"
1650       EOL"  vec3 aLenABC    = vec3 (length (aSideA), length (aSideB), length (aSideC));"
1651       EOL"  vec3 aHeightABC = vec3 (aQuadArea) / aLenABC;"
1652       EOL"  aHeightABC = max (aHeightABC, vec3 (10.0 * occLineWidth));" // avoid shrunk presentation disappearing at distance
1653       EOL"  float aQuadModeHeightC = occIsQuadMode ? occLineWidth + 1.0 : 0.0;";
1654   }
1655
1656   for (Standard_Integer aVertIter = 0; aVertIter < 3; ++aVertIter)
1657   {
1658     const TCollection_AsciiString aVertIndex (aVertIter);
1659     // pass variables from Vertex shader to Fragment shader through Geometry shader
1660     for (OpenGl_ShaderObject::ShaderVariableList::Iterator aVarListIter (theStageInOuts); aVarListIter.More(); aVarListIter.Next())
1661     {
1662       if (aVarListIter.Value().Stages == (Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT))
1663       {
1664         const TCollection_AsciiString aVarName = aVarListIter.Value().Name.Token (" ", 2);
1665         aSrcMainGeom += TCollection_AsciiString()
1666          + EOL"  geomOut." + aVarName + " = geomIn[" + aVertIndex + "]." + aVarName + ";";
1667       }
1668     }
1669
1670     if ((theBits & OpenGl_PO_MeshEdges) != 0)
1671     {
1672       switch (aVertIter)
1673       {
1674         case 0: aSrcMainGeom += EOL"  EdgeDistance = vec3 (aHeightABC[0], 0.0, aQuadModeHeightC);"; break;
1675         case 1: aSrcMainGeom += EOL"  EdgeDistance = vec3 (0.0, aHeightABC[1], aQuadModeHeightC);"; break;
1676         case 2: aSrcMainGeom += EOL"  EdgeDistance = vec3 (0.0, 0.0, aHeightABC[2]);"; break;
1677       }
1678     }
1679     aSrcMainGeom += TCollection_AsciiString()
1680      + EOL"  gl_Position = gl_in[" + aVertIndex + "].gl_Position;"
1681        EOL"  EmitVertex();";
1682   }
1683   aSrcMainGeom +=
1684     EOL"  EndPrimitive();"
1685     EOL"}";
1686
1687   return aSrcMainGeom;
1688 }
1689
1690 // =======================================================================
1691 // function : prepareStdProgramUnlit
1692 // purpose  :
1693 // =======================================================================
1694 Standard_Boolean OpenGl_ShaderManager::prepareStdProgramUnlit (Handle(OpenGl_ShaderProgram)& theProgram,
1695                                                                const Standard_Integer        theBits)
1696 {
1697   Handle(Graphic3d_ShaderProgram) aProgramSrc = new Graphic3d_ShaderProgram();
1698   TCollection_AsciiString aSrcVert, aSrcVertExtraMain, aSrcVertExtraFunc, aSrcGetAlpha, aSrcVertEndMain;
1699   TCollection_AsciiString aSrcFrag, aSrcFragExtraMain;
1700   TCollection_AsciiString aSrcFragGetColor     = EOL"vec4 getColor(void) { return occColor; }";
1701   TCollection_AsciiString aSrcFragMainGetColor = EOL"  occSetFragColor (getFinalColor());";
1702   OpenGl_ShaderObject::ShaderVariableList aUniforms, aStageInOuts;
1703
1704   if ((theBits & OpenGl_PO_Point) != 0)
1705   {
1706   #if defined(GL_ES_VERSION_2_0)
1707     aSrcVertExtraMain += EOL"  gl_PointSize = occPointSize;";
1708   #endif
1709
1710     if ((theBits & OpenGl_PO_TextureRGB) != 0)
1711     {
1712       aSrcFragGetColor =
1713         EOL"vec4 getColor(void) { return occTexture2D(occSamplerBaseColor, " THE_VEC2_glPointCoord "); }";
1714     }
1715
1716     if (textureUsed (theBits))
1717     {
1718       aSrcGetAlpha = pointSpriteAlphaSrc (theBits);
1719
1720     #if !defined(GL_ES_VERSION_2_0)
1721       if (myContext->core11 != NULL
1722         && myContext->IsGlGreaterEqual (2, 1))
1723       {
1724         aProgramSrc->SetHeader ("#version 120"); // gl_PointCoord has been added since GLSL 1.2
1725       }
1726     #endif
1727
1728       aSrcFragMainGetColor =
1729         EOL"  vec4 aColor = getColor();"
1730         EOL"  aColor.a = getAlpha();"
1731         EOL"  if (aColor.a <= 0.1) discard;"
1732         EOL"  occSetFragColor (aColor);";
1733     }
1734     else
1735     {
1736       aSrcFragMainGetColor =
1737         EOL"  vec4 aColor = getColor();"
1738         EOL"  if (aColor.a <= 0.1) discard;"
1739         EOL"  occSetFragColor (aColor);";
1740     }
1741   }
1742   else
1743   {
1744     if ((theBits & OpenGl_PO_TextureRGB) != 0 || (theBits & OpenGl_PO_TextureEnv) != 0)
1745     {
1746       aStageInOuts.Append (OpenGl_ShaderObject::ShaderVariable ("vec4 TexCoord", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
1747     }
1748
1749     if ((theBits & OpenGl_PO_TextureRGB) != 0)
1750     {
1751       aSrcVertExtraMain += THE_VARY_TexCoord_Trsf;
1752
1753       aSrcFragGetColor =
1754         EOL"vec4 getColor(void) { return occTexture2D(occSamplerBaseColor, TexCoord.st / TexCoord.w); }";
1755     }
1756     else if ((theBits & OpenGl_PO_TextureEnv) != 0)
1757     {
1758       aSrcVertExtraFunc = THE_FUNC_transformNormal;
1759
1760       aSrcVertExtraMain +=
1761         EOL"  vec4 aPosition = occWorldViewMatrix * occModelWorldMatrix * occVertex;"
1762         EOL"  vec3 aNormal   = transformNormal (occNormal);"
1763         EOL"  vec3 aReflect  = reflect (normalize (aPosition.xyz), aNormal);"
1764         EOL"  aReflect.z += 1.0;"
1765         EOL"  TexCoord = vec4(aReflect.xy * inversesqrt (dot (aReflect, aReflect)) * 0.5 + vec2 (0.5), 0.0, 1.0);";
1766
1767       aSrcFragGetColor =
1768         EOL"vec4 getColor(void) { return occTexture2D (occSamplerBaseColor, TexCoord.st); }";
1769     }
1770   }
1771   if ((theBits & OpenGl_PO_VertColor) != 0)
1772   {
1773     aStageInOuts.Append (OpenGl_ShaderObject::ShaderVariable ("vec4 VertColor", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
1774     aSrcVertExtraMain += EOL"  VertColor = occVertColor;";
1775     aSrcFragGetColor  =  EOL"vec4 getColor(void) { return VertColor; }";
1776   }
1777
1778   int aNbClipPlanes = 0;
1779   if ((theBits & OpenGl_PO_ClipPlanesN) != 0)
1780   {
1781     aStageInOuts.Append (OpenGl_ShaderObject::ShaderVariable ("vec4 PositionWorld", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
1782     aStageInOuts.Append (OpenGl_ShaderObject::ShaderVariable ("vec4 Position",      Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
1783     aSrcVertExtraMain +=
1784       EOL"  PositionWorld = occModelWorldMatrix * occVertex;"
1785       EOL"  Position      = occWorldViewMatrix * PositionWorld;";
1786
1787     if ((theBits & OpenGl_PO_ClipPlanesN) == OpenGl_PO_ClipPlanesN)
1788     {
1789       aNbClipPlanes = Graphic3d_ShaderProgram::THE_MAX_CLIP_PLANES_DEFAULT;
1790       aSrcFragExtraMain += (theBits & OpenGl_PO_ClipChains) != 0
1791                          ? THE_FRAG_CLIP_CHAINS_N
1792                          : THE_FRAG_CLIP_PLANES_N;
1793     }
1794     else if ((theBits & OpenGl_PO_ClipPlanes1) != 0)
1795     {
1796       aNbClipPlanes = 1;
1797       aSrcFragExtraMain += THE_FRAG_CLIP_PLANES_1;
1798     }
1799     else if ((theBits & OpenGl_PO_ClipPlanes2) != 0)
1800     {
1801       aNbClipPlanes = 2;
1802       aSrcFragExtraMain += (theBits & OpenGl_PO_ClipChains) != 0
1803                          ? THE_FRAG_CLIP_CHAINS_2
1804                          : THE_FRAG_CLIP_PLANES_2;
1805     }
1806   }
1807   if ((theBits & OpenGl_PO_WriteOit) != 0)
1808   {
1809     aProgramSrc->SetNbFragmentOutputs (2);
1810     aProgramSrc->SetWeightOitOutput (true);
1811   }
1812
1813   if ((theBits & OpenGl_PO_StippleLine) != 0)
1814   {
1815     const Standard_Integer aBits = defaultGlslVersion (aProgramSrc, "unlit", theBits);
1816     if ((aBits & OpenGl_PO_StippleLine) != 0)
1817     {
1818       aUniforms.Append (OpenGl_ShaderObject::ShaderVariable ("int   uPattern", Graphic3d_TOS_FRAGMENT));
1819       aUniforms.Append (OpenGl_ShaderObject::ShaderVariable ("float uFactor",  Graphic3d_TOS_FRAGMENT));
1820       aStageInOuts.Append (OpenGl_ShaderObject::ShaderVariable ("vec2 ScreenSpaceCoord", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
1821       aSrcVertEndMain =
1822         EOL"  ScreenSpaceCoord = gl_Position.xy / gl_Position.w;";
1823       aSrcFragMainGetColor =
1824         EOL"  float anAngle      = atan (dFdx (ScreenSpaceCoord.x), dFdy (ScreenSpaceCoord.y));"
1825         EOL"  float aRotatePoint = gl_FragCoord.x * sin (anAngle) + gl_FragCoord.y * cos (anAngle);"
1826         EOL"  uint  aBit         = uint (floor (aRotatePoint / uFactor + 0.5)) & 15U;"
1827         EOL"  if ((uint (uPattern) & (1U << aBit)) == 0U) discard;"
1828         EOL"  vec4 aColor = getFinalColor();"
1829         EOL"  if (aColor.a <= 0.1) discard;"
1830         EOL"  occSetFragColor (aColor);";
1831     }
1832     else
1833     {
1834       myContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_HIGH, "Warning: stipple lines in GLSL will be ignored.");
1835     }
1836   }
1837
1838   aSrcVert =
1839       aSrcVertExtraFunc
1840     + EOL"void main()"
1841       EOL"{"
1842     + aSrcVertExtraMain
1843     + EOL"  gl_Position = occProjectionMatrix * occWorldViewMatrix * occModelWorldMatrix * occVertex;"
1844     + aSrcVertEndMain
1845     + EOL"}";
1846
1847   TCollection_AsciiString aSrcGeom = prepareGeomMainSrc (aUniforms, aStageInOuts, theBits);
1848   aSrcFragGetColor += (theBits & OpenGl_PO_MeshEdges) != 0
1849     ? THE_FRAG_WIREFRAME_COLOR
1850     : EOL"#define getFinalColor getColor";
1851
1852   aSrcFrag =
1853       aSrcFragGetColor
1854     + aSrcGetAlpha
1855     + EOL"void main()"
1856       EOL"{"
1857     + aSrcFragExtraMain
1858     + aSrcFragMainGetColor
1859     + EOL"}";
1860
1861   defaultGlslVersion (aProgramSrc, "unlit", theBits);
1862   aProgramSrc->SetNbLightsMax (0);
1863   aProgramSrc->SetNbClipPlanesMax (aNbClipPlanes);
1864   aProgramSrc->SetAlphaTest ((theBits & OpenGl_PO_AlphaTest) != 0);
1865   const Standard_Integer aNbGeomInputVerts = !aSrcGeom.IsEmpty() ? 3 : 0;
1866   aProgramSrc->AttachShader (OpenGl_ShaderObject::CreateFromSource (aSrcVert, Graphic3d_TOS_VERTEX,   aUniforms, aStageInOuts, "", "", aNbGeomInputVerts));
1867   aProgramSrc->AttachShader (OpenGl_ShaderObject::CreateFromSource (aSrcGeom, Graphic3d_TOS_GEOMETRY, aUniforms, aStageInOuts, "geomIn", "geomOut", aNbGeomInputVerts));
1868   aProgramSrc->AttachShader (OpenGl_ShaderObject::CreateFromSource (aSrcFrag, Graphic3d_TOS_FRAGMENT, aUniforms, aStageInOuts, "", "", aNbGeomInputVerts));
1869   TCollection_AsciiString aKey;
1870   if (!Create (aProgramSrc, aKey, theProgram))
1871   {
1872     theProgram = new OpenGl_ShaderProgram(); // just mark as invalid
1873     return Standard_False;
1874   }
1875   return Standard_True;
1876 }
1877
1878 // =======================================================================
1879 // function : pointSpriteShadingSrc
1880 // purpose  :
1881 // =======================================================================
1882 TCollection_AsciiString OpenGl_ShaderManager::pointSpriteShadingSrc (const TCollection_AsciiString theBaseColorSrc,
1883                                                                      const Standard_Integer theBits)
1884 {
1885   TCollection_AsciiString aSrcFragGetColor;
1886   if ((theBits & OpenGl_PO_TextureA) != 0)
1887   {
1888     aSrcFragGetColor = pointSpriteAlphaSrc (theBits) +
1889       EOL"vec4 getColor(void)"
1890       EOL"{"
1891       EOL"  vec4 aColor = " + theBaseColorSrc + ";"
1892       EOL"  aColor.a = getAlpha();"
1893       EOL"  if (aColor.a <= 0.1) discard;"
1894       EOL"  return aColor;"
1895       EOL"}";
1896   }
1897   else if ((theBits & OpenGl_PO_TextureRGB) != 0)
1898   {
1899     aSrcFragGetColor = TCollection_AsciiString() +
1900       EOL"vec4 getColor(void)"
1901       EOL"{"
1902       EOL"  vec4 aColor = " + theBaseColorSrc + ";"
1903       EOL"  aColor = occTexture2D(occSamplerBaseColor, " THE_VEC2_glPointCoord ") * aColor;"
1904       EOL"  if (aColor.a <= 0.1) discard;"
1905       EOL"  return aColor;"
1906       EOL"}";
1907   }
1908
1909   return aSrcFragGetColor;
1910 }
1911
1912 // =======================================================================
1913 // function : stdComputeLighting
1914 // purpose  :
1915 // =======================================================================
1916 TCollection_AsciiString OpenGl_ShaderManager::stdComputeLighting (Standard_Integer& theNbLights,
1917                                                                   Standard_Boolean  theHasVertColor)
1918 {
1919   TCollection_AsciiString aLightsFunc, aLightsLoop;
1920   theNbLights = 0;
1921   const Handle(Graphic3d_LightSet)& aLights = myLightSourceState.LightSources();
1922   if (!aLights.IsNull())
1923   {
1924     theNbLights = aLights->NbEnabled();
1925     if (theNbLights <= THE_NB_UNROLLED_LIGHTS_MAX)
1926     {
1927       Standard_Integer anIndex = 0;
1928       for (Graphic3d_LightSet::Iterator aLightIter (aLights, Graphic3d_LightSet::IterationFilter_ExcludeDisabledAndAmbient);
1929            aLightIter.More(); aLightIter.Next(), ++anIndex)
1930       {
1931         switch (aLightIter.Value()->Type())
1932         {
1933           case Graphic3d_TOLS_AMBIENT:
1934             --anIndex;
1935             break; // skip ambient
1936           case Graphic3d_TOLS_DIRECTIONAL:
1937             aLightsLoop = aLightsLoop + EOL"    directionalLight (" + anIndex + ", theNormal, theView, theIsFront);";
1938             break;
1939           case Graphic3d_TOLS_POSITIONAL:
1940             aLightsLoop = aLightsLoop + EOL"    pointLight (" + anIndex + ", theNormal, theView, aPoint, theIsFront);";
1941             break;
1942           case Graphic3d_TOLS_SPOT:
1943             aLightsLoop = aLightsLoop + EOL"    spotLight (" + anIndex + ", theNormal, theView, aPoint, theIsFront);";
1944             break;
1945         }
1946       }
1947     }
1948     else
1949     {
1950       theNbLights = roundUpMaxLightSources (theNbLights);
1951       bool isFirstInLoop = true;
1952       aLightsLoop = aLightsLoop +
1953         EOL"    for (int anIndex = 0; anIndex < occLightSourcesCount; ++anIndex)"
1954         EOL"    {"
1955         EOL"      int aType = occLight_Type (anIndex);";
1956       if (aLights->NbEnabledLightsOfType (Graphic3d_TOLS_DIRECTIONAL) > 0)
1957       {
1958         isFirstInLoop = false;
1959         aLightsLoop +=
1960           EOL"      if (aType == OccLightType_Direct)"
1961           EOL"      {"
1962           EOL"        directionalLight (anIndex, theNormal, theView, theIsFront);"
1963           EOL"      }";
1964       }
1965       if (aLights->NbEnabledLightsOfType (Graphic3d_TOLS_POSITIONAL) > 0)
1966       {
1967         if (!isFirstInLoop)
1968         {
1969           aLightsLoop += EOL"      else ";
1970         }
1971         isFirstInLoop = false;
1972         aLightsLoop +=
1973           EOL"      if (aType == OccLightType_Point)"
1974           EOL"      {"
1975           EOL"        pointLight (anIndex, theNormal, theView, aPoint, theIsFront);"
1976           EOL"      }";
1977       }
1978       if (aLights->NbEnabledLightsOfType (Graphic3d_TOLS_SPOT) > 0)
1979       {
1980         if (!isFirstInLoop)
1981         {
1982           aLightsLoop += EOL"      else ";
1983         }
1984         isFirstInLoop = false;
1985         aLightsLoop +=
1986           EOL"      if (aType == OccLightType_Spot)"
1987           EOL"      {"
1988           EOL"        spotLight (anIndex, theNormal, theView, aPoint, theIsFront);"
1989           EOL"      }";
1990       }
1991       aLightsLoop += EOL"    }";
1992     }
1993     if (aLights->NbEnabledLightsOfType (Graphic3d_TOLS_DIRECTIONAL) == 1
1994      && theNbLights == 1)
1995     {
1996       // use the version with hard-coded first index
1997       aLightsLoop = EOL"    directionalLightFirst(theNormal, theView, theIsFront);";
1998       aLightsFunc += THE_FUNC_directionalLightFirst;
1999     }
2000     else if (aLights->NbEnabledLightsOfType (Graphic3d_TOLS_DIRECTIONAL) > 0)
2001     {
2002       aLightsFunc += THE_FUNC_directionalLight;
2003     }
2004     if (aLights->NbEnabledLightsOfType (Graphic3d_TOLS_POSITIONAL) > 0)
2005     {
2006       aLightsFunc += THE_FUNC_pointLight;
2007     }
2008     if (aLights->NbEnabledLightsOfType (Graphic3d_TOLS_SPOT) > 0)
2009     {
2010       aLightsFunc += THE_FUNC_spotLight;
2011     }
2012   }
2013
2014   TCollection_AsciiString aGetMatAmbient = "theIsFront ? occFrontMaterial_Ambient()  : occBackMaterial_Ambient();";
2015   TCollection_AsciiString aGetMatDiffuse = "theIsFront ? occFrontMaterial_Diffuse()  : occBackMaterial_Diffuse();";
2016   if (theHasVertColor)
2017   {
2018     aGetMatAmbient = "getVertColor();";
2019     aGetMatDiffuse = "getVertColor();";
2020   }
2021
2022   return TCollection_AsciiString()
2023     + THE_FUNC_lightDef
2024     + aLightsFunc
2025     + EOL
2026       EOL"vec4 computeLighting (in vec3 theNormal,"
2027       EOL"                      in vec3 theView,"
2028       EOL"                      in vec4 thePoint,"
2029       EOL"                      in bool theIsFront)"
2030       EOL"{"
2031       EOL"  Ambient  = occLightAmbient.rgb;"
2032       EOL"  Diffuse  = vec3 (0.0);"
2033       EOL"  Specular = vec3 (0.0);"
2034       EOL"  vec3 aPoint = thePoint.xyz / thePoint.w;"
2035     + aLightsLoop
2036     + EOL"  vec4 aMatAmbient  = " + aGetMatAmbient
2037     + EOL"  vec4 aMatDiffuse  = " + aGetMatDiffuse
2038     + EOL"  vec4 aMatSpecular = theIsFront ? occFrontMaterial_Specular() : occBackMaterial_Specular();"
2039       EOL"  vec4 aMatEmission = theIsFront ? occFrontMaterial_Emission() : occBackMaterial_Emission();"
2040       EOL"  vec3 aColor = Ambient  * aMatAmbient.rgb"
2041       EOL"              + Diffuse  * aMatDiffuse.rgb"
2042       EOL"              + Specular * aMatSpecular.rgb"
2043       EOL"                         + aMatEmission.rgb;"
2044       EOL"  return vec4 (aColor, aMatDiffuse.a);"
2045       EOL"}";
2046 }
2047
2048 // =======================================================================
2049 // function : prepareStdProgramGouraud
2050 // purpose  :
2051 // =======================================================================
2052 Standard_Boolean OpenGl_ShaderManager::prepareStdProgramGouraud (Handle(OpenGl_ShaderProgram)& theProgram,
2053                                                                  const Standard_Integer        theBits)
2054 {
2055   Handle(Graphic3d_ShaderProgram) aProgramSrc = new Graphic3d_ShaderProgram();
2056   TCollection_AsciiString aSrcVert, aSrcVertColor, aSrcVertExtraMain;
2057   TCollection_AsciiString aSrcFrag, aSrcFragExtraMain;
2058   TCollection_AsciiString aSrcFragGetColor = EOL"vec4 getColor(void) { return gl_FrontFacing ? FrontColor : BackColor; }";
2059   OpenGl_ShaderObject::ShaderVariableList aUniforms, aStageInOuts;
2060
2061   if ((theBits & OpenGl_PO_Point) != 0)
2062   {
2063   #if defined(GL_ES_VERSION_2_0)
2064     aSrcVertExtraMain += EOL"  gl_PointSize = occPointSize;";
2065   #endif
2066
2067     if (textureUsed (theBits))
2068     {
2069       #if !defined(GL_ES_VERSION_2_0)
2070         if (myContext->core11 != NULL
2071          && myContext->IsGlGreaterEqual (2, 1))
2072         {
2073           aProgramSrc->SetHeader ("#version 120"); // gl_PointCoord has been added since GLSL 1.2
2074         }
2075       #endif
2076
2077       aSrcFragGetColor = pointSpriteShadingSrc ("gl_FrontFacing ? FrontColor : BackColor", theBits);
2078     }
2079   }
2080   else
2081   {
2082     if ((theBits & OpenGl_PO_TextureRGB) != 0)
2083     {
2084       aStageInOuts.Append (OpenGl_ShaderObject::ShaderVariable ("vec4 TexCoord", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
2085       aSrcVertExtraMain += THE_VARY_TexCoord_Trsf;
2086
2087       aSrcFragGetColor =
2088         EOL"vec4 getColor(void)"
2089         EOL"{"
2090         EOL"  vec4 aColor = gl_FrontFacing ? FrontColor : BackColor;"
2091         EOL"  return occTexture2D(occSamplerBaseColor, TexCoord.st / TexCoord.w) * aColor;"
2092         EOL"}";
2093     }
2094   }
2095
2096   if ((theBits & OpenGl_PO_VertColor) != 0)
2097   {
2098     aSrcVertColor = EOL"vec4 getVertColor(void) { return occVertColor; }";
2099   }
2100
2101   int aNbClipPlanes = 0;
2102   if ((theBits & OpenGl_PO_ClipPlanesN) != 0)
2103   {
2104     aStageInOuts.Append (OpenGl_ShaderObject::ShaderVariable ("vec4 PositionWorld", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
2105     aStageInOuts.Append (OpenGl_ShaderObject::ShaderVariable ("vec4 Position",      Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
2106     aSrcVertExtraMain +=
2107       EOL"  PositionWorld = aPositionWorld;"
2108       EOL"  Position      = aPosition;";
2109
2110     if ((theBits & OpenGl_PO_ClipPlanesN) == OpenGl_PO_ClipPlanesN)
2111     {
2112       aNbClipPlanes = Graphic3d_ShaderProgram::THE_MAX_CLIP_PLANES_DEFAULT;
2113       aSrcFragExtraMain += (theBits & OpenGl_PO_ClipChains) != 0
2114                          ? THE_FRAG_CLIP_CHAINS_N
2115                          : THE_FRAG_CLIP_PLANES_N;
2116     }
2117     else if ((theBits & OpenGl_PO_ClipPlanes1) != 0)
2118     {
2119       aNbClipPlanes = 1;
2120       aSrcFragExtraMain += THE_FRAG_CLIP_PLANES_1;
2121     }
2122     else if ((theBits & OpenGl_PO_ClipPlanes2) != 0)
2123     {
2124       aNbClipPlanes = 2;
2125       aSrcFragExtraMain += (theBits & OpenGl_PO_ClipChains) != 0
2126                           ? THE_FRAG_CLIP_CHAINS_2
2127                           : THE_FRAG_CLIP_PLANES_2;
2128     }
2129   }
2130   if ((theBits & OpenGl_PO_WriteOit) != 0)
2131   {
2132     aProgramSrc->SetNbFragmentOutputs (2);
2133     aProgramSrc->SetWeightOitOutput (true);
2134   }
2135
2136   aStageInOuts.Append (OpenGl_ShaderObject::ShaderVariable ("vec4 FrontColor", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
2137   aStageInOuts.Append (OpenGl_ShaderObject::ShaderVariable ("vec4 BackColor",  Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
2138
2139   Standard_Integer aNbLights = 0;
2140   const TCollection_AsciiString aLights = stdComputeLighting (aNbLights, (theBits & OpenGl_PO_VertColor) != 0);
2141   aSrcVert = TCollection_AsciiString()
2142     + THE_FUNC_transformNormal
2143     + EOL
2144     + aSrcVertColor
2145     + aLights
2146     + EOL"void main()"
2147       EOL"{"
2148       EOL"  vec4 aPositionWorld = occModelWorldMatrix * occVertex;"
2149       EOL"  vec4 aPosition      = occWorldViewMatrix * aPositionWorld;"
2150       EOL"  vec3 aNormal        = transformNormal (occNormal);"
2151       EOL"  vec3 aView          = vec3 (0.0, 0.0, 1.0);"
2152       EOL"  FrontColor  = computeLighting (normalize (aNormal), normalize (aView), aPosition, true);"
2153       EOL"  BackColor   = computeLighting (normalize (aNormal), normalize (aView), aPosition, false);"
2154     + aSrcVertExtraMain
2155     + EOL"  gl_Position = occProjectionMatrix * occWorldViewMatrix * occModelWorldMatrix * occVertex;"
2156       EOL"}";
2157
2158   TCollection_AsciiString aSrcGeom = prepareGeomMainSrc (aUniforms, aStageInOuts, theBits);
2159   aSrcFragGetColor += (theBits & OpenGl_PO_MeshEdges) != 0
2160     ? THE_FRAG_WIREFRAME_COLOR
2161     : EOL"#define getFinalColor getColor";
2162
2163   aSrcFrag = TCollection_AsciiString()
2164     + aSrcFragGetColor
2165     + EOL"void main()"
2166       EOL"{"
2167     + aSrcFragExtraMain
2168     + EOL"  occSetFragColor (getFinalColor());"
2169     + EOL"}";
2170
2171   const TCollection_AsciiString aProgId = TCollection_AsciiString ("gouraud-") + genLightKey (myLightSourceState.LightSources()) + "-";
2172   defaultGlslVersion (aProgramSrc, aProgId, theBits);
2173   aProgramSrc->SetNbLightsMax (aNbLights);
2174   aProgramSrc->SetNbClipPlanesMax (aNbClipPlanes);
2175   aProgramSrc->SetAlphaTest ((theBits & OpenGl_PO_AlphaTest) != 0);
2176   const Standard_Integer aNbGeomInputVerts = !aSrcGeom.IsEmpty() ? 3 : 0;
2177   aProgramSrc->AttachShader (OpenGl_ShaderObject::CreateFromSource (aSrcVert, Graphic3d_TOS_VERTEX,   aUniforms, aStageInOuts, "", "", aNbGeomInputVerts));
2178   aProgramSrc->AttachShader (OpenGl_ShaderObject::CreateFromSource (aSrcGeom, Graphic3d_TOS_GEOMETRY, aUniforms, aStageInOuts, "geomIn", "geomOut", aNbGeomInputVerts));
2179   aProgramSrc->AttachShader (OpenGl_ShaderObject::CreateFromSource (aSrcFrag, Graphic3d_TOS_FRAGMENT, aUniforms, aStageInOuts, "", "", aNbGeomInputVerts));
2180   TCollection_AsciiString aKey;
2181   if (!Create (aProgramSrc, aKey, theProgram))
2182   {
2183     theProgram = new OpenGl_ShaderProgram(); // just mark as invalid
2184     return Standard_False;
2185   }
2186   return Standard_True;
2187 }
2188
2189 // =======================================================================
2190 // function : prepareStdProgramPhong
2191 // purpose  :
2192 // =======================================================================
2193 Standard_Boolean OpenGl_ShaderManager::prepareStdProgramPhong (Handle(OpenGl_ShaderProgram)& theProgram,
2194                                                                const Standard_Integer        theBits,
2195                                                                const Standard_Boolean        theIsFlatNormal)
2196 {
2197   #define thePhongCompLight "computeLighting (normalize (Normal), normalize (View), Position, gl_FrontFacing)"
2198   const bool isFlatNormal = theIsFlatNormal
2199                          && myContext->hasFlatShading != OpenGl_FeatureNotAvailable;
2200   const char* aDFdxSignReversion = "";
2201 #if defined(GL_ES_VERSION_2_0)
2202   if (isFlatNormal != theIsFlatNormal)
2203   {
2204     myContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION,
2205                             GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_MEDIUM,
2206                             "Warning: flat shading requires OpenGL ES 3.0+ or GL_OES_standard_derivatives extension.");
2207   }
2208   else if (isFlatNormal
2209         && myContext->Vendor().Search("qualcomm") != -1)
2210   {
2211     // workaround Adreno driver bug computing reversed normal using dFdx/dFdy
2212     aDFdxSignReversion = "-";
2213     myContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_MEDIUM,
2214                             "Warning: applied workaround for flat shading normal computation using dFdx/dFdy on Adreno");
2215   }
2216 #endif
2217   Handle(Graphic3d_ShaderProgram) aProgramSrc = new Graphic3d_ShaderProgram();
2218   TCollection_AsciiString aSrcVert, aSrcVertExtraFunc, aSrcVertExtraMain;
2219   TCollection_AsciiString aSrcFrag, aSrcFragExtraOut, aSrcFragGetVertColor, aSrcFragExtraMain;
2220   TCollection_AsciiString aSrcFragGetColor = EOL"vec4 getColor(void) { return " thePhongCompLight "; }";
2221   OpenGl_ShaderObject::ShaderVariableList aUniforms, aStageInOuts;
2222   if ((theBits & OpenGl_PO_Point) != 0)
2223   {
2224   #if defined(GL_ES_VERSION_2_0)
2225     aSrcVertExtraMain += EOL"  gl_PointSize = occPointSize;";
2226   #endif
2227
2228     if (textureUsed (theBits))
2229     {
2230       #if !defined(GL_ES_VERSION_2_0)
2231         if (myContext->core11 != NULL
2232          && myContext->IsGlGreaterEqual (2, 1))
2233         {
2234           aProgramSrc->SetHeader ("#version 120"); // gl_PointCoord has been added since GLSL 1.2
2235         }
2236       #endif
2237
2238       aSrcFragGetColor = pointSpriteShadingSrc (thePhongCompLight, theBits);
2239     }
2240   }
2241   else
2242   {
2243     if ((theBits & OpenGl_PO_TextureRGB) != 0)
2244     {
2245       aStageInOuts.Append (OpenGl_ShaderObject::ShaderVariable ("vec4 TexCoord", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
2246       aSrcVertExtraMain += THE_VARY_TexCoord_Trsf;
2247
2248       aSrcFragGetColor =
2249         EOL"vec4 getColor(void)"
2250         EOL"{"
2251         EOL"  vec4 aColor = " thePhongCompLight ";"
2252         EOL"  return occTexture2D(occSamplerBaseColor, TexCoord.st / TexCoord.w) * aColor;"
2253         EOL"}";
2254     }
2255   }
2256
2257   if ((theBits & OpenGl_PO_VertColor) != 0)
2258   {
2259     aStageInOuts.Append (OpenGl_ShaderObject::ShaderVariable ("vec4 VertColor", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
2260     aSrcVertExtraMain   += EOL"  VertColor = occVertColor;";
2261     aSrcFragGetVertColor = EOL"vec4 getVertColor(void) { return VertColor; }";
2262   }
2263
2264   int aNbClipPlanes = 0;
2265   if ((theBits & OpenGl_PO_ClipPlanesN) != 0)
2266   {
2267     if ((theBits & OpenGl_PO_ClipPlanesN) == OpenGl_PO_ClipPlanesN)
2268     {
2269       aNbClipPlanes = Graphic3d_ShaderProgram::THE_MAX_CLIP_PLANES_DEFAULT;
2270       aSrcFragExtraMain += (theBits & OpenGl_PO_ClipChains) != 0
2271                          ? THE_FRAG_CLIP_CHAINS_N
2272                          : THE_FRAG_CLIP_PLANES_N;
2273     }
2274     else if ((theBits & OpenGl_PO_ClipPlanes1) != 0)
2275     {
2276       aNbClipPlanes = 1;
2277       aSrcFragExtraMain += THE_FRAG_CLIP_PLANES_1;
2278     }
2279     else if ((theBits & OpenGl_PO_ClipPlanes2) != 0)
2280     {
2281       aNbClipPlanes = 2;
2282       aSrcFragExtraMain += (theBits & OpenGl_PO_ClipChains) != 0
2283                          ? THE_FRAG_CLIP_CHAINS_2
2284                          : THE_FRAG_CLIP_PLANES_2;
2285     }
2286   }
2287   if ((theBits & OpenGl_PO_WriteOit) != 0)
2288   {
2289     aProgramSrc->SetNbFragmentOutputs (2);
2290     aProgramSrc->SetWeightOitOutput (true);
2291   }
2292
2293   if (isFlatNormal)
2294   {
2295     aSrcFragExtraOut  += EOL"vec3 Normal;";
2296     aSrcFragExtraMain += TCollection_AsciiString()
2297       + EOL"  Normal = " + aDFdxSignReversion + "normalize (cross (dFdx (Position.xyz / Position.w), dFdy (Position.xyz / Position.w)));"
2298         EOL"  if (!gl_FrontFacing) { Normal = -Normal; }";
2299   }
2300   else
2301   {
2302     aStageInOuts.Append (OpenGl_ShaderObject::ShaderVariable ("vec3 Normal", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
2303     aSrcVertExtraFunc += THE_FUNC_transformNormal;
2304     aSrcVertExtraMain += EOL"  Normal = transformNormal (occNormal);";
2305   }
2306
2307   aStageInOuts.Append (OpenGl_ShaderObject::ShaderVariable ("vec4 PositionWorld", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
2308   aStageInOuts.Append (OpenGl_ShaderObject::ShaderVariable ("vec4 Position",      Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
2309   aStageInOuts.Append (OpenGl_ShaderObject::ShaderVariable ("vec3 View",          Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
2310
2311   aSrcVert = TCollection_AsciiString()
2312     + aSrcVertExtraFunc
2313     + EOL"void main()"
2314       EOL"{"
2315       EOL"  PositionWorld = occModelWorldMatrix * occVertex;"
2316       EOL"  Position      = occWorldViewMatrix * PositionWorld;"
2317     + EOL"  View          = vec3 (0.0, 0.0, 1.0);"
2318     + aSrcVertExtraMain
2319     + EOL"  gl_Position = occProjectionMatrix * occWorldViewMatrix * occModelWorldMatrix * occVertex;"
2320       EOL"}";
2321
2322   TCollection_AsciiString aSrcGeom = prepareGeomMainSrc (aUniforms, aStageInOuts, theBits);
2323   aSrcFragGetColor += (theBits & OpenGl_PO_MeshEdges) != 0
2324     ? THE_FRAG_WIREFRAME_COLOR
2325     : EOL"#define getFinalColor getColor";
2326
2327   Standard_Integer aNbLights = 0;
2328   const TCollection_AsciiString aLights = stdComputeLighting (aNbLights, (theBits & OpenGl_PO_VertColor) != 0);
2329   aSrcFrag = TCollection_AsciiString()
2330     + EOL
2331     + aSrcFragExtraOut
2332     + aSrcFragGetVertColor
2333     + aLights
2334     + aSrcFragGetColor
2335     + EOL
2336       EOL"void main()"
2337       EOL"{"
2338     + aSrcFragExtraMain
2339     + EOL"  occSetFragColor (getFinalColor());"
2340     + EOL"}";
2341
2342   const TCollection_AsciiString aProgId = TCollection_AsciiString (theIsFlatNormal ? "flat-" : "phong-") + genLightKey (myLightSourceState.LightSources()) + "-";
2343   defaultGlslVersion (aProgramSrc, aProgId, theBits, isFlatNormal);
2344   aProgramSrc->SetNbLightsMax (aNbLights);
2345   aProgramSrc->SetNbClipPlanesMax (aNbClipPlanes);
2346   aProgramSrc->SetAlphaTest ((theBits & OpenGl_PO_AlphaTest) != 0);
2347   const Standard_Integer aNbGeomInputVerts = !aSrcGeom.IsEmpty() ? 3 : 0;
2348   aProgramSrc->AttachShader (OpenGl_ShaderObject::CreateFromSource (aSrcVert, Graphic3d_TOS_VERTEX,   aUniforms, aStageInOuts, "", "", aNbGeomInputVerts));
2349   aProgramSrc->AttachShader (OpenGl_ShaderObject::CreateFromSource (aSrcGeom, Graphic3d_TOS_GEOMETRY, aUniforms, aStageInOuts, "geomIn", "geomOut", aNbGeomInputVerts));
2350   aProgramSrc->AttachShader (OpenGl_ShaderObject::CreateFromSource (aSrcFrag, Graphic3d_TOS_FRAGMENT, aUniforms, aStageInOuts, "", "", aNbGeomInputVerts));
2351   TCollection_AsciiString aKey;
2352   if (!Create (aProgramSrc, aKey, theProgram))
2353   {
2354     theProgram = new OpenGl_ShaderProgram(); // just mark as invalid
2355     return Standard_False;
2356   }
2357   return Standard_True;
2358 }
2359
2360 // =======================================================================
2361 // function : prepareStdProgramStereo
2362 // purpose  :
2363 // =======================================================================
2364 Standard_Boolean OpenGl_ShaderManager::prepareStdProgramStereo (Handle(OpenGl_ShaderProgram)& theProgram,
2365                                                                 const Graphic3d_StereoMode    theStereoMode)
2366 {
2367   Handle(Graphic3d_ShaderProgram) aProgramSrc = new Graphic3d_ShaderProgram();
2368   OpenGl_ShaderObject::ShaderVariableList aUniforms, aStageInOuts;
2369
2370   aStageInOuts.Append (OpenGl_ShaderObject::ShaderVariable ("vec2 TexCoord", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
2371   TCollection_AsciiString aSrcVert =
2372       EOL"void main()"
2373       EOL"{"
2374       EOL"  TexCoord    = occVertex.zw;"
2375       EOL"  gl_Position = vec4(occVertex.x, occVertex.y, 0.0, 1.0);"
2376       EOL"}";
2377
2378   TCollection_AsciiString aSrcFrag;
2379   aUniforms.Append (OpenGl_ShaderObject::ShaderVariable ("sampler2D uLeftSampler",  Graphic3d_TOS_FRAGMENT));
2380   aUniforms.Append (OpenGl_ShaderObject::ShaderVariable ("sampler2D uRightSampler", Graphic3d_TOS_FRAGMENT));
2381   const char* aName = "stereo";
2382   switch (theStereoMode)
2383   {
2384     case Graphic3d_StereoMode_Anaglyph:
2385     {
2386       aName = "anaglyph";
2387       aUniforms.Append (OpenGl_ShaderObject::ShaderVariable ("mat4 uMultL", Graphic3d_TOS_FRAGMENT));
2388       aUniforms.Append (OpenGl_ShaderObject::ShaderVariable ("mat4 uMultR", Graphic3d_TOS_FRAGMENT));
2389       aSrcFrag =
2390           EOL"const vec4 THE_POW_UP   =       vec4 (2.2, 2.2, 2.2, 1.0);"
2391           EOL"const vec4 THE_POW_DOWN = 1.0 / vec4 (2.2, 2.2, 2.2, 1.0);"
2392           EOL
2393           EOL"void main()"
2394           EOL"{"
2395           EOL"  vec4 aColorL = occTexture2D (uLeftSampler,  TexCoord);"
2396           EOL"  vec4 aColorR = occTexture2D (uRightSampler, TexCoord);"
2397           EOL"  aColorL = pow (aColorL, THE_POW_UP);" // normalize
2398           EOL"  aColorR = pow (aColorR, THE_POW_UP);"
2399           EOL"  vec4 aColor = uMultR * aColorR + uMultL * aColorL;"
2400           EOL"  occSetFragColor (pow (aColor, THE_POW_DOWN));"
2401           EOL"}";
2402       break;
2403     }
2404     case Graphic3d_StereoMode_RowInterlaced:
2405     {
2406       aName = "row-interlaced";
2407       aSrcFrag =
2408           EOL"void main()"
2409           EOL"{"
2410           EOL"  vec4 aColorL = occTexture2D (uLeftSampler,  TexCoord);"
2411           EOL"  vec4 aColorR = occTexture2D (uRightSampler, TexCoord);"
2412           EOL"  if (int (mod (gl_FragCoord.y - 1023.5, 2.0)) != 1)"
2413           EOL"  {"
2414           EOL"    occSetFragColor (aColorL);"
2415           EOL"  }"
2416           EOL"  else"
2417           EOL"  {"
2418           EOL"    occSetFragColor (aColorR);"
2419           EOL"  }"
2420           EOL"}";
2421       break;
2422     }
2423     case Graphic3d_StereoMode_ColumnInterlaced:
2424     {
2425       aName = "column-interlaced";
2426       aSrcFrag =
2427           EOL"void main()"
2428           EOL"{"
2429           EOL"  vec4 aColorL = occTexture2D (uLeftSampler,  TexCoord);"
2430           EOL"  vec4 aColorR = occTexture2D (uRightSampler, TexCoord);"
2431           EOL"  if (int (mod (gl_FragCoord.x - 1023.5, 2.0)) == 1)"
2432           EOL"  {"
2433           EOL"    occSetFragColor (aColorL);"
2434           EOL"  }"
2435           EOL"  else"
2436           EOL"  {"
2437           EOL"    occSetFragColor (aColorR);"
2438           EOL"  }"
2439           EOL"}";
2440       break;
2441     }
2442     case Graphic3d_StereoMode_ChessBoard:
2443     {
2444       aName = "chessboard";
2445       aSrcFrag =
2446           EOL"void main()"
2447           EOL"{"
2448           EOL"  vec4 aColorL = occTexture2D (uLeftSampler,  TexCoord);"
2449           EOL"  vec4 aColorR = occTexture2D (uRightSampler, TexCoord);"
2450           EOL"  bool isEvenX = int(mod(floor(gl_FragCoord.x - 1023.5), 2.0)) != 1;"
2451           EOL"  bool isEvenY = int(mod(floor(gl_FragCoord.y - 1023.5), 2.0)) == 1;"
2452           EOL"  if ((isEvenX && isEvenY) || (!isEvenX && !isEvenY))"
2453           EOL"  {"
2454           EOL"    occSetFragColor (aColorL);"
2455           EOL"  }"
2456           EOL"  else"
2457           EOL"  {"
2458           EOL"    occSetFragColor (aColorR);"
2459           EOL"  }"
2460           EOL"}";
2461       break;
2462     }
2463     case Graphic3d_StereoMode_SideBySide:
2464     {
2465       aName = "sidebyside";
2466       aSrcFrag =
2467           EOL"void main()"
2468           EOL"{"
2469           EOL"  vec2 aTexCoord = vec2 (TexCoord.x * 2.0, TexCoord.y);"
2470           EOL"  if (TexCoord.x > 0.5)"
2471           EOL"  {"
2472           EOL"    aTexCoord.x -= 1.0;"
2473           EOL"  }"
2474           EOL"  vec4 aColorL = occTexture2D (uLeftSampler,  aTexCoord);"
2475           EOL"  vec4 aColorR = occTexture2D (uRightSampler, aTexCoord);"
2476           EOL"  if (TexCoord.x <= 0.5)"
2477           EOL"  {"
2478           EOL"    occSetFragColor (aColorL);"
2479           EOL"  }"
2480           EOL"  else"
2481           EOL"  {"
2482           EOL"    occSetFragColor (aColorR);"
2483           EOL"  }"
2484           EOL"}";
2485       break;
2486     }
2487     case Graphic3d_StereoMode_OverUnder:
2488     {
2489       aName = "overunder";
2490       aSrcFrag =
2491           EOL"void main()"
2492           EOL"{"
2493           EOL"  vec2 aTexCoord = vec2 (TexCoord.x, TexCoord.y * 2.0);"
2494           EOL"  if (TexCoord.y > 0.5)"
2495           EOL"  {"
2496           EOL"    aTexCoord.y -= 1.0;"
2497           EOL"  }"
2498           EOL"  vec4 aColorL = occTexture2D (uLeftSampler,  aTexCoord);"
2499           EOL"  vec4 aColorR = occTexture2D (uRightSampler, aTexCoord);"
2500           EOL"  if (TexCoord.y <= 0.5)"
2501           EOL"  {"
2502           EOL"    occSetFragColor (aColorL);"
2503           EOL"  }"
2504           EOL"  else"
2505           EOL"  {"
2506           EOL"    occSetFragColor (aColorR);"
2507           EOL"  }"
2508           EOL"}";
2509       break;
2510     }
2511     case Graphic3d_StereoMode_QuadBuffer:
2512     case Graphic3d_StereoMode_SoftPageFlip:
2513     default:
2514     {
2515       /*const Handle(OpenGl_ShaderProgram)& aProgram = myStereoPrograms[Graphic3d_StereoMode_QuadBuffer];
2516       if (!aProgram.IsNull())
2517       {
2518         return aProgram->IsValid();
2519       }*/
2520       aSrcFrag =
2521           EOL"void main()"
2522           EOL"{"
2523           EOL"  vec4 aColorL = occTexture2D (uLeftSampler,  TexCoord);"
2524           EOL"  vec4 aColorR = occTexture2D (uRightSampler, TexCoord);"
2525           EOL"  aColorL.b = 0.0;"
2526           EOL"  aColorL.g = 0.0;"
2527           EOL"  aColorR.r = 0.0;"
2528           EOL"  occSetFragColor (aColorL + aColorR);"
2529           EOL"}";
2530       break;
2531     }
2532   }
2533
2534   defaultGlslVersion (aProgramSrc, aName, 0);
2535   aProgramSrc->SetNbLightsMax (0);
2536   aProgramSrc->SetNbClipPlanesMax (0);
2537   aProgramSrc->AttachShader (OpenGl_ShaderObject::CreateFromSource (aSrcVert, Graphic3d_TOS_VERTEX,   aUniforms, aStageInOuts));
2538   aProgramSrc->AttachShader (OpenGl_ShaderObject::CreateFromSource (aSrcFrag, Graphic3d_TOS_FRAGMENT, aUniforms, aStageInOuts));
2539   TCollection_AsciiString aKey;
2540   if (!Create (aProgramSrc, aKey, theProgram))
2541   {
2542     theProgram = new OpenGl_ShaderProgram(); // just mark as invalid
2543     return Standard_False;
2544   }
2545
2546   myContext->BindProgram (theProgram);
2547   theProgram->SetSampler (myContext, "uLeftSampler",  Graphic3d_TextureUnit_0);
2548   theProgram->SetSampler (myContext, "uRightSampler", Graphic3d_TextureUnit_1);
2549   myContext->BindProgram (NULL);
2550   return Standard_True;
2551 }
2552
2553 // =======================================================================
2554 // function : prepareStdProgramBoundBox
2555 // purpose  :
2556 // =======================================================================
2557 Standard_Boolean OpenGl_ShaderManager::prepareStdProgramBoundBox()
2558 {
2559   Handle(Graphic3d_ShaderProgram) aProgramSrc = new Graphic3d_ShaderProgram();
2560
2561   OpenGl_ShaderObject::ShaderVariableList aUniforms, aStageInOuts;
2562   aUniforms.Append (OpenGl_ShaderObject::ShaderVariable ("vec3 occBBoxCenter", Graphic3d_TOS_VERTEX));
2563   aUniforms.Append (OpenGl_ShaderObject::ShaderVariable ("vec3 occBBoxSize",   Graphic3d_TOS_VERTEX));
2564
2565   TCollection_AsciiString aSrcVert =
2566     EOL"void main()"
2567     EOL"{"
2568     EOL"  vec4 aCenter = vec4(occVertex.xyz * occBBoxSize + occBBoxCenter, 1.0);"
2569     EOL"  vec4 aPos    = vec4(occVertex.xyz * occBBoxSize + occBBoxCenter, 1.0);"
2570     EOL"  gl_Position = occProjectionMatrix * occWorldViewMatrix * occModelWorldMatrix * aPos;"
2571     EOL"}";
2572
2573   TCollection_AsciiString aSrcFrag =
2574     EOL"void main()"
2575     EOL"{"
2576     EOL"  occSetFragColor (occColor);"
2577     EOL"}";
2578
2579   defaultGlslVersion (aProgramSrc, "bndbox", 0);
2580   aProgramSrc->SetNbLightsMax (0);
2581   aProgramSrc->SetNbClipPlanesMax (0);
2582   aProgramSrc->AttachShader (OpenGl_ShaderObject::CreateFromSource (aSrcVert, Graphic3d_TOS_VERTEX,   aUniforms, aStageInOuts));
2583   aProgramSrc->AttachShader (OpenGl_ShaderObject::CreateFromSource (aSrcFrag, Graphic3d_TOS_FRAGMENT, aUniforms, aStageInOuts));
2584   TCollection_AsciiString aKey;
2585   if (!Create (aProgramSrc, aKey, myBoundBoxProgram))
2586   {
2587     myBoundBoxProgram = new OpenGl_ShaderProgram(); // just mark as invalid
2588     return Standard_False;
2589   }
2590
2591   const OpenGl_Vec4 aMin (-0.5f, -0.5f, -0.5f, 1.0f);
2592   const OpenGl_Vec4 anAxisShifts[3] =
2593   {
2594     OpenGl_Vec4 (1.0f, 0.0f, 0.0f, 0.0f),
2595     OpenGl_Vec4 (0.0f, 1.0f, 0.0f, 0.0f),
2596     OpenGl_Vec4 (0.0f, 0.0f, 1.0f, 0.0f)
2597   };
2598
2599   const OpenGl_Vec4 aLookup1 (0.0f, 1.0f, 0.0f, 1.0f);
2600   const OpenGl_Vec4 aLookup2 (0.0f, 0.0f, 1.0f, 1.0f);
2601   OpenGl_Vec4 aLinesVertices[24];
2602   for (int anAxis = 0, aVertex = 0; anAxis < 3; ++anAxis)
2603   {
2604     for (int aCompIter = 0; aCompIter < 4; ++aCompIter)
2605     {
2606       aLinesVertices[aVertex++] = aMin
2607         + anAxisShifts[(anAxis + 1) % 3] * aLookup1[aCompIter]
2608         + anAxisShifts[(anAxis + 2) % 3] * aLookup2[aCompIter];
2609
2610       aLinesVertices[aVertex++] = aMin
2611         + anAxisShifts[anAxis]
2612         + anAxisShifts[(anAxis + 1) % 3] * aLookup1[aCompIter]
2613         + anAxisShifts[(anAxis + 2) % 3] * aLookup2[aCompIter];
2614     }
2615   }
2616   if (myContext->ToUseVbo())
2617   {
2618     myBoundBoxVertBuffer = new OpenGl_VertexBuffer();
2619     if (myBoundBoxVertBuffer->Init (myContext, 4, 24, aLinesVertices[0].GetData()))
2620     {
2621       myContext->ShareResource ("OpenGl_ShaderManager_BndBoxVbo", myBoundBoxVertBuffer);
2622       return Standard_True;
2623     }
2624   }
2625   myBoundBoxVertBuffer = new OpenGl_VertexBufferCompat();
2626   myBoundBoxVertBuffer->Init (myContext, 4, 24, aLinesVertices[0].GetData());
2627   myContext->ShareResource ("OpenGl_ShaderManager_BndBoxVbo", myBoundBoxVertBuffer);
2628   return Standard_True;
2629 }
2630
2631 // =======================================================================
2632 // function : bindProgramWithState
2633 // purpose  :
2634 // =======================================================================
2635 Standard_Boolean OpenGl_ShaderManager::bindProgramWithState (const Handle(OpenGl_ShaderProgram)& theProgram)
2636 {
2637   const Standard_Boolean isBound = myContext->BindProgram (theProgram);
2638   if (isBound
2639   && !theProgram.IsNull())
2640   {
2641     theProgram->ApplyVariables (myContext);
2642   }
2643   PushState (theProgram);
2644   return isBound;
2645 }