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