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