0032121: Draw Harness, ViewerTest - implement -reset option for vlight command
[occt.git] / src / Graphic3d / Graphic3d_ShaderManager.cxx
1 // Copyright (c) 2013-2021 OPEN CASCADE SAS
2 //
3 // This file is part of Open CASCADE Technology software library.
4 //
5 // This library is free software; you can redistribute it and/or modify it under
6 // the terms of the GNU Lesser General Public License version 2.1 as published
7 // by the Free Software Foundation, with special exception defined in the file
8 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
9 // distribution for complete text of the license and disclaimer of any warranty.
10 //
11 // Alternatively, this file may be used under the terms of Open CASCADE
12 // commercial license or contractual agreement.
13
14 #include <Graphic3d_ShaderManager.hxx>
15
16 #include <Graphic3d_LightSet.hxx>
17 #include <Graphic3d_ShaderProgram.hxx>
18 #include <Message.hxx>
19
20 #include "../Shaders/Shaders_DirectionalLightShadow_glsl.pxx"
21 #include "../Shaders/Shaders_PBRDistribution_glsl.pxx"
22 #include "../Shaders/Shaders_PBRDirectionalLight_glsl.pxx"
23 #include "../Shaders/Shaders_PBRGeometry_glsl.pxx"
24 #include "../Shaders/Shaders_PBRFresnel_glsl.pxx"
25 #include "../Shaders/Shaders_PBRCookTorrance_glsl.pxx"
26 #include "../Shaders/Shaders_PBRIllumination_glsl.pxx"
27 #include "../Shaders/Shaders_PBRPointLight_glsl.pxx"
28 #include "../Shaders/Shaders_PBRSpotLight_glsl.pxx"
29 #include "../Shaders/Shaders_PBREnvBaking_fs.pxx"
30 #include "../Shaders/Shaders_PBREnvBaking_vs.pxx"
31 #include "../Shaders/Shaders_PhongDirectionalLight_glsl.pxx"
32 #include "../Shaders/Shaders_PhongPointLight_glsl.pxx"
33 #include "../Shaders/Shaders_PhongSpotLight_glsl.pxx"
34 #include "../Shaders/Shaders_PointLightAttenuation_glsl.pxx"
35 #include "../Shaders/Shaders_TangentSpaceNormal_glsl.pxx"
36
37 IMPLEMENT_STANDARD_RTTIEXT(Graphic3d_ShaderManager, Standard_Transient)
38
39 namespace
40 {
41   //! Number specifying maximum number of light sources to prepare a GLSL program with unrolled loop.
42   const Standard_Integer THE_NB_UNROLLED_LIGHTS_MAX = 32;
43
44   //! Compute the size of array storing holding light sources definition.
45   static Standard_Integer roundUpMaxLightSources (Standard_Integer theNbLights)
46   {
47     Standard_Integer aMaxLimit = THE_NB_UNROLLED_LIGHTS_MAX;
48     for (; aMaxLimit < theNbLights; aMaxLimit *= 2) {}
49     return aMaxLimit;
50   }
51
52 #define EOL "\n"
53
54 //! Compute TexCoord value in Vertex Shader
55 const char THE_VARY_TexCoord_Trsf[] =
56   EOL"  float aRotSin = occTextureTrsf_RotationSin();"
57   EOL"  float aRotCos = occTextureTrsf_RotationCos();"
58   EOL"  vec2  aTex2   = vec2 (occTexCoord.x * aRotCos - occTexCoord.y * aRotSin,"
59   EOL"                        occTexCoord.x * aRotSin + occTexCoord.y * aRotCos);"
60   EOL"  aTex2 = (aTex2 + occTextureTrsf_Translation()) * occTextureTrsf_Scale();"
61   EOL"  TexCoord = vec4(aTex2, occTexCoord.zw);";
62
63 //! Auxiliary function to flip gl_PointCoord vertically
64 #define THE_VEC2_glPointCoord "vec2 (gl_PointCoord.x, 1.0 - gl_PointCoord.y)"
65
66 //! Auxiliary function to transform normal from model to view coordinate system.
67 const char THE_FUNC_transformNormal_view[] =
68   EOL"vec3 transformNormal (in vec3 theNormal)"
69   EOL"{"
70   EOL"  vec4 aResult = occWorldViewMatrixInverseTranspose"
71   EOL"               * occModelWorldMatrixInverseTranspose"
72   EOL"               * vec4 (theNormal, 0.0);"
73   EOL"  return normalize (aResult.xyz);"
74   EOL"}";
75
76 //! The same function as THE_FUNC_transformNormal but is used in PBR pipeline.
77 //! The normals are expected to be in world coordinate system in PBR pipeline.
78 const char THE_FUNC_transformNormal_world[] =
79   EOL"vec3 transformNormal (in vec3 theNormal)"
80   EOL"{"
81   EOL"  vec4 aResult = occModelWorldMatrixInverseTranspose"
82   EOL"               * vec4 (theNormal, 0.0);"
83   EOL"  return normalize (aResult.xyz);"
84   EOL"}";
85
86 //! Global shader variable for color definition with lighting enabled.
87 const char THE_FUNC_lightDef[] =
88   EOL"vec3 Ambient;"   //!< Ambient  contribution of light sources
89   EOL"vec3 Diffuse;"   //!< Diffuse  contribution of light sources
90   EOL"vec3 Specular;"; //!< Specular contribution of light sources
91
92 //! Global shader variable for color definition with lighting enabled.
93 const char THE_FUNC_PBR_lightDef[] =
94   EOL"vec3  DirectLighting;" //!< Accumulator of direct lighting from light sources
95   EOL"vec4  BaseColor;"      //!< Base color (albedo) of material for PBR
96   EOL"float Metallic;"       //!< Metallic coefficient of material
97   EOL"float NormalizedRoughness;" //!< Normalized roughness coefficient of material
98   EOL"float Roughness;"      //!< Roughness coefficient of material
99   EOL"vec3  Emission;"       //!< Light intensity emitted by material
100   EOL"float IOR;";           //!< Material's index of refraction
101
102 //! The same as Shaders_PhongDirectionalLight_glsl but for the light with zero index
103 //! (avoids limitations on some mobile devices).
104 const char THE_FUNC_directionalLightFirst[] =
105   EOL"void directionalLightFirst (in vec3 theNormal,"
106   EOL"                            in vec3 theView,"
107   EOL"                            in bool theIsFront,"
108   EOL"                            in float theShadow)"
109   EOL"{"
110   EOL"  vec3 aLight = occLight_Position (0);"
111   EOL
112   EOL"  vec3 aHalf = normalize (aLight + theView);"
113   EOL
114   EOL"  vec3  aFaceSideNormal = theIsFront ? theNormal : -theNormal;"
115   EOL"  float aNdotL = max (0.0, dot (aFaceSideNormal, aLight));"
116   EOL"  float aNdotH = max (0.0, dot (aFaceSideNormal, aHalf ));"
117   EOL
118   EOL"  float aSpecl = 0.0;"
119   EOL"  if (aNdotL > 0.0)"
120   EOL"  {"
121   EOL"    aSpecl = pow (aNdotH, occMaterial_Shininess(theIsFront));"
122   EOL"  }"
123   EOL
124   EOL"  Diffuse  += occLight_Diffuse(0)  * aNdotL * theShadow;"
125   EOL"  Specular += occLight_Specular(0) * aSpecl * theShadow;"
126   EOL"}";
127
128 //! Returns the real cubemap fetching direction considering sides orientation, memory layout and vertical flip.
129 const char THE_FUNC_cubemap_vector_transform[] =
130   EOL"vec3 cubemapVectorTransform (in vec3 theVector,"
131   EOL"                             in int  theYCoeff,"
132   EOL"                             in int  theZCoeff)"
133   EOL"{"
134   EOL"  theVector = theVector.yzx;"
135   EOL"  theVector.y *= float(theYCoeff);"
136   EOL"  theVector.z *= float(theZCoeff);"
137   EOL"  return theVector;"
138   EOL"}";
139
140 //! Process clipping planes in Fragment Shader.
141 //! Should be added at the beginning of the main() function.
142 const char THE_FRAG_CLIP_PLANES_N[] =
143   EOL"  for (int aPlaneIter = 0; aPlaneIter < occClipPlaneCount; ++aPlaneIter)"
144   EOL"  {"
145   EOL"    vec4 aClipEquation = occClipPlaneEquations[aPlaneIter];"
146   EOL"    if (dot (aClipEquation.xyz, PositionWorld.xyz / PositionWorld.w) + aClipEquation.w < 0.0)"
147   EOL"    {"
148   EOL"      discard;"
149   EOL"    }"
150   EOL"  }";
151
152 //! Process chains of clipping planes in Fragment Shader.
153 const char THE_FRAG_CLIP_CHAINS_N[] =
154 EOL"  for (int aPlaneIter = 0; aPlaneIter < occClipPlaneCount;)"
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"      if (occClipPlaneChains[aPlaneIter] == 1)"
160 EOL"      {"
161 EOL"        discard;"
162 EOL"      }"
163 EOL"      aPlaneIter += 1;"
164 EOL"    }"
165 EOL"    else"
166 EOL"    {"
167 EOL"      aPlaneIter += occClipPlaneChains[aPlaneIter];"
168 EOL"    }"
169 EOL"  }";
170
171 //! Process 1 clipping plane in Fragment Shader.
172 const char THE_FRAG_CLIP_PLANES_1[] =
173   EOL"  vec4 aClipEquation0 = occClipPlaneEquations[0];"
174   EOL"  if (dot (aClipEquation0.xyz, PositionWorld.xyz / PositionWorld.w) + aClipEquation0.w < 0.0)"
175   EOL"  {"
176   EOL"    discard;"
177   EOL"  }";
178
179 //! Process 2 clipping planes in Fragment Shader.
180 const char THE_FRAG_CLIP_PLANES_2[] =
181   EOL"  vec4 aClipEquation0 = occClipPlaneEquations[0];"
182   EOL"  vec4 aClipEquation1 = occClipPlaneEquations[1];"
183   EOL"  if (dot (aClipEquation0.xyz, PositionWorld.xyz / PositionWorld.w) + aClipEquation0.w < 0.0"
184   EOL"   || dot (aClipEquation1.xyz, PositionWorld.xyz / PositionWorld.w) + aClipEquation1.w < 0.0)"
185   EOL"  {"
186   EOL"    discard;"
187   EOL"  }";
188
189 //! Process a chain of 2 clipping planes in Fragment Shader (3/4 section).
190 const char THE_FRAG_CLIP_CHAINS_2[] =
191 EOL"  vec4 aClipEquation0 = occClipPlaneEquations[0];"
192 EOL"  vec4 aClipEquation1 = occClipPlaneEquations[1];"
193 EOL"  if (dot (aClipEquation0.xyz, PositionWorld.xyz / PositionWorld.w) + aClipEquation0.w < 0.0"
194 EOL"   && dot (aClipEquation1.xyz, PositionWorld.xyz / PositionWorld.w) + aClipEquation1.w < 0.0)"
195 EOL"  {"
196 EOL"    discard;"
197 EOL"  }";
198
199 //! Modify color for Wireframe presentation.
200 const char THE_FRAG_WIREFRAME_COLOR[] =
201 EOL"vec4 getFinalColor(void)"
202 EOL"{"
203 EOL"  float aDistance = min (min (EdgeDistance[0], EdgeDistance[1]), EdgeDistance[2]);"
204 EOL"  bool isHollow = occWireframeColor.a < 0.0;"
205 EOL"  float aMixVal = smoothstep (occLineWidth - occLineFeather * 0.5, occLineWidth + occLineFeather * 0.5, aDistance);"
206 EOL"  vec4 aMixColor = isHollow"
207 EOL"                 ? vec4 (getColor().rgb, 1.0 - aMixVal)"          // edges only (of interior color)
208 EOL"                 : mix (occWireframeColor, getColor(), aMixVal);" // interior + edges
209 EOL"  return aMixColor;"
210 EOL"}";
211
212 //! Compute gl_Position vertex shader output.
213 const char THE_VERT_gl_Position[] =
214 EOL"  gl_Position = occProjectionMatrix * occWorldViewMatrix * occModelWorldMatrix * occVertex;";
215
216 //! Displace gl_Position alongside vertex normal for outline rendering.
217 //! This code adds silhouette only for smooth surfaces of closed primitive, and produces visual artifacts on sharp edges.
218 const char THE_VERT_gl_Position_OUTLINE[] =
219 EOL"  float anOutlineDisp = occOrthoScale > 0.0 ? occOrthoScale : gl_Position.w;"
220 EOL"  vec4  anOutlinePos  = occVertex + vec4 (occNormal * (occSilhouetteThickness * anOutlineDisp), 0.0);"
221 EOL"  gl_Position = occProjectionMatrix * occWorldViewMatrix * occModelWorldMatrix * anOutlinePos;";
222
223 }
224
225 // =======================================================================
226 // function : genLightKey
227 // purpose  :
228 // =======================================================================
229 TCollection_AsciiString Graphic3d_ShaderManager::genLightKey (const Handle(Graphic3d_LightSet)& theLights,
230                                                               const bool theHasShadowMap) const
231 {
232   if (theLights->NbEnabled() <= THE_NB_UNROLLED_LIGHTS_MAX)
233   {
234     return theHasShadowMap
235          ? TCollection_AsciiString ("ls_") + theLights->KeyEnabledLong()
236          : TCollection_AsciiString ("l_")  + theLights->KeyEnabledLong();
237   }
238
239   const Standard_Integer aMaxLimit = roundUpMaxLightSources (theLights->NbEnabled());
240   return TCollection_AsciiString ("l_") + theLights->KeyEnabledShort() + aMaxLimit;
241 }
242
243 // =======================================================================
244 // function : Graphic3d_ShaderManager
245 // purpose  :
246 // =======================================================================
247 Graphic3d_ShaderManager::Graphic3d_ShaderManager (Aspect_GraphicsLibrary theGapi)
248 : myGapi (theGapi),
249   // desktop defines a dedicated API for point size, with gl_PointSize added later to GLSL
250   myHasFlatShading (true),
251   myToReverseDFdxSign (false),
252   mySetPointSize (myGapi == Aspect_GraphicsLibrary_OpenGLES),
253   myUseRedAlpha (false),
254   myToEmulateDepthClamp (true),
255   mySRgbState (true)
256 {
257   memset (myGlslExtensions, 0, sizeof(myGlslExtensions));
258 }
259
260 // =======================================================================
261 // function : ~Graphic3d_ShaderManager
262 // purpose  :
263 // =======================================================================
264 Graphic3d_ShaderManager::~Graphic3d_ShaderManager()
265 {
266   //
267 }
268
269 // =======================================================================
270 // function : hasGlslBitwiseOps
271 // purpose  :
272 // =======================================================================
273 bool Graphic3d_ShaderManager::hasGlslBitwiseOps() const
274 {
275   switch (myGapi)
276   {
277     case Aspect_GraphicsLibrary_OpenGL:
278     {
279       return IsGapiGreaterEqual (3, 0)
280           || myGlslExtensions[Graphic3d_GlslExtension_GL_EXT_gpu_shader4];
281     }
282     case Aspect_GraphicsLibrary_OpenGLES:
283     {
284       return IsGapiGreaterEqual (3, 0);
285     }
286   }
287   return false;
288 }
289
290 // =======================================================================
291 // function : defaultGlslVersion
292 // purpose  :
293 // =======================================================================
294 int Graphic3d_ShaderManager::defaultGlslVersion (const Handle(Graphic3d_ShaderProgram)& theProgram,
295                                                  const TCollection_AsciiString& theName,
296                                                  int theBits,
297                                                  bool theUsesDerivates) const
298 {
299   int aBits = theBits;
300   const bool toUseDerivates = theUsesDerivates
301                           || (theBits & Graphic3d_ShaderFlags_StippleLine) != 0
302                           || (theBits & Graphic3d_ShaderFlags_HasTextures) == Graphic3d_ShaderFlags_TextureNormal;
303   switch (myGapi)
304   {
305     case Aspect_GraphicsLibrary_OpenGL:
306     {
307       if (IsGapiGreaterEqual (3, 2))
308       {
309         theProgram->SetHeader ("#version 150");
310       }
311       else
312       {
313         // TangentSpaceNormal() function uses mat2x3 type
314         const bool toUseMat2x3 = (theBits & Graphic3d_ShaderFlags_HasTextures) == Graphic3d_ShaderFlags_TextureNormal;
315         // gl_PointCoord has been added since GLSL 1.2
316         const bool toUsePointCoord = (theBits & Graphic3d_ShaderFlags_PointSprite) != 0;
317         if (toUseMat2x3 || toUsePointCoord)
318         {
319           if (IsGapiGreaterEqual (2, 1))
320           {
321             theProgram->SetHeader ("#version 120");
322           }
323         }
324         if ((theBits & Graphic3d_ShaderFlags_StippleLine) != 0
325          || theProgram->IsPBR())
326         {
327           if (IsGapiGreaterEqual (3, 0))
328           {
329             theProgram->SetHeader ("#version 130");
330           }
331           else if (myGlslExtensions[Graphic3d_GlslExtension_GL_EXT_gpu_shader4])
332           {
333             // GL_EXT_gpu_shader4 defines GLSL type "unsigned int", while core GLSL specs define type "uint"
334             theProgram->SetHeader ("#extension GL_EXT_gpu_shader4 : enable\n"
335                                    "#define uint unsigned int");
336           }
337         }
338       }
339       (void )toUseDerivates;
340       break;
341     }
342     case Aspect_GraphicsLibrary_OpenGLES:
343     {
344     #if defined(__EMSCRIPTEN__)
345       if (IsGapiGreaterEqual (3, 0))
346       {
347         // consider this is browser responsibility to provide working WebGL 2.0 implementation
348         // and black-list broken drivers (there is no OpenGL ES greater than 3.0)
349         theProgram->SetHeader ("#version 300 es");
350       }
351     #endif
352       // prefer "100 es" on OpenGL ES 3.0- devices (save the features unavailable before "300 es")
353       // and    "300 es" on OpenGL ES 3.1+ devices
354       if (IsGapiGreaterEqual (3, 1))
355       {
356         if ((theBits & Graphic3d_ShaderFlags_NeedsGeomShader) != 0)
357         {
358           theProgram->SetHeader (IsGapiGreaterEqual (3, 2) ? "#version 320 es" : "#version 310 es");
359         }
360         else
361         {
362           theProgram->SetHeader ("#version 300 es");
363         }
364       }
365       else
366       {
367         TCollection_AsciiString aGles2Extensions;
368         if (theProgram->IsPBR())
369         {
370           if (IsGapiGreaterEqual (3, 0))
371           {
372             theProgram->SetHeader ("#version 300 es");
373           }
374           else if (myGlslExtensions[Graphic3d_GlslExtension_GL_EXT_shader_texture_lod])
375           {
376             aGles2Extensions += "#extension GL_EXT_shader_texture_lod : enable\n"
377                                 "#define textureCubeLod textureCubeLodEXT\n";
378           }
379         }
380         if ((theBits & Graphic3d_ShaderFlags_WriteOit) != 0
381          || (theBits & Graphic3d_ShaderFlags_OitDepthPeeling) != 0
382          || (theBits & Graphic3d_ShaderFlags_StippleLine) != 0)
383         {
384           if (IsGapiGreaterEqual (3, 0))
385           {
386             theProgram->SetHeader ("#version 300 es");
387           }
388           else
389           {
390             aBits = aBits & ~Graphic3d_ShaderFlags_WriteOit;
391             aBits = aBits & ~Graphic3d_ShaderFlags_OitDepthPeeling;
392             if (!myGlslExtensions[Graphic3d_GlslExtension_GL_OES_standard_derivatives])
393             {
394               aBits = aBits & ~Graphic3d_ShaderFlags_StippleLine;
395             }
396           }
397         }
398         if (toUseDerivates)
399         {
400           if (IsGapiGreaterEqual (3, 0))
401           {
402             theProgram->SetHeader ("#version 300 es");
403           }
404           else if (myGlslExtensions[Graphic3d_GlslExtension_GL_OES_standard_derivatives])
405           {
406             aGles2Extensions += "#extension GL_OES_standard_derivatives : enable\n";
407           }
408         }
409
410         if (!aGles2Extensions.IsEmpty())
411         {
412           theProgram->SetHeader (aGles2Extensions);
413         }
414       }
415       break;
416     }
417   }
418
419   // should fit Graphic3d_ShaderFlags_NB
420   char aBitsStr[64];
421   Sprintf (aBitsStr, "%04x", aBits);
422   theProgram->SetId (TCollection_AsciiString ("occt_") + theName + aBitsStr);
423   return aBits;
424 }
425
426 // =======================================================================
427 // function : defaultOitGlslVersion
428 // purpose  :
429 // =======================================================================
430 void Graphic3d_ShaderManager::defaultOitGlslVersion (const Handle(Graphic3d_ShaderProgram)& theProgram,
431                                                      const TCollection_AsciiString& theName,
432                                                      bool theMsaa) const
433 {
434   switch (myGapi)
435   {
436     case Aspect_GraphicsLibrary_OpenGL:
437     {
438       if (theMsaa)
439       {
440         if (IsGapiGreaterEqual (4, 0))
441         {
442           theProgram->SetHeader ("#version 400");
443         }
444       }
445       else
446       {
447         if (IsGapiGreaterEqual (3, 2))
448         {
449           theProgram->SetHeader ("#version 150");
450         }
451       }
452       break;
453     }
454     case Aspect_GraphicsLibrary_OpenGLES:
455     {
456       if (theMsaa)
457       {
458         if (IsGapiGreaterEqual (3, 2))
459         {
460           theProgram->SetHeader ("#version 320 es");
461         }
462         else if (IsGapiGreaterEqual (3, 0))
463         {
464           theProgram->SetHeader ("#version 300 es"); // with GL_OES_sample_variables extension
465         }
466       }
467       else
468       {
469         if (IsGapiGreaterEqual (3, 0))
470         {
471           theProgram->SetHeader ("#version 300 es");
472         }
473       }
474       break;
475     }
476   }
477   theProgram->SetId (TCollection_AsciiString ("occt_") + theName + (theMsaa ? "_msaa" : ""));
478 }
479
480 // =======================================================================
481 // function : getStdProgramFont
482 // purpose  :
483 // =======================================================================
484 Handle(Graphic3d_ShaderProgram) Graphic3d_ShaderManager::getStdProgramFont() const
485 {
486   Graphic3d_ShaderObject::ShaderVariableList aUniforms, aStageInOuts;
487   aUniforms   .Append (Graphic3d_ShaderObject::ShaderVariable ("sampler2D occSamplerBaseColor", Graphic3d_TOS_FRAGMENT));
488   aStageInOuts.Append (Graphic3d_ShaderObject::ShaderVariable ("vec2 TexCoord", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
489
490   TCollection_AsciiString aSrcVert = TCollection_AsciiString()
491     + EOL"void main()"
492       EOL"{"
493       EOL"  TexCoord = occTexCoord.st;"
494     + THE_VERT_gl_Position
495     + EOL"}";
496
497   TCollection_AsciiString
498     aSrcGetAlpha = myUseRedAlpha
499                  ? EOL"float getAlpha(void) { return occTexture2D(occSamplerBaseColor, TexCoord.st).r; }"
500                  : EOL"float getAlpha(void) { return occTexture2D(occSamplerBaseColor, TexCoord.st).a; }";
501
502   TCollection_AsciiString aSrcFrag =
503        aSrcGetAlpha
504      + EOL"void main()"
505        EOL"{"
506        EOL"  vec4 aColor = occColor;"
507        EOL"  aColor.a *= getAlpha();"
508        EOL"  if (aColor.a <= 0.285) discard;"
509        EOL"  occSetFragColor (aColor);"
510        EOL"}";
511
512   Handle(Graphic3d_ShaderProgram) aProgramSrc = new Graphic3d_ShaderProgram();
513   defaultGlslVersion (aProgramSrc, "font", 0);
514   aProgramSrc->SetDefaultSampler (false);
515   aProgramSrc->SetNbLightsMax (0);
516   aProgramSrc->SetNbShadowMaps (0);
517   aProgramSrc->SetNbClipPlanesMax (0);
518   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (aSrcVert, Graphic3d_TOS_VERTEX,   aUniforms, aStageInOuts));
519   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (aSrcFrag, Graphic3d_TOS_FRAGMENT, aUniforms, aStageInOuts));
520   return aProgramSrc;
521 }
522
523 // =======================================================================
524 // function : getStdProgramFboBlit
525 // purpose  :
526 // =======================================================================
527 Handle(Graphic3d_ShaderProgram) Graphic3d_ShaderManager::getStdProgramFboBlit (Standard_Integer theNbSamples,
528                                                                                Standard_Boolean theIsFallback_sRGB) const
529 {
530   Graphic3d_ShaderObject::ShaderVariableList aUniforms, aStageInOuts;
531   aStageInOuts.Append (Graphic3d_ShaderObject::ShaderVariable ("vec2 TexCoord", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
532
533   TCollection_AsciiString aSrcVert =
534       EOL"void main()"
535       EOL"{"
536       EOL"  TexCoord    = occVertex.zw;"
537       EOL"  gl_Position = vec4(occVertex.x, occVertex.y, 0.0, 1.0);"
538       EOL"}";
539
540   TCollection_AsciiString aSrcFrag;
541   if (theNbSamples > 1)
542   {
543     if (myGapi == Aspect_GraphicsLibrary_OpenGLES)
544     {
545       aUniforms.Append (Graphic3d_ShaderObject::ShaderVariable ("highp sampler2DMS uColorSampler", Graphic3d_TOS_FRAGMENT));
546       aUniforms.Append (Graphic3d_ShaderObject::ShaderVariable ("highp sampler2DMS uDepthSampler", Graphic3d_TOS_FRAGMENT));
547     }
548     else
549     {
550       aUniforms.Append (Graphic3d_ShaderObject::ShaderVariable ("sampler2DMS uColorSampler", Graphic3d_TOS_FRAGMENT));
551       aUniforms.Append (Graphic3d_ShaderObject::ShaderVariable ("sampler2DMS uDepthSampler", Graphic3d_TOS_FRAGMENT));
552     }
553
554     aSrcFrag = TCollection_AsciiString()
555     + EOL"#define THE_NUM_SAMPLES " + theNbSamples
556     + (theIsFallback_sRGB ? EOL"#define THE_SHIFT_sRGB" : "")
557     + EOL"void main()"
558       EOL"{"
559       EOL"  ivec2 aSize  = textureSize (uColorSampler);"
560       EOL"  ivec2 anUV   = ivec2 (vec2 (aSize) * TexCoord);"
561       EOL"  gl_FragDepth = texelFetch (uDepthSampler, anUV, THE_NUM_SAMPLES / 2 - 1).r;"
562       EOL
563       EOL"  vec4 aColor = vec4 (0.0);"
564       EOL"  for (int aSample = 0; aSample < THE_NUM_SAMPLES; ++aSample)"
565       EOL"  {"
566       EOL"    vec4 aVal = texelFetch (uColorSampler, anUV, aSample);"
567       EOL"    aColor += aVal;"
568       EOL"  }"
569       EOL"  aColor /= float(THE_NUM_SAMPLES);"
570       EOL"#ifdef THE_SHIFT_sRGB"
571       EOL"  aColor.rgb = pow (aColor.rgb, vec3 (1.0 / 2.2));"
572       EOL"#endif"
573       EOL"  occSetFragColor (aColor);"
574       EOL"}";
575   }
576   else
577   {
578     aUniforms.Append (Graphic3d_ShaderObject::ShaderVariable ("sampler2D uColorSampler", Graphic3d_TOS_FRAGMENT));
579     aUniforms.Append (Graphic3d_ShaderObject::ShaderVariable ("sampler2D uDepthSampler", Graphic3d_TOS_FRAGMENT));
580     aSrcFrag = TCollection_AsciiString()
581     + (theIsFallback_sRGB ? EOL"#define THE_SHIFT_sRGB" : "")
582     + EOL"void main()"
583       EOL"{"
584       EOL"  gl_FragDepth = occTexture2D (uDepthSampler, TexCoord).r;"
585       EOL"  vec4  aColor = occTexture2D (uColorSampler, TexCoord);"
586       EOL"#ifdef THE_SHIFT_sRGB"
587       EOL"  aColor.rgb = pow (aColor.rgb, vec3 (1.0 / 2.2));"
588       EOL"#endif"
589       EOL"  occSetFragColor (aColor);"
590       EOL"}";
591   }
592
593   Handle(Graphic3d_ShaderProgram) aProgramSrc = new Graphic3d_ShaderProgram();
594   switch (myGapi)
595   {
596     case Aspect_GraphicsLibrary_OpenGL:
597     {
598       if (IsGapiGreaterEqual (3, 2))
599       {
600         aProgramSrc->SetHeader ("#version 150");
601       }
602       break;
603     }
604     case Aspect_GraphicsLibrary_OpenGLES:
605     {
606       if (IsGapiGreaterEqual (3, 1))
607       {
608         // required for MSAA sampler
609         aProgramSrc->SetHeader ("#version 310 es");
610       }
611       else if (IsGapiGreaterEqual (3, 0))
612       {
613         aProgramSrc->SetHeader ("#version 300 es");
614       }
615       else if (myGlslExtensions[Graphic3d_GlslExtension_GL_EXT_frag_depth])
616       {
617         aProgramSrc->SetHeader ("#extension GL_EXT_frag_depth : enable"
618                                 EOL"#define gl_FragDepth gl_FragDepthEXT");
619       }
620       else
621       {
622         // there is no way to draw into depth buffer
623         aSrcFrag =
624           EOL"void main()"
625           EOL"{"
626           EOL"  occSetFragColor (occTexture2D (uColorSampler, TexCoord));"
627           EOL"}";
628       }
629       break;
630     }
631   }
632
633   TCollection_AsciiString anId = "occt_blit";
634   if (theNbSamples > 1)
635   {
636     anId += TCollection_AsciiString ("_msaa") + theNbSamples;
637   }
638   if (theIsFallback_sRGB)
639   {
640     anId += "_gamma";
641   }
642   aProgramSrc->SetId (anId);
643   aProgramSrc->SetDefaultSampler (false);
644   aProgramSrc->SetNbLightsMax (0);
645   aProgramSrc->SetNbShadowMaps (0);
646   aProgramSrc->SetNbClipPlanesMax (0);
647   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (aSrcVert, Graphic3d_TOS_VERTEX,   aUniforms, aStageInOuts));
648   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (aSrcFrag, Graphic3d_TOS_FRAGMENT, aUniforms, aStageInOuts));
649   return aProgramSrc;
650 }
651
652 // =======================================================================
653 // function : getStdProgramOitCompositing
654 // purpose  :
655 // =======================================================================
656 Handle(Graphic3d_ShaderProgram) Graphic3d_ShaderManager::getStdProgramOitCompositing (const Standard_Boolean theMsaa) const
657 {
658   Handle(Graphic3d_ShaderProgram) aProgramSrc = new Graphic3d_ShaderProgram();
659   TCollection_AsciiString aSrcVert, aSrcFrag;
660
661   Graphic3d_ShaderObject::ShaderVariableList aUniforms, aStageInOuts;
662   aStageInOuts.Append (Graphic3d_ShaderObject::ShaderVariable ("vec2 TexCoord", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
663
664   aSrcVert =
665     EOL"void main()"
666     EOL"{"
667     EOL"  TexCoord    = occVertex.zw;"
668     EOL"  gl_Position = vec4 (occVertex.x, occVertex.y, 0.0, 1.0);"
669     EOL"}";
670
671   if (!theMsaa)
672   {
673     aUniforms.Append (Graphic3d_ShaderObject::ShaderVariable ("sampler2D uAccumTexture",  Graphic3d_TOS_FRAGMENT));
674     aUniforms.Append (Graphic3d_ShaderObject::ShaderVariable ("sampler2D uWeightTexture", Graphic3d_TOS_FRAGMENT));
675     aSrcFrag =
676       EOL"void main()"
677       EOL"{"
678       EOL"  vec4 aAccum   = occTexture2D (uAccumTexture,  TexCoord);"
679       EOL"  float aWeight = occTexture2D (uWeightTexture, TexCoord).r;"
680       EOL"  occSetFragColor (vec4 (aAccum.rgb / max (aWeight, 0.00001), aAccum.a));"
681       EOL"}";
682   }
683   else
684   {
685     aUniforms.Append (Graphic3d_ShaderObject::ShaderVariable ("sampler2DMS uAccumTexture",  Graphic3d_TOS_FRAGMENT));
686     aUniforms.Append (Graphic3d_ShaderObject::ShaderVariable ("sampler2DMS uWeightTexture", Graphic3d_TOS_FRAGMENT));
687     aSrcFrag =
688       EOL"void main()"
689       EOL"{"
690       EOL"  ivec2 aTexel  = ivec2 (vec2 (textureSize (uAccumTexture)) * TexCoord);"
691       EOL"  vec4 aAccum   = texelFetch (uAccumTexture,  aTexel, gl_SampleID);"
692       EOL"  float aWeight = texelFetch (uWeightTexture, aTexel, gl_SampleID).r;"
693       EOL"  occSetFragColor (vec4 (aAccum.rgb / max (aWeight, 0.00001), aAccum.a));"
694       EOL"}";
695   }
696   defaultOitGlslVersion (aProgramSrc, "weight_oit", theMsaa);
697
698   aProgramSrc->SetDefaultSampler (false);
699   aProgramSrc->SetNbLightsMax (0);
700   aProgramSrc->SetNbShadowMaps (0);
701   aProgramSrc->SetNbClipPlanesMax (0);
702   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (aSrcVert, Graphic3d_TOS_VERTEX,   aUniforms, aStageInOuts));
703   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (aSrcFrag, Graphic3d_TOS_FRAGMENT, aUniforms, aStageInOuts));
704   return aProgramSrc;
705 }
706
707 // =======================================================================
708 // function : getStdProgramOitDepthPeelingBlend
709 // purpose  :
710 // =======================================================================
711 Handle(Graphic3d_ShaderProgram) Graphic3d_ShaderManager::getStdProgramOitDepthPeelingBlend (Standard_Boolean theMsaa) const
712 {
713   Handle(Graphic3d_ShaderProgram) aProgramSrc = new Graphic3d_ShaderProgram();
714   TCollection_AsciiString aSrcVert, aSrcFrag;
715
716   Graphic3d_ShaderObject::ShaderVariableList aUniforms, aStageInOuts;
717   aSrcVert =
718     EOL"void main()"
719     EOL"{"
720     EOL"  gl_Position = vec4 (occVertex.x, occVertex.y, 0.0, 1.0);"
721     EOL"}";
722
723   aUniforms.Append (Graphic3d_ShaderObject::ShaderVariable (theMsaa
724                                                        ? "sampler2DMS uDepthPeelingBackColor"
725                                                        :   "sampler2D uDepthPeelingBackColor", Graphic3d_TOS_FRAGMENT));
726   aSrcFrag = TCollection_AsciiString()
727   + EOL"void main()"
728     EOL"{"
729     EOL"  #define THE_SAMPLE_ID " + (theMsaa ? "gl_SampleID" : "0")
730   + EOL"  occFragColor = texelFetch (uDepthPeelingBackColor, ivec2 (gl_FragCoord.xy), THE_SAMPLE_ID);"
731     EOL"  if (occFragColor.a == 0.0) { discard; }"
732     EOL"}";
733
734   defaultOitGlslVersion (aProgramSrc, "oit_peeling_blend", theMsaa);
735   aProgramSrc->SetDefaultSampler (false);
736   aProgramSrc->SetNbLightsMax (0);
737   aProgramSrc->SetNbClipPlanesMax (0);
738   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (aSrcVert, Graphic3d_TOS_VERTEX,   aUniforms, aStageInOuts));
739   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (aSrcFrag, Graphic3d_TOS_FRAGMENT, aUniforms, aStageInOuts));
740   return aProgramSrc;
741 }
742
743 // =======================================================================
744 // function : getStdProgramOitDepthPeelingFlush
745 // purpose  :
746 // =======================================================================
747 Handle(Graphic3d_ShaderProgram) Graphic3d_ShaderManager::getStdProgramOitDepthPeelingFlush (Standard_Boolean theMsaa) const
748 {
749   Handle(Graphic3d_ShaderProgram) aProgramSrc = new Graphic3d_ShaderProgram();
750   TCollection_AsciiString aSrcVert, aSrcFrag;
751
752   Graphic3d_ShaderObject::ShaderVariableList aUniforms, aStageInOuts;
753   aSrcVert =
754     EOL"void main()"
755     EOL"{"
756     EOL"  gl_Position = vec4 (occVertex.x, occVertex.y, 0.0, 1.0);"
757     EOL"}";
758
759   aUniforms.Append (Graphic3d_ShaderObject::ShaderVariable (theMsaa
760                                                        ? "sampler2DMS uDepthPeelingFrontColor"
761                                                        :   "sampler2D uDepthPeelingFrontColor", Graphic3d_TOS_FRAGMENT));
762   aUniforms.Append (Graphic3d_ShaderObject::ShaderVariable (theMsaa
763                                                        ? "sampler2DMS uDepthPeelingBackColor"
764                                                        :   "sampler2D uDepthPeelingBackColor", Graphic3d_TOS_FRAGMENT));
765   aSrcFrag = TCollection_AsciiString()
766   + EOL"void main()"
767     EOL"{"
768     EOL"  #define THE_SAMPLE_ID " + (theMsaa ? "gl_SampleID" : "0")
769   + EOL"  ivec2 aFragCoord  = ivec2 (gl_FragCoord.xy);"
770     EOL"  vec4  aFrontColor = texelFetch (uDepthPeelingFrontColor, aFragCoord, THE_SAMPLE_ID);"
771     EOL"  vec4  aBackColor  = texelFetch (uDepthPeelingBackColor,  aFragCoord, THE_SAMPLE_ID);"
772     EOL"  float anAlphaMult = 1.0 - aFrontColor.a;"
773     EOL"  occFragColor = vec4 (aFrontColor.rgb + anAlphaMult * aBackColor.rgb, aFrontColor.a + aBackColor.a);"
774     EOL"}";
775
776   defaultOitGlslVersion (aProgramSrc, "oit_peeling_flush", theMsaa);
777   aProgramSrc->SetDefaultSampler (false);
778   aProgramSrc->SetNbLightsMax (0);
779   aProgramSrc->SetNbClipPlanesMax (0);
780   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (aSrcVert, Graphic3d_TOS_VERTEX,   aUniforms, aStageInOuts));
781   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (aSrcFrag, Graphic3d_TOS_FRAGMENT, aUniforms, aStageInOuts));
782   return aProgramSrc;
783 }
784
785 // =======================================================================
786 // function : pointSpriteAlphaSrc
787 // purpose  :
788 // =======================================================================
789 TCollection_AsciiString Graphic3d_ShaderManager::pointSpriteAlphaSrc (Standard_Integer theBits) const
790 {
791   const bool isAlpha = (theBits & Graphic3d_ShaderFlags_PointSpriteA) == Graphic3d_ShaderFlags_PointSpriteA;
792   return isAlpha && myUseRedAlpha
793        ? EOL"float getAlpha(void) { return occTexture2D(occSamplerPointSprite, " THE_VEC2_glPointCoord ").r; }"
794        : EOL"float getAlpha(void) { return occTexture2D(occSamplerPointSprite, " THE_VEC2_glPointCoord ").a; }";
795 }
796
797 // =======================================================================
798 // function : pointSpriteShadingSrc
799 // purpose  :
800 // =======================================================================
801 TCollection_AsciiString Graphic3d_ShaderManager::pointSpriteShadingSrc (const TCollection_AsciiString& theBaseColorSrc,
802                                                                         Standard_Integer theBits) const
803 {
804   TCollection_AsciiString aSrcFragGetColor;
805   if ((theBits & Graphic3d_ShaderFlags_PointSpriteA) == Graphic3d_ShaderFlags_PointSpriteA)
806   {
807     aSrcFragGetColor = pointSpriteAlphaSrc (theBits) +
808       EOL"vec4 getColor(void)"
809       EOL"{"
810       EOL"  vec4 aColor = " + theBaseColorSrc + ";"
811       EOL"  aColor.a = getAlpha();"
812       EOL"  if (aColor.a <= 0.1) discard;"
813       EOL"  return aColor;"
814       EOL"}";
815   }
816   else if ((theBits & Graphic3d_ShaderFlags_PointSprite) == Graphic3d_ShaderFlags_PointSprite)
817   {
818     aSrcFragGetColor = TCollection_AsciiString() +
819       EOL"vec4 getColor(void)"
820       EOL"{"
821       EOL"  vec4 aColor = " + theBaseColorSrc + ";"
822       EOL"  aColor = occTexture2D(occSamplerPointSprite, " THE_VEC2_glPointCoord ") * aColor;"
823       EOL"  if (aColor.a <= 0.1) discard;"
824       EOL"  return aColor;"
825       EOL"}";
826   }
827
828   return aSrcFragGetColor;
829 }
830
831 //! Prepare GLSL source for geometry shader according to parameters.
832 static TCollection_AsciiString prepareGeomMainSrc (Graphic3d_ShaderObject::ShaderVariableList& theUnifoms,
833                                                    Graphic3d_ShaderObject::ShaderVariableList& theStageInOuts,
834                                                    Standard_Integer theBits)
835 {
836   if ((theBits & Graphic3d_ShaderFlags_NeedsGeomShader) == 0)
837   {
838     return TCollection_AsciiString();
839   }
840
841   TCollection_AsciiString aSrcMainGeom =
842     EOL"void main()"
843     EOL"{";
844
845   if ((theBits & Graphic3d_ShaderFlags_MeshEdges) != 0)
846   {
847     theUnifoms.Append    (Graphic3d_ShaderObject::ShaderVariable ("vec4 occViewport",       Graphic3d_TOS_GEOMETRY));
848     theUnifoms.Append    (Graphic3d_ShaderObject::ShaderVariable ("bool occIsQuadMode",     Graphic3d_TOS_GEOMETRY));
849     theUnifoms.Append    (Graphic3d_ShaderObject::ShaderVariable ("float occLineWidth",     Graphic3d_TOS_GEOMETRY));
850     theUnifoms.Append    (Graphic3d_ShaderObject::ShaderVariable ("float occLineWidth",     Graphic3d_TOS_FRAGMENT));
851     theUnifoms.Append    (Graphic3d_ShaderObject::ShaderVariable ("float occLineFeather",   Graphic3d_TOS_FRAGMENT));
852     theUnifoms.Append    (Graphic3d_ShaderObject::ShaderVariable ("vec4 occWireframeColor", Graphic3d_TOS_FRAGMENT));
853     theStageInOuts.Append(Graphic3d_ShaderObject::ShaderVariable ("vec3 EdgeDistance",      Graphic3d_TOS_GEOMETRY | Graphic3d_TOS_FRAGMENT));
854
855     aSrcMainGeom = TCollection_AsciiString()
856     + EOL"vec3 ViewPortTransform (vec4 theVec)"
857       EOL"{"
858       EOL"  vec3 aWinCoord = theVec.xyz / theVec.w;"
859       EOL"  aWinCoord    = aWinCoord * 0.5 + 0.5;"
860       EOL"  aWinCoord.xy = aWinCoord.xy * occViewport.zw + occViewport.xy;"
861       EOL"  return aWinCoord;"
862       EOL"}"
863     + aSrcMainGeom
864     + EOL"  vec3 aSideA = ViewPortTransform (gl_in[2].gl_Position) - ViewPortTransform (gl_in[1].gl_Position);"
865       EOL"  vec3 aSideB = ViewPortTransform (gl_in[2].gl_Position) - ViewPortTransform (gl_in[0].gl_Position);"
866       EOL"  vec3 aSideC = ViewPortTransform (gl_in[1].gl_Position) - ViewPortTransform (gl_in[0].gl_Position);"
867       EOL"  float aQuadArea = abs (aSideB.x * aSideC.y - aSideB.y * aSideC.x);"
868       EOL"  vec3 aLenABC    = vec3 (length (aSideA), length (aSideB), length (aSideC));"
869       EOL"  vec3 aHeightABC = vec3 (aQuadArea) / aLenABC;"
870       EOL"  aHeightABC = max (aHeightABC, vec3 (10.0 * occLineWidth));" // avoid shrunk presentation disappearing at distance
871       EOL"  float aQuadModeHeightC = occIsQuadMode ? occLineWidth + 1.0 : 0.0;";
872   }
873
874   for (Standard_Integer aVertIter = 0; aVertIter < 3; ++aVertIter)
875   {
876     const TCollection_AsciiString aVertIndex (aVertIter);
877     // pass variables from Vertex shader to Fragment shader through Geometry shader
878     for (Graphic3d_ShaderObject::ShaderVariableList::Iterator aVarListIter (theStageInOuts); aVarListIter.More(); aVarListIter.Next())
879     {
880       if (aVarListIter.Value().Stages == (Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT))
881       {
882         const TCollection_AsciiString aVarName = aVarListIter.Value().Name.Token (" ", 2);
883         if (aVarName.Value (aVarName.Length()) == ']')
884         {
885           // copy the whole array
886           const TCollection_AsciiString aVarName2 = aVarName.Token ("[", 1);
887           aSrcMainGeom += TCollection_AsciiString()
888             + EOL"  geomOut." + aVarName2 + " = geomIn[" + aVertIndex + "]." + aVarName2 + ";";
889         }
890         else
891         {
892           aSrcMainGeom += TCollection_AsciiString()
893            + EOL"  geomOut." + aVarName + " = geomIn[" + aVertIndex + "]." + aVarName + ";";
894          }
895       }
896     }
897
898     if ((theBits & Graphic3d_ShaderFlags_MeshEdges) != 0)
899     {
900       switch (aVertIter)
901       {
902         case 0: aSrcMainGeom += EOL"  EdgeDistance = vec3 (aHeightABC[0], 0.0, aQuadModeHeightC);"; break;
903         case 1: aSrcMainGeom += EOL"  EdgeDistance = vec3 (0.0, aHeightABC[1], aQuadModeHeightC);"; break;
904         case 2: aSrcMainGeom += EOL"  EdgeDistance = vec3 (0.0, 0.0, aHeightABC[2]);"; break;
905       }
906     }
907     aSrcMainGeom += TCollection_AsciiString()
908      + EOL"  gl_Position = gl_in[" + aVertIndex + "].gl_Position;"
909        EOL"  EmitVertex();";
910   }
911   aSrcMainGeom +=
912     EOL"  EndPrimitive();"
913     EOL"}";
914
915   return aSrcMainGeom;
916 }
917
918 // =======================================================================
919 // function : getStdProgramUnlit
920 // purpose  :
921 // =======================================================================
922 Handle(Graphic3d_ShaderProgram) Graphic3d_ShaderManager::getStdProgramUnlit (Standard_Integer theBits,
923                                                                              Standard_Boolean theIsOutline) const
924 {
925   Handle(Graphic3d_ShaderProgram) aProgramSrc = new Graphic3d_ShaderProgram();
926   TCollection_AsciiString aSrcVert, aSrcVertExtraMain, aSrcVertExtraFunc, aSrcGetAlpha, aSrcVertEndMain;
927   TCollection_AsciiString aSrcFrag, aSrcFragExtraMain;
928   TCollection_AsciiString aSrcFragGetColor     = EOL"vec4 getColor(void) { return occColor; }";
929   TCollection_AsciiString aSrcFragMainGetColor = EOL"  occSetFragColor (getFinalColor());";
930   Graphic3d_ShaderObject::ShaderVariableList aUniforms, aStageInOuts;
931
932   if ((theBits & Graphic3d_ShaderFlags_IsPoint) != 0)
933   {
934     if (mySetPointSize)
935     {
936       aSrcVertExtraMain += EOL"  gl_PointSize = occPointSize;";
937     }
938
939     if ((theBits & Graphic3d_ShaderFlags_PointSprite) != 0)
940     {
941       aUniforms.Append (Graphic3d_ShaderObject::ShaderVariable ("sampler2D occSamplerPointSprite", Graphic3d_TOS_FRAGMENT));
942       if ((theBits & Graphic3d_ShaderFlags_PointSpriteA) != Graphic3d_ShaderFlags_PointSpriteA)
943       {
944         aSrcFragGetColor =
945           EOL"vec4 getColor(void) { return occTexture2D(occSamplerPointSprite, " THE_VEC2_glPointCoord "); }";
946       }
947       else if ((theBits & Graphic3d_ShaderFlags_TextureRGB) != 0
948             && (theBits & Graphic3d_ShaderFlags_VertColor) == 0)
949       {
950         aProgramSrc->SetTextureSetBits (Graphic3d_TextureSetBits_BaseColor);
951         aUniforms   .Append (Graphic3d_ShaderObject::ShaderVariable ("sampler2D occSamplerBaseColor", Graphic3d_TOS_VERTEX));
952         aStageInOuts.Append (Graphic3d_ShaderObject::ShaderVariable ("vec4 VertColor", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
953         aSrcVertExtraMain +=
954           EOL"  VertColor = occTexture2D (occSamplerBaseColor, occTexCoord.xy);";
955         aSrcFragGetColor =
956           EOL"vec4 getColor(void) { return VertColor; }";
957       }
958
959       aSrcGetAlpha = pointSpriteAlphaSrc (theBits);
960       aSrcFragMainGetColor =
961         EOL"  vec4 aColor = getColor();"
962         EOL"  aColor.a = getAlpha();"
963         EOL"  if (aColor.a <= 0.1) discard;"
964         EOL"  occSetFragColor (aColor);";
965     }
966     else
967     {
968       if ((theBits & Graphic3d_ShaderFlags_TextureRGB) != 0
969        && (theBits & Graphic3d_ShaderFlags_VertColor) == 0)
970       {
971         aProgramSrc->SetTextureSetBits (Graphic3d_TextureSetBits_BaseColor);
972         aUniforms   .Append (Graphic3d_ShaderObject::ShaderVariable ("sampler2D occSamplerBaseColor", Graphic3d_TOS_VERTEX));
973         aStageInOuts.Append (Graphic3d_ShaderObject::ShaderVariable ("vec4 VertColor", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
974         aSrcVertExtraMain +=
975           EOL"  VertColor = occTexture2D (occSamplerBaseColor, occTexCoord.xy);";
976         aSrcFragGetColor =
977           EOL"vec4 getColor(void) { return VertColor; }";
978       }
979
980       aSrcFragMainGetColor =
981         EOL"  vec4 aColor = getColor();"
982         EOL"  if (aColor.a <= 0.1) discard;"
983         EOL"  occSetFragColor (aColor);";
984     }
985   }
986   else
987   {
988     if ((theBits & Graphic3d_ShaderFlags_HasTextures) != 0)
989     {
990       aUniforms   .Append (Graphic3d_ShaderObject::ShaderVariable ("sampler2D occSamplerBaseColor", Graphic3d_TOS_FRAGMENT));
991       aStageInOuts.Append (Graphic3d_ShaderObject::ShaderVariable ("vec4 TexCoord", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
992
993       if ((theBits & Graphic3d_ShaderFlags_HasTextures) == Graphic3d_ShaderFlags_TextureEnv)
994       {
995         aSrcVertExtraFunc = THE_FUNC_transformNormal_view;
996
997         aSrcVertExtraMain +=
998           EOL"  vec4 aPosition = occWorldViewMatrix * occModelWorldMatrix * occVertex;"
999           EOL"  vec3 aNormal   = transformNormal (occNormal);"
1000           EOL"  vec3 aReflect  = reflect (normalize (aPosition.xyz), aNormal);"
1001           EOL"  aReflect.z += 1.0;"
1002           EOL"  TexCoord = vec4(aReflect.xy * inversesqrt (dot (aReflect, aReflect)) * 0.5 + vec2 (0.5), 0.0, 1.0);";
1003
1004         aSrcFragGetColor =
1005           EOL"vec4 getColor(void) { return occTexture2D (occSamplerBaseColor, TexCoord.st); }";
1006       }
1007       else
1008       {
1009         aProgramSrc->SetTextureSetBits (Graphic3d_TextureSetBits_BaseColor);
1010         aSrcVertExtraMain += THE_VARY_TexCoord_Trsf;
1011
1012         aSrcFragGetColor =
1013           EOL"vec4 getColor(void) { return occTexture2D(occSamplerBaseColor, TexCoord.st / TexCoord.w); }";
1014       }
1015     }
1016   }
1017   if ((theBits & Graphic3d_ShaderFlags_VertColor) != 0)
1018   {
1019     aStageInOuts.Append (Graphic3d_ShaderObject::ShaderVariable ("vec4 VertColor", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
1020     aSrcVertExtraMain += EOL"  VertColor = occVertColor;";
1021     aSrcFragGetColor  =  EOL"vec4 getColor(void) { return VertColor; }";
1022   }
1023
1024   int aNbClipPlanes = 0;
1025   if ((theBits & Graphic3d_ShaderFlags_ClipPlanesN) != 0)
1026   {
1027     aStageInOuts.Append (Graphic3d_ShaderObject::ShaderVariable ("vec4 PositionWorld", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
1028     aSrcVertExtraMain +=
1029       EOL"  PositionWorld = occModelWorldMatrix * occVertex;";
1030
1031     if ((theBits & Graphic3d_ShaderFlags_ClipPlanesN) == Graphic3d_ShaderFlags_ClipPlanesN)
1032     {
1033       aNbClipPlanes = Graphic3d_ShaderProgram::THE_MAX_CLIP_PLANES_DEFAULT;
1034       aSrcFragExtraMain += (theBits & Graphic3d_ShaderFlags_ClipChains) != 0
1035                          ? THE_FRAG_CLIP_CHAINS_N
1036                          : THE_FRAG_CLIP_PLANES_N;
1037     }
1038     else if ((theBits & Graphic3d_ShaderFlags_ClipPlanes1) != 0)
1039     {
1040       aNbClipPlanes = 1;
1041       aSrcFragExtraMain += THE_FRAG_CLIP_PLANES_1;
1042     }
1043     else if ((theBits & Graphic3d_ShaderFlags_ClipPlanes2) != 0)
1044     {
1045       aNbClipPlanes = 2;
1046       aSrcFragExtraMain += (theBits & Graphic3d_ShaderFlags_ClipChains) != 0
1047                          ? THE_FRAG_CLIP_CHAINS_2
1048                          : THE_FRAG_CLIP_PLANES_2;
1049     }
1050   }
1051   if ((theBits & Graphic3d_ShaderFlags_OitDepthPeeling) != 0)
1052   {
1053     aProgramSrc->SetNbFragmentOutputs (3);
1054     aProgramSrc->SetOitOutput (Graphic3d_RTM_DEPTH_PEELING_OIT);
1055   }
1056   else if ((theBits & Graphic3d_ShaderFlags_WriteOit) != 0)
1057   {
1058     aProgramSrc->SetNbFragmentOutputs (2);
1059     aProgramSrc->SetOitOutput (Graphic3d_RTM_BLEND_OIT);
1060   }
1061
1062   if (theIsOutline)
1063   {
1064     aUniforms.Append (Graphic3d_ShaderObject::ShaderVariable ("float occOrthoScale",          Graphic3d_TOS_VERTEX));
1065     aUniforms.Append (Graphic3d_ShaderObject::ShaderVariable ("float occSilhouetteThickness", Graphic3d_TOS_VERTEX));
1066     aSrcVertEndMain = THE_VERT_gl_Position_OUTLINE;
1067   }
1068   else if ((theBits & Graphic3d_ShaderFlags_StippleLine) != 0)
1069   {
1070     const Standard_Integer aBits = defaultGlslVersion (aProgramSrc, "unlit", theBits);
1071     if ((aBits & Graphic3d_ShaderFlags_StippleLine) != 0)
1072     {
1073       if (hasGlslBitwiseOps())
1074       {
1075         aUniforms.Append (Graphic3d_ShaderObject::ShaderVariable ("int   occStipplePattern", Graphic3d_TOS_FRAGMENT));
1076       }
1077       else
1078       {
1079         aUniforms.Append (Graphic3d_ShaderObject::ShaderVariable ("bool  occStipplePattern[16]", Graphic3d_TOS_FRAGMENT));
1080       }
1081       aUniforms.Append (Graphic3d_ShaderObject::ShaderVariable ("float occStippleFactor",  Graphic3d_TOS_FRAGMENT));
1082       aUniforms.Append (Graphic3d_ShaderObject::ShaderVariable ("vec4 occViewport", Graphic3d_TOS_VERTEX));
1083       aStageInOuts.Append (Graphic3d_ShaderObject::ShaderVariable ("vec2 ScreenSpaceCoord", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
1084       aSrcVertEndMain =
1085         EOL"  vec2 aPosition   = gl_Position.xy / gl_Position.w;"
1086         EOL"  aPosition        = aPosition * 0.5 + 0.5;"
1087         EOL"  ScreenSpaceCoord = aPosition.xy * occViewport.zw + occViewport.xy;";
1088       aSrcFragMainGetColor = TCollection_AsciiString()
1089       + EOL"  vec2 anAxis = vec2 (0.0, 1.0);"
1090         EOL"  if (abs (dFdx (ScreenSpaceCoord.x)) - abs (dFdy (ScreenSpaceCoord.y)) > 0.001)"
1091         EOL"  {"
1092         EOL"    anAxis = vec2 (1.0, 0.0);"
1093         EOL"  }"
1094         EOL"  float aRotatePoint = dot (gl_FragCoord.xy, anAxis);"
1095       + (hasGlslBitwiseOps()
1096        ? EOL"  uint aBit = uint (floor (aRotatePoint / occStippleFactor + 0.5)) & 15U;"
1097          EOL"  if ((uint (occStipplePattern) & (1U << aBit)) == 0U) discard;"
1098        : EOL"  int aBit = int (mod (floor (aRotatePoint / occStippleFactor + 0.5), 16.0));"
1099          EOL"  if (!occStipplePattern[aBit]) discard;")
1100       + EOL"  vec4 aColor = getFinalColor();"
1101         EOL"  if (aColor.a <= 0.1) discard;"
1102         EOL"  occSetFragColor (aColor);";
1103     }
1104     else
1105     {
1106       Message::SendWarning ("Warning: stipple lines in GLSL will be ignored");
1107     }
1108   }
1109
1110   aSrcVert =
1111       aSrcVertExtraFunc
1112     + EOL"void main()"
1113       EOL"{"
1114     + aSrcVertExtraMain
1115     + THE_VERT_gl_Position
1116     + aSrcVertEndMain
1117     + EOL"}";
1118
1119   TCollection_AsciiString aSrcGeom = prepareGeomMainSrc (aUniforms, aStageInOuts, theBits);
1120   aSrcFragGetColor += (theBits & Graphic3d_ShaderFlags_MeshEdges) != 0
1121     ? THE_FRAG_WIREFRAME_COLOR
1122     : EOL"#define getFinalColor getColor";
1123
1124   aSrcFrag =
1125       aSrcFragGetColor
1126     + aSrcGetAlpha
1127     + EOL"void main()"
1128       EOL"{"
1129       EOL"  if (occFragEarlyReturn()) { return; }"
1130     + aSrcFragExtraMain
1131     + aSrcFragMainGetColor
1132     + EOL"}";
1133
1134   defaultGlslVersion (aProgramSrc, theIsOutline ? "outline" : "unlit", theBits);
1135   aProgramSrc->SetDefaultSampler (false);
1136   aProgramSrc->SetNbLightsMax (0);
1137   aProgramSrc->SetNbShadowMaps (0);
1138   aProgramSrc->SetNbClipPlanesMax (aNbClipPlanes);
1139   aProgramSrc->SetAlphaTest ((theBits & Graphic3d_ShaderFlags_AlphaTest) != 0);
1140   const Standard_Integer aNbGeomInputVerts = !aSrcGeom.IsEmpty() ? 3 : 0;
1141   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (aSrcVert, Graphic3d_TOS_VERTEX,   aUniforms, aStageInOuts, "", "", aNbGeomInputVerts));
1142   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (aSrcGeom, Graphic3d_TOS_GEOMETRY, aUniforms, aStageInOuts, "geomIn", "geomOut", aNbGeomInputVerts));
1143   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (aSrcFrag, Graphic3d_TOS_FRAGMENT, aUniforms, aStageInOuts, "", "", aNbGeomInputVerts));
1144   return aProgramSrc;
1145 }
1146
1147 // =======================================================================
1148 // function : stdComputeLighting
1149 // purpose  :
1150 // =======================================================================
1151 TCollection_AsciiString Graphic3d_ShaderManager::stdComputeLighting (Standard_Integer& theNbLights,
1152                                                                      const Handle(Graphic3d_LightSet)& theLights,
1153                                                                      Standard_Boolean  theHasVertColor,
1154                                                                      Standard_Boolean  theIsPBR,
1155                                                                      Standard_Boolean  theHasTexColor,
1156                                                                      Standard_Integer  theNbShadowMaps) const
1157 {
1158   TCollection_AsciiString aLightsFunc, aLightsLoop;
1159   theNbLights = 0;
1160   if (!theLights.IsNull())
1161   {
1162     theNbLights = theLights->NbEnabled();
1163     if (theNbLights <= THE_NB_UNROLLED_LIGHTS_MAX)
1164     {
1165       Standard_Integer anIndex = 0;
1166       if (theNbShadowMaps > 0)
1167       {
1168         for (Graphic3d_LightSet::Iterator aLightIter (theLights, Graphic3d_LightSet::IterationFilter_ExcludeDisabledAndAmbient);
1169              aLightIter.More(); aLightIter.Next())
1170         {
1171           if (aLightIter.Value()->Type() == Graphic3d_TypeOfLightSource_Directional
1172            && aLightIter.Value()->ToCastShadows())
1173           {
1174             aLightsLoop = aLightsLoop + EOL"    occDirectionalLight (" + anIndex + ", theNormal, theView, theIsFront,"
1175                                         EOL"                         occDirectionalLightShadow (occShadowMapSamplers[" + anIndex + "], " + anIndex + ", theNormal));";
1176             ++anIndex;
1177           }
1178         }
1179       }
1180       for (Graphic3d_LightSet::Iterator aLightIter (theLights, Graphic3d_LightSet::IterationFilter_ExcludeDisabledAndAmbient);
1181            aLightIter.More(); aLightIter.Next())
1182       {
1183         switch (aLightIter.Value()->Type())
1184         {
1185           case Graphic3d_TypeOfLightSource_Ambient:
1186           {
1187             break; // skip ambient
1188           }
1189           case Graphic3d_TypeOfLightSource_Directional:
1190           {
1191             if (theNbShadowMaps > 0
1192              && aLightIter.Value()->ToCastShadows())
1193             {
1194               break;
1195             }
1196             aLightsLoop = aLightsLoop + EOL"    occDirectionalLight (" + anIndex + ", theNormal, theView, theIsFront, 1.0);";
1197             ++anIndex;
1198             break;
1199           }
1200           case Graphic3d_TypeOfLightSource_Positional:
1201           {
1202             aLightsLoop = aLightsLoop + EOL"    occPointLight (" + anIndex + ", theNormal, theView, aPoint, theIsFront);";
1203             ++anIndex;
1204             break;
1205           }
1206           case Graphic3d_TypeOfLightSource_Spot:
1207           {
1208             aLightsLoop = aLightsLoop + EOL"    occSpotLight (" + anIndex + ", theNormal, theView, aPoint, theIsFront);";
1209             ++anIndex;
1210             break;
1211           }
1212         }
1213       }
1214     }
1215     else
1216     {
1217       theNbLights = roundUpMaxLightSources (theNbLights);
1218       bool isFirstInLoop = true;
1219       aLightsLoop = aLightsLoop +
1220         EOL"    for (int anIndex = 0; anIndex < occLightSourcesCount; ++anIndex)"
1221         EOL"    {"
1222         EOL"      int aType = occLight_Type (anIndex);";
1223       if (theLights->NbEnabledLightsOfType (Graphic3d_TypeOfLightSource_Directional) > 0)
1224       {
1225         isFirstInLoop = false;
1226         aLightsLoop +=
1227           EOL"      if (aType == OccLightType_Direct)"
1228           EOL"      {"
1229           EOL"        occDirectionalLight (anIndex, theNormal, theView, theIsFront, 1.0);"
1230           EOL"      }";
1231       }
1232       if (theLights->NbEnabledLightsOfType (Graphic3d_TypeOfLightSource_Positional) > 0)
1233       {
1234         if (!isFirstInLoop)
1235         {
1236           aLightsLoop += EOL"      else ";
1237         }
1238         isFirstInLoop = false;
1239         aLightsLoop +=
1240           EOL"      if (aType == OccLightType_Point)"
1241           EOL"      {"
1242           EOL"        occPointLight (anIndex, theNormal, theView, aPoint, theIsFront);"
1243           EOL"      }";
1244       }
1245       if (theLights->NbEnabledLightsOfType (Graphic3d_TypeOfLightSource_Spot) > 0)
1246       {
1247         if (!isFirstInLoop)
1248         {
1249           aLightsLoop += EOL"      else ";
1250         }
1251         isFirstInLoop = false;
1252         aLightsLoop +=
1253           EOL"      if (aType == OccLightType_Spot)"
1254           EOL"      {"
1255           EOL"        occSpotLight (anIndex, theNormal, theView, aPoint, theIsFront);"
1256           EOL"      }";
1257       }
1258       aLightsLoop += EOL"    }";
1259     }
1260
1261     if (theIsPBR)
1262     {
1263       aLightsFunc += Shaders_PBRDistribution_glsl;
1264       aLightsFunc += Shaders_PBRGeometry_glsl;
1265       aLightsFunc += Shaders_PBRFresnel_glsl;
1266       aLightsFunc += Shaders_PBRCookTorrance_glsl;
1267       aLightsFunc += Shaders_PBRIllumination_glsl;
1268     }
1269
1270     if (theLights->NbEnabledLightsOfType (Graphic3d_TypeOfLightSource_Directional) == 1
1271      && theNbLights == 1
1272      && !theIsPBR
1273      && theNbShadowMaps == 0)
1274     {
1275       // use the version with hard-coded first index
1276       aLightsLoop = EOL"    directionalLightFirst(theNormal, theView, theIsFront, 1.0);";
1277       aLightsFunc += THE_FUNC_directionalLightFirst;
1278     }
1279     else if (theLights->NbEnabledLightsOfType (Graphic3d_TypeOfLightSource_Directional) > 0)
1280     {
1281       if (theNbShadowMaps > 0)
1282       {
1283         aLightsFunc += Shaders_DirectionalLightShadow_glsl;
1284       }
1285       aLightsFunc += theIsPBR ? Shaders_PBRDirectionalLight_glsl : Shaders_PhongDirectionalLight_glsl;
1286     }
1287     if (theLights->NbEnabledLightsOfType (Graphic3d_TypeOfLightSource_Positional) > 0)
1288     {
1289       aLightsFunc += theIsPBR ? Shaders_PBRPointLight_glsl : Shaders_PhongPointLight_glsl;
1290     }
1291     if (theLights->NbEnabledLightsOfType (Graphic3d_TypeOfLightSource_Spot) > 0)
1292     {
1293       aLightsFunc += theIsPBR ? Shaders_PBRSpotLight_glsl : Shaders_PhongSpotLight_glsl;
1294     }
1295   }
1296
1297   if (!theIsPBR)
1298   {
1299     return TCollection_AsciiString()
1300     + THE_FUNC_lightDef
1301     + Shaders_PointLightAttenuation_glsl
1302     + aLightsFunc
1303     + EOL
1304       EOL"vec4 computeLighting (in vec3 theNormal,"
1305       EOL"                      in vec3 theView,"
1306       EOL"                      in vec4 thePoint,"
1307       EOL"                      in bool theIsFront)"
1308       EOL"{"
1309       EOL"  Ambient  = occLightAmbient.rgb;"
1310       EOL"  Diffuse  = vec3 (0.0);"
1311       EOL"  Specular = vec3 (0.0);"
1312       EOL"  vec3 aPoint = thePoint.xyz / thePoint.w;"
1313     + aLightsLoop
1314     + EOL"  vec3 aMatAmbient  = occMaterial_Ambient(theIsFront);"
1315       EOL"  vec4 aMatDiffuse  = occMaterial_Diffuse(theIsFront);"
1316       EOL"  vec3 aMatSpecular = occMaterial_Specular(theIsFront);"
1317       EOL"  vec4 aColor = vec4(Ambient * aMatAmbient + Diffuse * aMatDiffuse.rgb + Specular * aMatSpecular, aMatDiffuse.a);"
1318     + (theHasVertColor ?
1319       EOL"  aColor *= getVertColor();" : "")
1320     + (theHasTexColor ?
1321       EOL"#if defined(THE_HAS_TEXTURE_COLOR) && defined(FRAGMENT_SHADER)"
1322       EOL"  aColor *= occTexture2D(occSamplerBaseColor, TexCoord.st / TexCoord.w);"
1323       EOL"#endif" : "")
1324     + EOL"  occMaterialOcclusion(aColor.rgb, TexCoord.st / TexCoord.w);"
1325       EOL"  vec3 aMatEmission = occMaterialEmission(theIsFront, TexCoord.st / TexCoord.w);"
1326       EOL"  aColor.rgb += aMatEmission.rgb;"
1327       EOL"  return aColor;"
1328       EOL"}";
1329   }
1330   else
1331   {
1332     return TCollection_AsciiString()
1333     + THE_FUNC_PBR_lightDef
1334     + Shaders_PointLightAttenuation_glsl
1335     + aLightsFunc
1336     + EOL
1337       EOL"vec4 computeLighting (in vec3 theNormal,"
1338       EOL"                      in vec3 theView,"
1339       EOL"                      in vec4 thePoint,"
1340       EOL"                      in bool theIsFront)"
1341       EOL"{"
1342       EOL"  DirectLighting = vec3(0.0);"
1343       EOL"  BaseColor           = occMaterialBaseColor(theIsFront, TexCoord.st / TexCoord.w)" + (theHasVertColor ? " * getVertColor()" : "") + ";"
1344     + EOL"  Emission            = occMaterialEmission(theIsFront, TexCoord.st / TexCoord.w);"
1345       EOL"  Metallic            = occMaterialMetallic(theIsFront, TexCoord.st / TexCoord.w);"
1346       EOL"  NormalizedRoughness = occMaterialRoughness(theIsFront, TexCoord.st / TexCoord.w);"
1347       EOL"  Roughness = occRoughness (NormalizedRoughness);"
1348       EOL"  IOR       = occPBRMaterial_IOR (theIsFront);"
1349       EOL"  vec3 aPoint = thePoint.xyz / thePoint.w;"
1350     + aLightsLoop
1351     + EOL"  vec3 aColor = DirectLighting;"
1352       EOL"  vec3 anIndirectLightingSpec = occPBRFresnel (BaseColor.rgb, Metallic, IOR);"
1353       EOL"  vec2 aCoeff = occTexture2D (occEnvLUT, vec2(abs(dot(theView, theNormal)), NormalizedRoughness)).xy;"
1354       EOL"  anIndirectLightingSpec *= aCoeff.x;"
1355       EOL"  anIndirectLightingSpec += aCoeff.y;"
1356       EOL"  anIndirectLightingSpec *= occTextureCubeLod (occSpecIBLMap, -reflect (theView, theNormal), NormalizedRoughness * float (occNbSpecIBLLevels - 1)).rgb;"
1357       EOL"  vec3 aRefractionCoeff = 1.0 - occPBRFresnel (BaseColor.rgb, Metallic, NormalizedRoughness, IOR, abs(dot(theView, theNormal)));"
1358       EOL"  aRefractionCoeff *= (1.0 - Metallic);"
1359       EOL"  vec3 anIndirectLightingDiff = aRefractionCoeff * BaseColor.rgb * BaseColor.a;"
1360       EOL"  anIndirectLightingDiff *= occDiffIBLMap (theNormal).rgb;"
1361       EOL"  aColor += occLightAmbient.rgb * (anIndirectLightingDiff + anIndirectLightingSpec);"
1362       EOL"  aColor += Emission;"
1363       EOL"  occMaterialOcclusion(aColor, TexCoord.st / TexCoord.w);"
1364       EOL"  return vec4 (aColor, mix(1.0, BaseColor.a, aRefractionCoeff.x));"
1365       EOL"}";
1366   }
1367 }
1368
1369 // =======================================================================
1370 // function : getStdProgramGouraud
1371 // purpose  :
1372 // =======================================================================
1373 Handle(Graphic3d_ShaderProgram) Graphic3d_ShaderManager::getStdProgramGouraud (const Handle(Graphic3d_LightSet)& theLights,
1374                                                                                Standard_Integer theBits) const
1375 {
1376   Handle(Graphic3d_ShaderProgram) aProgramSrc = new Graphic3d_ShaderProgram();
1377   TCollection_AsciiString aSrcVert, aSrcVertColor, aSrcVertExtraMain;
1378   TCollection_AsciiString aSrcFrag, aSrcFragExtraMain;
1379   TCollection_AsciiString aSrcFragGetColor = EOL"vec4 getColor(void) { return gl_FrontFacing ? FrontColor : BackColor; }";
1380   Graphic3d_ShaderObject::ShaderVariableList aUniforms, aStageInOuts;
1381   bool toUseTexColor = false;
1382   if ((theBits & Graphic3d_ShaderFlags_IsPoint) != 0)
1383   {
1384     if (mySetPointSize)
1385     {
1386       aSrcVertExtraMain += EOL"  gl_PointSize = occPointSize;";
1387     }
1388
1389     if ((theBits & Graphic3d_ShaderFlags_PointSprite) != 0)
1390     {
1391       aUniforms.Append (Graphic3d_ShaderObject::ShaderVariable ("sampler2D occSamplerPointSprite", Graphic3d_TOS_FRAGMENT));
1392       aSrcFragGetColor = pointSpriteShadingSrc ("gl_FrontFacing ? FrontColor : BackColor", theBits);
1393     }
1394
1395     if ((theBits & Graphic3d_ShaderFlags_TextureRGB) != 0
1396      && (theBits & Graphic3d_ShaderFlags_VertColor) == 0)
1397     {
1398       aProgramSrc->SetTextureSetBits (Graphic3d_TextureSetBits_BaseColor);
1399       aUniforms.Append (Graphic3d_ShaderObject::ShaderVariable ("sampler2D occSamplerBaseColor", Graphic3d_TOS_VERTEX));
1400       aSrcVertColor = EOL"vec4 getVertColor(void) { return occTexture2D (occSamplerBaseColor, occTexCoord.xy); }";
1401     }
1402   }
1403   else
1404   {
1405     if ((theBits & Graphic3d_ShaderFlags_TextureRGB) != 0)
1406     {
1407       toUseTexColor = true;
1408       aProgramSrc->SetTextureSetBits (Graphic3d_TextureSetBits_BaseColor);
1409       aUniforms   .Append (Graphic3d_ShaderObject::ShaderVariable ("sampler2D occSamplerBaseColor", Graphic3d_TOS_FRAGMENT));
1410       aStageInOuts.Append (Graphic3d_ShaderObject::ShaderVariable ("vec4 TexCoord", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
1411       aSrcVertExtraMain += THE_VARY_TexCoord_Trsf;
1412
1413       aSrcFragGetColor =
1414         EOL"vec4 getColor(void)"
1415         EOL"{"
1416         EOL"  vec4 aColor = gl_FrontFacing ? FrontColor : BackColor;"
1417         EOL"  return occTexture2D(occSamplerBaseColor, TexCoord.st / TexCoord.w) * aColor;"
1418         EOL"}";
1419     }
1420   }
1421
1422   if ((theBits & Graphic3d_ShaderFlags_VertColor) != 0)
1423   {
1424     aSrcVertColor = EOL"vec4 getVertColor(void) { return occVertColor; }";
1425   }
1426
1427   int aNbClipPlanes = 0;
1428   if ((theBits & Graphic3d_ShaderFlags_ClipPlanesN) != 0)
1429   {
1430     aStageInOuts.Append (Graphic3d_ShaderObject::ShaderVariable ("vec4 PositionWorld", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
1431     aSrcVertExtraMain +=
1432       EOL"  PositionWorld = aPositionWorld;";
1433
1434     if ((theBits & Graphic3d_ShaderFlags_ClipPlanesN) == Graphic3d_ShaderFlags_ClipPlanesN)
1435     {
1436       aNbClipPlanes = Graphic3d_ShaderProgram::THE_MAX_CLIP_PLANES_DEFAULT;
1437       aSrcFragExtraMain += (theBits & Graphic3d_ShaderFlags_ClipChains) != 0
1438                          ? THE_FRAG_CLIP_CHAINS_N
1439                          : THE_FRAG_CLIP_PLANES_N;
1440     }
1441     else if ((theBits & Graphic3d_ShaderFlags_ClipPlanes1) != 0)
1442     {
1443       aNbClipPlanes = 1;
1444       aSrcFragExtraMain += THE_FRAG_CLIP_PLANES_1;
1445     }
1446     else if ((theBits & Graphic3d_ShaderFlags_ClipPlanes2) != 0)
1447     {
1448       aNbClipPlanes = 2;
1449       aSrcFragExtraMain += (theBits & Graphic3d_ShaderFlags_ClipChains) != 0
1450                           ? THE_FRAG_CLIP_CHAINS_2
1451                           : THE_FRAG_CLIP_PLANES_2;
1452     }
1453   }
1454   if ((theBits & Graphic3d_ShaderFlags_OitDepthPeeling) != 0)
1455   {
1456     aProgramSrc->SetNbFragmentOutputs (3);
1457     aProgramSrc->SetOitOutput (Graphic3d_RTM_DEPTH_PEELING_OIT);
1458   }
1459   else if ((theBits & Graphic3d_ShaderFlags_WriteOit) != 0)
1460   {
1461     aProgramSrc->SetNbFragmentOutputs (2);
1462     aProgramSrc->SetOitOutput (Graphic3d_RTM_BLEND_OIT);
1463   }
1464
1465   aStageInOuts.Append (Graphic3d_ShaderObject::ShaderVariable ("vec4 FrontColor", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
1466   aStageInOuts.Append (Graphic3d_ShaderObject::ShaderVariable ("vec4 BackColor",  Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
1467
1468   Standard_Integer aNbLights = 0;
1469   const TCollection_AsciiString aLights = stdComputeLighting (aNbLights, theLights, !aSrcVertColor.IsEmpty(), false, toUseTexColor, 0);
1470   aSrcVert = TCollection_AsciiString()
1471     + THE_FUNC_transformNormal_world
1472     + EOL
1473     + aSrcVertColor
1474     + aLights
1475     + EOL"void main()"
1476       EOL"{"
1477       EOL"  vec4 aPositionWorld = occModelWorldMatrix * occVertex;"
1478       EOL"  vec3 aNormal        = transformNormal (occNormal);"
1479       EOL"  vec3 aView;"
1480       EOL"  if (occProjectionMatrix[3][3] == 1.0)"
1481       EOL"  {"
1482       EOL"    aView = (occWorldViewMatrixInverse * vec4(0.0, 0.0, 1.0, 0.0)).xyz;"
1483       EOL"  }"
1484       EOL"  else"
1485       EOL"  {"
1486       EOL"    vec3 anEye = (occWorldViewMatrixInverse * vec4(0.0, 0.0, 0.0, 1.0)).xyz;"
1487       EOL"    aView = normalize (anEye - aPositionWorld.xyz);"
1488       EOL"  }"
1489       EOL"  FrontColor  = computeLighting (aNormal, aView, aPositionWorld, true);"
1490       EOL"  BackColor   = computeLighting (aNormal, aView, aPositionWorld, false);"
1491     + aSrcVertExtraMain
1492     + THE_VERT_gl_Position
1493     + EOL"}";
1494
1495   TCollection_AsciiString aSrcGeom = prepareGeomMainSrc (aUniforms, aStageInOuts, theBits);
1496   aSrcFragGetColor += (theBits & Graphic3d_ShaderFlags_MeshEdges) != 0
1497     ? THE_FRAG_WIREFRAME_COLOR
1498     : EOL"#define getFinalColor getColor";
1499
1500   aSrcFrag = TCollection_AsciiString()
1501     + aSrcFragGetColor
1502     + EOL"void main()"
1503       EOL"{"
1504       EOL"  if (occFragEarlyReturn()) { return; }"
1505     + aSrcFragExtraMain
1506     + EOL"  occSetFragColor (getFinalColor());"
1507     + EOL"}";
1508
1509   const TCollection_AsciiString aProgId = TCollection_AsciiString ("gouraud-") + genLightKey (theLights, false) + "-";
1510   defaultGlslVersion (aProgramSrc, aProgId, theBits);
1511   aProgramSrc->SetDefaultSampler (false);
1512   aProgramSrc->SetNbLightsMax (aNbLights);
1513   aProgramSrc->SetNbShadowMaps (0);
1514   aProgramSrc->SetNbClipPlanesMax (aNbClipPlanes);
1515   aProgramSrc->SetAlphaTest ((theBits & Graphic3d_ShaderFlags_AlphaTest) != 0);
1516   const Standard_Integer aNbGeomInputVerts = !aSrcGeom.IsEmpty() ? 3 : 0;
1517   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (aSrcVert, Graphic3d_TOS_VERTEX,   aUniforms, aStageInOuts, "", "", aNbGeomInputVerts));
1518   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (aSrcGeom, Graphic3d_TOS_GEOMETRY, aUniforms, aStageInOuts, "geomIn", "geomOut", aNbGeomInputVerts));
1519   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (aSrcFrag, Graphic3d_TOS_FRAGMENT, aUniforms, aStageInOuts, "", "", aNbGeomInputVerts));
1520   return aProgramSrc;
1521 }
1522
1523 // =======================================================================
1524 // function : getStdProgramPhong
1525 // purpose  :
1526 // =======================================================================
1527 Handle(Graphic3d_ShaderProgram) Graphic3d_ShaderManager::getStdProgramPhong (const Handle(Graphic3d_LightSet)& theLights,
1528                                                                              const Standard_Integer theBits,
1529                                                                              const Standard_Boolean theIsFlatNormal,
1530                                                                              const Standard_Boolean theIsPBR,
1531                                                                              const Standard_Integer theNbShadowMaps) const
1532 {
1533   TCollection_AsciiString aPhongCompLight = TCollection_AsciiString() +
1534     "computeLighting (normalize (Normal), normalize (View), PositionWorld, gl_FrontFacing)";
1535   const bool isFlatNormal = theIsFlatNormal && myHasFlatShading;
1536   const char* aDFdxSignReversion = myToReverseDFdxSign ? "-" : "";
1537   bool toUseTexColor = false;
1538   if (isFlatNormal != theIsFlatNormal)
1539   {
1540     Message::SendWarning ("Warning: flat shading requires OpenGL ES 3.0+ or GL_OES_standard_derivatives extension");
1541   }
1542   else if (isFlatNormal && myToReverseDFdxSign)
1543   {
1544     Message::SendWarning ("Warning: applied workaround for GLSL flat shading normal computation using dFdx/dFdy on Adreno");
1545   }
1546
1547   Handle(Graphic3d_ShaderProgram) aProgramSrc = new Graphic3d_ShaderProgram();
1548   aProgramSrc->SetPBR (theIsPBR);
1549
1550   TCollection_AsciiString aSrcVert, aSrcVertExtraFunc, aSrcVertExtraMain;
1551   TCollection_AsciiString aSrcFrag, aSrcFragGetVertColor, aSrcFragExtraMain;
1552   TCollection_AsciiString aSrcFragGetColor = TCollection_AsciiString() + EOL"vec4 getColor(void) { return " + aPhongCompLight +  "; }";
1553   Graphic3d_ShaderObject::ShaderVariableList aUniforms, aStageInOuts;
1554   if ((theBits & Graphic3d_ShaderFlags_IsPoint) != 0)
1555   {
1556     if (mySetPointSize)
1557     {
1558       aSrcVertExtraMain += EOL"  gl_PointSize = occPointSize;";
1559     }
1560
1561     if ((theBits & Graphic3d_ShaderFlags_PointSprite) != 0)
1562     {
1563       aUniforms.Append (Graphic3d_ShaderObject::ShaderVariable ("sampler2D occSamplerPointSprite", Graphic3d_TOS_FRAGMENT));
1564       aSrcFragGetColor = pointSpriteShadingSrc (aPhongCompLight, theBits);
1565     }
1566
1567     if ((theBits & Graphic3d_ShaderFlags_TextureRGB) != 0
1568      && (theBits & Graphic3d_ShaderFlags_VertColor) == 0)
1569     {
1570       aProgramSrc->SetTextureSetBits (Graphic3d_TextureSetBits_BaseColor);
1571       aUniforms   .Append (Graphic3d_ShaderObject::ShaderVariable ("sampler2D occSamplerBaseColor", Graphic3d_TOS_VERTEX));
1572       aStageInOuts.Append (Graphic3d_ShaderObject::ShaderVariable ("vec4 VertColor", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
1573
1574       aSrcVertExtraMain   += EOL"  VertColor = occTexture2D (occSamplerBaseColor, occTexCoord.xy);";
1575       aSrcFragGetVertColor = EOL"vec4 getVertColor(void) { return VertColor; }";
1576     }
1577   }
1578   else
1579   {
1580     if ((theBits & Graphic3d_ShaderFlags_TextureRGB) != 0)
1581     {
1582       toUseTexColor = true;
1583       aUniforms   .Append (Graphic3d_ShaderObject::ShaderVariable ("sampler2D occSamplerBaseColor", Graphic3d_TOS_FRAGMENT));
1584       aStageInOuts.Append (Graphic3d_ShaderObject::ShaderVariable ("vec4 TexCoord", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
1585       aSrcVertExtraMain += THE_VARY_TexCoord_Trsf;
1586
1587       Standard_Integer aTextureBits = Graphic3d_TextureSetBits_BaseColor | Graphic3d_TextureSetBits_Occlusion | Graphic3d_TextureSetBits_Emissive;
1588       if (theIsPBR)
1589       {
1590         aTextureBits |= Graphic3d_TextureSetBits_MetallicRoughness;
1591       }
1592       if ((theBits & Graphic3d_ShaderFlags_HasTextures) == Graphic3d_ShaderFlags_TextureNormal
1593        && !isFlatNormal)
1594       {
1595         if (myHasFlatShading)
1596         {
1597           aTextureBits |= Graphic3d_TextureSetBits_Normal;
1598         }
1599         else
1600         {
1601           Message::SendWarning ("Warning: ignoring Normal Map texture in GLSL due to hardware capabilities");
1602         }
1603       }
1604       aProgramSrc->SetTextureSetBits (aTextureBits);
1605     }
1606   }
1607
1608   if ((theBits & Graphic3d_ShaderFlags_VertColor) != 0)
1609   {
1610     aStageInOuts.Append (Graphic3d_ShaderObject::ShaderVariable ("vec4 VertColor", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
1611     aSrcVertExtraMain   += EOL"  VertColor = occVertColor;";
1612     aSrcFragGetVertColor = EOL"vec4 getVertColor(void) { return VertColor; }";
1613   }
1614
1615   int aNbClipPlanes = 0;
1616   if ((theBits & Graphic3d_ShaderFlags_ClipPlanesN) != 0)
1617   {
1618     if ((theBits & Graphic3d_ShaderFlags_ClipPlanesN) == Graphic3d_ShaderFlags_ClipPlanesN)
1619     {
1620       aNbClipPlanes = Graphic3d_ShaderProgram::THE_MAX_CLIP_PLANES_DEFAULT;
1621       aSrcFragExtraMain += (theBits & Graphic3d_ShaderFlags_ClipChains) != 0
1622                          ? THE_FRAG_CLIP_CHAINS_N
1623                          : THE_FRAG_CLIP_PLANES_N;
1624     }
1625     else if ((theBits & Graphic3d_ShaderFlags_ClipPlanes1) != 0)
1626     {
1627       aNbClipPlanes = 1;
1628       aSrcFragExtraMain += THE_FRAG_CLIP_PLANES_1;
1629     }
1630     else if ((theBits & Graphic3d_ShaderFlags_ClipPlanes2) != 0)
1631     {
1632       aNbClipPlanes = 2;
1633       aSrcFragExtraMain += (theBits & Graphic3d_ShaderFlags_ClipChains) != 0
1634                          ? THE_FRAG_CLIP_CHAINS_2
1635                          : THE_FRAG_CLIP_PLANES_2;
1636     }
1637   }
1638   if ((theBits & Graphic3d_ShaderFlags_OitDepthPeeling) != 0)
1639   {
1640     aProgramSrc->SetNbFragmentOutputs (3);
1641     aProgramSrc->SetOitOutput (Graphic3d_RTM_DEPTH_PEELING_OIT);
1642   }
1643   else if ((theBits & Graphic3d_ShaderFlags_WriteOit) != 0)
1644   {
1645     aProgramSrc->SetNbFragmentOutputs (2);
1646     aProgramSrc->SetOitOutput (Graphic3d_RTM_BLEND_OIT);
1647   }
1648
1649   if (isFlatNormal)
1650   {
1651     aSrcFragExtraMain += TCollection_AsciiString()
1652       + EOL"  Normal = " + aDFdxSignReversion + "normalize (cross (dFdx (PositionWorld.xyz / PositionWorld.w), dFdy (PositionWorld.xyz / PositionWorld.w)));"
1653         EOL"  if (!gl_FrontFacing) { Normal = -Normal; }";
1654   }
1655   else
1656   {
1657     aStageInOuts.Append(Graphic3d_ShaderObject::ShaderVariable("vec3 vNormal", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
1658     aSrcVertExtraFunc += THE_FUNC_transformNormal_world;
1659     aSrcVertExtraMain += EOL"  vNormal = transformNormal (occNormal);";
1660     aSrcFragExtraMain += EOL"  Normal = vNormal;";
1661
1662     if ((theBits & Graphic3d_ShaderFlags_IsPoint) == 0
1663      && (theBits & Graphic3d_ShaderFlags_HasTextures) == Graphic3d_ShaderFlags_TextureNormal
1664      && myHasFlatShading)
1665     {
1666       aSrcFrag += Shaders_TangentSpaceNormal_glsl;
1667       // apply normal map texture
1668       aSrcFragExtraMain +=
1669         EOL"#if defined(THE_HAS_TEXTURE_NORMAL)"
1670         EOL"  vec2 aTexCoord = TexCoord.st / TexCoord.w;"
1671         EOL"  vec4 aMapNormalValue = occTextureNormal(aTexCoord);"
1672         EOL"  if (aMapNormalValue.w > 0.5)"
1673         EOL"  {"
1674         EOL"    mat2 aDeltaUVMatrix = mat2 (dFdx(aTexCoord), dFdy(aTexCoord));"
1675         EOL"    mat2x3 aDeltaVectorMatrix = mat2x3 (dFdx (PositionWorld.xyz), dFdy (PositionWorld.xyz));"
1676         EOL"    Normal = TangentSpaceNormal (aDeltaUVMatrix, aDeltaVectorMatrix, aMapNormalValue.xyz, Normal, !gl_FrontFacing);"
1677         EOL"  }"
1678         EOL"#endif";
1679     }
1680   }
1681
1682   aStageInOuts.Append (Graphic3d_ShaderObject::ShaderVariable ("vec4 PositionWorld", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
1683   aStageInOuts.Append (Graphic3d_ShaderObject::ShaderVariable ("vec3 View",          Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
1684   if (theNbShadowMaps > 0)
1685   {
1686     aUniforms.Append (Graphic3d_ShaderObject::ShaderVariable ("mat4      occShadowMapMatrices[THE_NB_SHADOWMAPS]", Graphic3d_TOS_VERTEX));
1687     aUniforms.Append (Graphic3d_ShaderObject::ShaderVariable ("sampler2D occShadowMapSamplers[THE_NB_SHADOWMAPS]", Graphic3d_TOS_FRAGMENT));
1688     aUniforms.Append (Graphic3d_ShaderObject::ShaderVariable ("vec2      occShadowMapSizeBias",                    Graphic3d_TOS_FRAGMENT));
1689
1690     aStageInOuts.Append (Graphic3d_ShaderObject::ShaderVariable ("vec4 PosLightSpace[THE_NB_SHADOWMAPS]", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
1691     aSrcVertExtraMain +=
1692       EOL"  for (int aShadowIter = 0; aShadowIter < THE_NB_SHADOWMAPS; ++aShadowIter)"
1693       EOL"  {"
1694       EOL"    PosLightSpace[aShadowIter] = occShadowMapMatrices[aShadowIter] * PositionWorld;"
1695       EOL"  }";
1696   }
1697
1698   aSrcVert = TCollection_AsciiString()
1699     + aSrcVertExtraFunc
1700     + EOL"void main()"
1701       EOL"{"
1702       EOL"  PositionWorld = occModelWorldMatrix * occVertex;"
1703       EOL"  if (occProjectionMatrix[3][3] == 1.0)"
1704       EOL"  {"
1705       EOL"    View = (occWorldViewMatrixInverse * vec4(0.0, 0.0, 1.0, 0.0)).xyz;"
1706       EOL"  }"
1707       EOL"  else"
1708       EOL"  {"
1709       EOL"    vec3 anEye = (occWorldViewMatrixInverse * vec4(0.0, 0.0, 0.0, 1.0)).xyz;"
1710       EOL"    View = normalize (anEye - PositionWorld.xyz);"
1711       EOL"  }"
1712     + aSrcVertExtraMain
1713     + THE_VERT_gl_Position
1714     + EOL"}";
1715
1716   TCollection_AsciiString aSrcGeom = prepareGeomMainSrc (aUniforms, aStageInOuts, theBits);
1717   aSrcFragGetColor += (theBits & Graphic3d_ShaderFlags_MeshEdges) != 0
1718     ? THE_FRAG_WIREFRAME_COLOR
1719     : EOL"#define getFinalColor getColor";
1720
1721   Standard_Integer aNbLights = 0;
1722   const TCollection_AsciiString aLights = stdComputeLighting (aNbLights, theLights, !aSrcFragGetVertColor.IsEmpty(),
1723                                                               theIsPBR, toUseTexColor, theNbShadowMaps);
1724   aSrcFrag += TCollection_AsciiString()
1725     + EOL
1726     + aSrcFragGetVertColor
1727     + EOL"vec3  Normal;"
1728     + aLights
1729     + aSrcFragGetColor
1730     + EOL
1731       EOL"void main()"
1732       EOL"{"
1733       EOL"  if (occFragEarlyReturn()) { return; }"
1734     + aSrcFragExtraMain
1735     + EOL"  occSetFragColor (getFinalColor());"
1736     + EOL"}";
1737
1738   const TCollection_AsciiString aProgId = TCollection_AsciiString (theIsFlatNormal ? "flat-" : "phong-") + (theIsPBR ? "pbr-" : "")
1739                                         + genLightKey (theLights, theNbShadowMaps > 0) + "-";
1740   defaultGlslVersion (aProgramSrc, aProgId, theBits, isFlatNormal);
1741   aProgramSrc->SetDefaultSampler (false);
1742   aProgramSrc->SetNbLightsMax (aNbLights);
1743   aProgramSrc->SetNbShadowMaps (theNbShadowMaps);
1744   aProgramSrc->SetNbClipPlanesMax (aNbClipPlanes);
1745   aProgramSrc->SetAlphaTest ((theBits & Graphic3d_ShaderFlags_AlphaTest) != 0);
1746
1747   const Standard_Integer aNbGeomInputVerts = !aSrcGeom.IsEmpty() ? 3 : 0;
1748   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (aSrcVert, Graphic3d_TOS_VERTEX,   aUniforms, aStageInOuts, "", "", aNbGeomInputVerts));
1749   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (aSrcGeom, Graphic3d_TOS_GEOMETRY, aUniforms, aStageInOuts, "geomIn", "geomOut", aNbGeomInputVerts));
1750   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (aSrcFrag, Graphic3d_TOS_FRAGMENT, aUniforms, aStageInOuts, "", "", aNbGeomInputVerts));
1751   return aProgramSrc;
1752 }
1753
1754 // =======================================================================
1755 // function : getStdProgramStereo
1756 // purpose  :
1757 // =======================================================================
1758 Handle(Graphic3d_ShaderProgram) Graphic3d_ShaderManager::getStdProgramStereo (Graphic3d_StereoMode theStereoMode) const
1759 {
1760   Handle(Graphic3d_ShaderProgram) aProgramSrc = new Graphic3d_ShaderProgram();
1761   Graphic3d_ShaderObject::ShaderVariableList aUniforms, aStageInOuts;
1762
1763   aStageInOuts.Append (Graphic3d_ShaderObject::ShaderVariable ("vec2 TexCoord", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
1764   TCollection_AsciiString aSrcVert =
1765       EOL"void main()"
1766       EOL"{"
1767       EOL"  TexCoord    = occVertex.zw;"
1768       EOL"  gl_Position = vec4(occVertex.x, occVertex.y, 0.0, 1.0);"
1769       EOL"}";
1770
1771   TCollection_AsciiString aSrcFrag;
1772   aUniforms.Append (Graphic3d_ShaderObject::ShaderVariable ("sampler2D uLeftSampler",  Graphic3d_TOS_FRAGMENT));
1773   aUniforms.Append (Graphic3d_ShaderObject::ShaderVariable ("sampler2D uRightSampler", Graphic3d_TOS_FRAGMENT));
1774   const char* aName = "stereo";
1775   switch (theStereoMode)
1776   {
1777     case Graphic3d_StereoMode_Anaglyph:
1778     {
1779       aName = "anaglyph";
1780       aUniforms.Append (Graphic3d_ShaderObject::ShaderVariable ("mat4 uMultL", Graphic3d_TOS_FRAGMENT));
1781       aUniforms.Append (Graphic3d_ShaderObject::ShaderVariable ("mat4 uMultR", Graphic3d_TOS_FRAGMENT));
1782       const TCollection_AsciiString aNormalize = mySRgbState
1783                                                ? EOL"#define sRgb2linear(theColor) theColor"
1784                                                  EOL"#define linear2sRgb(theColor) theColor"
1785                                                : EOL"#define sRgb2linear(theColor) pow(theColor, vec4(2.2, 2.2, 2.2, 1.0))"
1786                                                  EOL"#define linear2sRgb(theColor) pow(theColor, 1.0 / vec4(2.2, 2.2, 2.2, 1.0))";
1787       aSrcFrag = aNormalize
1788       + EOL"void main()"
1789         EOL"{"
1790         EOL"  vec4 aColorL = occTexture2D (uLeftSampler,  TexCoord);"
1791         EOL"  vec4 aColorR = occTexture2D (uRightSampler, TexCoord);"
1792         EOL"  aColorL = sRgb2linear (aColorL);"
1793         EOL"  aColorR = sRgb2linear (aColorR);"
1794         EOL"  vec4 aColor = uMultR * aColorR + uMultL * aColorL;"
1795         EOL"  occSetFragColor (linear2sRgb (aColor));"
1796         EOL"}";
1797       break;
1798     }
1799     case Graphic3d_StereoMode_RowInterlaced:
1800     {
1801       aName = "row-interlaced";
1802       aSrcFrag =
1803           EOL"void main()"
1804           EOL"{"
1805           EOL"  vec4 aColorL = occTexture2D (uLeftSampler,  TexCoord);"
1806           EOL"  vec4 aColorR = occTexture2D (uRightSampler, TexCoord);"
1807           EOL"  if (int (mod (gl_FragCoord.y - 1023.5, 2.0)) != 1)"
1808           EOL"  {"
1809           EOL"    occSetFragColor (aColorL);"
1810           EOL"  }"
1811           EOL"  else"
1812           EOL"  {"
1813           EOL"    occSetFragColor (aColorR);"
1814           EOL"  }"
1815           EOL"}";
1816       break;
1817     }
1818     case Graphic3d_StereoMode_ColumnInterlaced:
1819     {
1820       aName = "column-interlaced";
1821       aSrcFrag =
1822           EOL"void main()"
1823           EOL"{"
1824           EOL"  vec4 aColorL = occTexture2D (uLeftSampler,  TexCoord);"
1825           EOL"  vec4 aColorR = occTexture2D (uRightSampler, TexCoord);"
1826           EOL"  if (int (mod (gl_FragCoord.x - 1023.5, 2.0)) == 1)"
1827           EOL"  {"
1828           EOL"    occSetFragColor (aColorL);"
1829           EOL"  }"
1830           EOL"  else"
1831           EOL"  {"
1832           EOL"    occSetFragColor (aColorR);"
1833           EOL"  }"
1834           EOL"}";
1835       break;
1836     }
1837     case Graphic3d_StereoMode_ChessBoard:
1838     {
1839       aName = "chessboard";
1840       aSrcFrag =
1841           EOL"void main()"
1842           EOL"{"
1843           EOL"  vec4 aColorL = occTexture2D (uLeftSampler,  TexCoord);"
1844           EOL"  vec4 aColorR = occTexture2D (uRightSampler, TexCoord);"
1845           EOL"  bool isEvenX = int(mod(floor(gl_FragCoord.x - 1023.5), 2.0)) != 1;"
1846           EOL"  bool isEvenY = int(mod(floor(gl_FragCoord.y - 1023.5), 2.0)) == 1;"
1847           EOL"  if ((isEvenX && isEvenY) || (!isEvenX && !isEvenY))"
1848           EOL"  {"
1849           EOL"    occSetFragColor (aColorL);"
1850           EOL"  }"
1851           EOL"  else"
1852           EOL"  {"
1853           EOL"    occSetFragColor (aColorR);"
1854           EOL"  }"
1855           EOL"}";
1856       break;
1857     }
1858     case Graphic3d_StereoMode_SideBySide:
1859     {
1860       aName = "sidebyside";
1861       aSrcFrag =
1862           EOL"void main()"
1863           EOL"{"
1864           EOL"  vec2 aTexCoord = vec2 (TexCoord.x * 2.0, TexCoord.y);"
1865           EOL"  if (TexCoord.x > 0.5)"
1866           EOL"  {"
1867           EOL"    aTexCoord.x -= 1.0;"
1868           EOL"  }"
1869           EOL"  vec4 aColorL = occTexture2D (uLeftSampler,  aTexCoord);"
1870           EOL"  vec4 aColorR = occTexture2D (uRightSampler, aTexCoord);"
1871           EOL"  if (TexCoord.x <= 0.5)"
1872           EOL"  {"
1873           EOL"    occSetFragColor (aColorL);"
1874           EOL"  }"
1875           EOL"  else"
1876           EOL"  {"
1877           EOL"    occSetFragColor (aColorR);"
1878           EOL"  }"
1879           EOL"}";
1880       break;
1881     }
1882     case Graphic3d_StereoMode_OverUnder:
1883     {
1884       aName = "overunder";
1885       aSrcFrag =
1886           EOL"void main()"
1887           EOL"{"
1888           EOL"  vec2 aTexCoord = vec2 (TexCoord.x, TexCoord.y * 2.0);"
1889           EOL"  if (TexCoord.y > 0.5)"
1890           EOL"  {"
1891           EOL"    aTexCoord.y -= 1.0;"
1892           EOL"  }"
1893           EOL"  vec4 aColorL = occTexture2D (uLeftSampler,  aTexCoord);"
1894           EOL"  vec4 aColorR = occTexture2D (uRightSampler, aTexCoord);"
1895           EOL"  if (TexCoord.y <= 0.5)"
1896           EOL"  {"
1897           EOL"    occSetFragColor (aColorL);"
1898           EOL"  }"
1899           EOL"  else"
1900           EOL"  {"
1901           EOL"    occSetFragColor (aColorR);"
1902           EOL"  }"
1903           EOL"}";
1904       break;
1905     }
1906     case Graphic3d_StereoMode_QuadBuffer:
1907     case Graphic3d_StereoMode_SoftPageFlip:
1908     case Graphic3d_StereoMode_OpenVR:
1909     default:
1910     {
1911       aSrcFrag =
1912           EOL"void main()"
1913           EOL"{"
1914           EOL"  vec4 aColorL = occTexture2D (uLeftSampler,  TexCoord);"
1915           EOL"  vec4 aColorR = occTexture2D (uRightSampler, TexCoord);"
1916           EOL"  aColorL.b = 0.0;"
1917           EOL"  aColorL.g = 0.0;"
1918           EOL"  aColorR.r = 0.0;"
1919           EOL"  occSetFragColor (aColorL + aColorR);"
1920           EOL"}";
1921       break;
1922     }
1923   }
1924
1925   defaultGlslVersion (aProgramSrc, aName, 0);
1926   aProgramSrc->SetDefaultSampler (false);
1927   aProgramSrc->SetNbLightsMax (0);
1928   aProgramSrc->SetNbShadowMaps (0);
1929   aProgramSrc->SetNbClipPlanesMax (0);
1930   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (aSrcVert, Graphic3d_TOS_VERTEX,   aUniforms, aStageInOuts));
1931   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (aSrcFrag, Graphic3d_TOS_FRAGMENT, aUniforms, aStageInOuts));
1932   return aProgramSrc;
1933 }
1934
1935 // =======================================================================
1936 // function : getStdProgramBoundBox
1937 // purpose  :
1938 // =======================================================================
1939 Handle(Graphic3d_ShaderProgram) Graphic3d_ShaderManager::getStdProgramBoundBox() const
1940 {
1941   Handle(Graphic3d_ShaderProgram) aProgramSrc = new Graphic3d_ShaderProgram();
1942
1943   Graphic3d_ShaderObject::ShaderVariableList aUniforms, aStageInOuts;
1944   aUniforms.Append (Graphic3d_ShaderObject::ShaderVariable ("vec3 occBBoxCenter", Graphic3d_TOS_VERTEX));
1945   aUniforms.Append (Graphic3d_ShaderObject::ShaderVariable ("vec3 occBBoxSize",   Graphic3d_TOS_VERTEX));
1946
1947   TCollection_AsciiString aSrcVert =
1948     EOL"void main()"
1949     EOL"{"
1950     EOL"  vec4 aCenter = vec4(occVertex.xyz * occBBoxSize + occBBoxCenter, 1.0);"
1951     EOL"  vec4 aPos    = vec4(occVertex.xyz * occBBoxSize + occBBoxCenter, 1.0);"
1952     EOL"  gl_Position = occProjectionMatrix * occWorldViewMatrix * occModelWorldMatrix * aPos;"
1953     EOL"}";
1954
1955   TCollection_AsciiString aSrcFrag =
1956     EOL"void main()"
1957     EOL"{"
1958     EOL"  occSetFragColor (occColor);"
1959     EOL"}";
1960
1961   defaultGlslVersion (aProgramSrc, "bndbox", 0);
1962   aProgramSrc->SetDefaultSampler (false);
1963   aProgramSrc->SetNbLightsMax (0);
1964   aProgramSrc->SetNbShadowMaps (0);
1965   aProgramSrc->SetNbClipPlanesMax (0);
1966   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (aSrcVert, Graphic3d_TOS_VERTEX,   aUniforms, aStageInOuts));
1967   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (aSrcFrag, Graphic3d_TOS_FRAGMENT, aUniforms, aStageInOuts));
1968   return aProgramSrc;
1969 }
1970
1971 // =======================================================================
1972 // function : getPBREnvBakingProgram
1973 // purpose  :
1974 // =======================================================================
1975 Handle(Graphic3d_ShaderProgram) Graphic3d_ShaderManager::getPBREnvBakingProgram (Standard_Integer theIndex) const
1976 {
1977   Standard_ASSERT_RAISE (theIndex >= 0 && theIndex <= 2,"");
1978   Handle(Graphic3d_ShaderProgram) aProgramSrc = new Graphic3d_ShaderProgram();
1979   Graphic3d_ShaderObject::ShaderVariableList aUniforms, aStageInOuts;
1980
1981   TCollection_AsciiString aSrcVert = TCollection_AsciiString()
1982   + THE_FUNC_cubemap_vector_transform
1983   + Shaders_PBREnvBaking_vs;
1984
1985   TCollection_AsciiString aSrcFrag = TCollection_AsciiString()
1986   + THE_FUNC_cubemap_vector_transform
1987   + Shaders_PBRDistribution_glsl
1988   + ((theIndex == 0 || theIndex == 2) ? "\n#define THE_TO_BAKE_DIFFUSE\n" : "\n#define THE_TO_BAKE_SPECULAR\n")
1989   + (theIndex == 2 ? "\n#define THE_TO_PACK_FLOAT\n" : "")
1990   + Shaders_PBREnvBaking_fs;
1991
1992   // constant array definition requires OpenGL 2.1+ or OpenGL ES 3.0+
1993   switch (myGapi)
1994   {
1995     case Aspect_GraphicsLibrary_OpenGL:
1996     {
1997       aProgramSrc->SetHeader ("#version 120");
1998       break;
1999     }
2000     case Aspect_GraphicsLibrary_OpenGLES:
2001     {
2002       if (IsGapiGreaterEqual (3, 0))
2003       {
2004         aProgramSrc->SetHeader ("#version 300 es");
2005       }
2006       else if (myGlslExtensions[Graphic3d_GlslExtension_GL_EXT_shader_texture_lod])
2007       {
2008         aProgramSrc->SetHeader ("#extension GL_EXT_shader_texture_lod : enable\n"
2009                                 "#define textureCubeLod textureCubeLodEXT");
2010       }
2011       else
2012       {
2013         Message::SendWarning ("Warning: incomplete PBR lighting implementation due to missing OpenGL ES 3.0 or GL_EXT_shader_texture_lod support.");
2014       }
2015       break;
2016     }
2017   }
2018
2019   static const char* THE_BAKE_NAMES[3] = { "pbr_env_baking_diffuse", "pbr_env_baking_specular", "pbr_env_baking_difffallback" };
2020   defaultGlslVersion (aProgramSrc, THE_BAKE_NAMES[theIndex], 0);
2021   aProgramSrc->SetDefaultSampler (false);
2022   aProgramSrc->SetNbLightsMax (0);
2023   aProgramSrc->SetNbShadowMaps (0);
2024   aProgramSrc->SetNbClipPlanesMax (0);
2025   aProgramSrc->SetPBR (true);
2026   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (aSrcVert, Graphic3d_TOS_VERTEX,   aUniforms, aStageInOuts));
2027   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (aSrcFrag, Graphic3d_TOS_FRAGMENT, aUniforms, aStageInOuts));
2028   return aProgramSrc;
2029 }
2030
2031 // =======================================================================
2032 // function : getBgCubeMapProgram
2033 // purpose  :
2034 // =======================================================================
2035 Handle(Graphic3d_ShaderProgram) Graphic3d_ShaderManager::getBgCubeMapProgram() const
2036 {
2037   Handle(Graphic3d_ShaderProgram) aProgSrc = new Graphic3d_ShaderProgram();
2038
2039   Graphic3d_ShaderObject::ShaderVariableList aUniforms, aStageInOuts;
2040   aStageInOuts.Append (Graphic3d_ShaderObject::ShaderVariable("vec3 ViewDirection", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
2041   aUniforms.Append (Graphic3d_ShaderObject::ShaderVariable ("samplerCube occSampler0", Graphic3d_TOS_FRAGMENT));
2042   aUniforms.Append (Graphic3d_ShaderObject::ShaderVariable ("int uYCoeff", Graphic3d_TOS_VERTEX));
2043   aUniforms.Append (Graphic3d_ShaderObject::ShaderVariable ("int uZCoeff", Graphic3d_TOS_VERTEX));
2044
2045   TCollection_AsciiString aSrcVert = TCollection_AsciiString()
2046   + THE_FUNC_cubemap_vector_transform
2047   + EOL"void main()"
2048     EOL"{"
2049     EOL"  ViewDirection = cubemapVectorTransform (occVertex.xyz, uYCoeff, uZCoeff);"
2050     EOL"  vec4 aPos = occProjectionMatrix * occWorldViewMatrix * vec4(occVertex.xyz, 1.0);"
2051     // setting Z to W ensures that final Z will be 1.0 after perspective division, (w/w=1))
2052     // which allows rendering skybox after everything else with depth test enabled (GL_LEQUAL)
2053     EOL"  gl_Position = aPos.xyww;"
2054     EOL"}";
2055
2056   TCollection_AsciiString aDepthClamp;
2057   if (myToEmulateDepthClamp)
2058   {
2059     // workaround Z clamping issues on some GPUs
2060     aDepthClamp = EOL"  gl_FragDepth = clamp (gl_FragDepth, 0.0, 1.0);";
2061     if (myGapi == Aspect_GraphicsLibrary_OpenGLES)
2062     {
2063       if (IsGapiGreaterEqual (3, 0))
2064       {
2065         aProgSrc->SetHeader ("#version 300 es");
2066       }
2067       else if (myGlslExtensions[Graphic3d_GlslExtension_GL_EXT_frag_depth])
2068       {
2069         aProgSrc->SetHeader ("#extension GL_EXT_frag_depth : enable"
2070                           EOL"#define gl_FragDepth gl_FragDepthEXT");
2071       }
2072       else
2073       {
2074         aDepthClamp.Clear();
2075       }
2076     }
2077   }
2078
2079   TCollection_AsciiString aSrcFrag = TCollection_AsciiString()
2080   + EOL"#define occEnvCubemap occSampler0"
2081     EOL"void main()"
2082     EOL"{"
2083     EOL"  occSetFragColor (vec4(occTextureCube (occEnvCubemap, ViewDirection).rgb, 1.0));"
2084   + aDepthClamp
2085   + EOL"}";
2086
2087   defaultGlslVersion (aProgSrc, "background_cubemap", 0);
2088   aProgSrc->SetDefaultSampler (false);
2089   aProgSrc->SetNbLightsMax (0);
2090   aProgSrc->SetNbShadowMaps (0);
2091   aProgSrc->SetNbClipPlanesMax (0);
2092   aProgSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (aSrcVert, Graphic3d_TOS_VERTEX,   aUniforms, aStageInOuts));
2093   aProgSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (aSrcFrag, Graphic3d_TOS_FRAGMENT, aUniforms, aStageInOuts));
2094   return aProgSrc;
2095 }