0027787: Visualization, TKOpenGl - Optimize rendering by additional check whether...
[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 * occModelWorldMatrix * 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 * occModelWorldMatrix * vec4 (aLight,   1.0));"
125   EOL"    aSpotDir = vec3 (occWorldViewMatrix * occModelWorldMatrix * 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 * occModelWorldMatrix * 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 * occModelWorldMatrix * 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 }
253
254 // =======================================================================
255 // function : OpenGl_ShaderManager
256 // purpose  : Creates new empty shader manager
257 // =======================================================================
258 OpenGl_ShaderManager::OpenGl_ShaderManager (OpenGl_Context* theContext)
259 : myShadingModel (Graphic3d_TOSM_VERTEX),
260   myContext  (theContext),
261   myLastView (NULL)
262 {
263   //
264 }
265
266 // =======================================================================
267 // function : ~OpenGl_ShaderManager
268 // purpose  : Releases resources of shader manager
269 // =======================================================================
270 OpenGl_ShaderManager::~OpenGl_ShaderManager()
271 {
272   myProgramList.Clear();
273 }
274
275 // =======================================================================
276 // function : clear
277 // purpose  :
278 // =======================================================================
279 void OpenGl_ShaderManager::clear()
280 {
281   myProgramList.Clear();
282   myLightPrograms.Nullify();
283   myFlatPrograms = OpenGl_SetOfShaderPrograms();
284   myMapOfLightPrograms.Clear();
285   myFontProgram.Nullify();
286   myBlitProgram.Nullify();
287   for (Standard_Integer aModeIter = 0; aModeIter < Graphic3d_StereoMode_NB; ++aModeIter)
288   {
289     myStereoPrograms[aModeIter].Nullify();
290   }
291   switchLightPrograms();
292 }
293
294 // =======================================================================
295 // function : Create
296 // purpose  : Creates new shader program
297 // =======================================================================
298 Standard_Boolean OpenGl_ShaderManager::Create (const Handle(Graphic3d_ShaderProgram)& theProxy,
299                                                TCollection_AsciiString&               theShareKey,
300                                                Handle(OpenGl_ShaderProgram)&          theProgram)
301 {
302   theProgram.Nullify();
303   if (theProxy.IsNull())
304   {
305     return Standard_False;
306   }
307
308   theShareKey = theProxy->GetId();
309   if (myContext->GetResource<Handle(OpenGl_ShaderProgram)> (theShareKey, theProgram))
310   {
311     if (theProgram->Share())
312     {
313       myProgramList.Append (theProgram);
314     }
315     return Standard_True;
316   }
317
318   theProgram = new OpenGl_ShaderProgram (theProxy);
319   if (!theProgram->Initialize (myContext, theProxy->ShaderObjects()))
320   {
321     theProgram->Release (myContext);
322     theShareKey.Clear();
323     theProgram.Nullify();
324     return Standard_False;
325   }
326
327   myProgramList.Append (theProgram);
328   myContext->ShareResource (theShareKey, theProgram);
329   return Standard_True;
330 }
331
332 // =======================================================================
333 // function : Unregister
334 // purpose  : Removes specified shader program from the manager
335 // =======================================================================
336 void OpenGl_ShaderManager::Unregister (TCollection_AsciiString&      theShareKey,
337                                        Handle(OpenGl_ShaderProgram)& theProgram)
338 {
339   for (OpenGl_ShaderProgramList::Iterator anIt (myProgramList); anIt.More(); anIt.Next())
340   {
341     if (anIt.Value() == theProgram)
342     {
343       if (!theProgram->UnShare())
344       {
345         theShareKey.Clear();
346         theProgram.Nullify();
347         return;
348       }
349
350       myProgramList.Remove (anIt);
351       break;
352     }
353   }
354
355   const TCollection_AsciiString anID = theProgram->myProxy->GetId();
356   if (anID.IsEmpty())
357   {
358     myContext->DelayedRelease (theProgram);
359     theProgram.Nullify();
360   }
361   else
362   {
363     theProgram.Nullify();
364     myContext->ReleaseResource (anID, Standard_True);
365   }
366 }
367
368 // =======================================================================
369 // function : ShaderPrograms
370 // purpose  : Returns list of registered shader programs
371 // =======================================================================
372 const OpenGl_ShaderProgramList& OpenGl_ShaderManager::ShaderPrograms() const
373 {
374   return myProgramList;
375 }
376
377 // =======================================================================
378 // function : Empty
379 // purpose  : Returns true if no program objects are attached
380 // =======================================================================
381 Standard_Boolean OpenGl_ShaderManager::IsEmpty() const
382 {
383   return myProgramList.IsEmpty();
384 }
385
386 // =======================================================================
387 // function : switchLightPrograms
388 // purpose  :
389 // =======================================================================
390 void OpenGl_ShaderManager::switchLightPrograms()
391 {
392   TCollection_AsciiString aKey (myShadingModel == Graphic3d_TOSM_FRAGMENT ? "p_" : "g_");
393   const OpenGl_ListOfLight* aLights = myLightSourceState.LightSources();
394   if (aLights != NULL)
395   {
396     for (OpenGl_ListOfLight::Iterator aLightIter (*aLights); aLightIter.More(); aLightIter.Next())
397     {
398       switch (aLightIter.Value().Type)
399       {
400         case Graphic3d_TOLS_AMBIENT:
401           break; // skip ambient
402         case Graphic3d_TOLS_DIRECTIONAL:
403           aKey += "d";
404           break;
405         case Graphic3d_TOLS_POSITIONAL:
406           aKey += "p";
407           break;
408         case Graphic3d_TOLS_SPOT:
409           aKey += "s";
410           break;
411       }
412     }
413   }
414
415   if (!myMapOfLightPrograms.Find (aKey, myLightPrograms))
416   {
417     myLightPrograms = new OpenGl_SetOfShaderPrograms();
418     myMapOfLightPrograms.Bind (aKey, myLightPrograms);
419   }
420 }
421
422 // =======================================================================
423 // function : UpdateLightSourceStateTo
424 // purpose  : Updates state of OCCT light sources
425 // =======================================================================
426 void OpenGl_ShaderManager::UpdateLightSourceStateTo (const OpenGl_ListOfLight* theLights)
427 {
428   myLightSourceState.Set (theLights);
429   myLightSourceState.Update();
430   switchLightPrograms();
431 }
432
433 // =======================================================================
434 // function : SetShadingModel
435 // purpose  :
436 // =======================================================================
437 void OpenGl_ShaderManager::SetShadingModel (const Graphic3d_TypeOfShadingModel theModel)
438 {
439   myShadingModel = theModel;
440   switchLightPrograms();
441 }
442
443 // =======================================================================
444 // function : SetProjectionState
445 // purpose  : Sets new state of OCCT projection transform
446 // =======================================================================
447 void OpenGl_ShaderManager::UpdateProjectionStateTo (const OpenGl_Mat4& theProjectionMatrix)
448 {
449   myProjectionState.Set (theProjectionMatrix);
450   myProjectionState.Update();
451 }
452
453 // =======================================================================
454 // function : SetModelWorldState
455 // purpose  : Sets new state of OCCT model-world transform
456 // =======================================================================
457 void OpenGl_ShaderManager::UpdateModelWorldStateTo (const OpenGl_Mat4& theModelWorldMatrix)
458 {
459   myModelWorldState.Set (theModelWorldMatrix);
460   myModelWorldState.Update();
461 }
462
463 // =======================================================================
464 // function : SetWorldViewState
465 // purpose  : Sets new state of OCCT world-view transform
466 // =======================================================================
467 void OpenGl_ShaderManager::UpdateWorldViewStateTo (const OpenGl_Mat4& theWorldViewMatrix)
468 {
469   myWorldViewState.Set (theWorldViewMatrix);
470   myWorldViewState.Update();
471 }
472
473 // =======================================================================
474 // function : LightSourceState
475 // purpose  : Returns current state of OCCT light sources
476 // =======================================================================
477 const OpenGl_LightSourceState& OpenGl_ShaderManager::LightSourceState() const
478 {
479   return myLightSourceState;
480 }
481
482 // =======================================================================
483 // function : ProjectionState
484 // purpose  : Returns current state of OCCT projection transform
485 // =======================================================================
486 const OpenGl_ProjectionState& OpenGl_ShaderManager::ProjectionState() const
487 {
488   return myProjectionState;
489 }
490
491 // =======================================================================
492 // function : ModelWorldState
493 // purpose  : Returns current state of OCCT model-world transform
494 // =======================================================================
495 const OpenGl_ModelWorldState& OpenGl_ShaderManager::ModelWorldState() const
496 {
497   return myModelWorldState;
498 }
499
500 // =======================================================================
501 // function : WorldViewState
502 // purpose  : Returns current state of OCCT world-view transform
503 // =======================================================================
504 const OpenGl_WorldViewState& OpenGl_ShaderManager::WorldViewState() const
505 {
506   return myWorldViewState;
507 }
508
509 //! Packed properties of light source
510 class OpenGl_ShaderLightParameters
511 {
512 public:
513
514   OpenGl_Vec4 Color;
515   OpenGl_Vec4 Position;
516   OpenGl_Vec4 Direction;
517   OpenGl_Vec4 Parameters;
518
519   //! Returns packed (serialized) representation of light source properties
520   const OpenGl_Vec4* Packed() const { return reinterpret_cast<const OpenGl_Vec4*> (this); }
521   static Standard_Integer NbOfVec4() { return 4; }
522
523 };
524
525 //! Packed light source type information
526 class OpenGl_ShaderLightType
527 {
528 public:
529
530   Standard_Integer Type;
531   Standard_Integer IsHeadlight;
532
533   //! Returns packed (serialized) representation of light source type
534   const OpenGl_Vec2i* Packed() const { return reinterpret_cast<const OpenGl_Vec2i*> (this); }
535   static Standard_Integer NbOfVec2i() { return 1; }
536
537 };
538
539 // =======================================================================
540 // function : PushLightSourceState
541 // purpose  : Pushes state of OCCT light sources to the program
542 // =======================================================================
543 void OpenGl_ShaderManager::PushLightSourceState (const Handle(OpenGl_ShaderProgram)& theProgram) const
544 {
545   if (myLightSourceState.Index() == theProgram->ActiveState (OpenGl_LIGHT_SOURCES_STATE)
546    || !theProgram->IsValid())
547   {
548     return;
549   }
550
551   OpenGl_ShaderLightType* aLightTypeArray = new OpenGl_ShaderLightType[OpenGLMaxLights];
552   for (Standard_Integer aLightIt = 0; aLightIt < OpenGLMaxLights; ++aLightIt)
553   {
554     aLightTypeArray[aLightIt].Type = -1;
555   }
556
557   const Standard_Integer aLightsDefNb = Min (myLightSourceState.LightSources()->Size(), OpenGLMaxLights);
558   if (aLightsDefNb < 1)
559   {
560     theProgram->SetUniform (myContext,
561                             theProgram->GetStateLocation (OpenGl_OCC_LIGHT_SOURCE_COUNT),
562                             0);
563     theProgram->SetUniform (myContext,
564                             theProgram->GetStateLocation (OpenGl_OCC_LIGHT_AMBIENT),
565                             OpenGl_Vec4 (0.0f, 0.0f, 0.0f, 0.0f));
566     theProgram->SetUniform (myContext,
567                             theProgram->GetStateLocation (OpenGl_OCC_LIGHT_SOURCE_TYPES),
568                             OpenGLMaxLights * OpenGl_ShaderLightType::NbOfVec2i(),
569                             aLightTypeArray[0].Packed());
570     theProgram->UpdateState (OpenGl_LIGHT_SOURCES_STATE, myLightSourceState.Index());
571     delete[] aLightTypeArray;
572     return;
573   }
574
575   OpenGl_ShaderLightParameters* aLightParamsArray = new OpenGl_ShaderLightParameters[aLightsDefNb];
576
577   OpenGl_Vec4 anAmbient (0.0f, 0.0f, 0.0f, 0.0f);
578   Standard_Integer aLightsNb = 0;
579   for (OpenGl_ListOfLight::Iterator anIter (*myLightSourceState.LightSources()); anIter.More(); anIter.Next())
580   {
581     const OpenGl_Light& aLight = anIter.Value();
582     if (aLight.Type == Graphic3d_TOLS_AMBIENT)
583     {
584       anAmbient += aLight.Color;
585       continue;
586     }
587     else if (aLightsNb >= OpenGLMaxLights)
588     {
589       continue;
590     }
591
592     OpenGl_ShaderLightType& aLightType = aLightTypeArray[aLightsNb];
593     aLightType.Type        = aLight.Type;
594     aLightType.IsHeadlight = aLight.IsHeadlight;
595
596     OpenGl_ShaderLightParameters& aLightParams = aLightParamsArray[aLightsNb];
597     aLightParams.Color    = aLight.Color;
598     aLightParams.Position = aLight.Type == Graphic3d_TOLS_DIRECTIONAL
599                          ? -aLight.Direction
600                          :  aLight.Position;
601     if (aLight.Type == Graphic3d_TOLS_SPOT)
602     {
603       aLightParams.Direction = aLight.Direction;
604     }
605     aLightParams.Parameters = aLight.Params;
606     ++aLightsNb;
607   }
608
609   theProgram->SetUniform (myContext,
610                           theProgram->GetStateLocation (OpenGl_OCC_LIGHT_SOURCE_COUNT),
611                           aLightsNb);
612   theProgram->SetUniform (myContext,
613                           theProgram->GetStateLocation (OpenGl_OCC_LIGHT_AMBIENT),
614                           anAmbient);
615   theProgram->SetUniform (myContext,
616                           theProgram->GetStateLocation (OpenGl_OCC_LIGHT_SOURCE_TYPES),
617                           OpenGLMaxLights * OpenGl_ShaderLightType::NbOfVec2i(),
618                           aLightTypeArray[0].Packed());
619   if (aLightsNb > 0)
620   {
621     theProgram->SetUniform (myContext,
622                             theProgram->GetStateLocation (OpenGl_OCC_LIGHT_SOURCE_PARAMS),
623                             aLightsNb * OpenGl_ShaderLightParameters::NbOfVec4(),
624                             aLightParamsArray[0].Packed());
625   }
626   delete[] aLightParamsArray;
627   delete[] aLightTypeArray;
628
629   theProgram->UpdateState (OpenGl_LIGHT_SOURCES_STATE, myLightSourceState.Index());
630 }
631
632 // =======================================================================
633 // function : PushProjectionState
634 // purpose  : Pushes state of OCCT projection transform to the program
635 // =======================================================================
636 void OpenGl_ShaderManager::PushProjectionState (const Handle(OpenGl_ShaderProgram)& theProgram) const
637 {
638   if (myProjectionState.Index() == theProgram->ActiveState (OpenGl_PROJECTION_STATE))
639   {
640     return;
641   }
642
643   theProgram->SetUniform (myContext,
644                           theProgram->GetStateLocation (OpenGl_OCC_PROJECTION_MATRIX),
645                           myProjectionState.ProjectionMatrix());
646
647   GLint aLocation = theProgram->GetStateLocation (OpenGl_OCC_PROJECTION_MATRIX_INVERSE);
648   if (aLocation != OpenGl_ShaderProgram::INVALID_LOCATION)
649   {
650     theProgram->SetUniform (myContext, aLocation, myProjectionState.ProjectionMatrixInverse());
651   }
652
653   theProgram->SetUniform (myContext,
654                           theProgram->GetStateLocation (OpenGl_OCC_PROJECTION_MATRIX_TRANSPOSE),
655                           myProjectionState.ProjectionMatrix(), true);
656
657   aLocation = theProgram->GetStateLocation (OpenGl_OCC_PROJECTION_MATRIX_INVERSE_TRANSPOSE);
658   if (aLocation != OpenGl_ShaderProgram::INVALID_LOCATION)
659   {
660     theProgram->SetUniform (myContext, aLocation, myProjectionState.ProjectionMatrixInverse(), true);
661   }
662
663   theProgram->UpdateState (OpenGl_PROJECTION_STATE, myProjectionState.Index());
664 }
665
666 // =======================================================================
667 // function : PushModelWorldState
668 // purpose  : Pushes state of OCCT model-world transform to the program
669 // =======================================================================
670 void OpenGl_ShaderManager::PushModelWorldState (const Handle(OpenGl_ShaderProgram)& theProgram) const
671 {
672   if (myModelWorldState.Index() == theProgram->ActiveState (OpenGl_MODEL_WORLD_STATE))
673   {
674     return;
675   }
676
677   theProgram->SetUniform (myContext,
678                           theProgram->GetStateLocation (OpenGl_OCC_MODEL_WORLD_MATRIX),
679                           myModelWorldState.ModelWorldMatrix());
680
681   GLint aLocation = theProgram->GetStateLocation (OpenGl_OCC_MODEL_WORLD_MATRIX_INVERSE);
682   if (aLocation != OpenGl_ShaderProgram::INVALID_LOCATION)
683   {
684     theProgram->SetUniform (myContext, aLocation, myModelWorldState.ModelWorldMatrixInverse());
685   }
686
687   theProgram->SetUniform (myContext,
688                           theProgram->GetStateLocation (OpenGl_OCC_MODEL_WORLD_MATRIX_TRANSPOSE),
689                           myModelWorldState.ModelWorldMatrix(), true);
690
691   aLocation = theProgram->GetStateLocation (OpenGl_OCC_MODEL_WORLD_MATRIX_INVERSE_TRANSPOSE);
692   if (aLocation != OpenGl_ShaderProgram::INVALID_LOCATION)
693   {
694     theProgram->SetUniform (myContext, aLocation, myModelWorldState.ModelWorldMatrixInverse(), true);
695   }
696
697   theProgram->UpdateState (OpenGl_MODEL_WORLD_STATE, myModelWorldState.Index());
698 }
699
700 // =======================================================================
701 // function : PushWorldViewState
702 // purpose  : Pushes state of OCCT world-view transform to the program
703 // =======================================================================
704 void OpenGl_ShaderManager::PushWorldViewState (const Handle(OpenGl_ShaderProgram)& theProgram) const
705 {
706   if (myWorldViewState.Index() == theProgram->ActiveState (OpenGl_WORLD_VIEW_STATE))
707   {
708     return;
709   }
710
711   theProgram->SetUniform (myContext,
712                           theProgram->GetStateLocation (OpenGl_OCC_WORLD_VIEW_MATRIX),
713                           myWorldViewState.WorldViewMatrix());
714
715   GLint aLocation = theProgram->GetStateLocation (OpenGl_OCC_WORLD_VIEW_MATRIX_INVERSE);
716   if (aLocation != OpenGl_ShaderProgram::INVALID_LOCATION)
717   {
718     theProgram->SetUniform (myContext, aLocation, myWorldViewState.WorldViewMatrixInverse());
719   }
720
721   theProgram->SetUniform (myContext,
722                           theProgram->GetStateLocation (OpenGl_OCC_WORLD_VIEW_MATRIX_TRANSPOSE),
723                           myWorldViewState.WorldViewMatrix(), true);
724
725   aLocation = theProgram->GetStateLocation (OpenGl_OCC_WORLD_VIEW_MATRIX_INVERSE_TRANSPOSE);
726   if (aLocation != OpenGl_ShaderProgram::INVALID_LOCATION)
727   {
728     theProgram->SetUniform (myContext, aLocation, myWorldViewState.WorldViewMatrixInverse(), true);
729   }
730
731   theProgram->UpdateState (OpenGl_WORLD_VIEW_STATE, myWorldViewState.Index());
732 }
733
734 // =======================================================================
735 // function : UpdateClippingState
736 // purpose  : Updates state of OCCT clipping planes
737 // =======================================================================
738 void OpenGl_ShaderManager::UpdateClippingState()
739 {
740   myClippingState.Update();
741 }
742
743 // =======================================================================
744 // function : RevertClippingState
745 // purpose  : Reverts state of OCCT clipping planes
746 // =======================================================================
747 void OpenGl_ShaderManager::RevertClippingState()
748 {
749   myClippingState.Revert();
750 }
751
752 // =======================================================================
753 // function : PushClippingState
754 // purpose  : Pushes state of OCCT clipping planes to the program
755 // =======================================================================
756 void OpenGl_ShaderManager::PushClippingState (const Handle(OpenGl_ShaderProgram)& theProgram) const
757 {
758   if (myClippingState.Index() == theProgram->ActiveState (OpenGl_CLIP_PLANES_STATE))
759   {
760     return;
761   }
762
763   theProgram->UpdateState (OpenGl_CLIP_PLANES_STATE, myClippingState.Index());
764   const GLint aLocEquations = theProgram->GetStateLocation (OpenGl_OCC_CLIP_PLANE_EQUATIONS);
765   if (aLocEquations == OpenGl_ShaderProgram::INVALID_LOCATION)
766   {
767     return;
768   }
769
770   GLint aPlanesNb = 0;
771   for (Graphic3d_SequenceOfHClipPlane::Iterator anIter (myContext->Clipping().Planes());
772        anIter.More(); anIter.Next())
773   {
774     const Handle(Graphic3d_ClipPlane)& aPlane = anIter.Value();
775     if (!myContext->Clipping().IsEnabled (aPlane))
776     {
777       continue;
778     }
779
780     ++aPlanesNb;
781   }
782   if (aPlanesNb < 1)
783   {
784     return;
785   }
786
787   OpenGl_Vec4 anEquations[THE_MAX_CLIP_PLANES];
788   GLuint aPlaneId = 0;
789   for (Graphic3d_SequenceOfHClipPlane::Iterator anIter (myContext->Clipping().Planes());
790        anIter.More(); anIter.Next())
791   {
792     const Handle(Graphic3d_ClipPlane)& aPlane = anIter.Value();
793     if (!myContext->Clipping().IsEnabled (aPlane))
794     {
795       continue;
796     }
797     else if (aPlaneId >= THE_MAX_CLIP_PLANES)
798     {
799       myContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION,
800         GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_MEDIUM,
801         "Warning: clipping planes limit (8) has been exceeded.");
802       break;
803     }
804
805     const Graphic3d_ClipPlane::Equation& anEquation = aPlane->GetEquation();
806     anEquations[aPlaneId] = OpenGl_Vec4 ((float) anEquation.x(),
807                                          (float) anEquation.y(),
808                                          (float) anEquation.z(),
809                                          (float) anEquation.w());
810     ++aPlaneId;
811   }
812
813   theProgram->SetUniform (myContext,
814                           theProgram->GetStateLocation (OpenGl_OCC_CLIP_PLANE_COUNT),
815                           aPlanesNb);
816   theProgram->SetUniform (myContext, aLocEquations, THE_MAX_CLIP_PLANES, anEquations);
817 }
818
819 // =======================================================================
820 // function : PushState
821 // purpose  : Pushes state of OCCT graphics parameters to the program
822 // =======================================================================
823 void OpenGl_ShaderManager::PushState (const Handle(OpenGl_ShaderProgram)& theProgram) const
824 {
825   PushClippingState    (theProgram);
826   PushWorldViewState   (theProgram);
827   PushModelWorldState  (theProgram);
828   PushProjectionState  (theProgram);
829   PushLightSourceState (theProgram);
830 }
831
832 // =======================================================================
833 // function : prepareStdProgramFont
834 // purpose  :
835 // =======================================================================
836 Standard_Boolean OpenGl_ShaderManager::prepareStdProgramFont()
837 {
838   Handle(Graphic3d_ShaderProgram) aProgramSrc = new Graphic3d_ShaderProgram();
839   TCollection_AsciiString aSrcVert = TCollection_AsciiString()
840      + EOL"THE_SHADER_OUT vec2 TexCoord;"
841        EOL"void main()"
842        EOL"{"
843        EOL"  TexCoord = occTexCoord.st;"
844        EOL"  gl_Position = occProjectionMatrix * occWorldViewMatrix * occModelWorldMatrix * occVertex;"
845        EOL"}";
846
847   TCollection_AsciiString
848     aSrcGetAlpha = EOL"float getAlpha(void) { return occTexture2D(occActiveSampler, TexCoord.st).a; }";
849 #if !defined(GL_ES_VERSION_2_0)
850   if (myContext->core11 == NULL)
851   {
852     aSrcGetAlpha = EOL"float getAlpha(void) { return occTexture2D(occActiveSampler, TexCoord.st).r; }";
853   }
854 #endif
855
856   TCollection_AsciiString aSrcFrag = TCollection_AsciiString() +
857      + EOL"THE_SHADER_IN vec2 TexCoord;"
858      + aSrcGetAlpha
859      + EOL"void main()"
860        EOL"{"
861        EOL"  vec4 aColor = occColor;"
862        EOL"  aColor.a *= getAlpha();"
863        EOL"  if (aColor.a <= 0.285) discard;"
864        EOL"  occFragColor = aColor;"
865        EOL"}";
866
867 #if !defined(GL_ES_VERSION_2_0)
868   if (myContext->core32 != NULL)
869   {
870     aProgramSrc->SetHeader ("#version 150");
871   }
872 #endif
873   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_VERTEX,   aSrcVert));
874   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_FRAGMENT, aSrcFrag));
875   TCollection_AsciiString aKey;
876   if (!Create (aProgramSrc, aKey, myFontProgram))
877   {
878     myFontProgram = new OpenGl_ShaderProgram(); // just mark as invalid
879     return Standard_False;
880   }
881   return Standard_True;
882 }
883
884 // =======================================================================
885 // function : prepareStdProgramFboBlit
886 // purpose  :
887 // =======================================================================
888 Standard_Boolean OpenGl_ShaderManager::prepareStdProgramFboBlit()
889 {
890   Handle(Graphic3d_ShaderProgram) aProgramSrc = new Graphic3d_ShaderProgram();
891   TCollection_AsciiString aSrcVert =
892       EOL"THE_SHADER_OUT vec2 TexCoord;"
893       EOL"void main()"
894       EOL"{"
895       EOL"  TexCoord    = occVertex.zw;"
896       EOL"  gl_Position = vec4(occVertex.x, occVertex.y, 0.0, 1.0);"
897       EOL"}";
898
899   TCollection_AsciiString aSrcFrag =
900       EOL"uniform sampler2D uColorSampler;"
901       EOL"uniform sampler2D uDepthSampler;"
902       EOL
903       EOL"THE_SHADER_IN vec2 TexCoord;"
904       EOL
905       EOL"void main()"
906       EOL"{"
907       EOL"  gl_FragDepth = occTexture2D (uDepthSampler, TexCoord).r;"
908       EOL"  occFragColor = occTexture2D (uColorSampler, TexCoord);"
909       EOL"}";
910
911 #if defined(GL_ES_VERSION_2_0)
912   if (myContext->IsGlGreaterEqual (3, 0))
913   {
914     aProgramSrc->SetHeader ("#version 300 es");
915   }
916   else
917   {
918     // there is no way to draw into depth buffer
919     aSrcFrag =
920       EOL"uniform sampler2D uColorSampler;"
921       EOL
922       EOL"THE_SHADER_IN vec2 TexCoord;"
923       EOL
924       EOL"void main()"
925       EOL"{"
926       EOL"  occFragColor = occTexture2D (uColorSampler, TexCoord);"
927       EOL"}";
928   }
929 #else
930   if (myContext->core32 != NULL)
931   {
932     aProgramSrc->SetHeader ("#version 150");
933   }
934 #endif
935   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_VERTEX,   aSrcVert));
936   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_FRAGMENT, aSrcFrag));
937   TCollection_AsciiString aKey;
938   if (!Create (aProgramSrc, aKey, myBlitProgram))
939   {
940     myBlitProgram = new OpenGl_ShaderProgram(); // just mark as invalid
941     return Standard_False;
942   }
943
944   myContext->BindProgram (myBlitProgram);
945   myBlitProgram->SetSampler (myContext, "uColorSampler", 0);
946   myBlitProgram->SetSampler (myContext, "uDepthSampler", 1);
947   myContext->BindProgram (NULL);
948   return Standard_True;
949 }
950
951 // =======================================================================
952 // function : pointSpriteAlphaSrc
953 // purpose  :
954 // =======================================================================
955 TCollection_AsciiString OpenGl_ShaderManager::pointSpriteAlphaSrc (const Standard_Integer theBits)
956 {
957   TCollection_AsciiString aSrcGetAlpha = EOL"float getAlpha(void) { return occTexture2D(occActiveSampler, " THE_VEC2_glPointCoord ").a; }";
958 #if !defined(GL_ES_VERSION_2_0)
959   if (myContext->core11 == NULL
960    && (theBits & OpenGl_PO_TextureA) != 0)
961   {
962     aSrcGetAlpha = EOL"float getAlpha(void) { return occTexture2D(occActiveSampler, " THE_VEC2_glPointCoord ").r; }";
963   }
964 #else
965   (void )theBits;
966 #endif
967   return aSrcGetAlpha;
968 }
969
970 namespace
971 {
972
973   // =======================================================================
974   // function : textureUsed
975   // purpose  :
976   // =======================================================================
977   static bool textureUsed (const Standard_Integer theBits)
978   {
979     return (theBits & OpenGl_PO_TextureA) != 0 || (theBits & OpenGl_PO_TextureRGB) != 0;
980   }
981
982 }
983
984 // =======================================================================
985 // function : prepareStdProgramFlat
986 // purpose  :
987 // =======================================================================
988 Standard_Boolean OpenGl_ShaderManager::prepareStdProgramFlat (Handle(OpenGl_ShaderProgram)& theProgram,
989                                                               const Standard_Integer        theBits)
990 {
991   Handle(Graphic3d_ShaderProgram) aProgramSrc = new Graphic3d_ShaderProgram();
992   TCollection_AsciiString aSrcVert, aSrcVertExtraOut, aSrcVertExtraMain, aSrcVertExtraFunc, aSrcGetAlpha, aSrcFrag, aSrcFragExtraOut, aSrcFragExtraMain;
993   TCollection_AsciiString aSrcFragGetColor     = EOL"vec4 getColor(void) { return occColor; }";
994   TCollection_AsciiString aSrcFragMainGetColor = EOL"  occFragColor = getColor();";
995   if ((theBits & OpenGl_PO_Point) != 0)
996   {
997   #if defined(GL_ES_VERSION_2_0)
998     aSrcVertExtraMain += EOL"  gl_PointSize = occPointSize;";
999   #endif
1000
1001     if ((theBits & OpenGl_PO_TextureRGB) != 0)
1002     {
1003       aSrcFragGetColor =
1004         EOL"vec4 getColor(void) { return occTexture2D(occActiveSampler, " THE_VEC2_glPointCoord "); }";
1005     }
1006
1007     if (textureUsed (theBits))
1008     {
1009       aSrcGetAlpha = pointSpriteAlphaSrc (theBits);
1010
1011     #if !defined(GL_ES_VERSION_2_0)
1012       if (myContext->core11 != NULL
1013         && myContext->IsGlGreaterEqual (2, 1))
1014       {
1015         aProgramSrc->SetHeader ("#version 120"); // gl_PointCoord has been added since GLSL 1.2
1016       }
1017     #endif
1018
1019       aSrcFragMainGetColor =
1020         EOL"  vec4 aColor = getColor();"
1021         EOL"  aColor.a = getAlpha();"
1022         EOL"  if (aColor.a <= 0.1) discard;"
1023         EOL"  occFragColor = aColor;";
1024     }
1025     else
1026     {
1027       aSrcFragMainGetColor =
1028         EOL"  vec4 aColor = getColor();"
1029         EOL"  if (aColor.a <= 0.1) discard;"
1030         EOL"  occFragColor = aColor;";
1031     }
1032   }
1033   else
1034   {
1035     if ((theBits & OpenGl_PO_TextureRGB) != 0)
1036     {
1037       aSrcVertExtraOut  += THE_VARY_TexCoord_OUT;
1038       aSrcFragExtraOut  += THE_VARY_TexCoord_IN;
1039       aSrcVertExtraMain += THE_VARY_TexCoord_Trsf;
1040
1041       aSrcFragGetColor =
1042         EOL"vec4 getColor(void) { return occTexture2D(occActiveSampler, TexCoord.st / TexCoord.w); }";
1043     }
1044     else if ((theBits & OpenGl_PO_TextureEnv) != 0)
1045     {
1046       aSrcVertExtraOut += THE_VARY_TexCoord_OUT;
1047       aSrcFragExtraOut += THE_VARY_TexCoord_IN;
1048
1049       aSrcVertExtraFunc = THE_FUNC_transformNormal;
1050
1051       aSrcVertExtraMain +=
1052         EOL"  vec4 aPosition = occWorldViewMatrix * occModelWorldMatrix * occVertex;"
1053         EOL"  vec3 aNormal   = transformNormal (occNormal);"
1054         EOL"  vec3 aReflect  = reflect (normalize (aPosition.xyz), aNormal);"
1055         EOL"  aReflect.z += 1.0;"
1056         EOL"  TexCoord = vec4(aReflect.xy * inversesqrt (dot (aReflect, aReflect)) * 0.5 + vec2 (0.5), 0.0, 1.0);";
1057
1058       aSrcFragGetColor =
1059         EOL"vec4 getColor(void) { return occTexture2D (occActiveSampler, TexCoord.st); }";
1060     }
1061   }
1062   if ((theBits & OpenGl_PO_VertColor) != 0)
1063   {
1064     aSrcVertExtraOut  += EOL"THE_SHADER_OUT vec4 VertColor;";
1065     aSrcVertExtraMain += EOL"  VertColor = occVertColor;";
1066     aSrcFragExtraOut  += EOL"THE_SHADER_IN  vec4 VertColor;";
1067     aSrcFragGetColor  =  EOL"vec4 getColor(void) { return VertColor; }";
1068   }
1069   if ((theBits & OpenGl_PO_ClipPlanesN) != 0)
1070   {
1071     aSrcVertExtraOut +=
1072       EOL"THE_SHADER_OUT vec4 PositionWorld;"
1073       EOL"THE_SHADER_OUT vec4 Position;";
1074     aSrcFragExtraOut +=
1075       EOL"THE_SHADER_IN  vec4 PositionWorld;"
1076       EOL"THE_SHADER_IN  vec4 Position;";
1077     aSrcVertExtraMain +=
1078       EOL"  PositionWorld = occModelWorldMatrix * occVertex;"
1079       EOL"  Position      = occWorldViewMatrix * PositionWorld;";
1080
1081     if ((theBits & OpenGl_PO_ClipPlanes1) != 0)
1082     {
1083       aSrcFragExtraMain += THE_FRAG_CLIP_PLANES_1;
1084     }
1085     else if ((theBits & OpenGl_PO_ClipPlanes2) != 0)
1086     {
1087       aSrcFragExtraMain += THE_FRAG_CLIP_PLANES_2;
1088     }
1089     else
1090     {
1091       aSrcFragExtraMain += THE_FRAG_CLIP_PLANES_N;
1092     }
1093   }
1094
1095   TCollection_AsciiString aSrcVertEndMain;
1096   if ((theBits & OpenGl_PO_StippleLine) != 0)
1097   {
1098     bool hasGlslBitOps = false;
1099   #if defined(GL_ES_VERSION_2_0)
1100     if (myContext->IsGlGreaterEqual (3, 0))
1101     {
1102       aProgramSrc->SetHeader ("#version 300 es");
1103       hasGlslBitOps = true;
1104     }
1105   #else
1106     if (myContext->IsGlGreaterEqual (3, 0))
1107     {
1108       aProgramSrc->SetHeader ("#version 130");
1109       hasGlslBitOps = true;
1110     }
1111     else if(myContext->CheckExtension("GL_EXT_gpu_shader4"))
1112     {
1113       aProgramSrc->SetHeader ("#extension GL_EXT_gpu_shader4 : enable");
1114       hasGlslBitOps = true;
1115     }
1116   #endif
1117
1118     if (hasGlslBitOps)
1119     {
1120       aSrcVertExtraOut +=
1121         EOL"THE_SHADER_OUT vec2 ScreenSpaceCoord;";
1122       aSrcFragExtraOut +=
1123         EOL"THE_SHADER_IN  vec2 ScreenSpaceCoord;"
1124         EOL"uniform int   uPattern;"
1125         EOL"uniform float uFactor;";
1126       aSrcVertEndMain =
1127         EOL"  ScreenSpaceCoord = gl_Position.xy / gl_Position.w;";
1128       aSrcFragMainGetColor =
1129         EOL"  float anAngle      = atan (dFdx (ScreenSpaceCoord.x), dFdy (ScreenSpaceCoord.y));"
1130         EOL"  float aRotatePoint = gl_FragCoord.x * sin (anAngle) + gl_FragCoord.y * cos (anAngle);"
1131         EOL"  uint  aBit         = uint (floor (aRotatePoint / uFactor + 0.5)) & 15U;"
1132         EOL"  if ((uint (uPattern) & (1U << aBit)) == 0U) discard;"
1133         EOL"  vec4 aColor = getColor();"
1134         EOL"  if (aColor.a <= 0.1) discard;"
1135         EOL"  occFragColor = aColor;";
1136     }
1137     else
1138     {
1139       const TCollection_ExtendedString aWarnMessage =
1140         "Warning: stipple lines in GLSL will be ignored.";
1141       myContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION,
1142         GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_HIGH, aWarnMessage);
1143     }
1144   }
1145
1146   aSrcVert =
1147       aSrcVertExtraFunc
1148     + aSrcVertExtraOut
1149     + EOL"void main()"
1150       EOL"{"
1151     + aSrcVertExtraMain
1152     + EOL"  gl_Position = occProjectionMatrix * occWorldViewMatrix * occModelWorldMatrix * occVertex;"
1153     + aSrcVertEndMain
1154     + EOL"}";
1155
1156   aSrcFrag =
1157       aSrcFragExtraOut
1158     + aSrcFragGetColor
1159     + aSrcGetAlpha
1160     + EOL"void main()"
1161       EOL"{"
1162     + aSrcFragExtraMain
1163     + aSrcFragMainGetColor
1164     + EOL"}";
1165
1166 #if !defined(GL_ES_VERSION_2_0)
1167   if (myContext->core32 != NULL)
1168   {
1169     aProgramSrc->SetHeader ("#version 150");
1170   }
1171 #endif
1172   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_VERTEX,   aSrcVert));
1173   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_FRAGMENT, aSrcFrag));
1174
1175   TCollection_AsciiString aKey;
1176   if (!Create (aProgramSrc, aKey, theProgram))
1177   {
1178     theProgram = new OpenGl_ShaderProgram(); // just mark as invalid
1179     return Standard_False;
1180   }
1181   return Standard_True;
1182 }
1183
1184 // =======================================================================
1185 // function : pointSpriteShadingSrc
1186 // purpose  :
1187 // =======================================================================
1188 TCollection_AsciiString OpenGl_ShaderManager::pointSpriteShadingSrc (const TCollection_AsciiString theBaseColorSrc,
1189                                                                      const Standard_Integer theBits)
1190 {
1191   TCollection_AsciiString aSrcFragGetColor;
1192   if ((theBits & OpenGl_PO_TextureA) != 0)
1193   {
1194     aSrcFragGetColor = pointSpriteAlphaSrc (theBits) +
1195       EOL"vec4 getColor(void)"
1196       EOL"{"
1197       EOL"  vec4 aColor = " + theBaseColorSrc + ";"
1198       EOL"  aColor.a = getAlpha();"
1199       EOL"  if (aColor.a <= 0.1) discard;"
1200       EOL"  return aColor;"
1201       EOL"}";
1202   }
1203   else if ((theBits & OpenGl_PO_TextureRGB) != 0)
1204   {
1205     aSrcFragGetColor = TCollection_AsciiString() +
1206       EOL"vec4 getColor(void)"
1207       EOL"{"
1208       EOL"  vec4 aColor = " + theBaseColorSrc + ";"
1209       EOL"  aColor = occTexture2D(occActiveSampler, " THE_VEC2_glPointCoord ") * aColor;"
1210       EOL"  if (aColor.a <= 0.1) discard;"
1211       EOL"  return aColor;"
1212       EOL"}";
1213   }
1214
1215   return aSrcFragGetColor;
1216 }
1217
1218 // =======================================================================
1219 // function : stdComputeLighting
1220 // purpose  :
1221 // =======================================================================
1222 TCollection_AsciiString OpenGl_ShaderManager::stdComputeLighting (const Standard_Boolean theHasVertColor)
1223 {
1224   Standard_Integer aLightsMap[Graphic3d_TOLS_SPOT + 1] = { 0, 0, 0, 0 };
1225   TCollection_AsciiString aLightsFunc, aLightsLoop;
1226   const OpenGl_ListOfLight* aLights = myLightSourceState.LightSources();
1227   if (aLights != NULL)
1228   {
1229     Standard_Integer anIndex = 0;
1230     for (OpenGl_ListOfLight::Iterator aLightIter (*aLights); aLightIter.More(); aLightIter.Next(), ++anIndex)
1231     {
1232       switch (aLightIter.Value().Type)
1233       {
1234         case Graphic3d_TOLS_AMBIENT:
1235           --anIndex;
1236           break; // skip ambient
1237         case Graphic3d_TOLS_DIRECTIONAL:
1238           aLightsLoop = aLightsLoop + EOL"    directionalLight (" + anIndex + ", theNormal, theView, theIsFront);";
1239           break;
1240         case Graphic3d_TOLS_POSITIONAL:
1241           aLightsLoop = aLightsLoop + EOL"    pointLight (" + anIndex + ", theNormal, theView, aPoint, theIsFront);";
1242           break;
1243         case Graphic3d_TOLS_SPOT:
1244           aLightsLoop = aLightsLoop + EOL"    spotLight (" + anIndex + ", theNormal, theView, aPoint, theIsFront);";
1245           break;
1246       }
1247       aLightsMap[aLightIter.Value().Type] += 1;
1248     }
1249     const Standard_Integer aNbLoopLights = aLightsMap[Graphic3d_TOLS_DIRECTIONAL]
1250                                          + aLightsMap[Graphic3d_TOLS_POSITIONAL]
1251                                          + aLightsMap[Graphic3d_TOLS_SPOT];
1252     if (aLightsMap[Graphic3d_TOLS_DIRECTIONAL] == 1
1253      && aNbLoopLights == 1)
1254     {
1255       // use the version with hard-coded first index
1256       aLightsLoop = EOL"    directionalLightFirst(theNormal, theView, theIsFront);";
1257       aLightsFunc += THE_FUNC_directionalLightFirst;
1258     }
1259     else if (aLightsMap[Graphic3d_TOLS_DIRECTIONAL] > 0)
1260     {
1261       aLightsFunc += THE_FUNC_directionalLight;
1262     }
1263     if (aLightsMap[Graphic3d_TOLS_POSITIONAL] > 0)
1264     {
1265       aLightsFunc += THE_FUNC_pointLight;
1266     }
1267     if (aLightsMap[Graphic3d_TOLS_SPOT] > 0)
1268     {
1269       aLightsFunc += THE_FUNC_spotLight;
1270     }
1271   }
1272
1273   TCollection_AsciiString aGetMatAmbient = "theIsFront ? occFrontMaterial_Ambient()  : occBackMaterial_Ambient();";
1274   TCollection_AsciiString aGetMatDiffuse = "theIsFront ? occFrontMaterial_Diffuse()  : occBackMaterial_Diffuse();";
1275   if (theHasVertColor)
1276   {
1277     aGetMatAmbient = "getVertColor();";
1278     aGetMatDiffuse = "getVertColor();";
1279   }
1280
1281   return TCollection_AsciiString()
1282     + THE_FUNC_lightDef
1283     + aLightsFunc
1284     + EOL
1285       EOL"vec4 computeLighting (in vec3 theNormal,"
1286       EOL"                      in vec3 theView,"
1287       EOL"                      in vec4 thePoint,"
1288       EOL"                      in bool theIsFront)"
1289       EOL"{"
1290       EOL"  Ambient  = occLightAmbient.rgb;"
1291       EOL"  Diffuse  = vec3 (0.0);"
1292       EOL"  Specular = vec3 (0.0);"
1293       EOL"  vec3 aPoint = thePoint.xyz / thePoint.w;"
1294     + aLightsLoop
1295     + EOL"  vec4 aMatAmbient  = " + aGetMatAmbient
1296     + EOL"  vec4 aMatDiffuse  = " + aGetMatDiffuse
1297     + EOL"  vec4 aMatSpecular = theIsFront ? occFrontMaterial_Specular() : occBackMaterial_Specular();"
1298       EOL"  vec4 aMatEmission = theIsFront ? occFrontMaterial_Emission() : occBackMaterial_Emission();"
1299       EOL"  vec3 aColor = Ambient  * aMatAmbient.rgb"
1300       EOL"              + Diffuse  * aMatDiffuse.rgb"
1301       EOL"              + Specular * aMatSpecular.rgb"
1302       EOL"                         + aMatEmission.rgb;"
1303       EOL"  return vec4 (aColor, aMatDiffuse.a);"
1304       EOL"}";
1305 }
1306
1307 // =======================================================================
1308 // function : prepareStdProgramGouraud
1309 // purpose  :
1310 // =======================================================================
1311 Standard_Boolean OpenGl_ShaderManager::prepareStdProgramGouraud (Handle(OpenGl_ShaderProgram)& theProgram,
1312                                                                  const Standard_Integer        theBits)
1313 {
1314   Handle(Graphic3d_ShaderProgram) aProgramSrc = new Graphic3d_ShaderProgram();
1315   TCollection_AsciiString aSrcVert, aSrcVertColor, aSrcVertExtraOut, aSrcVertExtraMain, aSrcFrag, aSrcFragExtraOut, aSrcFragExtraMain;
1316   TCollection_AsciiString aSrcFragGetColor = EOL"vec4 getColor(void) { return gl_FrontFacing ? FrontColor : BackColor; }";
1317   if ((theBits & OpenGl_PO_Point) != 0)
1318   {
1319   #if defined(GL_ES_VERSION_2_0)
1320     aSrcVertExtraMain += EOL"  gl_PointSize = occPointSize;";
1321   #endif
1322
1323     if (textureUsed (theBits))
1324     {
1325       #if !defined(GL_ES_VERSION_2_0)
1326         if (myContext->core11 != NULL
1327          && myContext->IsGlGreaterEqual (2, 1))
1328         {
1329           aProgramSrc->SetHeader ("#version 120"); // gl_PointCoord has been added since GLSL 1.2
1330         }
1331       #endif
1332
1333       aSrcFragGetColor = pointSpriteShadingSrc ("gl_FrontFacing ? FrontColor : BackColor", theBits);
1334     }
1335   }
1336   else
1337   {
1338     if ((theBits & OpenGl_PO_TextureRGB) != 0)
1339     {
1340       aSrcVertExtraOut  += THE_VARY_TexCoord_OUT;
1341       aSrcFragExtraOut  += THE_VARY_TexCoord_IN;
1342       aSrcVertExtraMain += THE_VARY_TexCoord_Trsf;
1343
1344       aSrcFragGetColor =
1345         EOL"vec4 getColor(void)"
1346         EOL"{"
1347         EOL"  vec4 aColor = gl_FrontFacing ? FrontColor : BackColor;"
1348         EOL"  return occTexture2D(occActiveSampler, TexCoord.st / TexCoord.w) * aColor;"
1349         EOL"}";
1350     }
1351   }
1352
1353   if ((theBits & OpenGl_PO_VertColor) != 0)
1354   {
1355     aSrcVertColor = EOL"vec4 getVertColor(void) { return occVertColor; }";
1356   }
1357
1358   if ((theBits & OpenGl_PO_ClipPlanesN) != 0)
1359   {
1360     aSrcVertExtraOut +=
1361       EOL"THE_SHADER_OUT vec4 PositionWorld;"
1362       EOL"THE_SHADER_OUT vec4 Position;";
1363     aSrcFragExtraOut +=
1364       EOL"THE_SHADER_IN  vec4 PositionWorld;"
1365       EOL"THE_SHADER_IN  vec4 Position;";
1366     aSrcVertExtraMain +=
1367       EOL"  PositionWorld = aPositionWorld;"
1368       EOL"  Position      = aPosition;";
1369
1370     if ((theBits & OpenGl_PO_ClipPlanes1) != 0)
1371     {
1372       aSrcFragExtraMain += THE_FRAG_CLIP_PLANES_1;
1373     }
1374     else if ((theBits & OpenGl_PO_ClipPlanes2) != 0)
1375     {
1376       aSrcFragExtraMain += THE_FRAG_CLIP_PLANES_2;
1377     }
1378     else
1379     {
1380       aSrcFragExtraMain += THE_FRAG_CLIP_PLANES_N;
1381     }
1382   }
1383
1384   const TCollection_AsciiString aLights = stdComputeLighting ((theBits & OpenGl_PO_VertColor) != 0);
1385   aSrcVert = TCollection_AsciiString()
1386     + THE_FUNC_transformNormal
1387     + EOL
1388     + aSrcVertColor
1389     + aLights
1390     + EOL
1391       EOL"THE_SHADER_OUT vec4 FrontColor;"
1392       EOL"THE_SHADER_OUT vec4 BackColor;"
1393       EOL
1394     + aSrcVertExtraOut
1395     + EOL"void main()"
1396       EOL"{"
1397       EOL"  vec4 aPositionWorld = occModelWorldMatrix * occVertex;"
1398       EOL"  vec4 aPosition      = occWorldViewMatrix * aPositionWorld;"
1399       EOL"  vec3 aNormal        = transformNormal (occNormal);"
1400       EOL"  vec3 aView          = vec3 (0.0, 0.0, 1.0);"
1401       EOL"  FrontColor  = computeLighting (normalize (aNormal), normalize (aView), aPosition, true);"
1402       EOL"  BackColor   = computeLighting (normalize (aNormal), normalize (aView), aPosition, false);"
1403     + aSrcVertExtraMain
1404     + EOL"  gl_Position = occProjectionMatrix * occWorldViewMatrix * occModelWorldMatrix * occVertex;"
1405       EOL"}";
1406
1407   aSrcFrag = TCollection_AsciiString()
1408     + EOL"THE_SHADER_IN vec4 FrontColor;"
1409       EOL"THE_SHADER_IN vec4 BackColor;"
1410     + aSrcFragExtraOut
1411     + aSrcFragGetColor
1412     + EOL"void main()"
1413       EOL"{"
1414     + aSrcFragExtraMain
1415     + EOL"  occFragColor = getColor();"
1416       EOL"}";
1417
1418 #if !defined(GL_ES_VERSION_2_0)
1419   if (myContext->core32 != NULL)
1420   {
1421     aProgramSrc->SetHeader ("#version 150");
1422   }
1423 #endif
1424   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_VERTEX,   aSrcVert));
1425   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_FRAGMENT, aSrcFrag));
1426   TCollection_AsciiString aKey;
1427   if (!Create (aProgramSrc, aKey, theProgram))
1428   {
1429     theProgram = new OpenGl_ShaderProgram(); // just mark as invalid
1430     return Standard_False;
1431   }
1432   return Standard_True;
1433 }
1434
1435 // =======================================================================
1436 // function : prepareStdProgramPhong
1437 // purpose  :
1438 // =======================================================================
1439 Standard_Boolean OpenGl_ShaderManager::prepareStdProgramPhong (Handle(OpenGl_ShaderProgram)& theProgram,
1440                                                                const Standard_Integer        theBits)
1441 {
1442   #define thePhongCompLight "computeLighting (normalize (Normal), normalize (View), Position, gl_FrontFacing)"
1443
1444   Handle(Graphic3d_ShaderProgram) aProgramSrc = new Graphic3d_ShaderProgram();
1445   TCollection_AsciiString aSrcVert, aSrcVertExtraOut, aSrcVertExtraMain, aSrcFrag, aSrcFragExtraOut, aSrcFragGetVertColor, aSrcFragExtraMain;
1446   TCollection_AsciiString aSrcFragGetColor = EOL"vec4 getColor(void) { return " thePhongCompLight "; }";
1447   if ((theBits & OpenGl_PO_Point) != 0)
1448   {
1449   #if defined(GL_ES_VERSION_2_0)
1450     aSrcVertExtraMain += EOL"  gl_PointSize = occPointSize;";
1451   #endif
1452
1453     if (textureUsed (theBits))
1454     {
1455       #if !defined(GL_ES_VERSION_2_0)
1456         if (myContext->core11 != NULL
1457          && myContext->IsGlGreaterEqual (2, 1))
1458         {
1459           aProgramSrc->SetHeader ("#version 120"); // gl_PointCoord has been added since GLSL 1.2
1460         }
1461       #endif
1462
1463       aSrcFragGetColor = pointSpriteShadingSrc (thePhongCompLight, theBits);
1464     }
1465   }
1466   else
1467   {
1468     if ((theBits & OpenGl_PO_TextureRGB) != 0)
1469     {
1470       aSrcVertExtraOut  += THE_VARY_TexCoord_OUT;
1471       aSrcFragExtraOut  += THE_VARY_TexCoord_IN;
1472       aSrcVertExtraMain += THE_VARY_TexCoord_Trsf;
1473
1474       aSrcFragGetColor =
1475         EOL"vec4 getColor(void)"
1476         EOL"{"
1477         EOL"  vec4 aColor = " thePhongCompLight ";"
1478         EOL"  return occTexture2D(occActiveSampler, TexCoord.st / TexCoord.w) * aColor;"
1479         EOL"}";
1480     }
1481   }
1482
1483   if ((theBits & OpenGl_PO_VertColor) != 0)
1484   {
1485     aSrcVertExtraOut    += EOL"THE_SHADER_OUT vec4 VertColor;";
1486     aSrcVertExtraMain   += EOL"  VertColor = occVertColor;";
1487     aSrcFragGetVertColor = EOL"THE_SHADER_IN  vec4 VertColor;"
1488                            EOL"vec4 getVertColor(void) { return VertColor; }";
1489   }
1490
1491   if ((theBits & OpenGl_PO_ClipPlanesN) != 0)
1492   {
1493     if ((theBits & OpenGl_PO_ClipPlanes1) != 0)
1494     {
1495       aSrcFragExtraMain += THE_FRAG_CLIP_PLANES_1;
1496     }
1497     else if ((theBits & OpenGl_PO_ClipPlanes2) != 0)
1498     {
1499       aSrcFragExtraMain += THE_FRAG_CLIP_PLANES_2;
1500     }
1501     else
1502     {
1503       aSrcFragExtraMain += THE_FRAG_CLIP_PLANES_N;
1504     }
1505   }
1506
1507   aSrcVert = TCollection_AsciiString()
1508     + THE_FUNC_transformNormal
1509     + EOL
1510       EOL"THE_SHADER_OUT vec4 PositionWorld;"
1511       EOL"THE_SHADER_OUT vec4 Position;"
1512       EOL"THE_SHADER_OUT vec3 Normal;"
1513       EOL"THE_SHADER_OUT vec3 View;"
1514       EOL
1515     + aSrcVertExtraOut
1516     + EOL"void main()"
1517       EOL"{"
1518       EOL"  PositionWorld = occModelWorldMatrix * occVertex;"
1519       EOL"  Position      = occWorldViewMatrix * PositionWorld;"
1520       EOL"  Normal        = transformNormal (occNormal);"
1521       EOL"  View          = vec3 (0.0, 0.0, 1.0);"
1522     + aSrcVertExtraMain
1523     + EOL"  gl_Position = occProjectionMatrix * occWorldViewMatrix * occModelWorldMatrix * occVertex;"
1524       EOL"}";
1525
1526   const TCollection_AsciiString aLights = stdComputeLighting ((theBits & OpenGl_PO_VertColor) != 0);
1527   aSrcFrag = TCollection_AsciiString()
1528     + EOL"THE_SHADER_IN vec4 PositionWorld;"
1529       EOL"THE_SHADER_IN vec4 Position;"
1530       EOL"THE_SHADER_IN vec3 Normal;"
1531       EOL"THE_SHADER_IN vec3 View;"
1532     + EOL
1533     + aSrcFragExtraOut
1534     + aSrcFragGetVertColor
1535     + aLights
1536     + aSrcFragGetColor
1537     + EOL
1538       EOL"void main()"
1539       EOL"{"
1540     + aSrcFragExtraMain
1541     + EOL"  occFragColor = getColor();"
1542       EOL"}";
1543
1544 #if !defined(GL_ES_VERSION_2_0)
1545   if (myContext->core32 != NULL)
1546   {
1547     aProgramSrc->SetHeader ("#version 150");
1548   }
1549 #endif
1550   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_VERTEX,   aSrcVert));
1551   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_FRAGMENT, aSrcFrag));
1552   TCollection_AsciiString aKey;
1553   if (!Create (aProgramSrc, aKey, theProgram))
1554   {
1555     theProgram = new OpenGl_ShaderProgram(); // just mark as invalid
1556     return Standard_False;
1557   }
1558   return Standard_True;
1559 }
1560
1561 // =======================================================================
1562 // function : prepareStdProgramStereo
1563 // purpose  :
1564 // =======================================================================
1565 Standard_Boolean OpenGl_ShaderManager::prepareStdProgramStereo (Handle(OpenGl_ShaderProgram)& theProgram,
1566                                                                 const Graphic3d_StereoMode    theStereoMode)
1567 {
1568   Handle(Graphic3d_ShaderProgram) aProgramSrc = new Graphic3d_ShaderProgram();
1569   TCollection_AsciiString aSrcVert =
1570       EOL"THE_SHADER_OUT vec2 TexCoord;"
1571       EOL"void main()"
1572       EOL"{"
1573       EOL"  TexCoord    = occVertex.zw;"
1574       EOL"  gl_Position = vec4(occVertex.x, occVertex.y, 0.0, 1.0);"
1575       EOL"}";
1576
1577   TCollection_AsciiString aSrcFrag;
1578   switch (theStereoMode)
1579   {
1580     case Graphic3d_StereoMode_Anaglyph:
1581     {
1582       aSrcFrag =
1583           EOL"uniform sampler2D uLeftSampler;"
1584           EOL"uniform sampler2D uRightSampler;"
1585           EOL
1586           EOL"uniform mat4 uMultL;"
1587           EOL"uniform mat4 uMultR;"
1588           EOL
1589           EOL"vec4 THE_POW_UP   = vec4 (2.2, 2.2, 2.2, 1.0);"
1590           EOL"vec4 THE_POW_DOWN = 1.0 / THE_POW_UP;"
1591           EOL
1592           EOL"THE_SHADER_IN vec2 TexCoord;"
1593           EOL
1594           EOL"void main()"
1595           EOL"{"
1596           EOL"  vec4 aColorL = occTexture2D (uLeftSampler,  TexCoord);"
1597           EOL"  vec4 aColorR = occTexture2D (uRightSampler, TexCoord);"
1598           EOL"  aColorL = pow (aColorL, THE_POW_UP);" // normalize
1599           EOL"  aColorR = pow (aColorR, THE_POW_UP);"
1600           EOL"  vec4 aColor = uMultR * aColorR + uMultL * aColorL;"
1601           EOL"  occFragColor = pow (aColor, THE_POW_DOWN);"
1602           EOL"}";
1603       break;
1604     }
1605     case Graphic3d_StereoMode_RowInterlaced:
1606     {
1607       aSrcFrag =
1608           EOL"uniform sampler2D uLeftSampler;"
1609           EOL"uniform sampler2D uRightSampler;"
1610           EOL
1611           EOL"THE_SHADER_IN vec2 TexCoord;"
1612           EOL
1613           EOL"void main()"
1614           EOL"{"
1615           EOL"  vec4 aColorL = occTexture2D (uLeftSampler,  TexCoord);"
1616           EOL"  vec4 aColorR = occTexture2D (uRightSampler, TexCoord);"
1617           EOL"  if (int (mod (gl_FragCoord.y - 1023.5, 2.0)) != 1)"
1618           EOL"  {"
1619           EOL"    occFragColor = aColorL;"
1620           EOL"  }"
1621           EOL"  else"
1622           EOL"  {"
1623           EOL"    occFragColor = aColorR;"
1624           EOL"  }"
1625           EOL"}";
1626       break;
1627     }
1628     case Graphic3d_StereoMode_ColumnInterlaced:
1629     {
1630       aSrcFrag =
1631           EOL"uniform sampler2D uLeftSampler;"
1632           EOL"uniform sampler2D uRightSampler;"
1633           EOL
1634           EOL"THE_SHADER_IN vec2 TexCoord;"
1635           EOL
1636           EOL"void main()"
1637           EOL"{"
1638           EOL"  vec4 aColorL = occTexture2D (uLeftSampler,  TexCoord);"
1639           EOL"  vec4 aColorR = occTexture2D (uRightSampler, TexCoord);"
1640           EOL"  if (int (mod (gl_FragCoord.x - 1023.5, 2.0)) == 1)"
1641           EOL"  {"
1642           EOL"    occFragColor = aColorL;"
1643           EOL"  }"
1644           EOL"  else"
1645           EOL"  {"
1646           EOL"    occFragColor = aColorR;"
1647           EOL"  }"
1648           EOL"}";
1649       break;
1650     }
1651     case Graphic3d_StereoMode_ChessBoard:
1652     {
1653       aSrcFrag =
1654           EOL"uniform sampler2D uLeftSampler;"
1655           EOL"uniform sampler2D uRightSampler;"
1656           EOL
1657           EOL"THE_SHADER_IN vec2 TexCoord;"
1658           EOL
1659           EOL"void main()"
1660           EOL"{"
1661           EOL"  vec4 aColorL = occTexture2D (uLeftSampler,  TexCoord);"
1662           EOL"  vec4 aColorR = occTexture2D (uRightSampler, TexCoord);"
1663           EOL"  bool isEvenX = int(mod(floor(gl_FragCoord.x - 1023.5), 2.0)) != 1;"
1664           EOL"  bool isEvenY = int(mod(floor(gl_FragCoord.y - 1023.5), 2.0)) == 1;"
1665           EOL"  if ((isEvenX && isEvenY) || (!isEvenX && !isEvenY))"
1666           EOL"  {"
1667           EOL"    occFragColor = aColorL;"
1668           EOL"  }"
1669           EOL"  else"
1670           EOL"  {"
1671           EOL"    occFragColor = aColorR;"
1672           EOL"  }"
1673           EOL"}";
1674       break;
1675     }
1676     case Graphic3d_StereoMode_SideBySide:
1677     {
1678       aSrcFrag =
1679           EOL"uniform sampler2D uLeftSampler;"
1680           EOL"uniform sampler2D uRightSampler;"
1681           EOL
1682           EOL"THE_SHADER_IN vec2 TexCoord;"
1683           EOL
1684           EOL"void main()"
1685           EOL"{"
1686           EOL"  vec2 aTexCoord = vec2 (TexCoord.x * 2.0, TexCoord.y);"
1687           EOL"  if (TexCoord.x > 0.5)"
1688           EOL"  {"
1689           EOL"    aTexCoord.x -= 1.0;"
1690           EOL"  }"
1691           EOL"  vec4 aColorL = occTexture2D (uLeftSampler,  aTexCoord);"
1692           EOL"  vec4 aColorR = occTexture2D (uRightSampler, aTexCoord);"
1693           EOL"  if (TexCoord.x <= 0.5)"
1694           EOL"  {"
1695           EOL"    occFragColor = aColorL;"
1696           EOL"  }"
1697           EOL"  else"
1698           EOL"  {"
1699           EOL"    occFragColor = aColorR;"
1700           EOL"  }"
1701           EOL"}";
1702       break;
1703     }
1704     case Graphic3d_StereoMode_OverUnder:
1705     {
1706       aSrcFrag =
1707           EOL"uniform sampler2D uLeftSampler;"
1708           EOL"uniform sampler2D uRightSampler;"
1709           EOL
1710           EOL"THE_SHADER_IN vec2 TexCoord;"
1711           EOL
1712           EOL"void main()"
1713           EOL"{"
1714           EOL"  vec2 aTexCoord = vec2 (TexCoord.x, TexCoord.y * 2.0);"
1715           EOL"  if (TexCoord.y > 0.5)"
1716           EOL"  {"
1717           EOL"    aTexCoord.y -= 1.0;"
1718           EOL"  }"
1719           EOL"  vec4 aColorL = occTexture2D (uLeftSampler,  aTexCoord);"
1720           EOL"  vec4 aColorR = occTexture2D (uRightSampler, aTexCoord);"
1721           EOL"  if (TexCoord.y <= 0.5)"
1722           EOL"  {"
1723           EOL"    occFragColor = aColorL;"
1724           EOL"  }"
1725           EOL"  else"
1726           EOL"  {"
1727           EOL"    occFragColor = aColorR;"
1728           EOL"  }"
1729           EOL"}";
1730       break;
1731     }
1732     case Graphic3d_StereoMode_QuadBuffer:
1733     case Graphic3d_StereoMode_SoftPageFlip:
1734     default:
1735     {
1736       /*const Handle(OpenGl_ShaderProgram)& aProgram = myStereoPrograms[Graphic3d_StereoMode_QuadBuffer];
1737       if (!aProgram.IsNull())
1738       {
1739         return aProgram->IsValid();
1740       }*/
1741       aSrcFrag =
1742           EOL"uniform sampler2D uLeftSampler;"
1743           EOL"uniform sampler2D uRightSampler;"
1744           EOL
1745           EOL"THE_SHADER_IN vec2 TexCoord;"
1746           EOL
1747           EOL"void main()"
1748           EOL"{"
1749           EOL"  vec4 aColorL = occTexture2D (uLeftSampler,  TexCoord);"
1750           EOL"  vec4 aColorR = occTexture2D (uRightSampler, TexCoord);"
1751           EOL"  aColorL.b = 0.0;"
1752           EOL"  aColorL.g = 0.0;"
1753           EOL"  aColorR.r = 0.0;"
1754           EOL"  occFragColor = aColorL + aColorR;"
1755           EOL"}";
1756       break;
1757     }
1758   }
1759
1760 #if !defined(GL_ES_VERSION_2_0)
1761   if (myContext->core32 != NULL)
1762   {
1763     aProgramSrc->SetHeader ("#version 150");
1764   }
1765 #endif
1766
1767   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_VERTEX,   aSrcVert));
1768   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_FRAGMENT, aSrcFrag));
1769   TCollection_AsciiString aKey;
1770   if (!Create (aProgramSrc, aKey, theProgram))
1771   {
1772     theProgram = new OpenGl_ShaderProgram(); // just mark as invalid
1773     return Standard_False;
1774   }
1775
1776   myContext->BindProgram (theProgram);
1777   theProgram->SetSampler (myContext, "uLeftSampler",  0);
1778   theProgram->SetSampler (myContext, "uRightSampler", 1);
1779   myContext->BindProgram (NULL);
1780   return Standard_True;
1781 }
1782
1783 // =======================================================================
1784 // function : bindProgramWithState
1785 // purpose  :
1786 // =======================================================================
1787 Standard_Boolean OpenGl_ShaderManager::bindProgramWithState (const Handle(OpenGl_ShaderProgram)& theProgram)
1788 {
1789   if (!myContext->BindProgram (theProgram))
1790   {
1791     return Standard_False;
1792   }
1793   theProgram->ApplyVariables (myContext);
1794
1795   PushState (theProgram);
1796   return Standard_True;
1797 }