0030571: Visualization, TKOpenGl - mapped texture is ignored while drawing points
[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  : Pushes state of OCCT light sources to the program
633 // =======================================================================
634 void OpenGl_ShaderManager::PushLightSourceState (const Handle(OpenGl_ShaderProgram)& theProgram) const
635 {
636   if (myLightSourceState.Index() == theProgram->ActiveState (OpenGl_LIGHT_SOURCES_STATE))
637   {
638     return;
639   }
640
641   theProgram->UpdateState (OpenGl_LIGHT_SOURCES_STATE, myLightSourceState.Index());
642   if (theProgram == myFfpProgram)
643   {
644   #if !defined(GL_ES_VERSION_2_0)
645     if (myContext->core11 == NULL)
646     {
647       return;
648     }
649
650     GLenum aLightGlId = GL_LIGHT0;
651     const OpenGl_Mat4 aModelView = myWorldViewState.WorldViewMatrix() * myModelWorldState.ModelWorldMatrix();
652     for (Graphic3d_LightSet::Iterator aLightIt (myLightSourceState.LightSources(), Graphic3d_LightSet::IterationFilter_ExcludeDisabledAndAmbient);
653          aLightIt.More(); aLightIt.Next())
654     {
655       if (aLightGlId > GL_LIGHT7) // only 8 lights in FFP...
656       {
657         myContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_MEDIUM,
658                                 "Warning: light sources limit (8) has been exceeded within Fixed-function pipeline.");
659         continue;
660       }
661
662       bindLight (*aLightIt.Value(), aLightGlId, aModelView, myContext);
663       ++aLightGlId;
664     }
665
666     // apply accumulated ambient color
667     const Graphic3d_Vec4 anAmbient = !myLightSourceState.LightSources().IsNull()
668                                     ? myLightSourceState.LightSources()->AmbientColor()
669                                     : Graphic3d_Vec4 (0.0f, 0.0f, 0.0f, 1.0f);
670     myContext->core11->glLightModelfv (GL_LIGHT_MODEL_AMBIENT, anAmbient.GetData());
671
672     // GL_LIGHTING is managed by drawers to switch between shaded / no lighting output,
673     // therefore managing the state here does not have any effect - do it just for consistency.
674     if (aLightGlId != GL_LIGHT0)
675     {
676       ::glEnable (GL_LIGHTING);
677     }
678     else
679     {
680       ::glDisable (GL_LIGHTING);
681     }
682     // switch off unused lights
683     for (; aLightGlId <= GL_LIGHT7; ++aLightGlId)
684     {
685       ::glDisable (aLightGlId);
686     }
687   #endif
688     return;
689   }
690
691   const Standard_Integer aNbLightsMax = theProgram->NbLightsMax();
692   const GLint anAmbientLoc = theProgram->GetStateLocation (OpenGl_OCC_LIGHT_AMBIENT);
693   if (aNbLightsMax == 0
694    && anAmbientLoc == OpenGl_ShaderProgram::INVALID_LOCATION)
695   {
696     return;
697   }
698
699   if (myLightTypeArray.Size() < aNbLightsMax)
700   {
701     myLightTypeArray  .Resize (0, aNbLightsMax - 1, false);
702     myLightParamsArray.Resize (0, aNbLightsMax - 1, false);
703   }
704   for (Standard_Integer aLightIt = 0; aLightIt < aNbLightsMax; ++aLightIt)
705   {
706     myLightTypeArray.ChangeValue (aLightIt).Type = -1;
707   }
708
709   if (myLightSourceState.LightSources().IsNull()
710    || myLightSourceState.LightSources()->IsEmpty())
711   {
712     theProgram->SetUniform (myContext,
713                             theProgram->GetStateLocation (OpenGl_OCC_LIGHT_SOURCE_COUNT),
714                             0);
715     theProgram->SetUniform (myContext,
716                             anAmbientLoc,
717                             OpenGl_Vec4 (0.0f, 0.0f, 0.0f, 0.0f));
718     theProgram->SetUniform (myContext,
719                             theProgram->GetStateLocation (OpenGl_OCC_LIGHT_SOURCE_TYPES),
720                             aNbLightsMax * OpenGl_ShaderLightType::NbOfVec2i(),
721                             myLightTypeArray.First().Packed());
722     return;
723   }
724
725   Standard_Integer aLightsNb = 0;
726   for (Graphic3d_LightSet::Iterator anIter (myLightSourceState.LightSources(), Graphic3d_LightSet::IterationFilter_ExcludeDisabledAndAmbient);
727        anIter.More(); anIter.Next())
728   {
729     const Graphic3d_CLight& aLight = *anIter.Value();
730     if (aLightsNb >= aNbLightsMax)
731     {
732       if (aNbLightsMax != 0)
733       {
734         myContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_MEDIUM,
735                                 TCollection_AsciiString("Warning: light sources limit (") + aNbLightsMax + ") has been exceeded.");
736       }
737       continue;
738     }
739
740     OpenGl_ShaderLightType&       aLightType   = myLightTypeArray.ChangeValue (aLightsNb);
741     OpenGl_ShaderLightParameters& aLightParams = myLightParamsArray.ChangeValue (aLightsNb);
742     if (!aLight.IsEnabled()) // has no affect with Graphic3d_LightSet::IterationFilter_ExcludeDisabled - here just for consistency
743     {
744       // 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
745       aLightType.Type        = -1; // Graphic3d_TOLS_AMBIENT can be used instead
746       aLightType.IsHeadlight = false;
747       aLightParams.Color     = OpenGl_Vec4 (0.0f, 0.0f, 0.0f, 0.0f);
748       ++aLightsNb;
749       continue;
750     }
751
752     aLightType.Type        = aLight.Type();
753     aLightType.IsHeadlight = aLight.IsHeadlight();
754     aLightParams.Color     = aLight.PackedColor();
755     if (aLight.Type() == Graphic3d_TOLS_DIRECTIONAL)
756     {
757       aLightParams.Position = -aLight.PackedDirection();
758     }
759     else if (!aLight.IsHeadlight())
760     {
761       aLightParams.Position.x() = static_cast<float>(aLight.Position().X() - myLocalOrigin.X());
762       aLightParams.Position.y() = static_cast<float>(aLight.Position().Y() - myLocalOrigin.Y());
763       aLightParams.Position.z() = static_cast<float>(aLight.Position().Z() - myLocalOrigin.Z());
764       aLightParams.Position.w() = 1.0f;
765     }
766     else
767     {
768       aLightParams.Position.x() = static_cast<float>(aLight.Position().X());
769       aLightParams.Position.y() = static_cast<float>(aLight.Position().Y());
770       aLightParams.Position.z() = static_cast<float>(aLight.Position().Z());
771       aLightParams.Position.w() = 1.0f;
772     }
773
774     if (aLight.Type() == Graphic3d_TOLS_SPOT)
775     {
776       aLightParams.Direction = aLight.PackedDirection();
777     }
778     aLightParams.Parameters = aLight.PackedParams();
779     ++aLightsNb;
780   }
781
782   const Graphic3d_Vec4& anAmbient = myLightSourceState.LightSources()->AmbientColor();
783   theProgram->SetUniform (myContext,
784                           theProgram->GetStateLocation (OpenGl_OCC_LIGHT_SOURCE_COUNT),
785                           aLightsNb);
786   theProgram->SetUniform (myContext,
787                           anAmbientLoc,
788                           anAmbient);
789   theProgram->SetUniform (myContext,
790                           theProgram->GetStateLocation (OpenGl_OCC_LIGHT_SOURCE_TYPES),
791                           aNbLightsMax * OpenGl_ShaderLightType::NbOfVec2i(),
792                           myLightTypeArray.First().Packed());
793   if (aLightsNb > 0)
794   {
795     theProgram->SetUniform (myContext,
796                             theProgram->GetStateLocation (OpenGl_OCC_LIGHT_SOURCE_PARAMS),
797                             aLightsNb * OpenGl_ShaderLightParameters::NbOfVec4(),
798                             myLightParamsArray.First().Packed());
799   }
800 }
801
802 // =======================================================================
803 // function : PushProjectionState
804 // purpose  : Pushes state of OCCT projection transform to the program
805 // =======================================================================
806 void OpenGl_ShaderManager::PushProjectionState (const Handle(OpenGl_ShaderProgram)& theProgram) const
807 {
808   if (myProjectionState.Index() == theProgram->ActiveState (OpenGl_PROJECTION_STATE))
809   {
810     return;
811   }
812
813   theProgram->UpdateState (OpenGl_PROJECTION_STATE, myProjectionState.Index());
814   if (theProgram == myFfpProgram)
815   {
816   #if !defined(GL_ES_VERSION_2_0)
817     if (myContext->core11 != NULL)
818     {
819       myContext->core11->glMatrixMode (GL_PROJECTION);
820       myContext->core11->glLoadMatrixf (myProjectionState.ProjectionMatrix());
821     }
822   #endif
823     return;
824   }
825
826   theProgram->SetUniform (myContext,
827                           theProgram->GetStateLocation (OpenGl_OCC_PROJECTION_MATRIX),
828                           myProjectionState.ProjectionMatrix());
829
830   GLint aLocation = theProgram->GetStateLocation (OpenGl_OCC_PROJECTION_MATRIX_INVERSE);
831   if (aLocation != OpenGl_ShaderProgram::INVALID_LOCATION)
832   {
833     theProgram->SetUniform (myContext, aLocation, myProjectionState.ProjectionMatrixInverse());
834   }
835
836   theProgram->SetUniform (myContext,
837                           theProgram->GetStateLocation (OpenGl_OCC_PROJECTION_MATRIX_TRANSPOSE),
838                           myProjectionState.ProjectionMatrix(), true);
839
840   aLocation = theProgram->GetStateLocation (OpenGl_OCC_PROJECTION_MATRIX_INVERSE_TRANSPOSE);
841   if (aLocation != OpenGl_ShaderProgram::INVALID_LOCATION)
842   {
843     theProgram->SetUniform (myContext, aLocation, myProjectionState.ProjectionMatrixInverse(), true);
844   }
845 }
846
847 // =======================================================================
848 // function : PushModelWorldState
849 // purpose  : Pushes state of OCCT model-world transform to the program
850 // =======================================================================
851 void OpenGl_ShaderManager::PushModelWorldState (const Handle(OpenGl_ShaderProgram)& theProgram) const
852 {
853   if (myModelWorldState.Index() == theProgram->ActiveState (OpenGl_MODEL_WORLD_STATE))
854   {
855     return;
856   }
857
858   theProgram->UpdateState (OpenGl_MODEL_WORLD_STATE, myModelWorldState.Index());
859   if (theProgram == myFfpProgram)
860   {
861   #if !defined(GL_ES_VERSION_2_0)
862     if (myContext->core11 != NULL)
863     {
864       const OpenGl_Mat4 aModelView = myWorldViewState.WorldViewMatrix() * myModelWorldState.ModelWorldMatrix();
865       myContext->core11->glMatrixMode (GL_MODELVIEW);
866       myContext->core11->glLoadMatrixf (aModelView.GetData());
867       theProgram->UpdateState (OpenGl_WORLD_VIEW_STATE, myWorldViewState.Index());
868     }
869   #endif
870     return;
871   }
872
873   theProgram->SetUniform (myContext,
874                           theProgram->GetStateLocation (OpenGl_OCC_MODEL_WORLD_MATRIX),
875                           myModelWorldState.ModelWorldMatrix());
876
877   GLint aLocation = theProgram->GetStateLocation (OpenGl_OCC_MODEL_WORLD_MATRIX_INVERSE);
878   if (aLocation != OpenGl_ShaderProgram::INVALID_LOCATION)
879   {
880     theProgram->SetUniform (myContext, aLocation, myModelWorldState.ModelWorldMatrixInverse());
881   }
882
883   theProgram->SetUniform (myContext,
884                           theProgram->GetStateLocation (OpenGl_OCC_MODEL_WORLD_MATRIX_TRANSPOSE),
885                           myModelWorldState.ModelWorldMatrix(), true);
886
887   aLocation = theProgram->GetStateLocation (OpenGl_OCC_MODEL_WORLD_MATRIX_INVERSE_TRANSPOSE);
888   if (aLocation != OpenGl_ShaderProgram::INVALID_LOCATION)
889   {
890     theProgram->SetUniform (myContext, aLocation, myModelWorldState.ModelWorldMatrixInverse(), true);
891   }
892 }
893
894 // =======================================================================
895 // function : PushWorldViewState
896 // purpose  : Pushes state of OCCT world-view transform to the program
897 // =======================================================================
898 void OpenGl_ShaderManager::PushWorldViewState (const Handle(OpenGl_ShaderProgram)& theProgram) const
899 {
900   if (myWorldViewState.Index() == theProgram->ActiveState (OpenGl_WORLD_VIEW_STATE))
901   {
902     return;
903   }
904
905   theProgram->UpdateState (OpenGl_WORLD_VIEW_STATE, myWorldViewState.Index());
906   if (theProgram == myFfpProgram)
907   {
908   #if !defined(GL_ES_VERSION_2_0)
909     if (myContext->core11 != NULL)
910     {
911       const OpenGl_Mat4 aModelView = myWorldViewState.WorldViewMatrix() * myModelWorldState.ModelWorldMatrix();
912       myContext->core11->glMatrixMode (GL_MODELVIEW);
913       myContext->core11->glLoadMatrixf (aModelView.GetData());
914       theProgram->UpdateState (OpenGl_MODEL_WORLD_STATE, myModelWorldState.Index());
915     }
916   #endif
917     return;
918   }
919
920   theProgram->SetUniform (myContext,
921                           theProgram->GetStateLocation (OpenGl_OCC_WORLD_VIEW_MATRIX),
922                           myWorldViewState.WorldViewMatrix());
923
924   GLint aLocation = theProgram->GetStateLocation (OpenGl_OCC_WORLD_VIEW_MATRIX_INVERSE);
925   if (aLocation != OpenGl_ShaderProgram::INVALID_LOCATION)
926   {
927     theProgram->SetUniform (myContext, aLocation, myWorldViewState.WorldViewMatrixInverse());
928   }
929
930   theProgram->SetUniform (myContext,
931                           theProgram->GetStateLocation (OpenGl_OCC_WORLD_VIEW_MATRIX_TRANSPOSE),
932                           myWorldViewState.WorldViewMatrix(), true);
933
934   aLocation = theProgram->GetStateLocation (OpenGl_OCC_WORLD_VIEW_MATRIX_INVERSE_TRANSPOSE);
935   if (aLocation != OpenGl_ShaderProgram::INVALID_LOCATION)
936   {
937     theProgram->SetUniform (myContext, aLocation, myWorldViewState.WorldViewMatrixInverse(), true);
938   }
939 }
940
941 // =======================================================================
942 // function : UpdateClippingState
943 // purpose  : Updates state of OCCT clipping planes
944 // =======================================================================
945 void OpenGl_ShaderManager::UpdateClippingState()
946 {
947   myClippingState.Update();
948 }
949
950 // =======================================================================
951 // function : RevertClippingState
952 // purpose  : Reverts state of OCCT clipping planes
953 // =======================================================================
954 void OpenGl_ShaderManager::RevertClippingState()
955 {
956   myClippingState.Revert();
957 }
958
959 // =======================================================================
960 // function : PushClippingState
961 // purpose  : Pushes state of OCCT clipping planes to the program
962 // =======================================================================
963 void OpenGl_ShaderManager::PushClippingState (const Handle(OpenGl_ShaderProgram)& theProgram) const
964 {
965   if (myClippingState.Index() == theProgram->ActiveState (OpenGl_CLIP_PLANES_STATE))
966   {
967     return;
968   }
969
970   theProgram->UpdateState (OpenGl_CLIP_PLANES_STATE, myClippingState.Index());
971   if (theProgram == myFfpProgram)
972   {
973   #if !defined(GL_ES_VERSION_2_0)
974     if (myContext->core11 == NULL)
975     {
976       return;
977     }
978
979     const Standard_Integer aNbMaxPlanes = myContext->MaxClipPlanes();
980     if (myClipPlaneArrayFfp.Size() < aNbMaxPlanes)
981     {
982       myClipPlaneArrayFfp.Resize (0, aNbMaxPlanes - 1, false);
983     }
984
985     Standard_Integer aPlaneId = 0;
986     Standard_Boolean toRestoreModelView = Standard_False;
987     const Handle(Graphic3d_ClipPlane)& aCappedChain = myContext->Clipping().CappedChain();
988     for (OpenGl_ClippingIterator aPlaneIter (myContext->Clipping()); aPlaneIter.More(); aPlaneIter.Next())
989     {
990       const Handle(Graphic3d_ClipPlane)& aPlane = aPlaneIter.Value();
991       if (aPlaneIter.IsDisabled()
992        || aPlane->IsChain()
993        || (aPlane == aCappedChain
994         && myContext->Clipping().IsCappingEnableAllExcept()))
995       {
996         continue;
997       }
998       else if (aPlaneId >= aNbMaxPlanes)
999       {
1000         myContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_MEDIUM,
1001                                 TCollection_ExtendedString("Warning: clipping planes limit (") + aNbMaxPlanes + ") has been exceeded.");
1002         break;
1003       }
1004
1005       const Graphic3d_ClipPlane::Equation& anEquation = aPlane->GetEquation();
1006       OpenGl_Vec4d& aPlaneEq = myClipPlaneArrayFfp.ChangeValue (aPlaneId);
1007       aPlaneEq.x() = anEquation.x();
1008       aPlaneEq.y() = anEquation.y();
1009       aPlaneEq.z() = anEquation.z();
1010       aPlaneEq.w() = anEquation.w();
1011       if (myHasLocalOrigin)
1012       {
1013         const gp_XYZ        aPos = aPlane->ToPlane().Position().Location().XYZ() - myLocalOrigin;
1014         const Standard_Real aD   = -(anEquation.x() * aPos.X() + anEquation.y() * aPos.Y() + anEquation.z() * aPos.Z());
1015         aPlaneEq.w() = aD;
1016       }
1017
1018       const GLenum anFfpPlaneID = GL_CLIP_PLANE0 + aPlaneId;
1019       if (anFfpPlaneID == GL_CLIP_PLANE0)
1020       {
1021         // set either identity or pure view matrix
1022         toRestoreModelView = Standard_True;
1023         myContext->core11->glMatrixMode (GL_MODELVIEW);
1024         myContext->core11->glLoadMatrixf (myWorldViewState.WorldViewMatrix().GetData());
1025       }
1026
1027       ::glEnable (anFfpPlaneID);
1028       myContext->core11->glClipPlane (anFfpPlaneID, aPlaneEq);
1029
1030       ++aPlaneId;
1031     }
1032
1033     // switch off unused lights
1034     for (; aPlaneId < aNbMaxPlanes; ++aPlaneId)
1035     {
1036       ::glDisable (GL_CLIP_PLANE0 + aPlaneId);
1037     }
1038
1039     // restore combined model-view matrix
1040     if (toRestoreModelView)
1041     {
1042       const OpenGl_Mat4 aModelView = myWorldViewState.WorldViewMatrix() * myModelWorldState.ModelWorldMatrix();
1043       myContext->core11->glLoadMatrixf (aModelView.GetData());
1044     }
1045   #endif
1046     return;
1047   }
1048
1049   const GLint aLocEquations = theProgram->GetStateLocation (OpenGl_OCC_CLIP_PLANE_EQUATIONS);
1050   if (aLocEquations == OpenGl_ShaderProgram::INVALID_LOCATION)
1051   {
1052     return;
1053   }
1054
1055   const Standard_Integer aNbClipPlanesMax = theProgram->NbClipPlanesMax();
1056   const Standard_Integer aNbPlanes = Min (myContext->Clipping().NbClippingOrCappingOn(), aNbClipPlanesMax);
1057   if (aNbPlanes < 1)
1058   {
1059     theProgram->SetUniform (myContext, theProgram->GetStateLocation (OpenGl_OCC_CLIP_PLANE_COUNT), 0);
1060     return;
1061   }
1062
1063   if (myClipPlaneArray.Size() < aNbClipPlanesMax)
1064   {
1065     myClipPlaneArray.Resize (0, aNbClipPlanesMax - 1, false);
1066     myClipChainArray.Resize (0, aNbClipPlanesMax - 1, false);
1067   }
1068
1069   Standard_Integer aPlaneId = 0;
1070   const Handle(Graphic3d_ClipPlane)& aCappedChain = myContext->Clipping().CappedChain();
1071   for (OpenGl_ClippingIterator aPlaneIter (myContext->Clipping()); aPlaneIter.More(); aPlaneIter.Next())
1072   {
1073     const Handle(Graphic3d_ClipPlane)& aPlane = aPlaneIter.Value();
1074     if (aPlaneIter.IsDisabled())
1075     {
1076       continue;
1077     }
1078
1079     if (myContext->Clipping().IsCappingDisableAllExcept())
1080     {
1081       // enable only specific (sub) plane
1082       if (aPlane != aCappedChain)
1083       {
1084         continue;
1085       }
1086
1087       Standard_Integer aSubPlaneIndex = 1;
1088       for (const Graphic3d_ClipPlane* aSubPlaneIter = aCappedChain.get(); aSubPlaneIter != NULL; aSubPlaneIter = aSubPlaneIter->ChainNextPlane().get(), ++aSubPlaneIndex)
1089       {
1090         if (aSubPlaneIndex == myContext->Clipping().CappedSubPlane())
1091         {
1092           addClippingPlane (aPlaneId, *aSubPlaneIter, aSubPlaneIter->GetEquation(), 1);
1093           break;
1094         }
1095       }
1096       break;
1097     }
1098     else if (aPlane == aCappedChain) // && myContext->Clipping().IsCappingEnableAllExcept()
1099     {
1100       // enable sub-planes within processed Chain as reversed and ORed, excluding filtered plane
1101       if (aPlaneId + aPlane->NbChainNextPlanes() - 1 > aNbClipPlanesMax)
1102       {
1103         myContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_HIGH,
1104                                 TCollection_AsciiString("Error: clipping planes limit (") + aNbClipPlanesMax + ") has been exceeded.");
1105         break;
1106       }
1107
1108       Standard_Integer aSubPlaneIndex = 1;
1109       for (const Graphic3d_ClipPlane* aSubPlaneIter = aPlane.get(); aSubPlaneIter != NULL; aSubPlaneIter = aSubPlaneIter->ChainNextPlane().get(), ++aSubPlaneIndex)
1110       {
1111         if (aSubPlaneIndex != -myContext->Clipping().CappedSubPlane())
1112         {
1113           addClippingPlane (aPlaneId, *aSubPlaneIter, aSubPlaneIter->ReversedEquation(), 1);
1114         }
1115       }
1116     }
1117     else
1118     {
1119       // normal case
1120       if (aPlaneId + aPlane->NbChainNextPlanes() > aNbClipPlanesMax)
1121       {
1122         myContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_HIGH,
1123                                 TCollection_AsciiString("Error: clipping planes limit (") + aNbClipPlanesMax + ") has been exceeded.");
1124         break;
1125       }
1126       for (const Graphic3d_ClipPlane* aSubPlaneIter = aPlane.get(); aSubPlaneIter != NULL; aSubPlaneIter = aSubPlaneIter->ChainNextPlane().get())
1127       {
1128         addClippingPlane (aPlaneId, *aSubPlaneIter, aSubPlaneIter->GetEquation(), aSubPlaneIter->NbChainNextPlanes());
1129       }
1130     }
1131   }
1132
1133   theProgram->SetUniform (myContext, theProgram->GetStateLocation (OpenGl_OCC_CLIP_PLANE_COUNT), aPlaneId);
1134   theProgram->SetUniform (myContext, aLocEquations, aNbClipPlanesMax, &myClipPlaneArray.First());
1135   theProgram->SetUniform (myContext, theProgram->GetStateLocation (OpenGl_OCC_CLIP_PLANE_CHAINS), aNbClipPlanesMax, &myClipChainArray.First());
1136 }
1137
1138 // =======================================================================
1139 // function : PushMaterialState
1140 // purpose  :
1141 // =======================================================================
1142 void OpenGl_ShaderManager::PushMaterialState (const Handle(OpenGl_ShaderProgram)& theProgram) const
1143 {
1144   if (myMaterialState.Index() == theProgram->ActiveState (OpenGl_MATERIAL_STATE))
1145   {
1146     return;
1147   }
1148
1149   const OpenGl_Material& aFrontMat = myMaterialState.FrontMaterial();
1150   const OpenGl_Material& aBackMat  = myMaterialState.BackMaterial();
1151   theProgram->UpdateState (OpenGl_MATERIAL_STATE, myMaterialState.Index());
1152   if (theProgram == myFfpProgram)
1153   {
1154   #if !defined(GL_ES_VERSION_2_0)
1155     if (myContext->core11 == NULL)
1156     {
1157       return;
1158     }
1159
1160     if (myMaterialState.AlphaCutoff() < ShortRealLast())
1161     {
1162       glAlphaFunc (GL_GEQUAL, myMaterialState.AlphaCutoff());
1163       glEnable (GL_ALPHA_TEST);
1164     }
1165     else
1166     {
1167       glDisable (GL_ALPHA_TEST);
1168     }
1169
1170     const GLenum aFrontFace = myMaterialState.ToDistinguish() ? GL_FRONT : GL_FRONT_AND_BACK;
1171     myContext->core11->glMaterialfv(aFrontFace, GL_AMBIENT,   aFrontMat.Ambient.GetData());
1172     myContext->core11->glMaterialfv(aFrontFace, GL_DIFFUSE,   aFrontMat.Diffuse.GetData());
1173     myContext->core11->glMaterialfv(aFrontFace, GL_SPECULAR,  aFrontMat.Specular.GetData());
1174     myContext->core11->glMaterialfv(aFrontFace, GL_EMISSION,  aFrontMat.Emission.GetData());
1175     myContext->core11->glMaterialf (aFrontFace, GL_SHININESS, aFrontMat.Shine());
1176     if (myMaterialState.ToDistinguish())
1177     {
1178       myContext->core11->glMaterialfv(GL_BACK, GL_AMBIENT,   aBackMat.Ambient.GetData());
1179       myContext->core11->glMaterialfv(GL_BACK, GL_DIFFUSE,   aBackMat.Diffuse.GetData());
1180       myContext->core11->glMaterialfv(GL_BACK, GL_SPECULAR,  aBackMat.Specular.GetData());
1181       myContext->core11->glMaterialfv(GL_BACK, GL_EMISSION,  aBackMat.Emission.GetData());
1182       myContext->core11->glMaterialf (GL_BACK, GL_SHININESS, aBackMat.Shine());
1183     }
1184   #endif
1185     return;
1186   }
1187
1188   theProgram->SetUniform (myContext,
1189                           theProgram->GetStateLocation (OpenGl_OCCT_ALPHA_CUTOFF),
1190                           myMaterialState.AlphaCutoff());
1191   theProgram->SetUniform (myContext,
1192                           theProgram->GetStateLocation (OpenGl_OCCT_TEXTURE_ENABLE),
1193                           myMaterialState.ToMapTexture()  ? 1 : 0);
1194   theProgram->SetUniform (myContext,
1195                           theProgram->GetStateLocation (OpenGl_OCCT_DISTINGUISH_MODE),
1196                           myMaterialState.ToDistinguish() ? 1 : 0);
1197
1198   if (const OpenGl_ShaderUniformLocation aLocFront = theProgram->GetStateLocation (OpenGl_OCCT_FRONT_MATERIAL))
1199   {
1200     theProgram->SetUniform (myContext, aLocFront, OpenGl_Material::NbOfVec4(),
1201                             aFrontMat.Packed());
1202   }
1203   if (const OpenGl_ShaderUniformLocation aLocBack = theProgram->GetStateLocation (OpenGl_OCCT_BACK_MATERIAL))
1204   {
1205     theProgram->SetUniform (myContext, aLocBack,  OpenGl_Material::NbOfVec4(),
1206                             aBackMat.Packed());
1207   }
1208 }
1209
1210 // =======================================================================
1211 // function : PushOitState
1212 // purpose  : Pushes state of OIT uniforms to the specified program
1213 // =======================================================================
1214 void OpenGl_ShaderManager::PushOitState (const Handle(OpenGl_ShaderProgram)& theProgram) const
1215 {
1216   if (!theProgram->IsValid())
1217   {
1218     return;
1219   }
1220
1221   if (myOitState.Index() == theProgram->ActiveState (OpenGL_OIT_STATE))
1222   {
1223     return;
1224   }
1225
1226   const GLint aLocOutput = theProgram->GetStateLocation (OpenGl_OCCT_OIT_OUTPUT);
1227   if (aLocOutput != OpenGl_ShaderProgram::INVALID_LOCATION)
1228   {
1229     theProgram->SetUniform (myContext, aLocOutput, myOitState.ToEnableWrite());
1230   }
1231
1232   const GLint aLocDepthFactor = theProgram->GetStateLocation (OpenGl_OCCT_OIT_DEPTH_FACTOR);
1233   if (aLocDepthFactor != OpenGl_ShaderProgram::INVALID_LOCATION)
1234   {
1235     theProgram->SetUniform (myContext, aLocDepthFactor, myOitState.DepthFactor());
1236   }
1237 }
1238
1239 // =======================================================================
1240 // function : PushInteriorState
1241 // purpose  :
1242 // =======================================================================
1243 void OpenGl_ShaderManager::PushInteriorState (const Handle(OpenGl_ShaderProgram)& theProgram,
1244                                               const Handle(Graphic3d_Aspects)& theAspect) const
1245 {
1246   if (theProgram.IsNull()
1247   || !theProgram->IsValid())
1248   {
1249     return;
1250   }
1251
1252   if (const OpenGl_ShaderUniformLocation aLocViewPort = theProgram->GetStateLocation (OpenGl_OCCT_VIEWPORT))
1253   {
1254     theProgram->SetUniform (myContext, aLocViewPort, OpenGl_Vec4 ((float )myContext->Viewport()[0], (float )myContext->Viewport()[1], (float )myContext->Viewport()[2], (float )myContext->Viewport()[3]));
1255   }
1256   if (const OpenGl_ShaderUniformLocation aLocLineWidth = theProgram->GetStateLocation (OpenGl_OCCT_LINE_WIDTH))
1257   {
1258     theProgram->SetUniform (myContext, aLocLineWidth, theAspect->EdgeWidth() * myContext->LineWidthScale());
1259     theProgram->SetUniform (myContext, theProgram->GetStateLocation (OpenGl_OCCT_LINE_FEATHER), myContext->LineFeather() * myContext->LineWidthScale());
1260   }
1261   if (const OpenGl_ShaderUniformLocation aLocWireframeColor = theProgram->GetStateLocation (OpenGl_OCCT_WIREFRAME_COLOR))
1262   {
1263     if (theAspect->InteriorStyle() == Aspect_IS_HOLLOW)
1264     {
1265       theProgram->SetUniform (myContext, aLocWireframeColor, OpenGl_Vec4 (-1.0f, -1.0f, -1.0f, -1.0f));
1266     }
1267     else
1268     {
1269       theProgram->SetUniform (myContext, aLocWireframeColor, theAspect->EdgeColorRGBA());
1270     }
1271   }
1272   if (const OpenGl_ShaderUniformLocation aLocQuadModeState = theProgram->GetStateLocation (OpenGl_OCCT_QUAD_MODE_STATE))
1273   {
1274     theProgram->SetUniform (myContext, aLocQuadModeState, theAspect->ToSkipFirstEdge() ? 1 : 0);
1275   }
1276 }
1277
1278 // =======================================================================
1279 // function : PushState
1280 // purpose  : Pushes state of OCCT graphics parameters to the program
1281 // =======================================================================
1282 void OpenGl_ShaderManager::PushState (const Handle(OpenGl_ShaderProgram)& theProgram) const
1283 {
1284   const Handle(OpenGl_ShaderProgram)& aProgram = !theProgram.IsNull() ? theProgram : myFfpProgram;
1285   PushClippingState    (aProgram);
1286   PushWorldViewState   (aProgram);
1287   PushModelWorldState  (aProgram);
1288   PushProjectionState  (aProgram);
1289   PushLightSourceState (aProgram);
1290   PushMaterialState    (aProgram);
1291   PushOitState         (aProgram);
1292 }
1293
1294 // =======================================================================
1295 // function : prepareStdProgramFont
1296 // purpose  :
1297 // =======================================================================
1298 Standard_Boolean OpenGl_ShaderManager::prepareStdProgramFont()
1299 {
1300   OpenGl_ShaderObject::ShaderVariableList aUniforms, aStageInOuts;
1301   aUniforms   .Append (OpenGl_ShaderObject::ShaderVariable ("sampler2D occSamplerBaseColor", Graphic3d_TOS_FRAGMENT));
1302   aStageInOuts.Append (OpenGl_ShaderObject::ShaderVariable ("vec2 TexCoord", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
1303
1304   TCollection_AsciiString aSrcVert = TCollection_AsciiString()
1305     + EOL"void main()"
1306       EOL"{"
1307       EOL"  TexCoord = occTexCoord.st;"
1308     + THE_VERT_gl_Position
1309     + EOL"}";
1310
1311   TCollection_AsciiString
1312     aSrcGetAlpha = EOL"float getAlpha(void) { return occTexture2D(occSamplerBaseColor, TexCoord.st).a; }";
1313 #if !defined(GL_ES_VERSION_2_0)
1314   if (myContext->core11 == NULL)
1315   {
1316     aSrcGetAlpha = EOL"float getAlpha(void) { return occTexture2D(occSamplerBaseColor, TexCoord.st).r; }";
1317   }
1318 #endif
1319
1320   TCollection_AsciiString aSrcFrag =
1321        aSrcGetAlpha
1322      + EOL"void main()"
1323        EOL"{"
1324        EOL"  vec4 aColor = occColor;"
1325        EOL"  aColor.a *= getAlpha();"
1326        EOL"  if (aColor.a <= 0.285) discard;"
1327        EOL"  occSetFragColor (aColor);"
1328        EOL"}";
1329
1330   Handle(Graphic3d_ShaderProgram) aProgramSrc = new Graphic3d_ShaderProgram();
1331   defaultGlslVersion (aProgramSrc, "font", 0);
1332   aProgramSrc->SetDefaultSampler (false);
1333   aProgramSrc->SetNbLightsMax (0);
1334   aProgramSrc->SetNbClipPlanesMax (0);
1335   aProgramSrc->AttachShader (OpenGl_ShaderObject::CreateFromSource (aSrcVert, Graphic3d_TOS_VERTEX,   aUniforms, aStageInOuts));
1336   aProgramSrc->AttachShader (OpenGl_ShaderObject::CreateFromSource (aSrcFrag, Graphic3d_TOS_FRAGMENT, aUniforms, aStageInOuts));
1337   TCollection_AsciiString aKey;
1338   if (!Create (aProgramSrc, aKey, myFontProgram))
1339   {
1340     myFontProgram = new OpenGl_ShaderProgram(); // just mark as invalid
1341     return Standard_False;
1342   }
1343   return Standard_True;
1344 }
1345
1346 // =======================================================================
1347 // function : prepareStdProgramFboBlit
1348 // purpose  :
1349 // =======================================================================
1350 Standard_Boolean OpenGl_ShaderManager::prepareStdProgramFboBlit()
1351 {
1352   OpenGl_ShaderObject::ShaderVariableList aUniforms, aStageInOuts;
1353   aStageInOuts.Append (OpenGl_ShaderObject::ShaderVariable ("vec2 TexCoord", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
1354
1355   TCollection_AsciiString aSrcVert =
1356       EOL"void main()"
1357       EOL"{"
1358       EOL"  TexCoord    = occVertex.zw;"
1359       EOL"  gl_Position = vec4(occVertex.x, occVertex.y, 0.0, 1.0);"
1360       EOL"}";
1361
1362   aUniforms.Append (OpenGl_ShaderObject::ShaderVariable ("sampler2D uColorSampler", Graphic3d_TOS_FRAGMENT));
1363   aUniforms.Append (OpenGl_ShaderObject::ShaderVariable ("sampler2D uDepthSampler", Graphic3d_TOS_FRAGMENT));
1364   TCollection_AsciiString aSrcFrag =
1365       EOL"void main()"
1366       EOL"{"
1367       EOL"  gl_FragDepth = occTexture2D (uDepthSampler, TexCoord).r;"
1368       EOL"  occSetFragColor (occTexture2D (uColorSampler, TexCoord));"
1369       EOL"}";
1370
1371   Handle(Graphic3d_ShaderProgram) aProgramSrc = new Graphic3d_ShaderProgram();
1372 #if defined(GL_ES_VERSION_2_0)
1373   if (myContext->IsGlGreaterEqual (3, 0))
1374   {
1375     aProgramSrc->SetHeader ("#version 300 es");
1376   }
1377   else if (myContext->extFragDepth)
1378   {
1379     aProgramSrc->SetHeader ("#extension GL_EXT_frag_depth : enable"
1380                          EOL"#define gl_FragDepth gl_FragDepthEXT");
1381   }
1382   else
1383   {
1384     // there is no way to draw into depth buffer
1385     aSrcFrag =
1386       EOL"void main()"
1387       EOL"{"
1388       EOL"  occSetFragColor (occTexture2D (uColorSampler, TexCoord));"
1389       EOL"}";
1390   }
1391 #else
1392   if (myContext->core32 != NULL)
1393   {
1394     aProgramSrc->SetHeader ("#version 150");
1395   }
1396 #endif
1397   aProgramSrc->SetId ("occt_blit");
1398   aProgramSrc->SetDefaultSampler (false);
1399   aProgramSrc->SetNbLightsMax (0);
1400   aProgramSrc->SetNbClipPlanesMax (0);
1401   aProgramSrc->AttachShader (OpenGl_ShaderObject::CreateFromSource (aSrcVert, Graphic3d_TOS_VERTEX,   aUniforms, aStageInOuts));
1402   aProgramSrc->AttachShader (OpenGl_ShaderObject::CreateFromSource (aSrcFrag, Graphic3d_TOS_FRAGMENT, aUniforms, aStageInOuts));
1403   TCollection_AsciiString aKey;
1404   if (!Create (aProgramSrc, aKey, myBlitProgram))
1405   {
1406     myBlitProgram = new OpenGl_ShaderProgram(); // just mark as invalid
1407     return Standard_False;
1408   }
1409
1410   myContext->BindProgram (myBlitProgram);
1411   myBlitProgram->SetSampler (myContext, "uColorSampler", Graphic3d_TextureUnit_0);
1412   myBlitProgram->SetSampler (myContext, "uDepthSampler", Graphic3d_TextureUnit_1);
1413   myContext->BindProgram (NULL);
1414   return Standard_True;
1415 }
1416
1417 // =======================================================================
1418 // function : prepareStdProgramOitCompositing
1419 // purpose  :
1420 // =======================================================================
1421 Standard_Boolean OpenGl_ShaderManager::prepareStdProgramOitCompositing (const Standard_Boolean theMsaa)
1422 {
1423   Handle(OpenGl_ShaderProgram)& aProgram = myOitCompositingProgram[theMsaa ? 1 : 0];
1424   Handle(Graphic3d_ShaderProgram) aProgramSrc = new Graphic3d_ShaderProgram();
1425   TCollection_AsciiString aSrcVert, aSrcFrag;
1426
1427   OpenGl_ShaderObject::ShaderVariableList aUniforms, aStageInOuts;
1428   aStageInOuts.Append (OpenGl_ShaderObject::ShaderVariable ("vec2 TexCoord", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
1429
1430   aSrcVert =
1431     EOL"void main()"
1432     EOL"{"
1433     EOL"  TexCoord    = occVertex.zw;"
1434     EOL"  gl_Position = vec4 (occVertex.x, occVertex.y, 0.0, 1.0);"
1435     EOL"}";
1436
1437   if (!theMsaa)
1438   {
1439     aUniforms.Append (OpenGl_ShaderObject::ShaderVariable ("sampler2D uAccumTexture",  Graphic3d_TOS_FRAGMENT));
1440     aUniforms.Append (OpenGl_ShaderObject::ShaderVariable ("sampler2D uWeightTexture", Graphic3d_TOS_FRAGMENT));
1441     aSrcFrag =
1442       EOL"void main()"
1443       EOL"{"
1444       EOL"  vec4 aAccum   = occTexture2D (uAccumTexture,  TexCoord);"
1445       EOL"  float aWeight = occTexture2D (uWeightTexture, TexCoord).r;"
1446       EOL"  occSetFragColor (vec4 (aAccum.rgb / max (aWeight, 0.00001), aAccum.a));"
1447       EOL"}";
1448   #if !defined(GL_ES_VERSION_2_0)
1449     if (myContext->IsGlGreaterEqual (3, 2))
1450     {
1451       aProgramSrc->SetHeader ("#version 150");
1452     }
1453   #else
1454     if (myContext->IsGlGreaterEqual (3, 0))
1455     {
1456       aProgramSrc->SetHeader ("#version 300 es");
1457     }
1458   #endif
1459   }
1460   else
1461   {
1462     aUniforms.Append (OpenGl_ShaderObject::ShaderVariable ("sampler2DMS uAccumTexture",  Graphic3d_TOS_FRAGMENT));
1463     aUniforms.Append (OpenGl_ShaderObject::ShaderVariable ("sampler2DMS uWeightTexture", Graphic3d_TOS_FRAGMENT));
1464     aSrcFrag =
1465       EOL"void main()"
1466       EOL"{"
1467       EOL"  ivec2 aTexel  = ivec2 (vec2 (textureSize (uAccumTexture)) * TexCoord);"
1468       EOL"  vec4 aAccum   = texelFetch (uAccumTexture,  aTexel, gl_SampleID);"
1469       EOL"  float aWeight = texelFetch (uWeightTexture, aTexel, gl_SampleID).r;"
1470       EOL"  occSetFragColor (vec4 (aAccum.rgb / max (aWeight, 0.00001), aAccum.a));"
1471       EOL"}";
1472   #if !defined(GL_ES_VERSION_2_0)
1473     if (myContext->IsGlGreaterEqual (4, 0))
1474     {
1475       aProgramSrc->SetHeader ("#version 400");
1476     }
1477   #else
1478     if (myContext->IsGlGreaterEqual (3, 2))
1479     {
1480       aProgramSrc->SetHeader ("#version 320 es");
1481     }
1482     else if (myContext->IsGlGreaterEqual (3, 0))
1483     {
1484       aProgramSrc->SetHeader ("#version 300 es"); // with GL_OES_sample_variables extension
1485     }
1486   #endif
1487   }
1488
1489   aProgramSrc->SetId (theMsaa ? "occt_weight-oit-msaa" : "occt_weight-oit");
1490   aProgramSrc->SetDefaultSampler (false);
1491   aProgramSrc->SetNbLightsMax (0);
1492   aProgramSrc->SetNbClipPlanesMax (0);
1493   aProgramSrc->AttachShader (OpenGl_ShaderObject::CreateFromSource (aSrcVert, Graphic3d_TOS_VERTEX,   aUniforms, aStageInOuts));
1494   aProgramSrc->AttachShader (OpenGl_ShaderObject::CreateFromSource (aSrcFrag, Graphic3d_TOS_FRAGMENT, aUniforms, aStageInOuts));
1495   TCollection_AsciiString aKey;
1496   if (!Create (aProgramSrc, aKey, aProgram))
1497   {
1498     aProgram = new OpenGl_ShaderProgram(); // just mark as invalid
1499     return Standard_False;
1500   }
1501
1502   myContext->BindProgram (aProgram);
1503   aProgram->SetSampler (myContext, "uAccumTexture",  Graphic3d_TextureUnit_0);
1504   aProgram->SetSampler (myContext, "uWeightTexture", Graphic3d_TextureUnit_1);
1505   myContext->BindProgram (Handle(OpenGl_ShaderProgram)());
1506   return Standard_True;
1507 }
1508
1509 // =======================================================================
1510 // function : pointSpriteAlphaSrc
1511 // purpose  :
1512 // =======================================================================
1513 TCollection_AsciiString OpenGl_ShaderManager::pointSpriteAlphaSrc (Standard_Integer theBits)
1514 {
1515   TCollection_AsciiString aSrcGetAlpha = EOL"float getAlpha(void) { return occTexture2D(occSamplerPointSprite, " THE_VEC2_glPointCoord ").a; }";
1516 #if !defined(GL_ES_VERSION_2_0)
1517   if (myContext->core11 == NULL
1518    && (theBits & OpenGl_PO_PointSpriteA) == OpenGl_PO_PointSpriteA)
1519   {
1520     aSrcGetAlpha = EOL"float getAlpha(void) { return occTexture2D(occSamplerPointSprite, " THE_VEC2_glPointCoord ").r; }";
1521   }
1522 #else
1523   (void )theBits;
1524 #endif
1525   return aSrcGetAlpha;
1526 }
1527
1528 // =======================================================================
1529 // function : defaultGlslVersion
1530 // purpose  :
1531 // =======================================================================
1532 int OpenGl_ShaderManager::defaultGlslVersion (const Handle(Graphic3d_ShaderProgram)& theProgram,
1533                                               const TCollection_AsciiString& theName,
1534                                               int theBits,
1535                                               bool theUsesDerivates) const
1536 {
1537   int aBits = theBits;
1538 #if !defined(GL_ES_VERSION_2_0)
1539   if (myContext->core32 != NULL)
1540   {
1541     theProgram->SetHeader ("#version 150");
1542   }
1543   else
1544   {
1545     if ((theBits & OpenGl_PO_StippleLine) != 0)
1546     {
1547       if (myContext->IsGlGreaterEqual (3, 0))
1548       {
1549         theProgram->SetHeader ("#version 130");
1550       }
1551       else if (myContext->CheckExtension ("GL_EXT_gpu_shader4"))
1552       {
1553         theProgram->SetHeader ("#extension GL_EXT_gpu_shader4 : enable");
1554       }
1555       else
1556       {
1557         aBits = aBits & ~OpenGl_PO_StippleLine;
1558       }
1559     }
1560   }
1561   (void )theUsesDerivates;
1562 #else
1563   // prefer "100 es" on OpenGL ES 3.0- devices (save the features unavailable before "300 es")
1564   // and    "300 es" on OpenGL ES 3.1+ devices
1565   if (myContext->IsGlGreaterEqual (3, 1))
1566   {
1567     if ((theBits & OpenGl_PO_NeedsGeomShader) != 0)
1568     {
1569       theProgram->SetHeader (myContext->hasGeometryStage != OpenGl_FeatureInExtensions ? "#version 320 es" : "#version 310 es");
1570     }
1571     else
1572     {
1573       theProgram->SetHeader ("#version 300 es");
1574     }
1575   }
1576   else
1577   {
1578     if ((theBits & OpenGl_PO_WriteOit) != 0
1579      || (theBits & OpenGl_PO_StippleLine) != 0)
1580     {
1581       if (myContext->IsGlGreaterEqual (3, 0))
1582       {
1583         theProgram->SetHeader ("#version 300 es");
1584       }
1585       else
1586       {
1587         aBits = aBits & ~OpenGl_PO_WriteOit;
1588         aBits = aBits & ~OpenGl_PO_StippleLine;
1589       }
1590     }
1591     if (theUsesDerivates)
1592     {
1593       if (myContext->IsGlGreaterEqual (3, 0))
1594       {
1595         theProgram->SetHeader ("#version 300 es");
1596       }
1597       else if (myContext->oesStdDerivatives)
1598       {
1599         theProgram->SetHeader ("#extension GL_OES_standard_derivatives : enable");
1600       }
1601     }
1602   }
1603 #endif
1604
1605   // should fit OpenGl_PO_NB
1606   char aBitsStr[64];
1607   Sprintf (aBitsStr, "%04x", aBits);
1608   theProgram->SetId (TCollection_AsciiString ("occt_") + theName + aBitsStr);
1609   return aBits;
1610 }
1611
1612 // =======================================================================
1613 // function : prepareGeomMainSrc
1614 // purpose  :
1615 // =======================================================================
1616 TCollection_AsciiString OpenGl_ShaderManager::prepareGeomMainSrc (OpenGl_ShaderObject::ShaderVariableList& theUnifoms,
1617                                                                   OpenGl_ShaderObject::ShaderVariableList& theStageInOuts,
1618                                                                   Standard_Integer theBits)
1619 {
1620   if ((theBits & OpenGl_PO_NeedsGeomShader) == 0)
1621   {
1622     return TCollection_AsciiString();
1623   }
1624
1625   TCollection_AsciiString aSrcMainGeom =
1626     EOL"void main()"
1627     EOL"{";
1628
1629   if ((theBits & OpenGl_PO_MeshEdges) != 0)
1630   {
1631     theUnifoms.Append    (OpenGl_ShaderObject::ShaderVariable ("vec4 occViewport",       Graphic3d_TOS_GEOMETRY));
1632     theUnifoms.Append    (OpenGl_ShaderObject::ShaderVariable ("bool occIsQuadMode",     Graphic3d_TOS_GEOMETRY));
1633     theUnifoms.Append    (OpenGl_ShaderObject::ShaderVariable ("float occLineWidth",     Graphic3d_TOS_GEOMETRY));
1634     theUnifoms.Append    (OpenGl_ShaderObject::ShaderVariable ("float occLineWidth",     Graphic3d_TOS_FRAGMENT));
1635     theUnifoms.Append    (OpenGl_ShaderObject::ShaderVariable ("float occLineFeather",   Graphic3d_TOS_FRAGMENT));
1636     theUnifoms.Append    (OpenGl_ShaderObject::ShaderVariable ("vec4 occWireframeColor", Graphic3d_TOS_FRAGMENT));
1637     theStageInOuts.Append(OpenGl_ShaderObject::ShaderVariable ("vec3 EdgeDistance",      Graphic3d_TOS_GEOMETRY | Graphic3d_TOS_FRAGMENT));
1638
1639     aSrcMainGeom = TCollection_AsciiString()
1640     + EOL"vec3 ViewPortTransform (vec4 theVec)"
1641       EOL"{"
1642       EOL"  vec3 aWinCoord = theVec.xyz / theVec.w;"
1643       EOL"  aWinCoord    = aWinCoord * 0.5 + 0.5;"
1644       EOL"  aWinCoord.xy = aWinCoord.xy * occViewport.zw + occViewport.xy;"
1645       EOL"  return aWinCoord;"
1646       EOL"}"
1647     + aSrcMainGeom
1648     + EOL"  vec3 aSideA = ViewPortTransform (gl_in[2].gl_Position) - ViewPortTransform (gl_in[1].gl_Position);"
1649       EOL"  vec3 aSideB = ViewPortTransform (gl_in[2].gl_Position) - ViewPortTransform (gl_in[0].gl_Position);"
1650       EOL"  vec3 aSideC = ViewPortTransform (gl_in[1].gl_Position) - ViewPortTransform (gl_in[0].gl_Position);"
1651       EOL"  float aQuadArea = abs (aSideB.x * aSideC.y - aSideB.y * aSideC.x);"
1652       EOL"  vec3 aLenABC    = vec3 (length (aSideA), length (aSideB), length (aSideC));"
1653       EOL"  vec3 aHeightABC = vec3 (aQuadArea) / aLenABC;"
1654       EOL"  aHeightABC = max (aHeightABC, vec3 (10.0 * occLineWidth));" // avoid shrunk presentation disappearing at distance
1655       EOL"  float aQuadModeHeightC = occIsQuadMode ? occLineWidth + 1.0 : 0.0;";
1656   }
1657
1658   for (Standard_Integer aVertIter = 0; aVertIter < 3; ++aVertIter)
1659   {
1660     const TCollection_AsciiString aVertIndex (aVertIter);
1661     // pass variables from Vertex shader to Fragment shader through Geometry shader
1662     for (OpenGl_ShaderObject::ShaderVariableList::Iterator aVarListIter (theStageInOuts); aVarListIter.More(); aVarListIter.Next())
1663     {
1664       if (aVarListIter.Value().Stages == (Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT))
1665       {
1666         const TCollection_AsciiString aVarName = aVarListIter.Value().Name.Token (" ", 2);
1667         aSrcMainGeom += TCollection_AsciiString()
1668          + EOL"  geomOut." + aVarName + " = geomIn[" + aVertIndex + "]." + aVarName + ";";
1669       }
1670     }
1671
1672     if ((theBits & OpenGl_PO_MeshEdges) != 0)
1673     {
1674       switch (aVertIter)
1675       {
1676         case 0: aSrcMainGeom += EOL"  EdgeDistance = vec3 (aHeightABC[0], 0.0, aQuadModeHeightC);"; break;
1677         case 1: aSrcMainGeom += EOL"  EdgeDistance = vec3 (0.0, aHeightABC[1], aQuadModeHeightC);"; break;
1678         case 2: aSrcMainGeom += EOL"  EdgeDistance = vec3 (0.0, 0.0, aHeightABC[2]);"; break;
1679       }
1680     }
1681     aSrcMainGeom += TCollection_AsciiString()
1682      + EOL"  gl_Position = gl_in[" + aVertIndex + "].gl_Position;"
1683        EOL"  EmitVertex();";
1684   }
1685   aSrcMainGeom +=
1686     EOL"  EndPrimitive();"
1687     EOL"}";
1688
1689   return aSrcMainGeom;
1690 }
1691
1692 // =======================================================================
1693 // function : prepareStdProgramUnlit
1694 // purpose  :
1695 // =======================================================================
1696 Standard_Boolean OpenGl_ShaderManager::prepareStdProgramUnlit (Handle(OpenGl_ShaderProgram)& theProgram,
1697                                                                Standard_Integer theBits,
1698                                                                Standard_Boolean theIsOutline)
1699 {
1700   Handle(Graphic3d_ShaderProgram) aProgramSrc = new Graphic3d_ShaderProgram();
1701   TCollection_AsciiString aSrcVert, aSrcVertExtraMain, aSrcVertExtraFunc, aSrcGetAlpha, aSrcVertEndMain;
1702   TCollection_AsciiString aSrcFrag, aSrcFragExtraMain;
1703   TCollection_AsciiString aSrcFragGetColor     = EOL"vec4 getColor(void) { return occColor; }";
1704   TCollection_AsciiString aSrcFragMainGetColor = EOL"  occSetFragColor (getFinalColor());";
1705   OpenGl_ShaderObject::ShaderVariableList aUniforms, aStageInOuts;
1706
1707   if ((theBits & OpenGl_PO_IsPoint) != 0)
1708   {
1709   #if defined(GL_ES_VERSION_2_0)
1710     aSrcVertExtraMain += EOL"  gl_PointSize = occPointSize;";
1711   #endif
1712
1713     if ((theBits & OpenGl_PO_PointSprite) != 0)
1714     {
1715       aUniforms.Append (OpenGl_ShaderObject::ShaderVariable ("sampler2D occSamplerPointSprite", Graphic3d_TOS_FRAGMENT));
1716       if ((theBits & OpenGl_PO_PointSpriteA) != OpenGl_PO_PointSpriteA)
1717       {
1718         aSrcFragGetColor =
1719           EOL"vec4 getColor(void) { return occTexture2D(occSamplerPointSprite, " THE_VEC2_glPointCoord "); }";
1720       }
1721       else if ((theBits & OpenGl_PO_HasTextures) == OpenGl_PO_TextureRGB
1722             && (theBits & OpenGl_PO_VertColor) == 0)
1723       {
1724         aUniforms   .Append (OpenGl_ShaderObject::ShaderVariable ("sampler2D occSamplerBaseColor", Graphic3d_TOS_VERTEX));
1725         aStageInOuts.Append (OpenGl_ShaderObject::ShaderVariable ("vec4 VertColor", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
1726         aSrcVertExtraMain +=
1727           EOL"  VertColor = occTexture2D (occSamplerBaseColor, occTexCoord.xy);";
1728         aSrcFragGetColor =
1729           EOL"vec4 getColor(void) { return VertColor; }";
1730       }
1731
1732       aSrcGetAlpha = pointSpriteAlphaSrc (theBits);
1733
1734     #if !defined(GL_ES_VERSION_2_0)
1735       if (myContext->core11 != NULL
1736         && myContext->IsGlGreaterEqual (2, 1))
1737       {
1738         aProgramSrc->SetHeader ("#version 120"); // gl_PointCoord has been added since GLSL 1.2
1739       }
1740     #endif
1741
1742       aSrcFragMainGetColor =
1743         EOL"  vec4 aColor = getColor();"
1744         EOL"  aColor.a = getAlpha();"
1745         EOL"  if (aColor.a <= 0.1) discard;"
1746         EOL"  occSetFragColor (aColor);";
1747     }
1748     else
1749     {
1750       if ((theBits & OpenGl_PO_HasTextures) == OpenGl_PO_TextureRGB
1751        && (theBits & OpenGl_PO_VertColor) == 0)
1752       {
1753         aUniforms   .Append (OpenGl_ShaderObject::ShaderVariable ("sampler2D occSamplerBaseColor", Graphic3d_TOS_VERTEX));
1754         aStageInOuts.Append (OpenGl_ShaderObject::ShaderVariable ("vec4 VertColor", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
1755         aSrcVertExtraMain +=
1756           EOL"  VertColor = occTexture2D (occSamplerBaseColor, occTexCoord.xy);";
1757         aSrcFragGetColor =
1758           EOL"vec4 getColor(void) { return VertColor; }";
1759       }
1760
1761       aSrcFragMainGetColor =
1762         EOL"  vec4 aColor = getColor();"
1763         EOL"  if (aColor.a <= 0.1) discard;"
1764         EOL"  occSetFragColor (aColor);";
1765     }
1766   }
1767   else
1768   {
1769     if ((theBits & OpenGl_PO_TextureRGB) != 0 || (theBits & OpenGl_PO_TextureEnv) != 0)
1770     {
1771       aUniforms   .Append (OpenGl_ShaderObject::ShaderVariable ("sampler2D occSamplerBaseColor", Graphic3d_TOS_FRAGMENT));
1772       aStageInOuts.Append (OpenGl_ShaderObject::ShaderVariable ("vec4 TexCoord", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
1773     }
1774
1775     if ((theBits & OpenGl_PO_HasTextures) == OpenGl_PO_TextureRGB)
1776     {
1777       aSrcVertExtraMain += THE_VARY_TexCoord_Trsf;
1778
1779       aSrcFragGetColor =
1780         EOL"vec4 getColor(void) { return occTexture2D(occSamplerBaseColor, TexCoord.st / TexCoord.w); }";
1781     }
1782     else if ((theBits & OpenGl_PO_TextureEnv) != 0)
1783     {
1784       aSrcVertExtraFunc = THE_FUNC_transformNormal;
1785
1786       aSrcVertExtraMain +=
1787         EOL"  vec4 aPosition = occWorldViewMatrix * occModelWorldMatrix * occVertex;"
1788         EOL"  vec3 aNormal   = transformNormal (occNormal);"
1789         EOL"  vec3 aReflect  = reflect (normalize (aPosition.xyz), aNormal);"
1790         EOL"  aReflect.z += 1.0;"
1791         EOL"  TexCoord = vec4(aReflect.xy * inversesqrt (dot (aReflect, aReflect)) * 0.5 + vec2 (0.5), 0.0, 1.0);";
1792
1793       aSrcFragGetColor =
1794         EOL"vec4 getColor(void) { return occTexture2D (occSamplerBaseColor, TexCoord.st); }";
1795     }
1796   }
1797   if ((theBits & OpenGl_PO_VertColor) != 0)
1798   {
1799     aStageInOuts.Append (OpenGl_ShaderObject::ShaderVariable ("vec4 VertColor", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
1800     aSrcVertExtraMain += EOL"  VertColor = occVertColor;";
1801     aSrcFragGetColor  =  EOL"vec4 getColor(void) { return VertColor; }";
1802   }
1803
1804   int aNbClipPlanes = 0;
1805   if ((theBits & OpenGl_PO_ClipPlanesN) != 0)
1806   {
1807     aStageInOuts.Append (OpenGl_ShaderObject::ShaderVariable ("vec4 PositionWorld", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
1808     aStageInOuts.Append (OpenGl_ShaderObject::ShaderVariable ("vec4 Position",      Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
1809     aSrcVertExtraMain +=
1810       EOL"  PositionWorld = occModelWorldMatrix * occVertex;"
1811       EOL"  Position      = occWorldViewMatrix * PositionWorld;";
1812
1813     if ((theBits & OpenGl_PO_ClipPlanesN) == OpenGl_PO_ClipPlanesN)
1814     {
1815       aNbClipPlanes = Graphic3d_ShaderProgram::THE_MAX_CLIP_PLANES_DEFAULT;
1816       aSrcFragExtraMain += (theBits & OpenGl_PO_ClipChains) != 0
1817                          ? THE_FRAG_CLIP_CHAINS_N
1818                          : THE_FRAG_CLIP_PLANES_N;
1819     }
1820     else if ((theBits & OpenGl_PO_ClipPlanes1) != 0)
1821     {
1822       aNbClipPlanes = 1;
1823       aSrcFragExtraMain += THE_FRAG_CLIP_PLANES_1;
1824     }
1825     else if ((theBits & OpenGl_PO_ClipPlanes2) != 0)
1826     {
1827       aNbClipPlanes = 2;
1828       aSrcFragExtraMain += (theBits & OpenGl_PO_ClipChains) != 0
1829                          ? THE_FRAG_CLIP_CHAINS_2
1830                          : THE_FRAG_CLIP_PLANES_2;
1831     }
1832   }
1833   if ((theBits & OpenGl_PO_WriteOit) != 0)
1834   {
1835     aProgramSrc->SetNbFragmentOutputs (2);
1836     aProgramSrc->SetWeightOitOutput (true);
1837   }
1838
1839   if (theIsOutline)
1840   {
1841     aUniforms.Append (OpenGl_ShaderObject::ShaderVariable ("float occOrthoScale",          Graphic3d_TOS_VERTEX));
1842     aUniforms.Append (OpenGl_ShaderObject::ShaderVariable ("float occSilhouetteThickness", Graphic3d_TOS_VERTEX));
1843     aSrcVertEndMain = THE_VERT_gl_Position_OUTLINE;
1844   }
1845   else if ((theBits & OpenGl_PO_StippleLine) != 0)
1846   {
1847     const Standard_Integer aBits = defaultGlslVersion (aProgramSrc, "unlit", theBits);
1848     if ((aBits & OpenGl_PO_StippleLine) != 0)
1849     {
1850       aUniforms.Append (OpenGl_ShaderObject::ShaderVariable ("int   uPattern", Graphic3d_TOS_FRAGMENT));
1851       aUniforms.Append (OpenGl_ShaderObject::ShaderVariable ("float uFactor",  Graphic3d_TOS_FRAGMENT));
1852       aStageInOuts.Append (OpenGl_ShaderObject::ShaderVariable ("vec2 ScreenSpaceCoord", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
1853       aSrcVertEndMain =
1854         EOL"  ScreenSpaceCoord = gl_Position.xy / gl_Position.w;";
1855       aSrcFragMainGetColor =
1856         EOL"  float anAngle      = atan (dFdx (ScreenSpaceCoord.x), dFdy (ScreenSpaceCoord.y));"
1857         EOL"  float aRotatePoint = gl_FragCoord.x * sin (anAngle) + gl_FragCoord.y * cos (anAngle);"
1858         EOL"  uint  aBit         = uint (floor (aRotatePoint / uFactor + 0.5)) & 15U;"
1859         EOL"  if ((uint (uPattern) & (1U << aBit)) == 0U) discard;"
1860         EOL"  vec4 aColor = getFinalColor();"
1861         EOL"  if (aColor.a <= 0.1) discard;"
1862         EOL"  occSetFragColor (aColor);";
1863     }
1864     else
1865     {
1866       myContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_HIGH, "Warning: stipple lines in GLSL will be ignored.");
1867     }
1868   }
1869
1870   aSrcVert =
1871       aSrcVertExtraFunc
1872     + EOL"void main()"
1873       EOL"{"
1874     + aSrcVertExtraMain
1875     + THE_VERT_gl_Position
1876     + aSrcVertEndMain
1877     + EOL"}";
1878
1879   TCollection_AsciiString aSrcGeom = prepareGeomMainSrc (aUniforms, aStageInOuts, theBits);
1880   aSrcFragGetColor += (theBits & OpenGl_PO_MeshEdges) != 0
1881     ? THE_FRAG_WIREFRAME_COLOR
1882     : EOL"#define getFinalColor getColor";
1883
1884   aSrcFrag =
1885       aSrcFragGetColor
1886     + aSrcGetAlpha
1887     + EOL"void main()"
1888       EOL"{"
1889     + aSrcFragExtraMain
1890     + aSrcFragMainGetColor
1891     + EOL"}";
1892
1893   defaultGlslVersion (aProgramSrc, theIsOutline ? "outline" : "unlit", theBits);
1894   aProgramSrc->SetDefaultSampler (false);
1895   aProgramSrc->SetNbLightsMax (0);
1896   aProgramSrc->SetNbClipPlanesMax (aNbClipPlanes);
1897   aProgramSrc->SetAlphaTest ((theBits & OpenGl_PO_AlphaTest) != 0);
1898   const Standard_Integer aNbGeomInputVerts = !aSrcGeom.IsEmpty() ? 3 : 0;
1899   aProgramSrc->AttachShader (OpenGl_ShaderObject::CreateFromSource (aSrcVert, Graphic3d_TOS_VERTEX,   aUniforms, aStageInOuts, "", "", aNbGeomInputVerts));
1900   aProgramSrc->AttachShader (OpenGl_ShaderObject::CreateFromSource (aSrcGeom, Graphic3d_TOS_GEOMETRY, aUniforms, aStageInOuts, "geomIn", "geomOut", aNbGeomInputVerts));
1901   aProgramSrc->AttachShader (OpenGl_ShaderObject::CreateFromSource (aSrcFrag, Graphic3d_TOS_FRAGMENT, aUniforms, aStageInOuts, "", "", aNbGeomInputVerts));
1902   TCollection_AsciiString aKey;
1903   if (!Create (aProgramSrc, aKey, theProgram))
1904   {
1905     theProgram = new OpenGl_ShaderProgram(); // just mark as invalid
1906     return Standard_False;
1907   }
1908   return Standard_True;
1909 }
1910
1911 // =======================================================================
1912 // function : pointSpriteShadingSrc
1913 // purpose  :
1914 // =======================================================================
1915 TCollection_AsciiString OpenGl_ShaderManager::pointSpriteShadingSrc (const TCollection_AsciiString& theBaseColorSrc,
1916                                                                      Standard_Integer theBits)
1917 {
1918   TCollection_AsciiString aSrcFragGetColor;
1919   if ((theBits & OpenGl_PO_PointSpriteA) == OpenGl_PO_PointSpriteA)
1920   {
1921     aSrcFragGetColor = pointSpriteAlphaSrc (theBits) +
1922       EOL"vec4 getColor(void)"
1923       EOL"{"
1924       EOL"  vec4 aColor = " + theBaseColorSrc + ";"
1925       EOL"  aColor.a = getAlpha();"
1926       EOL"  if (aColor.a <= 0.1) discard;"
1927       EOL"  return aColor;"
1928       EOL"}";
1929   }
1930   else if ((theBits & OpenGl_PO_PointSprite) == OpenGl_PO_PointSprite)
1931   {
1932     aSrcFragGetColor = TCollection_AsciiString() +
1933       EOL"vec4 getColor(void)"
1934       EOL"{"
1935       EOL"  vec4 aColor = " + theBaseColorSrc + ";"
1936       EOL"  aColor = occTexture2D(occSamplerPointSprite, " THE_VEC2_glPointCoord ") * aColor;"
1937       EOL"  if (aColor.a <= 0.1) discard;"
1938       EOL"  return aColor;"
1939       EOL"}";
1940   }
1941
1942   return aSrcFragGetColor;
1943 }
1944
1945 // =======================================================================
1946 // function : stdComputeLighting
1947 // purpose  :
1948 // =======================================================================
1949 TCollection_AsciiString OpenGl_ShaderManager::stdComputeLighting (Standard_Integer& theNbLights,
1950                                                                   Standard_Boolean  theHasVertColor)
1951 {
1952   TCollection_AsciiString aLightsFunc, aLightsLoop;
1953   theNbLights = 0;
1954   const Handle(Graphic3d_LightSet)& aLights = myLightSourceState.LightSources();
1955   if (!aLights.IsNull())
1956   {
1957     theNbLights = aLights->NbEnabled();
1958     if (theNbLights <= THE_NB_UNROLLED_LIGHTS_MAX)
1959     {
1960       Standard_Integer anIndex = 0;
1961       for (Graphic3d_LightSet::Iterator aLightIter (aLights, Graphic3d_LightSet::IterationFilter_ExcludeDisabledAndAmbient);
1962            aLightIter.More(); aLightIter.Next(), ++anIndex)
1963       {
1964         switch (aLightIter.Value()->Type())
1965         {
1966           case Graphic3d_TOLS_AMBIENT:
1967             --anIndex;
1968             break; // skip ambient
1969           case Graphic3d_TOLS_DIRECTIONAL:
1970             aLightsLoop = aLightsLoop + EOL"    directionalLight (" + anIndex + ", theNormal, theView, theIsFront);";
1971             break;
1972           case Graphic3d_TOLS_POSITIONAL:
1973             aLightsLoop = aLightsLoop + EOL"    pointLight (" + anIndex + ", theNormal, theView, aPoint, theIsFront);";
1974             break;
1975           case Graphic3d_TOLS_SPOT:
1976             aLightsLoop = aLightsLoop + EOL"    spotLight (" + anIndex + ", theNormal, theView, aPoint, theIsFront);";
1977             break;
1978         }
1979       }
1980     }
1981     else
1982     {
1983       theNbLights = roundUpMaxLightSources (theNbLights);
1984       bool isFirstInLoop = true;
1985       aLightsLoop = aLightsLoop +
1986         EOL"    for (int anIndex = 0; anIndex < occLightSourcesCount; ++anIndex)"
1987         EOL"    {"
1988         EOL"      int aType = occLight_Type (anIndex);";
1989       if (aLights->NbEnabledLightsOfType (Graphic3d_TOLS_DIRECTIONAL) > 0)
1990       {
1991         isFirstInLoop = false;
1992         aLightsLoop +=
1993           EOL"      if (aType == OccLightType_Direct)"
1994           EOL"      {"
1995           EOL"        directionalLight (anIndex, theNormal, theView, theIsFront);"
1996           EOL"      }";
1997       }
1998       if (aLights->NbEnabledLightsOfType (Graphic3d_TOLS_POSITIONAL) > 0)
1999       {
2000         if (!isFirstInLoop)
2001         {
2002           aLightsLoop += EOL"      else ";
2003         }
2004         isFirstInLoop = false;
2005         aLightsLoop +=
2006           EOL"      if (aType == OccLightType_Point)"
2007           EOL"      {"
2008           EOL"        pointLight (anIndex, theNormal, theView, aPoint, theIsFront);"
2009           EOL"      }";
2010       }
2011       if (aLights->NbEnabledLightsOfType (Graphic3d_TOLS_SPOT) > 0)
2012       {
2013         if (!isFirstInLoop)
2014         {
2015           aLightsLoop += EOL"      else ";
2016         }
2017         isFirstInLoop = false;
2018         aLightsLoop +=
2019           EOL"      if (aType == OccLightType_Spot)"
2020           EOL"      {"
2021           EOL"        spotLight (anIndex, theNormal, theView, aPoint, theIsFront);"
2022           EOL"      }";
2023       }
2024       aLightsLoop += EOL"    }";
2025     }
2026     if (aLights->NbEnabledLightsOfType (Graphic3d_TOLS_DIRECTIONAL) == 1
2027      && theNbLights == 1)
2028     {
2029       // use the version with hard-coded first index
2030       aLightsLoop = EOL"    directionalLightFirst(theNormal, theView, theIsFront);";
2031       aLightsFunc += THE_FUNC_directionalLightFirst;
2032     }
2033     else if (aLights->NbEnabledLightsOfType (Graphic3d_TOLS_DIRECTIONAL) > 0)
2034     {
2035       aLightsFunc += THE_FUNC_directionalLight;
2036     }
2037     if (aLights->NbEnabledLightsOfType (Graphic3d_TOLS_POSITIONAL) > 0)
2038     {
2039       aLightsFunc += THE_FUNC_pointLight;
2040     }
2041     if (aLights->NbEnabledLightsOfType (Graphic3d_TOLS_SPOT) > 0)
2042     {
2043       aLightsFunc += THE_FUNC_spotLight;
2044     }
2045   }
2046
2047   TCollection_AsciiString aGetMatAmbient = "theIsFront ? occFrontMaterial_Ambient()  : occBackMaterial_Ambient();";
2048   TCollection_AsciiString aGetMatDiffuse = "theIsFront ? occFrontMaterial_Diffuse()  : occBackMaterial_Diffuse();";
2049   if (theHasVertColor)
2050   {
2051     aGetMatAmbient = "getVertColor();";
2052     aGetMatDiffuse = "getVertColor();";
2053   }
2054
2055   return TCollection_AsciiString()
2056     + THE_FUNC_lightDef
2057     + aLightsFunc
2058     + EOL
2059       EOL"vec4 computeLighting (in vec3 theNormal,"
2060       EOL"                      in vec3 theView,"
2061       EOL"                      in vec4 thePoint,"
2062       EOL"                      in bool theIsFront)"
2063       EOL"{"
2064       EOL"  Ambient  = occLightAmbient.rgb;"
2065       EOL"  Diffuse  = vec3 (0.0);"
2066       EOL"  Specular = vec3 (0.0);"
2067       EOL"  vec3 aPoint = thePoint.xyz / thePoint.w;"
2068     + aLightsLoop
2069     + EOL"  vec4 aMatAmbient  = " + aGetMatAmbient
2070     + EOL"  vec4 aMatDiffuse  = " + aGetMatDiffuse
2071     + EOL"  vec4 aMatSpecular = theIsFront ? occFrontMaterial_Specular() : occBackMaterial_Specular();"
2072       EOL"  vec4 aMatEmission = theIsFront ? occFrontMaterial_Emission() : occBackMaterial_Emission();"
2073       EOL"  vec3 aColor = Ambient  * aMatAmbient.rgb"
2074       EOL"              + Diffuse  * aMatDiffuse.rgb"
2075       EOL"              + Specular * aMatSpecular.rgb"
2076       EOL"                         + aMatEmission.rgb;"
2077       EOL"  return vec4 (aColor, aMatDiffuse.a);"
2078       EOL"}";
2079 }
2080
2081 // =======================================================================
2082 // function : prepareStdProgramGouraud
2083 // purpose  :
2084 // =======================================================================
2085 Standard_Boolean OpenGl_ShaderManager::prepareStdProgramGouraud (Handle(OpenGl_ShaderProgram)& theProgram,
2086                                                                  const Standard_Integer        theBits)
2087 {
2088   Handle(Graphic3d_ShaderProgram) aProgramSrc = new Graphic3d_ShaderProgram();
2089   TCollection_AsciiString aSrcVert, aSrcVertColor, aSrcVertExtraMain;
2090   TCollection_AsciiString aSrcFrag, aSrcFragExtraMain;
2091   TCollection_AsciiString aSrcFragGetColor = EOL"vec4 getColor(void) { return gl_FrontFacing ? FrontColor : BackColor; }";
2092   OpenGl_ShaderObject::ShaderVariableList aUniforms, aStageInOuts;
2093
2094   if ((theBits & OpenGl_PO_IsPoint) != 0)
2095   {
2096   #if defined(GL_ES_VERSION_2_0)
2097     aSrcVertExtraMain += EOL"  gl_PointSize = occPointSize;";
2098   #endif
2099
2100     if ((theBits & OpenGl_PO_PointSprite) != 0)
2101     {
2102     #if !defined(GL_ES_VERSION_2_0)
2103       if (myContext->core11 != NULL
2104         && myContext->IsGlGreaterEqual (2, 1))
2105       {
2106         aProgramSrc->SetHeader ("#version 120"); // gl_PointCoord has been added since GLSL 1.2
2107       }
2108     #endif
2109
2110       aUniforms.Append (OpenGl_ShaderObject::ShaderVariable ("sampler2D occSamplerPointSprite", Graphic3d_TOS_FRAGMENT));
2111       aSrcFragGetColor = pointSpriteShadingSrc ("gl_FrontFacing ? FrontColor : BackColor", theBits);
2112     }
2113
2114     if ((theBits & OpenGl_PO_HasTextures) == OpenGl_PO_TextureRGB
2115      && (theBits & OpenGl_PO_VertColor) == 0)
2116     {
2117       aUniforms.Append (OpenGl_ShaderObject::ShaderVariable ("sampler2D occSamplerBaseColor", Graphic3d_TOS_VERTEX));
2118       aSrcVertColor = EOL"vec4 getVertColor(void) { return occTexture2D (occSamplerBaseColor, occTexCoord.xy); }";
2119     }
2120   }
2121   else
2122   {
2123     if ((theBits & OpenGl_PO_HasTextures) == OpenGl_PO_TextureRGB)
2124     {
2125       aUniforms   .Append (OpenGl_ShaderObject::ShaderVariable ("sampler2D occSamplerBaseColor", Graphic3d_TOS_FRAGMENT));
2126       aStageInOuts.Append (OpenGl_ShaderObject::ShaderVariable ("vec4 TexCoord", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
2127       aSrcVertExtraMain += THE_VARY_TexCoord_Trsf;
2128
2129       aSrcFragGetColor =
2130         EOL"vec4 getColor(void)"
2131         EOL"{"
2132         EOL"  vec4 aColor = gl_FrontFacing ? FrontColor : BackColor;"
2133         EOL"  return occTexture2D(occSamplerBaseColor, TexCoord.st / TexCoord.w) * aColor;"
2134         EOL"}";
2135     }
2136   }
2137
2138   if ((theBits & OpenGl_PO_VertColor) != 0)
2139   {
2140     aSrcVertColor = EOL"vec4 getVertColor(void) { return occVertColor; }";
2141   }
2142
2143   int aNbClipPlanes = 0;
2144   if ((theBits & OpenGl_PO_ClipPlanesN) != 0)
2145   {
2146     aStageInOuts.Append (OpenGl_ShaderObject::ShaderVariable ("vec4 PositionWorld", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
2147     aStageInOuts.Append (OpenGl_ShaderObject::ShaderVariable ("vec4 Position",      Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
2148     aSrcVertExtraMain +=
2149       EOL"  PositionWorld = aPositionWorld;"
2150       EOL"  Position      = aPosition;";
2151
2152     if ((theBits & OpenGl_PO_ClipPlanesN) == OpenGl_PO_ClipPlanesN)
2153     {
2154       aNbClipPlanes = Graphic3d_ShaderProgram::THE_MAX_CLIP_PLANES_DEFAULT;
2155       aSrcFragExtraMain += (theBits & OpenGl_PO_ClipChains) != 0
2156                          ? THE_FRAG_CLIP_CHAINS_N
2157                          : THE_FRAG_CLIP_PLANES_N;
2158     }
2159     else if ((theBits & OpenGl_PO_ClipPlanes1) != 0)
2160     {
2161       aNbClipPlanes = 1;
2162       aSrcFragExtraMain += THE_FRAG_CLIP_PLANES_1;
2163     }
2164     else if ((theBits & OpenGl_PO_ClipPlanes2) != 0)
2165     {
2166       aNbClipPlanes = 2;
2167       aSrcFragExtraMain += (theBits & OpenGl_PO_ClipChains) != 0
2168                           ? THE_FRAG_CLIP_CHAINS_2
2169                           : THE_FRAG_CLIP_PLANES_2;
2170     }
2171   }
2172   if ((theBits & OpenGl_PO_WriteOit) != 0)
2173   {
2174     aProgramSrc->SetNbFragmentOutputs (2);
2175     aProgramSrc->SetWeightOitOutput (true);
2176   }
2177
2178   aStageInOuts.Append (OpenGl_ShaderObject::ShaderVariable ("vec4 FrontColor", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
2179   aStageInOuts.Append (OpenGl_ShaderObject::ShaderVariable ("vec4 BackColor",  Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
2180
2181   Standard_Integer aNbLights = 0;
2182   const TCollection_AsciiString aLights = stdComputeLighting (aNbLights, !aSrcVertColor.IsEmpty());
2183   aSrcVert = TCollection_AsciiString()
2184     + THE_FUNC_transformNormal
2185     + EOL
2186     + aSrcVertColor
2187     + aLights
2188     + EOL"void main()"
2189       EOL"{"
2190       EOL"  vec4 aPositionWorld = occModelWorldMatrix * occVertex;"
2191       EOL"  vec4 aPosition      = occWorldViewMatrix * aPositionWorld;"
2192       EOL"  vec3 aNormal        = transformNormal (occNormal);"
2193       EOL"  vec3 aView          = vec3 (0.0, 0.0, 1.0);"
2194       EOL"  FrontColor  = computeLighting (normalize (aNormal), normalize (aView), aPosition, true);"
2195       EOL"  BackColor   = computeLighting (normalize (aNormal), normalize (aView), aPosition, false);"
2196     + aSrcVertExtraMain
2197     + THE_VERT_gl_Position
2198     + EOL"}";
2199
2200   TCollection_AsciiString aSrcGeom = prepareGeomMainSrc (aUniforms, aStageInOuts, theBits);
2201   aSrcFragGetColor += (theBits & OpenGl_PO_MeshEdges) != 0
2202     ? THE_FRAG_WIREFRAME_COLOR
2203     : EOL"#define getFinalColor getColor";
2204
2205   aSrcFrag = TCollection_AsciiString()
2206     + aSrcFragGetColor
2207     + EOL"void main()"
2208       EOL"{"
2209     + aSrcFragExtraMain
2210     + EOL"  occSetFragColor (getFinalColor());"
2211     + EOL"}";
2212
2213   const TCollection_AsciiString aProgId = TCollection_AsciiString ("gouraud-") + genLightKey (myLightSourceState.LightSources()) + "-";
2214   defaultGlslVersion (aProgramSrc, aProgId, theBits);
2215   aProgramSrc->SetDefaultSampler (false);
2216   aProgramSrc->SetNbLightsMax (aNbLights);
2217   aProgramSrc->SetNbClipPlanesMax (aNbClipPlanes);
2218   aProgramSrc->SetAlphaTest ((theBits & OpenGl_PO_AlphaTest) != 0);
2219   const Standard_Integer aNbGeomInputVerts = !aSrcGeom.IsEmpty() ? 3 : 0;
2220   aProgramSrc->AttachShader (OpenGl_ShaderObject::CreateFromSource (aSrcVert, Graphic3d_TOS_VERTEX,   aUniforms, aStageInOuts, "", "", aNbGeomInputVerts));
2221   aProgramSrc->AttachShader (OpenGl_ShaderObject::CreateFromSource (aSrcGeom, Graphic3d_TOS_GEOMETRY, aUniforms, aStageInOuts, "geomIn", "geomOut", aNbGeomInputVerts));
2222   aProgramSrc->AttachShader (OpenGl_ShaderObject::CreateFromSource (aSrcFrag, Graphic3d_TOS_FRAGMENT, aUniforms, aStageInOuts, "", "", aNbGeomInputVerts));
2223   TCollection_AsciiString aKey;
2224   if (!Create (aProgramSrc, aKey, theProgram))
2225   {
2226     theProgram = new OpenGl_ShaderProgram(); // just mark as invalid
2227     return Standard_False;
2228   }
2229   return Standard_True;
2230 }
2231
2232 // =======================================================================
2233 // function : prepareStdProgramPhong
2234 // purpose  :
2235 // =======================================================================
2236 Standard_Boolean OpenGl_ShaderManager::prepareStdProgramPhong (Handle(OpenGl_ShaderProgram)& theProgram,
2237                                                                const Standard_Integer        theBits,
2238                                                                const Standard_Boolean        theIsFlatNormal)
2239 {
2240   #define thePhongCompLight "computeLighting (normalize (Normal), normalize (View), Position, gl_FrontFacing)"
2241   const bool isFlatNormal = theIsFlatNormal
2242                          && myContext->hasFlatShading != OpenGl_FeatureNotAvailable;
2243   const char* aDFdxSignReversion = "";
2244 #if defined(GL_ES_VERSION_2_0)
2245   if (isFlatNormal != theIsFlatNormal)
2246   {
2247     myContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION,
2248                             GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_MEDIUM,
2249                             "Warning: flat shading requires OpenGL ES 3.0+ or GL_OES_standard_derivatives extension.");
2250   }
2251   else if (isFlatNormal
2252         && myContext->Vendor().Search("qualcomm") != -1)
2253   {
2254     // workaround Adreno driver bug computing reversed normal using dFdx/dFdy
2255     aDFdxSignReversion = "-";
2256     myContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_MEDIUM,
2257                             "Warning: applied workaround for flat shading normal computation using dFdx/dFdy on Adreno");
2258   }
2259 #endif
2260   Handle(Graphic3d_ShaderProgram) aProgramSrc = new Graphic3d_ShaderProgram();
2261   TCollection_AsciiString aSrcVert, aSrcVertExtraFunc, aSrcVertExtraMain;
2262   TCollection_AsciiString aSrcFrag, aSrcFragExtraOut, aSrcFragGetVertColor, aSrcFragExtraMain;
2263   TCollection_AsciiString aSrcFragGetColor = EOL"vec4 getColor(void) { return " thePhongCompLight "; }";
2264   OpenGl_ShaderObject::ShaderVariableList aUniforms, aStageInOuts;
2265   if ((theBits & OpenGl_PO_IsPoint) != 0)
2266   {
2267   #if defined(GL_ES_VERSION_2_0)
2268     aSrcVertExtraMain += EOL"  gl_PointSize = occPointSize;";
2269   #endif
2270
2271     if ((theBits & OpenGl_PO_PointSprite) != 0)
2272     {
2273     #if !defined(GL_ES_VERSION_2_0)
2274       if (myContext->core11 != NULL
2275         && myContext->IsGlGreaterEqual (2, 1))
2276       {
2277         aProgramSrc->SetHeader ("#version 120"); // gl_PointCoord has been added since GLSL 1.2
2278       }
2279     #endif
2280
2281       aUniforms.Append (OpenGl_ShaderObject::ShaderVariable ("sampler2D occSamplerPointSprite", Graphic3d_TOS_FRAGMENT));
2282       aSrcFragGetColor = pointSpriteShadingSrc (thePhongCompLight, theBits);
2283     }
2284
2285     if ((theBits & OpenGl_PO_HasTextures) == OpenGl_PO_TextureRGB
2286      && (theBits & OpenGl_PO_VertColor) == 0)
2287     {
2288       aUniforms   .Append (OpenGl_ShaderObject::ShaderVariable ("sampler2D occSamplerBaseColor", Graphic3d_TOS_VERTEX));
2289       aStageInOuts.Append (OpenGl_ShaderObject::ShaderVariable ("vec4 VertColor", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
2290
2291       aSrcVertExtraMain   += EOL"  VertColor = occTexture2D (occSamplerBaseColor, occTexCoord.xy);";
2292       aSrcFragGetVertColor = EOL"vec4 getVertColor(void) { return VertColor; }";
2293     }
2294   }
2295   else
2296   {
2297     if ((theBits & OpenGl_PO_HasTextures) == OpenGl_PO_TextureRGB)
2298     {
2299       aUniforms   .Append (OpenGl_ShaderObject::ShaderVariable ("sampler2D occSamplerBaseColor", Graphic3d_TOS_FRAGMENT));
2300       aStageInOuts.Append (OpenGl_ShaderObject::ShaderVariable ("vec4 TexCoord", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
2301       aSrcVertExtraMain += THE_VARY_TexCoord_Trsf;
2302
2303       aSrcFragGetColor =
2304         EOL"vec4 getColor(void)"
2305         EOL"{"
2306         EOL"  vec4 aColor = " thePhongCompLight ";"
2307         EOL"  return occTexture2D(occSamplerBaseColor, TexCoord.st / TexCoord.w) * aColor;"
2308         EOL"}";
2309     }
2310   }
2311
2312   if ((theBits & OpenGl_PO_VertColor) != 0)
2313   {
2314     aStageInOuts.Append (OpenGl_ShaderObject::ShaderVariable ("vec4 VertColor", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
2315     aSrcVertExtraMain   += EOL"  VertColor = occVertColor;";
2316     aSrcFragGetVertColor = EOL"vec4 getVertColor(void) { return VertColor; }";
2317   }
2318
2319   int aNbClipPlanes = 0;
2320   if ((theBits & OpenGl_PO_ClipPlanesN) != 0)
2321   {
2322     if ((theBits & OpenGl_PO_ClipPlanesN) == OpenGl_PO_ClipPlanesN)
2323     {
2324       aNbClipPlanes = Graphic3d_ShaderProgram::THE_MAX_CLIP_PLANES_DEFAULT;
2325       aSrcFragExtraMain += (theBits & OpenGl_PO_ClipChains) != 0
2326                          ? THE_FRAG_CLIP_CHAINS_N
2327                          : THE_FRAG_CLIP_PLANES_N;
2328     }
2329     else if ((theBits & OpenGl_PO_ClipPlanes1) != 0)
2330     {
2331       aNbClipPlanes = 1;
2332       aSrcFragExtraMain += THE_FRAG_CLIP_PLANES_1;
2333     }
2334     else if ((theBits & OpenGl_PO_ClipPlanes2) != 0)
2335     {
2336       aNbClipPlanes = 2;
2337       aSrcFragExtraMain += (theBits & OpenGl_PO_ClipChains) != 0
2338                          ? THE_FRAG_CLIP_CHAINS_2
2339                          : THE_FRAG_CLIP_PLANES_2;
2340     }
2341   }
2342   if ((theBits & OpenGl_PO_WriteOit) != 0)
2343   {
2344     aProgramSrc->SetNbFragmentOutputs (2);
2345     aProgramSrc->SetWeightOitOutput (true);
2346   }
2347
2348   if (isFlatNormal)
2349   {
2350     aSrcFragExtraOut  += EOL"vec3 Normal;";
2351     aSrcFragExtraMain += TCollection_AsciiString()
2352       + EOL"  Normal = " + aDFdxSignReversion + "normalize (cross (dFdx (Position.xyz / Position.w), dFdy (Position.xyz / Position.w)));"
2353         EOL"  if (!gl_FrontFacing) { Normal = -Normal; }";
2354   }
2355   else
2356   {
2357     aStageInOuts.Append (OpenGl_ShaderObject::ShaderVariable ("vec3 Normal", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
2358     aSrcVertExtraFunc += THE_FUNC_transformNormal;
2359     aSrcVertExtraMain += EOL"  Normal = transformNormal (occNormal);";
2360   }
2361
2362   aStageInOuts.Append (OpenGl_ShaderObject::ShaderVariable ("vec4 PositionWorld", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
2363   aStageInOuts.Append (OpenGl_ShaderObject::ShaderVariable ("vec4 Position",      Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
2364   aStageInOuts.Append (OpenGl_ShaderObject::ShaderVariable ("vec3 View",          Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
2365
2366   aSrcVert = TCollection_AsciiString()
2367     + aSrcVertExtraFunc
2368     + EOL"void main()"
2369       EOL"{"
2370       EOL"  PositionWorld = occModelWorldMatrix * occVertex;"
2371       EOL"  Position      = occWorldViewMatrix * PositionWorld;"
2372     + EOL"  View          = vec3 (0.0, 0.0, 1.0);"
2373     + aSrcVertExtraMain
2374     + THE_VERT_gl_Position
2375     + EOL"}";
2376
2377   TCollection_AsciiString aSrcGeom = prepareGeomMainSrc (aUniforms, aStageInOuts, theBits);
2378   aSrcFragGetColor += (theBits & OpenGl_PO_MeshEdges) != 0
2379     ? THE_FRAG_WIREFRAME_COLOR
2380     : EOL"#define getFinalColor getColor";
2381
2382   Standard_Integer aNbLights = 0;
2383   const TCollection_AsciiString aLights = stdComputeLighting (aNbLights, !aSrcFragGetVertColor.IsEmpty());
2384   aSrcFrag = TCollection_AsciiString()
2385     + EOL
2386     + aSrcFragExtraOut
2387     + aSrcFragGetVertColor
2388     + aLights
2389     + aSrcFragGetColor
2390     + EOL
2391       EOL"void main()"
2392       EOL"{"
2393     + aSrcFragExtraMain
2394     + EOL"  occSetFragColor (getFinalColor());"
2395     + EOL"}";
2396
2397   const TCollection_AsciiString aProgId = TCollection_AsciiString (theIsFlatNormal ? "flat-" : "phong-") + genLightKey (myLightSourceState.LightSources()) + "-";
2398   defaultGlslVersion (aProgramSrc, aProgId, theBits, isFlatNormal);
2399   aProgramSrc->SetDefaultSampler (false);
2400   aProgramSrc->SetNbLightsMax (aNbLights);
2401   aProgramSrc->SetNbClipPlanesMax (aNbClipPlanes);
2402   aProgramSrc->SetAlphaTest ((theBits & OpenGl_PO_AlphaTest) != 0);
2403   const Standard_Integer aNbGeomInputVerts = !aSrcGeom.IsEmpty() ? 3 : 0;
2404   aProgramSrc->AttachShader (OpenGl_ShaderObject::CreateFromSource (aSrcVert, Graphic3d_TOS_VERTEX,   aUniforms, aStageInOuts, "", "", aNbGeomInputVerts));
2405   aProgramSrc->AttachShader (OpenGl_ShaderObject::CreateFromSource (aSrcGeom, Graphic3d_TOS_GEOMETRY, aUniforms, aStageInOuts, "geomIn", "geomOut", aNbGeomInputVerts));
2406   aProgramSrc->AttachShader (OpenGl_ShaderObject::CreateFromSource (aSrcFrag, Graphic3d_TOS_FRAGMENT, aUniforms, aStageInOuts, "", "", aNbGeomInputVerts));
2407   TCollection_AsciiString aKey;
2408   if (!Create (aProgramSrc, aKey, theProgram))
2409   {
2410     theProgram = new OpenGl_ShaderProgram(); // just mark as invalid
2411     return Standard_False;
2412   }
2413   return Standard_True;
2414 }
2415
2416 // =======================================================================
2417 // function : prepareStdProgramStereo
2418 // purpose  :
2419 // =======================================================================
2420 Standard_Boolean OpenGl_ShaderManager::prepareStdProgramStereo (Handle(OpenGl_ShaderProgram)& theProgram,
2421                                                                 const Graphic3d_StereoMode    theStereoMode)
2422 {
2423   Handle(Graphic3d_ShaderProgram) aProgramSrc = new Graphic3d_ShaderProgram();
2424   OpenGl_ShaderObject::ShaderVariableList aUniforms, aStageInOuts;
2425
2426   aStageInOuts.Append (OpenGl_ShaderObject::ShaderVariable ("vec2 TexCoord", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
2427   TCollection_AsciiString aSrcVert =
2428       EOL"void main()"
2429       EOL"{"
2430       EOL"  TexCoord    = occVertex.zw;"
2431       EOL"  gl_Position = vec4(occVertex.x, occVertex.y, 0.0, 1.0);"
2432       EOL"}";
2433
2434   TCollection_AsciiString aSrcFrag;
2435   aUniforms.Append (OpenGl_ShaderObject::ShaderVariable ("sampler2D uLeftSampler",  Graphic3d_TOS_FRAGMENT));
2436   aUniforms.Append (OpenGl_ShaderObject::ShaderVariable ("sampler2D uRightSampler", Graphic3d_TOS_FRAGMENT));
2437   const char* aName = "stereo";
2438   switch (theStereoMode)
2439   {
2440     case Graphic3d_StereoMode_Anaglyph:
2441     {
2442       aName = "anaglyph";
2443       aUniforms.Append (OpenGl_ShaderObject::ShaderVariable ("mat4 uMultL", Graphic3d_TOS_FRAGMENT));
2444       aUniforms.Append (OpenGl_ShaderObject::ShaderVariable ("mat4 uMultR", Graphic3d_TOS_FRAGMENT));
2445       aSrcFrag =
2446           EOL"const vec4 THE_POW_UP   =       vec4 (2.2, 2.2, 2.2, 1.0);"
2447           EOL"const vec4 THE_POW_DOWN = 1.0 / vec4 (2.2, 2.2, 2.2, 1.0);"
2448           EOL
2449           EOL"void main()"
2450           EOL"{"
2451           EOL"  vec4 aColorL = occTexture2D (uLeftSampler,  TexCoord);"
2452           EOL"  vec4 aColorR = occTexture2D (uRightSampler, TexCoord);"
2453           EOL"  aColorL = pow (aColorL, THE_POW_UP);" // normalize
2454           EOL"  aColorR = pow (aColorR, THE_POW_UP);"
2455           EOL"  vec4 aColor = uMultR * aColorR + uMultL * aColorL;"
2456           EOL"  occSetFragColor (pow (aColor, THE_POW_DOWN));"
2457           EOL"}";
2458       break;
2459     }
2460     case Graphic3d_StereoMode_RowInterlaced:
2461     {
2462       aName = "row-interlaced";
2463       aSrcFrag =
2464           EOL"void main()"
2465           EOL"{"
2466           EOL"  vec4 aColorL = occTexture2D (uLeftSampler,  TexCoord);"
2467           EOL"  vec4 aColorR = occTexture2D (uRightSampler, TexCoord);"
2468           EOL"  if (int (mod (gl_FragCoord.y - 1023.5, 2.0)) != 1)"
2469           EOL"  {"
2470           EOL"    occSetFragColor (aColorL);"
2471           EOL"  }"
2472           EOL"  else"
2473           EOL"  {"
2474           EOL"    occSetFragColor (aColorR);"
2475           EOL"  }"
2476           EOL"}";
2477       break;
2478     }
2479     case Graphic3d_StereoMode_ColumnInterlaced:
2480     {
2481       aName = "column-interlaced";
2482       aSrcFrag =
2483           EOL"void main()"
2484           EOL"{"
2485           EOL"  vec4 aColorL = occTexture2D (uLeftSampler,  TexCoord);"
2486           EOL"  vec4 aColorR = occTexture2D (uRightSampler, TexCoord);"
2487           EOL"  if (int (mod (gl_FragCoord.x - 1023.5, 2.0)) == 1)"
2488           EOL"  {"
2489           EOL"    occSetFragColor (aColorL);"
2490           EOL"  }"
2491           EOL"  else"
2492           EOL"  {"
2493           EOL"    occSetFragColor (aColorR);"
2494           EOL"  }"
2495           EOL"}";
2496       break;
2497     }
2498     case Graphic3d_StereoMode_ChessBoard:
2499     {
2500       aName = "chessboard";
2501       aSrcFrag =
2502           EOL"void main()"
2503           EOL"{"
2504           EOL"  vec4 aColorL = occTexture2D (uLeftSampler,  TexCoord);"
2505           EOL"  vec4 aColorR = occTexture2D (uRightSampler, TexCoord);"
2506           EOL"  bool isEvenX = int(mod(floor(gl_FragCoord.x - 1023.5), 2.0)) != 1;"
2507           EOL"  bool isEvenY = int(mod(floor(gl_FragCoord.y - 1023.5), 2.0)) == 1;"
2508           EOL"  if ((isEvenX && isEvenY) || (!isEvenX && !isEvenY))"
2509           EOL"  {"
2510           EOL"    occSetFragColor (aColorL);"
2511           EOL"  }"
2512           EOL"  else"
2513           EOL"  {"
2514           EOL"    occSetFragColor (aColorR);"
2515           EOL"  }"
2516           EOL"}";
2517       break;
2518     }
2519     case Graphic3d_StereoMode_SideBySide:
2520     {
2521       aName = "sidebyside";
2522       aSrcFrag =
2523           EOL"void main()"
2524           EOL"{"
2525           EOL"  vec2 aTexCoord = vec2 (TexCoord.x * 2.0, TexCoord.y);"
2526           EOL"  if (TexCoord.x > 0.5)"
2527           EOL"  {"
2528           EOL"    aTexCoord.x -= 1.0;"
2529           EOL"  }"
2530           EOL"  vec4 aColorL = occTexture2D (uLeftSampler,  aTexCoord);"
2531           EOL"  vec4 aColorR = occTexture2D (uRightSampler, aTexCoord);"
2532           EOL"  if (TexCoord.x <= 0.5)"
2533           EOL"  {"
2534           EOL"    occSetFragColor (aColorL);"
2535           EOL"  }"
2536           EOL"  else"
2537           EOL"  {"
2538           EOL"    occSetFragColor (aColorR);"
2539           EOL"  }"
2540           EOL"}";
2541       break;
2542     }
2543     case Graphic3d_StereoMode_OverUnder:
2544     {
2545       aName = "overunder";
2546       aSrcFrag =
2547           EOL"void main()"
2548           EOL"{"
2549           EOL"  vec2 aTexCoord = vec2 (TexCoord.x, TexCoord.y * 2.0);"
2550           EOL"  if (TexCoord.y > 0.5)"
2551           EOL"  {"
2552           EOL"    aTexCoord.y -= 1.0;"
2553           EOL"  }"
2554           EOL"  vec4 aColorL = occTexture2D (uLeftSampler,  aTexCoord);"
2555           EOL"  vec4 aColorR = occTexture2D (uRightSampler, aTexCoord);"
2556           EOL"  if (TexCoord.y <= 0.5)"
2557           EOL"  {"
2558           EOL"    occSetFragColor (aColorL);"
2559           EOL"  }"
2560           EOL"  else"
2561           EOL"  {"
2562           EOL"    occSetFragColor (aColorR);"
2563           EOL"  }"
2564           EOL"}";
2565       break;
2566     }
2567     case Graphic3d_StereoMode_QuadBuffer:
2568     case Graphic3d_StereoMode_SoftPageFlip:
2569     default:
2570     {
2571       /*const Handle(OpenGl_ShaderProgram)& aProgram = myStereoPrograms[Graphic3d_StereoMode_QuadBuffer];
2572       if (!aProgram.IsNull())
2573       {
2574         return aProgram->IsValid();
2575       }*/
2576       aSrcFrag =
2577           EOL"void main()"
2578           EOL"{"
2579           EOL"  vec4 aColorL = occTexture2D (uLeftSampler,  TexCoord);"
2580           EOL"  vec4 aColorR = occTexture2D (uRightSampler, TexCoord);"
2581           EOL"  aColorL.b = 0.0;"
2582           EOL"  aColorL.g = 0.0;"
2583           EOL"  aColorR.r = 0.0;"
2584           EOL"  occSetFragColor (aColorL + aColorR);"
2585           EOL"}";
2586       break;
2587     }
2588   }
2589
2590   defaultGlslVersion (aProgramSrc, aName, 0);
2591   aProgramSrc->SetDefaultSampler (false);
2592   aProgramSrc->SetNbLightsMax (0);
2593   aProgramSrc->SetNbClipPlanesMax (0);
2594   aProgramSrc->AttachShader (OpenGl_ShaderObject::CreateFromSource (aSrcVert, Graphic3d_TOS_VERTEX,   aUniforms, aStageInOuts));
2595   aProgramSrc->AttachShader (OpenGl_ShaderObject::CreateFromSource (aSrcFrag, Graphic3d_TOS_FRAGMENT, aUniforms, aStageInOuts));
2596   TCollection_AsciiString aKey;
2597   if (!Create (aProgramSrc, aKey, theProgram))
2598   {
2599     theProgram = new OpenGl_ShaderProgram(); // just mark as invalid
2600     return Standard_False;
2601   }
2602
2603   myContext->BindProgram (theProgram);
2604   theProgram->SetSampler (myContext, "uLeftSampler",  Graphic3d_TextureUnit_0);
2605   theProgram->SetSampler (myContext, "uRightSampler", Graphic3d_TextureUnit_1);
2606   myContext->BindProgram (NULL);
2607   return Standard_True;
2608 }
2609
2610 // =======================================================================
2611 // function : prepareStdProgramBoundBox
2612 // purpose  :
2613 // =======================================================================
2614 Standard_Boolean OpenGl_ShaderManager::prepareStdProgramBoundBox()
2615 {
2616   Handle(Graphic3d_ShaderProgram) aProgramSrc = new Graphic3d_ShaderProgram();
2617
2618   OpenGl_ShaderObject::ShaderVariableList aUniforms, aStageInOuts;
2619   aUniforms.Append (OpenGl_ShaderObject::ShaderVariable ("vec3 occBBoxCenter", Graphic3d_TOS_VERTEX));
2620   aUniforms.Append (OpenGl_ShaderObject::ShaderVariable ("vec3 occBBoxSize",   Graphic3d_TOS_VERTEX));
2621
2622   TCollection_AsciiString aSrcVert =
2623     EOL"void main()"
2624     EOL"{"
2625     EOL"  vec4 aCenter = vec4(occVertex.xyz * occBBoxSize + occBBoxCenter, 1.0);"
2626     EOL"  vec4 aPos    = vec4(occVertex.xyz * occBBoxSize + occBBoxCenter, 1.0);"
2627     EOL"  gl_Position = occProjectionMatrix * occWorldViewMatrix * occModelWorldMatrix * aPos;"
2628     EOL"}";
2629
2630   TCollection_AsciiString aSrcFrag =
2631     EOL"void main()"
2632     EOL"{"
2633     EOL"  occSetFragColor (occColor);"
2634     EOL"}";
2635
2636   defaultGlslVersion (aProgramSrc, "bndbox", 0);
2637   aProgramSrc->SetDefaultSampler (false);
2638   aProgramSrc->SetNbLightsMax (0);
2639   aProgramSrc->SetNbClipPlanesMax (0);
2640   aProgramSrc->AttachShader (OpenGl_ShaderObject::CreateFromSource (aSrcVert, Graphic3d_TOS_VERTEX,   aUniforms, aStageInOuts));
2641   aProgramSrc->AttachShader (OpenGl_ShaderObject::CreateFromSource (aSrcFrag, Graphic3d_TOS_FRAGMENT, aUniforms, aStageInOuts));
2642   TCollection_AsciiString aKey;
2643   if (!Create (aProgramSrc, aKey, myBoundBoxProgram))
2644   {
2645     myBoundBoxProgram = new OpenGl_ShaderProgram(); // just mark as invalid
2646     return Standard_False;
2647   }
2648
2649   const OpenGl_Vec4 aMin (-0.5f, -0.5f, -0.5f, 1.0f);
2650   const OpenGl_Vec4 anAxisShifts[3] =
2651   {
2652     OpenGl_Vec4 (1.0f, 0.0f, 0.0f, 0.0f),
2653     OpenGl_Vec4 (0.0f, 1.0f, 0.0f, 0.0f),
2654     OpenGl_Vec4 (0.0f, 0.0f, 1.0f, 0.0f)
2655   };
2656
2657   const OpenGl_Vec4 aLookup1 (0.0f, 1.0f, 0.0f, 1.0f);
2658   const OpenGl_Vec4 aLookup2 (0.0f, 0.0f, 1.0f, 1.0f);
2659   OpenGl_Vec4 aLinesVertices[24];
2660   for (int anAxis = 0, aVertex = 0; anAxis < 3; ++anAxis)
2661   {
2662     for (int aCompIter = 0; aCompIter < 4; ++aCompIter)
2663     {
2664       aLinesVertices[aVertex++] = aMin
2665         + anAxisShifts[(anAxis + 1) % 3] * aLookup1[aCompIter]
2666         + anAxisShifts[(anAxis + 2) % 3] * aLookup2[aCompIter];
2667
2668       aLinesVertices[aVertex++] = aMin
2669         + anAxisShifts[anAxis]
2670         + anAxisShifts[(anAxis + 1) % 3] * aLookup1[aCompIter]
2671         + anAxisShifts[(anAxis + 2) % 3] * aLookup2[aCompIter];
2672     }
2673   }
2674   if (myContext->ToUseVbo())
2675   {
2676     myBoundBoxVertBuffer = new OpenGl_VertexBuffer();
2677     if (myBoundBoxVertBuffer->Init (myContext, 4, 24, aLinesVertices[0].GetData()))
2678     {
2679       myContext->ShareResource ("OpenGl_ShaderManager_BndBoxVbo", myBoundBoxVertBuffer);
2680       return Standard_True;
2681     }
2682   }
2683   myBoundBoxVertBuffer = new OpenGl_VertexBufferCompat();
2684   myBoundBoxVertBuffer->Init (myContext, 4, 24, aLinesVertices[0].GetData());
2685   myContext->ShareResource ("OpenGl_ShaderManager_BndBoxVbo", myBoundBoxVertBuffer);
2686   return Standard_True;
2687 }
2688
2689 // =======================================================================
2690 // function : bindProgramWithState
2691 // purpose  :
2692 // =======================================================================
2693 Standard_Boolean OpenGl_ShaderManager::bindProgramWithState (const Handle(OpenGl_ShaderProgram)& theProgram)
2694 {
2695   const Standard_Boolean isBound = myContext->BindProgram (theProgram);
2696   if (isBound
2697   && !theProgram.IsNull())
2698   {
2699     theProgram->ApplyVariables (myContext);
2700   }
2701   PushState (theProgram);
2702   return isBound;
2703 }
2704
2705 // =======================================================================
2706 // function : BindMarkerProgram
2707 // purpose  :
2708 // =======================================================================
2709 Standard_Boolean OpenGl_ShaderManager::BindMarkerProgram (const Handle(OpenGl_TextureSet)& theTextures,
2710                                                           Graphic3d_TypeOfShadingModel theShadingModel,
2711                                                           Graphic3d_AlphaMode theAlphaMode,
2712                                                           Standard_Boolean theHasVertColor,
2713                                                           const Handle(OpenGl_ShaderProgram)& theCustomProgram)
2714 {
2715   if (!theCustomProgram.IsNull()
2716     || myContext->caps->ffpEnable)
2717   {
2718     return bindProgramWithState (theCustomProgram);
2719   }
2720
2721   Standard_Integer aBits = getProgramBits (theTextures, theAlphaMode, Aspect_IS_SOLID, theHasVertColor, false, false);
2722   if (!theTextures.IsNull()
2723     && theTextures->HasPointSprite())
2724   {
2725     aBits |= theTextures->Last()->IsAlpha() ? OpenGl_PO_PointSpriteA : OpenGl_PO_PointSprite;
2726   }
2727   else
2728   {
2729     aBits |= OpenGl_PO_PointSimple;
2730   }
2731   Handle(OpenGl_ShaderProgram)& aProgram = getStdProgram (theShadingModel, aBits);
2732   return bindProgramWithState (aProgram);
2733 }