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