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