0032201: Visualization, TKOpenGl - unify Phong/PBR material properties getters
[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 = vec3 (occWorldViewMatrix * vec4 (occLight_Position (0), 0.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     aStageInOuts.Append (Graphic3d_ShaderObject::ShaderVariable ("vec4 Position",      Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
1029     aSrcVertExtraMain +=
1030       EOL"  PositionWorld = occModelWorldMatrix * occVertex;"
1031       EOL"  Position      = occWorldViewMatrix * PositionWorld;";
1032
1033     if ((theBits & Graphic3d_ShaderFlags_ClipPlanesN) == Graphic3d_ShaderFlags_ClipPlanesN)
1034     {
1035       aNbClipPlanes = Graphic3d_ShaderProgram::THE_MAX_CLIP_PLANES_DEFAULT;
1036       aSrcFragExtraMain += (theBits & Graphic3d_ShaderFlags_ClipChains) != 0
1037                          ? THE_FRAG_CLIP_CHAINS_N
1038                          : THE_FRAG_CLIP_PLANES_N;
1039     }
1040     else if ((theBits & Graphic3d_ShaderFlags_ClipPlanes1) != 0)
1041     {
1042       aNbClipPlanes = 1;
1043       aSrcFragExtraMain += THE_FRAG_CLIP_PLANES_1;
1044     }
1045     else if ((theBits & Graphic3d_ShaderFlags_ClipPlanes2) != 0)
1046     {
1047       aNbClipPlanes = 2;
1048       aSrcFragExtraMain += (theBits & Graphic3d_ShaderFlags_ClipChains) != 0
1049                          ? THE_FRAG_CLIP_CHAINS_2
1050                          : THE_FRAG_CLIP_PLANES_2;
1051     }
1052   }
1053   if ((theBits & Graphic3d_ShaderFlags_OitDepthPeeling) != 0)
1054   {
1055     aProgramSrc->SetNbFragmentOutputs (3);
1056     aProgramSrc->SetOitOutput (Graphic3d_RTM_DEPTH_PEELING_OIT);
1057   }
1058   else if ((theBits & Graphic3d_ShaderFlags_WriteOit) != 0)
1059   {
1060     aProgramSrc->SetNbFragmentOutputs (2);
1061     aProgramSrc->SetOitOutput (Graphic3d_RTM_BLEND_OIT);
1062   }
1063
1064   if (theIsOutline)
1065   {
1066     aUniforms.Append (Graphic3d_ShaderObject::ShaderVariable ("float occOrthoScale",          Graphic3d_TOS_VERTEX));
1067     aUniforms.Append (Graphic3d_ShaderObject::ShaderVariable ("float occSilhouetteThickness", Graphic3d_TOS_VERTEX));
1068     aSrcVertEndMain = THE_VERT_gl_Position_OUTLINE;
1069   }
1070   else if ((theBits & Graphic3d_ShaderFlags_StippleLine) != 0)
1071   {
1072     const Standard_Integer aBits = defaultGlslVersion (aProgramSrc, "unlit", theBits);
1073     if ((aBits & Graphic3d_ShaderFlags_StippleLine) != 0)
1074     {
1075       if (hasGlslBitwiseOps())
1076       {
1077         aUniforms.Append (Graphic3d_ShaderObject::ShaderVariable ("int   occStipplePattern", Graphic3d_TOS_FRAGMENT));
1078       }
1079       else
1080       {
1081         aUniforms.Append (Graphic3d_ShaderObject::ShaderVariable ("bool  occStipplePattern[16]", Graphic3d_TOS_FRAGMENT));
1082       }
1083       aUniforms.Append (Graphic3d_ShaderObject::ShaderVariable ("float occStippleFactor",  Graphic3d_TOS_FRAGMENT));
1084       aUniforms.Append (Graphic3d_ShaderObject::ShaderVariable ("vec4 occViewport", Graphic3d_TOS_VERTEX));
1085       aStageInOuts.Append (Graphic3d_ShaderObject::ShaderVariable ("vec2 ScreenSpaceCoord", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
1086       aSrcVertEndMain =
1087         EOL"  vec2 aPosition   = gl_Position.xy / gl_Position.w;"
1088         EOL"  aPosition        = aPosition * 0.5 + 0.5;"
1089         EOL"  ScreenSpaceCoord = aPosition.xy * occViewport.zw + occViewport.xy;";
1090       aSrcFragMainGetColor = TCollection_AsciiString()
1091       + EOL"  vec2 anAxis = vec2 (0.0, 1.0);"
1092         EOL"  if (abs (dFdx (ScreenSpaceCoord.x)) - abs (dFdy (ScreenSpaceCoord.y)) > 0.001)"
1093         EOL"  {"
1094         EOL"    anAxis = vec2 (1.0, 0.0);"
1095         EOL"  }"
1096         EOL"  float aRotatePoint = dot (gl_FragCoord.xy, anAxis);"
1097       + (hasGlslBitwiseOps()
1098        ? EOL"  uint aBit = uint (floor (aRotatePoint / occStippleFactor + 0.5)) & 15U;"
1099          EOL"  if ((uint (occStipplePattern) & (1U << aBit)) == 0U) discard;"
1100        : EOL"  int aBit = int (mod (floor (aRotatePoint / occStippleFactor + 0.5), 16.0));"
1101          EOL"  if (!occStipplePattern[aBit]) discard;")
1102       + EOL"  vec4 aColor = getFinalColor();"
1103         EOL"  if (aColor.a <= 0.1) discard;"
1104         EOL"  occSetFragColor (aColor);";
1105     }
1106     else
1107     {
1108       Message::SendWarning ("Warning: stipple lines in GLSL will be ignored");
1109     }
1110   }
1111
1112   aSrcVert =
1113       aSrcVertExtraFunc
1114     + EOL"void main()"
1115       EOL"{"
1116     + aSrcVertExtraMain
1117     + THE_VERT_gl_Position
1118     + aSrcVertEndMain
1119     + EOL"}";
1120
1121   TCollection_AsciiString aSrcGeom = prepareGeomMainSrc (aUniforms, aStageInOuts, theBits);
1122   aSrcFragGetColor += (theBits & Graphic3d_ShaderFlags_MeshEdges) != 0
1123     ? THE_FRAG_WIREFRAME_COLOR
1124     : EOL"#define getFinalColor getColor";
1125
1126   aSrcFrag =
1127       aSrcFragGetColor
1128     + aSrcGetAlpha
1129     + EOL"void main()"
1130       EOL"{"
1131       EOL"  if (occFragEarlyReturn()) { return; }"
1132     + aSrcFragExtraMain
1133     + aSrcFragMainGetColor
1134     + EOL"}";
1135
1136   defaultGlslVersion (aProgramSrc, theIsOutline ? "outline" : "unlit", theBits);
1137   aProgramSrc->SetDefaultSampler (false);
1138   aProgramSrc->SetNbLightsMax (0);
1139   aProgramSrc->SetNbShadowMaps (0);
1140   aProgramSrc->SetNbClipPlanesMax (aNbClipPlanes);
1141   aProgramSrc->SetAlphaTest ((theBits & Graphic3d_ShaderFlags_AlphaTest) != 0);
1142   const Standard_Integer aNbGeomInputVerts = !aSrcGeom.IsEmpty() ? 3 : 0;
1143   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (aSrcVert, Graphic3d_TOS_VERTEX,   aUniforms, aStageInOuts, "", "", aNbGeomInputVerts));
1144   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (aSrcGeom, Graphic3d_TOS_GEOMETRY, aUniforms, aStageInOuts, "geomIn", "geomOut", aNbGeomInputVerts));
1145   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (aSrcFrag, Graphic3d_TOS_FRAGMENT, aUniforms, aStageInOuts, "", "", aNbGeomInputVerts));
1146   return aProgramSrc;
1147 }
1148
1149 // =======================================================================
1150 // function : stdComputeLighting
1151 // purpose  :
1152 // =======================================================================
1153 TCollection_AsciiString Graphic3d_ShaderManager::stdComputeLighting (Standard_Integer& theNbLights,
1154                                                                      const Handle(Graphic3d_LightSet)& theLights,
1155                                                                      Standard_Boolean  theHasVertColor,
1156                                                                      Standard_Boolean  theIsPBR,
1157                                                                      Standard_Boolean  theHasTexColor,
1158                                                                      Standard_Integer  theNbShadowMaps) const
1159 {
1160   TCollection_AsciiString aLightsFunc, aLightsLoop;
1161   theNbLights = 0;
1162   if (!theLights.IsNull())
1163   {
1164     theNbLights = theLights->NbEnabled();
1165     if (theNbLights <= THE_NB_UNROLLED_LIGHTS_MAX)
1166     {
1167       Standard_Integer anIndex = 0;
1168       if (theNbShadowMaps > 0)
1169       {
1170         for (Graphic3d_LightSet::Iterator aLightIter (theLights, Graphic3d_LightSet::IterationFilter_ExcludeDisabledAndAmbient);
1171              aLightIter.More(); aLightIter.Next())
1172         {
1173           if (aLightIter.Value()->Type() == Graphic3d_TOLS_DIRECTIONAL
1174            && aLightIter.Value()->ToCastShadows())
1175           {
1176             aLightsLoop = aLightsLoop + EOL"    occDirectionalLight (" + anIndex + ", theNormal, theView, theIsFront,"
1177                                         EOL"                         occDirectionalLightShadow (occShadowMapSamplers[" + anIndex + "], " + anIndex + ", theNormal));";
1178             ++anIndex;
1179           }
1180         }
1181       }
1182       for (Graphic3d_LightSet::Iterator aLightIter (theLights, Graphic3d_LightSet::IterationFilter_ExcludeDisabledAndAmbient);
1183            aLightIter.More(); aLightIter.Next())
1184       {
1185         switch (aLightIter.Value()->Type())
1186         {
1187           case Graphic3d_TOLS_AMBIENT:
1188           {
1189             break; // skip ambient
1190           }
1191           case Graphic3d_TOLS_DIRECTIONAL:
1192           {
1193             if (theNbShadowMaps > 0
1194              && aLightIter.Value()->ToCastShadows())
1195             {
1196               break;
1197             }
1198             aLightsLoop = aLightsLoop + EOL"    occDirectionalLight (" + anIndex + ", theNormal, theView, theIsFront, 1.0);";
1199             ++anIndex;
1200             break;
1201           }
1202           case Graphic3d_TOLS_POSITIONAL:
1203           {
1204             aLightsLoop = aLightsLoop + EOL"    occPointLight (" + anIndex + ", theNormal, theView, aPoint, theIsFront);";
1205             ++anIndex;
1206             break;
1207           }
1208           case Graphic3d_TOLS_SPOT:
1209           {
1210             aLightsLoop = aLightsLoop + EOL"    occSpotLight (" + anIndex + ", theNormal, theView, aPoint, theIsFront);";
1211             ++anIndex;
1212             break;
1213           }
1214         }
1215       }
1216     }
1217     else
1218     {
1219       theNbLights = roundUpMaxLightSources (theNbLights);
1220       bool isFirstInLoop = true;
1221       aLightsLoop = aLightsLoop +
1222         EOL"    for (int anIndex = 0; anIndex < occLightSourcesCount; ++anIndex)"
1223         EOL"    {"
1224         EOL"      int aType = occLight_Type (anIndex);";
1225       if (theLights->NbEnabledLightsOfType (Graphic3d_TOLS_DIRECTIONAL) > 0)
1226       {
1227         isFirstInLoop = false;
1228         aLightsLoop +=
1229           EOL"      if (aType == OccLightType_Direct)"
1230           EOL"      {"
1231           EOL"        occDirectionalLight (anIndex, theNormal, theView, theIsFront, 1.0);"
1232           EOL"      }";
1233       }
1234       if (theLights->NbEnabledLightsOfType (Graphic3d_TOLS_POSITIONAL) > 0)
1235       {
1236         if (!isFirstInLoop)
1237         {
1238           aLightsLoop += EOL"      else ";
1239         }
1240         isFirstInLoop = false;
1241         aLightsLoop +=
1242           EOL"      if (aType == OccLightType_Point)"
1243           EOL"      {"
1244           EOL"        occPointLight (anIndex, theNormal, theView, aPoint, theIsFront);"
1245           EOL"      }";
1246       }
1247       if (theLights->NbEnabledLightsOfType (Graphic3d_TOLS_SPOT) > 0)
1248       {
1249         if (!isFirstInLoop)
1250         {
1251           aLightsLoop += EOL"      else ";
1252         }
1253         isFirstInLoop = false;
1254         aLightsLoop +=
1255           EOL"      if (aType == OccLightType_Spot)"
1256           EOL"      {"
1257           EOL"        occSpotLight (anIndex, theNormal, theView, aPoint, theIsFront);"
1258           EOL"      }";
1259       }
1260       aLightsLoop += EOL"    }";
1261     }
1262
1263     if (theIsPBR)
1264     {
1265       aLightsFunc += Shaders_PBRDistribution_glsl;
1266       aLightsFunc += Shaders_PBRGeometry_glsl;
1267       aLightsFunc += Shaders_PBRFresnel_glsl;
1268       aLightsFunc += Shaders_PBRCookTorrance_glsl;
1269       aLightsFunc += Shaders_PBRIllumination_glsl;
1270     }
1271
1272     if (theLights->NbEnabledLightsOfType (Graphic3d_TOLS_DIRECTIONAL) == 1
1273      && theNbLights == 1
1274      && !theIsPBR
1275      && theNbShadowMaps == 0)
1276     {
1277       // use the version with hard-coded first index
1278       aLightsLoop = EOL"    directionalLightFirst(theNormal, theView, theIsFront, 1.0);";
1279       aLightsFunc += THE_FUNC_directionalLightFirst;
1280     }
1281     else if (theLights->NbEnabledLightsOfType (Graphic3d_TOLS_DIRECTIONAL) > 0)
1282     {
1283       if (theNbShadowMaps > 0)
1284       {
1285         aLightsFunc += Shaders_DirectionalLightShadow_glsl;
1286       }
1287       aLightsFunc += theIsPBR ? Shaders_PBRDirectionalLight_glsl : Shaders_PhongDirectionalLight_glsl;
1288     }
1289     if (theLights->NbEnabledLightsOfType (Graphic3d_TOLS_POSITIONAL) > 0)
1290     {
1291       aLightsFunc += theIsPBR ? Shaders_PBRPointLight_glsl : Shaders_PhongPointLight_glsl;
1292     }
1293     if (theLights->NbEnabledLightsOfType (Graphic3d_TOLS_SPOT) > 0)
1294     {
1295       aLightsFunc += theIsPBR ? Shaders_PBRSpotLight_glsl : Shaders_PhongSpotLight_glsl;
1296     }
1297   }
1298
1299   TCollection_AsciiString aGetMatAmbient = "occMaterial_Ambient(theIsFront);";
1300   TCollection_AsciiString aGetMatDiffuse = "occMaterial_Diffuse(theIsFront);";
1301   if (theHasVertColor)
1302   {
1303     aGetMatAmbient = "getVertColor().rgb;";
1304     aGetMatDiffuse = "getVertColor();";
1305   }
1306
1307   if (!theIsPBR)
1308   {
1309     return TCollection_AsciiString()
1310     + THE_FUNC_lightDef
1311     + Shaders_PointLightAttenuation_glsl
1312     + aLightsFunc
1313     + EOL
1314       EOL"vec4 computeLighting (in vec3 theNormal,"
1315       EOL"                      in vec3 theView,"
1316       EOL"                      in vec4 thePoint,"
1317       EOL"                      in bool theIsFront)"
1318       EOL"{"
1319       EOL"  Ambient  = occLightAmbient.rgb;"
1320       EOL"  Diffuse  = vec3 (0.0);"
1321       EOL"  Specular = vec3 (0.0);"
1322       EOL"  vec3 aPoint = thePoint.xyz / thePoint.w;"
1323     + aLightsLoop
1324     + EOL"  vec3 aMatAmbient  = " + aGetMatAmbient
1325     + EOL"  vec4 aMatDiffuse  = " + aGetMatDiffuse
1326     + EOL"  vec3 aMatSpecular = occMaterial_Specular(theIsFront);"
1327       EOL"  vec4 aColor = vec4(Ambient * aMatAmbient + Diffuse * aMatDiffuse.rgb + Specular * aMatSpecular, aMatDiffuse.a);"
1328     + (theHasTexColor ?
1329       EOL"#if defined(THE_HAS_TEXTURE_COLOR) && defined(FRAGMENT_SHADER)"
1330       EOL"  aColor *= occTexture2D(occSamplerBaseColor, TexCoord.st / TexCoord.w);"
1331       EOL"#endif" : "")
1332     + EOL"  occMaterialOcclusion(aColor.rgb, TexCoord.st / TexCoord.w);"
1333       EOL"  vec3 aMatEmission = occMaterialEmission(theIsFront, TexCoord.st / TexCoord.w);"
1334       EOL"  aColor.rgb += aMatEmission.rgb;"
1335       EOL"  return aColor;"
1336       EOL"}";
1337   }
1338   else
1339   {
1340     return TCollection_AsciiString()
1341     + THE_FUNC_PBR_lightDef
1342     + Shaders_PointLightAttenuation_glsl
1343     + aLightsFunc
1344     + EOL
1345       EOL"vec4 computeLighting (in vec3 theNormal,"
1346       EOL"                      in vec3 theView,"
1347       EOL"                      in vec4 thePoint,"
1348       EOL"                      in bool theIsFront)"
1349       EOL"{"
1350       EOL"  DirectLighting = vec3(0.0);"
1351       EOL"  BaseColor = " + (theHasVertColor ? "getVertColor();" : "occMaterialBaseColor(theIsFront, TexCoord.st / TexCoord.w);")
1352     + EOL"  Emission            = occMaterialEmission(theIsFront, TexCoord.st / TexCoord.w);"
1353       EOL"  Metallic            = occMaterialMetallic(theIsFront, TexCoord.st / TexCoord.w);"
1354       EOL"  NormalizedRoughness = occMaterialRoughness(theIsFront, TexCoord.st / TexCoord.w);"
1355       EOL"  Roughness = occRoughness (NormalizedRoughness);"
1356       EOL"  IOR       = occPBRMaterial_IOR (theIsFront);"
1357       EOL"  vec3 aPoint = thePoint.xyz / thePoint.w;"
1358     + aLightsLoop
1359     + EOL"  vec3 aColor = DirectLighting;"
1360       EOL"  vec3 anIndirectLightingSpec = occPBRFresnel (BaseColor.rgb, Metallic, IOR);"
1361       EOL"  vec2 aCoeff = occTexture2D (occEnvLUT, vec2(abs(dot(theView, theNormal)), NormalizedRoughness)).xy;"
1362       EOL"  anIndirectLightingSpec *= aCoeff.x;"
1363       EOL"  anIndirectLightingSpec += aCoeff.y;"
1364       EOL"  anIndirectLightingSpec *= occTextureCubeLod (occSpecIBLMap, -reflect (theView, theNormal), NormalizedRoughness * float (occNbSpecIBLLevels - 1)).rgb;"
1365       EOL"  vec3 aRefractionCoeff = 1.0 - occPBRFresnel (BaseColor.rgb, Metallic, NormalizedRoughness, IOR, abs(dot(theView, theNormal)));"
1366       EOL"  aRefractionCoeff *= (1.0 - Metallic);"
1367       EOL"  vec3 anIndirectLightingDiff = aRefractionCoeff * BaseColor.rgb * BaseColor.a;"
1368       EOL"  anIndirectLightingDiff *= occDiffIBLMap (theNormal).rgb;"
1369       EOL"  aColor += occLightAmbient.rgb * (anIndirectLightingDiff + anIndirectLightingSpec);"
1370       EOL"  aColor += Emission;"
1371       EOL"  occMaterialOcclusion(aColor, TexCoord.st / TexCoord.w);"
1372       EOL"  return vec4 (aColor, mix(1.0, BaseColor.a, aRefractionCoeff.x));"
1373       EOL"}";
1374   }
1375 }
1376
1377 // =======================================================================
1378 // function : getStdProgramGouraud
1379 // purpose  :
1380 // =======================================================================
1381 Handle(Graphic3d_ShaderProgram) Graphic3d_ShaderManager::getStdProgramGouraud (const Handle(Graphic3d_LightSet)& theLights,
1382                                                                                Standard_Integer theBits) const
1383 {
1384   Handle(Graphic3d_ShaderProgram) aProgramSrc = new Graphic3d_ShaderProgram();
1385   TCollection_AsciiString aSrcVert, aSrcVertColor, aSrcVertExtraMain;
1386   TCollection_AsciiString aSrcFrag, aSrcFragExtraMain;
1387   TCollection_AsciiString aSrcFragGetColor = EOL"vec4 getColor(void) { return gl_FrontFacing ? FrontColor : BackColor; }";
1388   Graphic3d_ShaderObject::ShaderVariableList aUniforms, aStageInOuts;
1389   bool toUseTexColor = false;
1390   if ((theBits & Graphic3d_ShaderFlags_IsPoint) != 0)
1391   {
1392     if (mySetPointSize)
1393     {
1394       aSrcVertExtraMain += EOL"  gl_PointSize = occPointSize;";
1395     }
1396
1397     if ((theBits & Graphic3d_ShaderFlags_PointSprite) != 0)
1398     {
1399       aUniforms.Append (Graphic3d_ShaderObject::ShaderVariable ("sampler2D occSamplerPointSprite", Graphic3d_TOS_FRAGMENT));
1400       aSrcFragGetColor = pointSpriteShadingSrc ("gl_FrontFacing ? FrontColor : BackColor", theBits);
1401     }
1402
1403     if ((theBits & Graphic3d_ShaderFlags_TextureRGB) != 0
1404      && (theBits & Graphic3d_ShaderFlags_VertColor) == 0)
1405     {
1406       aProgramSrc->SetTextureSetBits (Graphic3d_TextureSetBits_BaseColor);
1407       aUniforms.Append (Graphic3d_ShaderObject::ShaderVariable ("sampler2D occSamplerBaseColor", Graphic3d_TOS_VERTEX));
1408       aSrcVertColor = EOL"vec4 getVertColor(void) { return occTexture2D (occSamplerBaseColor, occTexCoord.xy); }";
1409     }
1410   }
1411   else
1412   {
1413     if ((theBits & Graphic3d_ShaderFlags_TextureRGB) != 0)
1414     {
1415       toUseTexColor = true;
1416       aProgramSrc->SetTextureSetBits (Graphic3d_TextureSetBits_BaseColor);
1417       aUniforms   .Append (Graphic3d_ShaderObject::ShaderVariable ("sampler2D occSamplerBaseColor", Graphic3d_TOS_FRAGMENT));
1418       aStageInOuts.Append (Graphic3d_ShaderObject::ShaderVariable ("vec4 TexCoord", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
1419       aSrcVertExtraMain += THE_VARY_TexCoord_Trsf;
1420
1421       aSrcFragGetColor =
1422         EOL"vec4 getColor(void)"
1423         EOL"{"
1424         EOL"  vec4 aColor = gl_FrontFacing ? FrontColor : BackColor;"
1425         EOL"  return occTexture2D(occSamplerBaseColor, TexCoord.st / TexCoord.w) * aColor;"
1426         EOL"}";
1427     }
1428   }
1429
1430   if ((theBits & Graphic3d_ShaderFlags_VertColor) != 0)
1431   {
1432     aSrcVertColor = EOL"vec4 getVertColor(void) { return occVertColor; }";
1433   }
1434
1435   int aNbClipPlanes = 0;
1436   if ((theBits & Graphic3d_ShaderFlags_ClipPlanesN) != 0)
1437   {
1438     aStageInOuts.Append (Graphic3d_ShaderObject::ShaderVariable ("vec4 PositionWorld", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
1439     aStageInOuts.Append (Graphic3d_ShaderObject::ShaderVariable ("vec4 Position",      Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
1440     aSrcVertExtraMain +=
1441       EOL"  PositionWorld = aPositionWorld;"
1442       EOL"  Position      = aPosition;";
1443
1444     if ((theBits & Graphic3d_ShaderFlags_ClipPlanesN) == Graphic3d_ShaderFlags_ClipPlanesN)
1445     {
1446       aNbClipPlanes = Graphic3d_ShaderProgram::THE_MAX_CLIP_PLANES_DEFAULT;
1447       aSrcFragExtraMain += (theBits & Graphic3d_ShaderFlags_ClipChains) != 0
1448                          ? THE_FRAG_CLIP_CHAINS_N
1449                          : THE_FRAG_CLIP_PLANES_N;
1450     }
1451     else if ((theBits & Graphic3d_ShaderFlags_ClipPlanes1) != 0)
1452     {
1453       aNbClipPlanes = 1;
1454       aSrcFragExtraMain += THE_FRAG_CLIP_PLANES_1;
1455     }
1456     else if ((theBits & Graphic3d_ShaderFlags_ClipPlanes2) != 0)
1457     {
1458       aNbClipPlanes = 2;
1459       aSrcFragExtraMain += (theBits & Graphic3d_ShaderFlags_ClipChains) != 0
1460                           ? THE_FRAG_CLIP_CHAINS_2
1461                           : THE_FRAG_CLIP_PLANES_2;
1462     }
1463   }
1464   if ((theBits & Graphic3d_ShaderFlags_OitDepthPeeling) != 0)
1465   {
1466     aProgramSrc->SetNbFragmentOutputs (3);
1467     aProgramSrc->SetOitOutput (Graphic3d_RTM_DEPTH_PEELING_OIT);
1468   }
1469   else if ((theBits & Graphic3d_ShaderFlags_WriteOit) != 0)
1470   {
1471     aProgramSrc->SetNbFragmentOutputs (2);
1472     aProgramSrc->SetOitOutput (Graphic3d_RTM_BLEND_OIT);
1473   }
1474
1475   aStageInOuts.Append (Graphic3d_ShaderObject::ShaderVariable ("vec4 FrontColor", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
1476   aStageInOuts.Append (Graphic3d_ShaderObject::ShaderVariable ("vec4 BackColor",  Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
1477
1478   Standard_Integer aNbLights = 0;
1479   const TCollection_AsciiString aLights = stdComputeLighting (aNbLights, theLights, !aSrcVertColor.IsEmpty(), false, toUseTexColor, 0);
1480   aSrcVert = TCollection_AsciiString()
1481     + THE_FUNC_transformNormal_view
1482     + EOL
1483     + aSrcVertColor
1484     + aLights
1485     + EOL"void main()"
1486       EOL"{"
1487       EOL"  vec4 aPositionWorld = occModelWorldMatrix * occVertex;"
1488       EOL"  vec4 aPosition      = occWorldViewMatrix * aPositionWorld;"
1489       EOL"  vec3 aNormal        = transformNormal (occNormal);"
1490       EOL"  vec3 aView          = vec3 (0.0, 0.0, 1.0);"
1491       EOL"  FrontColor  = computeLighting (aNormal, aView, aPosition, true);"
1492       EOL"  BackColor   = computeLighting (aNormal, aView, aPosition, false);"
1493     + aSrcVertExtraMain
1494     + THE_VERT_gl_Position
1495     + EOL"}";
1496
1497   TCollection_AsciiString aSrcGeom = prepareGeomMainSrc (aUniforms, aStageInOuts, theBits);
1498   aSrcFragGetColor += (theBits & Graphic3d_ShaderFlags_MeshEdges) != 0
1499     ? THE_FRAG_WIREFRAME_COLOR
1500     : EOL"#define getFinalColor getColor";
1501
1502   aSrcFrag = TCollection_AsciiString()
1503     + aSrcFragGetColor
1504     + EOL"void main()"
1505       EOL"{"
1506       EOL"  if (occFragEarlyReturn()) { return; }"
1507     + aSrcFragExtraMain
1508     + EOL"  occSetFragColor (getFinalColor());"
1509     + EOL"}";
1510
1511   const TCollection_AsciiString aProgId = TCollection_AsciiString ("gouraud-") + genLightKey (theLights, false) + "-";
1512   defaultGlslVersion (aProgramSrc, aProgId, theBits);
1513   aProgramSrc->SetDefaultSampler (false);
1514   aProgramSrc->SetNbLightsMax (aNbLights);
1515   aProgramSrc->SetNbShadowMaps (0);
1516   aProgramSrc->SetNbClipPlanesMax (aNbClipPlanes);
1517   aProgramSrc->SetAlphaTest ((theBits & Graphic3d_ShaderFlags_AlphaTest) != 0);
1518   const Standard_Integer aNbGeomInputVerts = !aSrcGeom.IsEmpty() ? 3 : 0;
1519   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (aSrcVert, Graphic3d_TOS_VERTEX,   aUniforms, aStageInOuts, "", "", aNbGeomInputVerts));
1520   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (aSrcGeom, Graphic3d_TOS_GEOMETRY, aUniforms, aStageInOuts, "geomIn", "geomOut", aNbGeomInputVerts));
1521   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (aSrcFrag, Graphic3d_TOS_FRAGMENT, aUniforms, aStageInOuts, "", "", aNbGeomInputVerts));
1522   return aProgramSrc;
1523 }
1524
1525 // =======================================================================
1526 // function : getStdProgramPhong
1527 // purpose  :
1528 // =======================================================================
1529 Handle(Graphic3d_ShaderProgram) Graphic3d_ShaderManager::getStdProgramPhong (const Handle(Graphic3d_LightSet)& theLights,
1530                                                                              const Standard_Integer theBits,
1531                                                                              const Standard_Boolean theIsFlatNormal,
1532                                                                              const Standard_Boolean theIsPBR,
1533                                                                              const Standard_Integer theNbShadowMaps) const
1534 {
1535   TCollection_AsciiString aPosition = theIsPBR ? "PositionWorld" : "Position";
1536   TCollection_AsciiString aPhongCompLight = TCollection_AsciiString() +
1537     "computeLighting (normalize (Normal), normalize (View), " + aPosition + ", gl_FrontFacing)";
1538   const bool isFlatNormal = theIsFlatNormal && myHasFlatShading;
1539   const char* aDFdxSignReversion = myToReverseDFdxSign ? "-" : "";
1540   bool toUseTexColor = false;
1541   if (isFlatNormal != theIsFlatNormal)
1542   {
1543     Message::SendWarning ("Warning: flat shading requires OpenGL ES 3.0+ or GL_OES_standard_derivatives extension");
1544   }
1545   else if (isFlatNormal && myToReverseDFdxSign)
1546   {
1547     Message::SendWarning ("Warning: applied workaround for GLSL flat shading normal computation using dFdx/dFdy on Adreno");
1548   }
1549
1550   Handle(Graphic3d_ShaderProgram) aProgramSrc = new Graphic3d_ShaderProgram();
1551   aProgramSrc->SetPBR (theIsPBR);
1552
1553   TCollection_AsciiString aSrcVert, aSrcVertExtraFunc, aSrcVertExtraMain;
1554   TCollection_AsciiString aSrcFrag, aSrcFragGetVertColor, aSrcFragExtraMain;
1555   TCollection_AsciiString aSrcFragGetColor = TCollection_AsciiString() + EOL"vec4 getColor(void) { return " + aPhongCompLight +  "; }";
1556   Graphic3d_ShaderObject::ShaderVariableList aUniforms, aStageInOuts;
1557   if ((theBits & Graphic3d_ShaderFlags_IsPoint) != 0)
1558   {
1559     if (mySetPointSize)
1560     {
1561       aSrcVertExtraMain += EOL"  gl_PointSize = occPointSize;";
1562     }
1563
1564     if ((theBits & Graphic3d_ShaderFlags_PointSprite) != 0)
1565     {
1566       aUniforms.Append (Graphic3d_ShaderObject::ShaderVariable ("sampler2D occSamplerPointSprite", Graphic3d_TOS_FRAGMENT));
1567       aSrcFragGetColor = pointSpriteShadingSrc (aPhongCompLight, theBits);
1568     }
1569
1570     if ((theBits & Graphic3d_ShaderFlags_TextureRGB) != 0
1571      && (theBits & Graphic3d_ShaderFlags_VertColor) == 0)
1572     {
1573       aProgramSrc->SetTextureSetBits (Graphic3d_TextureSetBits_BaseColor);
1574       aUniforms   .Append (Graphic3d_ShaderObject::ShaderVariable ("sampler2D occSamplerBaseColor", Graphic3d_TOS_VERTEX));
1575       aStageInOuts.Append (Graphic3d_ShaderObject::ShaderVariable ("vec4 VertColor", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
1576
1577       aSrcVertExtraMain   += EOL"  VertColor = occTexture2D (occSamplerBaseColor, occTexCoord.xy);";
1578       aSrcFragGetVertColor = EOL"vec4 getVertColor(void) { return VertColor; }";
1579     }
1580   }
1581   else
1582   {
1583     if ((theBits & Graphic3d_ShaderFlags_TextureRGB) != 0)
1584     {
1585       toUseTexColor = true;
1586       aUniforms   .Append (Graphic3d_ShaderObject::ShaderVariable ("sampler2D occSamplerBaseColor", Graphic3d_TOS_FRAGMENT));
1587       aStageInOuts.Append (Graphic3d_ShaderObject::ShaderVariable ("vec4 TexCoord", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
1588       aSrcVertExtraMain += THE_VARY_TexCoord_Trsf;
1589
1590       Standard_Integer aTextureBits = Graphic3d_TextureSetBits_BaseColor | Graphic3d_TextureSetBits_Occlusion | Graphic3d_TextureSetBits_Emissive;
1591       if (theIsPBR)
1592       {
1593         aTextureBits |= Graphic3d_TextureSetBits_MetallicRoughness;
1594       }
1595       if ((theBits & Graphic3d_ShaderFlags_HasTextures) == Graphic3d_ShaderFlags_TextureNormal
1596        && !isFlatNormal)
1597       {
1598         if (myHasFlatShading)
1599         {
1600           aTextureBits |= Graphic3d_TextureSetBits_Normal;
1601         }
1602         else
1603         {
1604           Message::SendWarning ("Warning: ignoring Normal Map texture in GLSL due to hardware capabilities");
1605         }
1606       }
1607       aProgramSrc->SetTextureSetBits (aTextureBits);
1608     }
1609   }
1610
1611   if ((theBits & Graphic3d_ShaderFlags_VertColor) != 0)
1612   {
1613     aStageInOuts.Append (Graphic3d_ShaderObject::ShaderVariable ("vec4 VertColor", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
1614     aSrcVertExtraMain   += EOL"  VertColor = occVertColor;";
1615     aSrcFragGetVertColor = EOL"vec4 getVertColor(void) { return VertColor; }";
1616   }
1617
1618   int aNbClipPlanes = 0;
1619   if ((theBits & Graphic3d_ShaderFlags_ClipPlanesN) != 0)
1620   {
1621     if ((theBits & Graphic3d_ShaderFlags_ClipPlanesN) == Graphic3d_ShaderFlags_ClipPlanesN)
1622     {
1623       aNbClipPlanes = Graphic3d_ShaderProgram::THE_MAX_CLIP_PLANES_DEFAULT;
1624       aSrcFragExtraMain += (theBits & Graphic3d_ShaderFlags_ClipChains) != 0
1625                          ? THE_FRAG_CLIP_CHAINS_N
1626                          : THE_FRAG_CLIP_PLANES_N;
1627     }
1628     else if ((theBits & Graphic3d_ShaderFlags_ClipPlanes1) != 0)
1629     {
1630       aNbClipPlanes = 1;
1631       aSrcFragExtraMain += THE_FRAG_CLIP_PLANES_1;
1632     }
1633     else if ((theBits & Graphic3d_ShaderFlags_ClipPlanes2) != 0)
1634     {
1635       aNbClipPlanes = 2;
1636       aSrcFragExtraMain += (theBits & Graphic3d_ShaderFlags_ClipChains) != 0
1637                          ? THE_FRAG_CLIP_CHAINS_2
1638                          : THE_FRAG_CLIP_PLANES_2;
1639     }
1640   }
1641   if ((theBits & Graphic3d_ShaderFlags_OitDepthPeeling) != 0)
1642   {
1643     aProgramSrc->SetNbFragmentOutputs (3);
1644     aProgramSrc->SetOitOutput (Graphic3d_RTM_DEPTH_PEELING_OIT);
1645   }
1646   else if ((theBits & Graphic3d_ShaderFlags_WriteOit) != 0)
1647   {
1648     aProgramSrc->SetNbFragmentOutputs (2);
1649     aProgramSrc->SetOitOutput (Graphic3d_RTM_BLEND_OIT);
1650   }
1651
1652   if (isFlatNormal)
1653   {
1654     aSrcFragExtraMain += TCollection_AsciiString()
1655       + EOL"  Normal = " + aDFdxSignReversion + "normalize (cross (dFdx (" + aPosition + ".xyz / " + aPosition + ".w), dFdy (" + aPosition + ".xyz / " + aPosition + ".w)));"
1656         EOL"  if (!gl_FrontFacing) { Normal = -Normal; }";
1657   }
1658   else
1659   {
1660     aStageInOuts.Append(Graphic3d_ShaderObject::ShaderVariable("vec3 vNormal", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
1661     aSrcVertExtraFunc += THE_FUNC_transformNormal_world;
1662     aSrcVertExtraMain += EOL"  vNormal = transformNormal (occNormal);";
1663     aSrcFragExtraMain += EOL"  Normal = vNormal;";
1664
1665     if ((theBits & Graphic3d_ShaderFlags_IsPoint) == 0
1666      && (theBits & Graphic3d_ShaderFlags_HasTextures) == Graphic3d_ShaderFlags_TextureNormal
1667      && myHasFlatShading)
1668     {
1669       aSrcFrag += Shaders_TangentSpaceNormal_glsl;
1670       // apply normal map texture
1671       aSrcFragExtraMain +=
1672         EOL"#if defined(THE_HAS_TEXTURE_NORMAL)"
1673         EOL"  vec2 aTexCoord = TexCoord.st / TexCoord.w;"
1674         EOL"  vec4 aMapNormalValue = occTextureNormal(aTexCoord);"
1675         EOL"  if (aMapNormalValue.w > 0.5)"
1676         EOL"  {"
1677         EOL"    mat2 aDeltaUVMatrix = mat2 (dFdx(aTexCoord), dFdy(aTexCoord));"
1678         EOL"    mat2x3 aDeltaVectorMatrix = mat2x3 (dFdx (PositionWorld.xyz), dFdy (PositionWorld.xyz));"
1679         EOL"    Normal = TangentSpaceNormal (aDeltaUVMatrix, aDeltaVectorMatrix, aMapNormalValue.xyz, Normal, !gl_FrontFacing);"
1680         EOL"  }"
1681         EOL"#endif";
1682     }
1683     if (!theIsPBR)
1684     {
1685       aSrcFragExtraMain +=
1686         EOL"  Normal = normalize ((occWorldViewMatrixInverseTranspose * vec4 (Normal, 0.0)).xyz);";
1687     }
1688   }
1689
1690   aStageInOuts.Append (Graphic3d_ShaderObject::ShaderVariable ("vec4 PositionWorld", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
1691   aStageInOuts.Append (Graphic3d_ShaderObject::ShaderVariable ("vec4 Position",      Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
1692   aStageInOuts.Append (Graphic3d_ShaderObject::ShaderVariable ("vec3 View",          Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
1693   if (theNbShadowMaps > 0)
1694   {
1695     aUniforms.Append (Graphic3d_ShaderObject::ShaderVariable ("mat4      occShadowMapMatrices[THE_NB_SHADOWMAPS]", Graphic3d_TOS_VERTEX));
1696     aUniforms.Append (Graphic3d_ShaderObject::ShaderVariable ("sampler2D occShadowMapSamplers[THE_NB_SHADOWMAPS]", Graphic3d_TOS_FRAGMENT));
1697     aUniforms.Append (Graphic3d_ShaderObject::ShaderVariable ("vec2      occShadowMapSizeBias",                    Graphic3d_TOS_FRAGMENT));
1698
1699     aStageInOuts.Append (Graphic3d_ShaderObject::ShaderVariable ("vec4 PosLightSpace[THE_NB_SHADOWMAPS]", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
1700     aSrcVertExtraMain +=
1701       EOL"  for (int aShadowIter = 0; aShadowIter < THE_NB_SHADOWMAPS; ++aShadowIter)"
1702       EOL"  {"
1703       EOL"    PosLightSpace[aShadowIter] = occShadowMapMatrices[aShadowIter] * PositionWorld;"
1704       EOL"  }";
1705   }
1706
1707   aSrcVert = TCollection_AsciiString()
1708     + aSrcVertExtraFunc
1709     + EOL"void main()"
1710       EOL"{"
1711       EOL"  PositionWorld = occModelWorldMatrix * occVertex;"
1712       EOL"  Position      = occWorldViewMatrix * PositionWorld;"
1713       EOL"  if (occProjectionMatrix[3][3] == 1.0)"
1714       EOL"  {"
1715       EOL"    View = vec3(0.0, 0.0, 1.0);"
1716       EOL"  }"
1717       EOL"  else"
1718       EOL"  {"
1719       EOL"    View = -Position.xyz;"
1720       EOL"  }"
1721     + (theIsPBR ? EOL"  View = (occWorldViewMatrixInverse * vec4(View, 0.0)).xyz;" : "")
1722     + aSrcVertExtraMain
1723     + THE_VERT_gl_Position
1724     + EOL"}";
1725
1726   TCollection_AsciiString aSrcGeom = prepareGeomMainSrc (aUniforms, aStageInOuts, theBits);
1727   aSrcFragGetColor += (theBits & Graphic3d_ShaderFlags_MeshEdges) != 0
1728     ? THE_FRAG_WIREFRAME_COLOR
1729     : EOL"#define getFinalColor getColor";
1730
1731   Standard_Integer aNbLights = 0;
1732   const TCollection_AsciiString aLights = stdComputeLighting (aNbLights, theLights, !aSrcFragGetVertColor.IsEmpty(),
1733                                                               theIsPBR, toUseTexColor, theNbShadowMaps);
1734   aSrcFrag += TCollection_AsciiString()
1735     + EOL
1736     + aSrcFragGetVertColor
1737     + EOL"vec3  Normal;"
1738     + aLights
1739     + aSrcFragGetColor
1740     + EOL
1741       EOL"void main()"
1742       EOL"{"
1743       EOL"  if (occFragEarlyReturn()) { return; }"
1744     + aSrcFragExtraMain
1745     + EOL"  occSetFragColor (getFinalColor());"
1746     + EOL"}";
1747
1748   const TCollection_AsciiString aProgId = TCollection_AsciiString (theIsFlatNormal ? "flat-" : "phong-") + (theIsPBR ? "pbr-" : "")
1749                                         + genLightKey (theLights, theNbShadowMaps > 0) + "-";
1750   defaultGlslVersion (aProgramSrc, aProgId, theBits, isFlatNormal);
1751   aProgramSrc->SetDefaultSampler (false);
1752   aProgramSrc->SetNbLightsMax (aNbLights);
1753   aProgramSrc->SetNbShadowMaps (theNbShadowMaps);
1754   aProgramSrc->SetNbClipPlanesMax (aNbClipPlanes);
1755   aProgramSrc->SetAlphaTest ((theBits & Graphic3d_ShaderFlags_AlphaTest) != 0);
1756
1757   const Standard_Integer aNbGeomInputVerts = !aSrcGeom.IsEmpty() ? 3 : 0;
1758   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (aSrcVert, Graphic3d_TOS_VERTEX,   aUniforms, aStageInOuts, "", "", aNbGeomInputVerts));
1759   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (aSrcGeom, Graphic3d_TOS_GEOMETRY, aUniforms, aStageInOuts, "geomIn", "geomOut", aNbGeomInputVerts));
1760   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (aSrcFrag, Graphic3d_TOS_FRAGMENT, aUniforms, aStageInOuts, "", "", aNbGeomInputVerts));
1761   return aProgramSrc;
1762 }
1763
1764 // =======================================================================
1765 // function : getStdProgramStereo
1766 // purpose  :
1767 // =======================================================================
1768 Handle(Graphic3d_ShaderProgram) Graphic3d_ShaderManager::getStdProgramStereo (Graphic3d_StereoMode theStereoMode) const
1769 {
1770   Handle(Graphic3d_ShaderProgram) aProgramSrc = new Graphic3d_ShaderProgram();
1771   Graphic3d_ShaderObject::ShaderVariableList aUniforms, aStageInOuts;
1772
1773   aStageInOuts.Append (Graphic3d_ShaderObject::ShaderVariable ("vec2 TexCoord", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
1774   TCollection_AsciiString aSrcVert =
1775       EOL"void main()"
1776       EOL"{"
1777       EOL"  TexCoord    = occVertex.zw;"
1778       EOL"  gl_Position = vec4(occVertex.x, occVertex.y, 0.0, 1.0);"
1779       EOL"}";
1780
1781   TCollection_AsciiString aSrcFrag;
1782   aUniforms.Append (Graphic3d_ShaderObject::ShaderVariable ("sampler2D uLeftSampler",  Graphic3d_TOS_FRAGMENT));
1783   aUniforms.Append (Graphic3d_ShaderObject::ShaderVariable ("sampler2D uRightSampler", Graphic3d_TOS_FRAGMENT));
1784   const char* aName = "stereo";
1785   switch (theStereoMode)
1786   {
1787     case Graphic3d_StereoMode_Anaglyph:
1788     {
1789       aName = "anaglyph";
1790       aUniforms.Append (Graphic3d_ShaderObject::ShaderVariable ("mat4 uMultL", Graphic3d_TOS_FRAGMENT));
1791       aUniforms.Append (Graphic3d_ShaderObject::ShaderVariable ("mat4 uMultR", Graphic3d_TOS_FRAGMENT));
1792       const TCollection_AsciiString aNormalize = mySRgbState
1793                                                ? EOL"#define sRgb2linear(theColor) theColor"
1794                                                  EOL"#define linear2sRgb(theColor) theColor"
1795                                                : EOL"#define sRgb2linear(theColor) pow(theColor, vec4(2.2, 2.2, 2.2, 1.0))"
1796                                                  EOL"#define linear2sRgb(theColor) pow(theColor, 1.0 / vec4(2.2, 2.2, 2.2, 1.0))";
1797       aSrcFrag = aNormalize
1798       + EOL"void main()"
1799         EOL"{"
1800         EOL"  vec4 aColorL = occTexture2D (uLeftSampler,  TexCoord);"
1801         EOL"  vec4 aColorR = occTexture2D (uRightSampler, TexCoord);"
1802         EOL"  aColorL = sRgb2linear (aColorL);"
1803         EOL"  aColorR = sRgb2linear (aColorR);"
1804         EOL"  vec4 aColor = uMultR * aColorR + uMultL * aColorL;"
1805         EOL"  occSetFragColor (linear2sRgb (aColor));"
1806         EOL"}";
1807       break;
1808     }
1809     case Graphic3d_StereoMode_RowInterlaced:
1810     {
1811       aName = "row-interlaced";
1812       aSrcFrag =
1813           EOL"void main()"
1814           EOL"{"
1815           EOL"  vec4 aColorL = occTexture2D (uLeftSampler,  TexCoord);"
1816           EOL"  vec4 aColorR = occTexture2D (uRightSampler, TexCoord);"
1817           EOL"  if (int (mod (gl_FragCoord.y - 1023.5, 2.0)) != 1)"
1818           EOL"  {"
1819           EOL"    occSetFragColor (aColorL);"
1820           EOL"  }"
1821           EOL"  else"
1822           EOL"  {"
1823           EOL"    occSetFragColor (aColorR);"
1824           EOL"  }"
1825           EOL"}";
1826       break;
1827     }
1828     case Graphic3d_StereoMode_ColumnInterlaced:
1829     {
1830       aName = "column-interlaced";
1831       aSrcFrag =
1832           EOL"void main()"
1833           EOL"{"
1834           EOL"  vec4 aColorL = occTexture2D (uLeftSampler,  TexCoord);"
1835           EOL"  vec4 aColorR = occTexture2D (uRightSampler, TexCoord);"
1836           EOL"  if (int (mod (gl_FragCoord.x - 1023.5, 2.0)) == 1)"
1837           EOL"  {"
1838           EOL"    occSetFragColor (aColorL);"
1839           EOL"  }"
1840           EOL"  else"
1841           EOL"  {"
1842           EOL"    occSetFragColor (aColorR);"
1843           EOL"  }"
1844           EOL"}";
1845       break;
1846     }
1847     case Graphic3d_StereoMode_ChessBoard:
1848     {
1849       aName = "chessboard";
1850       aSrcFrag =
1851           EOL"void main()"
1852           EOL"{"
1853           EOL"  vec4 aColorL = occTexture2D (uLeftSampler,  TexCoord);"
1854           EOL"  vec4 aColorR = occTexture2D (uRightSampler, TexCoord);"
1855           EOL"  bool isEvenX = int(mod(floor(gl_FragCoord.x - 1023.5), 2.0)) != 1;"
1856           EOL"  bool isEvenY = int(mod(floor(gl_FragCoord.y - 1023.5), 2.0)) == 1;"
1857           EOL"  if ((isEvenX && isEvenY) || (!isEvenX && !isEvenY))"
1858           EOL"  {"
1859           EOL"    occSetFragColor (aColorL);"
1860           EOL"  }"
1861           EOL"  else"
1862           EOL"  {"
1863           EOL"    occSetFragColor (aColorR);"
1864           EOL"  }"
1865           EOL"}";
1866       break;
1867     }
1868     case Graphic3d_StereoMode_SideBySide:
1869     {
1870       aName = "sidebyside";
1871       aSrcFrag =
1872           EOL"void main()"
1873           EOL"{"
1874           EOL"  vec2 aTexCoord = vec2 (TexCoord.x * 2.0, TexCoord.y);"
1875           EOL"  if (TexCoord.x > 0.5)"
1876           EOL"  {"
1877           EOL"    aTexCoord.x -= 1.0;"
1878           EOL"  }"
1879           EOL"  vec4 aColorL = occTexture2D (uLeftSampler,  aTexCoord);"
1880           EOL"  vec4 aColorR = occTexture2D (uRightSampler, aTexCoord);"
1881           EOL"  if (TexCoord.x <= 0.5)"
1882           EOL"  {"
1883           EOL"    occSetFragColor (aColorL);"
1884           EOL"  }"
1885           EOL"  else"
1886           EOL"  {"
1887           EOL"    occSetFragColor (aColorR);"
1888           EOL"  }"
1889           EOL"}";
1890       break;
1891     }
1892     case Graphic3d_StereoMode_OverUnder:
1893     {
1894       aName = "overunder";
1895       aSrcFrag =
1896           EOL"void main()"
1897           EOL"{"
1898           EOL"  vec2 aTexCoord = vec2 (TexCoord.x, TexCoord.y * 2.0);"
1899           EOL"  if (TexCoord.y > 0.5)"
1900           EOL"  {"
1901           EOL"    aTexCoord.y -= 1.0;"
1902           EOL"  }"
1903           EOL"  vec4 aColorL = occTexture2D (uLeftSampler,  aTexCoord);"
1904           EOL"  vec4 aColorR = occTexture2D (uRightSampler, aTexCoord);"
1905           EOL"  if (TexCoord.y <= 0.5)"
1906           EOL"  {"
1907           EOL"    occSetFragColor (aColorL);"
1908           EOL"  }"
1909           EOL"  else"
1910           EOL"  {"
1911           EOL"    occSetFragColor (aColorR);"
1912           EOL"  }"
1913           EOL"}";
1914       break;
1915     }
1916     case Graphic3d_StereoMode_QuadBuffer:
1917     case Graphic3d_StereoMode_SoftPageFlip:
1918     case Graphic3d_StereoMode_OpenVR:
1919     default:
1920     {
1921       aSrcFrag =
1922           EOL"void main()"
1923           EOL"{"
1924           EOL"  vec4 aColorL = occTexture2D (uLeftSampler,  TexCoord);"
1925           EOL"  vec4 aColorR = occTexture2D (uRightSampler, TexCoord);"
1926           EOL"  aColorL.b = 0.0;"
1927           EOL"  aColorL.g = 0.0;"
1928           EOL"  aColorR.r = 0.0;"
1929           EOL"  occSetFragColor (aColorL + aColorR);"
1930           EOL"}";
1931       break;
1932     }
1933   }
1934
1935   defaultGlslVersion (aProgramSrc, aName, 0);
1936   aProgramSrc->SetDefaultSampler (false);
1937   aProgramSrc->SetNbLightsMax (0);
1938   aProgramSrc->SetNbShadowMaps (0);
1939   aProgramSrc->SetNbClipPlanesMax (0);
1940   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (aSrcVert, Graphic3d_TOS_VERTEX,   aUniforms, aStageInOuts));
1941   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (aSrcFrag, Graphic3d_TOS_FRAGMENT, aUniforms, aStageInOuts));
1942   return aProgramSrc;
1943 }
1944
1945 // =======================================================================
1946 // function : getStdProgramBoundBox
1947 // purpose  :
1948 // =======================================================================
1949 Handle(Graphic3d_ShaderProgram) Graphic3d_ShaderManager::getStdProgramBoundBox() const
1950 {
1951   Handle(Graphic3d_ShaderProgram) aProgramSrc = new Graphic3d_ShaderProgram();
1952
1953   Graphic3d_ShaderObject::ShaderVariableList aUniforms, aStageInOuts;
1954   aUniforms.Append (Graphic3d_ShaderObject::ShaderVariable ("vec3 occBBoxCenter", Graphic3d_TOS_VERTEX));
1955   aUniforms.Append (Graphic3d_ShaderObject::ShaderVariable ("vec3 occBBoxSize",   Graphic3d_TOS_VERTEX));
1956
1957   TCollection_AsciiString aSrcVert =
1958     EOL"void main()"
1959     EOL"{"
1960     EOL"  vec4 aCenter = vec4(occVertex.xyz * occBBoxSize + occBBoxCenter, 1.0);"
1961     EOL"  vec4 aPos    = vec4(occVertex.xyz * occBBoxSize + occBBoxCenter, 1.0);"
1962     EOL"  gl_Position = occProjectionMatrix * occWorldViewMatrix * occModelWorldMatrix * aPos;"
1963     EOL"}";
1964
1965   TCollection_AsciiString aSrcFrag =
1966     EOL"void main()"
1967     EOL"{"
1968     EOL"  occSetFragColor (occColor);"
1969     EOL"}";
1970
1971   defaultGlslVersion (aProgramSrc, "bndbox", 0);
1972   aProgramSrc->SetDefaultSampler (false);
1973   aProgramSrc->SetNbLightsMax (0);
1974   aProgramSrc->SetNbShadowMaps (0);
1975   aProgramSrc->SetNbClipPlanesMax (0);
1976   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (aSrcVert, Graphic3d_TOS_VERTEX,   aUniforms, aStageInOuts));
1977   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (aSrcFrag, Graphic3d_TOS_FRAGMENT, aUniforms, aStageInOuts));
1978   return aProgramSrc;
1979 }
1980
1981 // =======================================================================
1982 // function : getPBREnvBakingProgram
1983 // purpose  :
1984 // =======================================================================
1985 Handle(Graphic3d_ShaderProgram) Graphic3d_ShaderManager::getPBREnvBakingProgram (Standard_Integer theIndex) const
1986 {
1987   Standard_ASSERT_RAISE (theIndex >= 0 && theIndex <= 2,"");
1988   Handle(Graphic3d_ShaderProgram) aProgramSrc = new Graphic3d_ShaderProgram();
1989   Graphic3d_ShaderObject::ShaderVariableList aUniforms, aStageInOuts;
1990
1991   TCollection_AsciiString aSrcVert = TCollection_AsciiString()
1992   + THE_FUNC_cubemap_vector_transform
1993   + Shaders_PBREnvBaking_vs;
1994
1995   TCollection_AsciiString aSrcFrag = TCollection_AsciiString()
1996   + THE_FUNC_cubemap_vector_transform
1997   + Shaders_PBRDistribution_glsl
1998   + ((theIndex == 0 || theIndex == 2) ? "\n#define THE_TO_BAKE_DIFFUSE\n" : "\n#define THE_TO_BAKE_SPECULAR\n")
1999   + (theIndex == 2 ? "\n#define THE_TO_PACK_FLOAT\n" : "")
2000   + Shaders_PBREnvBaking_fs;
2001
2002   // constant array definition requires OpenGL 2.1+ or OpenGL ES 3.0+
2003   switch (myGapi)
2004   {
2005     case Aspect_GraphicsLibrary_OpenGL:
2006     {
2007       aProgramSrc->SetHeader ("#version 120");
2008       break;
2009     }
2010     case Aspect_GraphicsLibrary_OpenGLES:
2011     {
2012       if (IsGapiGreaterEqual (3, 0))
2013       {
2014         aProgramSrc->SetHeader ("#version 300 es");
2015       }
2016       else if (myGlslExtensions[Graphic3d_GlslExtension_GL_EXT_shader_texture_lod])
2017       {
2018         aProgramSrc->SetHeader ("#extension GL_EXT_shader_texture_lod : enable\n"
2019                                 "#define textureCubeLod textureCubeLodEXT");
2020       }
2021       else
2022       {
2023         Message::SendWarning ("Warning: incomplete PBR lighting implementation due to missing OpenGL ES 3.0 or GL_EXT_shader_texture_lod support.");
2024       }
2025       break;
2026     }
2027   }
2028
2029   static const char* THE_BAKE_NAMES[3] = { "pbr_env_baking_diffuse", "pbr_env_baking_specular", "pbr_env_baking_difffallback" };
2030   defaultGlslVersion (aProgramSrc, THE_BAKE_NAMES[theIndex], 0);
2031   aProgramSrc->SetDefaultSampler (false);
2032   aProgramSrc->SetNbLightsMax (0);
2033   aProgramSrc->SetNbShadowMaps (0);
2034   aProgramSrc->SetNbClipPlanesMax (0);
2035   aProgramSrc->SetPBR (true);
2036   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (aSrcVert, Graphic3d_TOS_VERTEX,   aUniforms, aStageInOuts));
2037   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (aSrcFrag, Graphic3d_TOS_FRAGMENT, aUniforms, aStageInOuts));
2038   return aProgramSrc;
2039 }
2040
2041 // =======================================================================
2042 // function : getBgCubeMapProgram
2043 // purpose  :
2044 // =======================================================================
2045 Handle(Graphic3d_ShaderProgram) Graphic3d_ShaderManager::getBgCubeMapProgram() const
2046 {
2047   Handle(Graphic3d_ShaderProgram) aProgSrc = new Graphic3d_ShaderProgram();
2048
2049   Graphic3d_ShaderObject::ShaderVariableList aUniforms, aStageInOuts;
2050   aStageInOuts.Append (Graphic3d_ShaderObject::ShaderVariable("vec3 ViewDirection", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
2051   aUniforms.Append (Graphic3d_ShaderObject::ShaderVariable ("samplerCube occSampler0", Graphic3d_TOS_FRAGMENT));
2052   aUniforms.Append (Graphic3d_ShaderObject::ShaderVariable ("int uYCoeff", Graphic3d_TOS_VERTEX));
2053   aUniforms.Append (Graphic3d_ShaderObject::ShaderVariable ("int uZCoeff", Graphic3d_TOS_VERTEX));
2054
2055   TCollection_AsciiString aSrcVert = TCollection_AsciiString()
2056   + THE_FUNC_cubemap_vector_transform
2057   + EOL"void main()"
2058     EOL"{"
2059     EOL"  ViewDirection = cubemapVectorTransform (occVertex.xyz, uYCoeff, uZCoeff);"
2060     EOL"  vec4 aPos = occProjectionMatrix * occWorldViewMatrix * vec4(occVertex.xyz, 1.0);"
2061     // setting Z to W ensures that final Z will be 1.0 after perspective division, (w/w=1))
2062     // which allows rendering skybox after everything else with depth test enabled (GL_LEQUAL)
2063     EOL"  gl_Position = aPos.xyww;"
2064     EOL"}";
2065
2066   TCollection_AsciiString aDepthClamp;
2067   if (myToEmulateDepthClamp)
2068   {
2069     // workaround Z clamping issues on some GPUs
2070     aDepthClamp = EOL"  gl_FragDepth = clamp (gl_FragDepth, 0.0, 1.0);";
2071     if (myGapi == Aspect_GraphicsLibrary_OpenGLES)
2072     {
2073       if (IsGapiGreaterEqual (3, 0))
2074       {
2075         aProgSrc->SetHeader ("#version 300 es");
2076       }
2077       else if (myGlslExtensions[Graphic3d_GlslExtension_GL_EXT_frag_depth])
2078       {
2079         aProgSrc->SetHeader ("#extension GL_EXT_frag_depth : enable"
2080                           EOL"#define gl_FragDepth gl_FragDepthEXT");
2081       }
2082       else
2083       {
2084         aDepthClamp.Clear();
2085       }
2086     }
2087   }
2088
2089   TCollection_AsciiString aSrcFrag = TCollection_AsciiString()
2090   + EOL"#define occEnvCubemap occSampler0"
2091     EOL"void main()"
2092     EOL"{"
2093     EOL"  occSetFragColor (vec4(occTextureCube (occEnvCubemap, ViewDirection).rgb, 1.0));"
2094   + aDepthClamp
2095   + EOL"}";
2096
2097   defaultGlslVersion (aProgSrc, "background_cubemap", 0);
2098   aProgSrc->SetDefaultSampler (false);
2099   aProgSrc->SetNbLightsMax (0);
2100   aProgSrc->SetNbShadowMaps (0);
2101   aProgSrc->SetNbClipPlanesMax (0);
2102   aProgSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (aSrcVert, Graphic3d_TOS_VERTEX,   aUniforms, aStageInOuts));
2103   aProgSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (aSrcFrag, Graphic3d_TOS_FRAGMENT, aUniforms, aStageInOuts));
2104   return aProgSrc;
2105 }