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