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