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