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