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