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