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