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