0027943: Visualization - fix broken shading by positional light for object with local...
[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 }
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   const GLint aNbPlanes = Min (myContext->Clipping().NbClippingOrCappingOn(), THE_MAX_CLIP_PLANES);
771   theProgram->SetUniform (myContext,
772                           theProgram->GetStateLocation (OpenGl_OCC_CLIP_PLANE_COUNT),
773                           aNbPlanes);
774   if (aNbPlanes < 1)
775   {
776     return;
777   }
778
779   OpenGl_Vec4 anEquations[THE_MAX_CLIP_PLANES];
780   GLuint aPlaneId = 0;
781   for (OpenGl_ClippingIterator aPlaneIter (myContext->Clipping()); aPlaneIter.More(); aPlaneIter.Next())
782   {
783     const Handle(Graphic3d_ClipPlane)& aPlane = aPlaneIter.Value();
784     if (aPlaneIter.IsDisabled())
785     {
786       continue;
787     }
788     else if (aPlaneId >= THE_MAX_CLIP_PLANES)
789     {
790       myContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION,
791         GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_MEDIUM,
792         "Warning: clipping planes limit (8) has been exceeded.");
793       break;
794     }
795
796     const Graphic3d_ClipPlane::Equation& anEquation = aPlane->GetEquation();
797     anEquations[aPlaneId] = OpenGl_Vec4 ((float) anEquation.x(),
798                                          (float) anEquation.y(),
799                                          (float) anEquation.z(),
800                                          (float) anEquation.w());
801     ++aPlaneId;
802   }
803
804   theProgram->SetUniform (myContext, aLocEquations, THE_MAX_CLIP_PLANES, anEquations);
805 }
806
807 // =======================================================================
808 // function : PushState
809 // purpose  : Pushes state of OCCT graphics parameters to the program
810 // =======================================================================
811 void OpenGl_ShaderManager::PushState (const Handle(OpenGl_ShaderProgram)& theProgram) const
812 {
813   PushClippingState    (theProgram);
814   PushWorldViewState   (theProgram);
815   PushModelWorldState  (theProgram);
816   PushProjectionState  (theProgram);
817   PushLightSourceState (theProgram);
818 }
819
820 // =======================================================================
821 // function : prepareStdProgramFont
822 // purpose  :
823 // =======================================================================
824 Standard_Boolean OpenGl_ShaderManager::prepareStdProgramFont()
825 {
826   Handle(Graphic3d_ShaderProgram) aProgramSrc = new Graphic3d_ShaderProgram();
827   TCollection_AsciiString aSrcVert = TCollection_AsciiString()
828      + EOL"THE_SHADER_OUT vec2 TexCoord;"
829        EOL"void main()"
830        EOL"{"
831        EOL"  TexCoord = occTexCoord.st;"
832        EOL"  gl_Position = occProjectionMatrix * occWorldViewMatrix * occModelWorldMatrix * occVertex;"
833        EOL"}";
834
835   TCollection_AsciiString
836     aSrcGetAlpha = EOL"float getAlpha(void) { return occTexture2D(occActiveSampler, TexCoord.st).a; }";
837 #if !defined(GL_ES_VERSION_2_0)
838   if (myContext->core11 == NULL)
839   {
840     aSrcGetAlpha = EOL"float getAlpha(void) { return occTexture2D(occActiveSampler, TexCoord.st).r; }";
841   }
842 #endif
843
844   TCollection_AsciiString aSrcFrag = TCollection_AsciiString() +
845      + EOL"THE_SHADER_IN vec2 TexCoord;"
846      + aSrcGetAlpha
847      + EOL"void main()"
848        EOL"{"
849        EOL"  vec4 aColor = occColor;"
850        EOL"  aColor.a *= getAlpha();"
851        EOL"  if (aColor.a <= 0.285) discard;"
852        EOL"  occFragColor = aColor;"
853        EOL"}";
854
855 #if !defined(GL_ES_VERSION_2_0)
856   if (myContext->core32 != NULL)
857   {
858     aProgramSrc->SetHeader ("#version 150");
859   }
860 #endif
861   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_VERTEX,   aSrcVert));
862   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_FRAGMENT, aSrcFrag));
863   TCollection_AsciiString aKey;
864   if (!Create (aProgramSrc, aKey, myFontProgram))
865   {
866     myFontProgram = new OpenGl_ShaderProgram(); // just mark as invalid
867     return Standard_False;
868   }
869   return Standard_True;
870 }
871
872 // =======================================================================
873 // function : prepareStdProgramFboBlit
874 // purpose  :
875 // =======================================================================
876 Standard_Boolean OpenGl_ShaderManager::prepareStdProgramFboBlit()
877 {
878   Handle(Graphic3d_ShaderProgram) aProgramSrc = new Graphic3d_ShaderProgram();
879   TCollection_AsciiString aSrcVert =
880       EOL"THE_SHADER_OUT vec2 TexCoord;"
881       EOL"void main()"
882       EOL"{"
883       EOL"  TexCoord    = occVertex.zw;"
884       EOL"  gl_Position = vec4(occVertex.x, occVertex.y, 0.0, 1.0);"
885       EOL"}";
886
887   TCollection_AsciiString aSrcFrag =
888       EOL"uniform sampler2D uColorSampler;"
889       EOL"uniform sampler2D uDepthSampler;"
890       EOL
891       EOL"THE_SHADER_IN vec2 TexCoord;"
892       EOL
893       EOL"void main()"
894       EOL"{"
895       EOL"  gl_FragDepth = occTexture2D (uDepthSampler, TexCoord).r;"
896       EOL"  occFragColor = occTexture2D (uColorSampler, TexCoord);"
897       EOL"}";
898
899 #if defined(GL_ES_VERSION_2_0)
900   if (myContext->IsGlGreaterEqual (3, 0))
901   {
902     aProgramSrc->SetHeader ("#version 300 es");
903   }
904   else if (myContext->extFragDepth)
905   {
906     aProgramSrc->SetHeader ("#extension GL_EXT_frag_depth : enable"
907                          EOL"#define gl_FragDepth gl_FragDepthEXT");
908   }
909   else
910   {
911     // there is no way to draw into depth buffer
912     aSrcFrag =
913       EOL"uniform sampler2D uColorSampler;"
914       EOL
915       EOL"THE_SHADER_IN vec2 TexCoord;"
916       EOL
917       EOL"void main()"
918       EOL"{"
919       EOL"  occFragColor = occTexture2D (uColorSampler, TexCoord);"
920       EOL"}";
921   }
922 #else
923   if (myContext->core32 != NULL)
924   {
925     aProgramSrc->SetHeader ("#version 150");
926   }
927 #endif
928   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_VERTEX,   aSrcVert));
929   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_FRAGMENT, aSrcFrag));
930   TCollection_AsciiString aKey;
931   if (!Create (aProgramSrc, aKey, myBlitProgram))
932   {
933     myBlitProgram = new OpenGl_ShaderProgram(); // just mark as invalid
934     return Standard_False;
935   }
936
937   myContext->BindProgram (myBlitProgram);
938   myBlitProgram->SetSampler (myContext, "uColorSampler", 0);
939   myBlitProgram->SetSampler (myContext, "uDepthSampler", 1);
940   myContext->BindProgram (NULL);
941   return Standard_True;
942 }
943
944 // =======================================================================
945 // function : pointSpriteAlphaSrc
946 // purpose  :
947 // =======================================================================
948 TCollection_AsciiString OpenGl_ShaderManager::pointSpriteAlphaSrc (const Standard_Integer theBits)
949 {
950   TCollection_AsciiString aSrcGetAlpha = EOL"float getAlpha(void) { return occTexture2D(occActiveSampler, " THE_VEC2_glPointCoord ").a; }";
951 #if !defined(GL_ES_VERSION_2_0)
952   if (myContext->core11 == NULL
953    && (theBits & OpenGl_PO_TextureA) != 0)
954   {
955     aSrcGetAlpha = EOL"float getAlpha(void) { return occTexture2D(occActiveSampler, " THE_VEC2_glPointCoord ").r; }";
956   }
957 #else
958   (void )theBits;
959 #endif
960   return aSrcGetAlpha;
961 }
962
963 namespace
964 {
965
966   // =======================================================================
967   // function : textureUsed
968   // purpose  :
969   // =======================================================================
970   static bool textureUsed (const Standard_Integer theBits)
971   {
972     return (theBits & OpenGl_PO_TextureA) != 0 || (theBits & OpenGl_PO_TextureRGB) != 0;
973   }
974
975 }
976
977 // =======================================================================
978 // function : prepareStdProgramFlat
979 // purpose  :
980 // =======================================================================
981 Standard_Boolean OpenGl_ShaderManager::prepareStdProgramFlat (Handle(OpenGl_ShaderProgram)& theProgram,
982                                                               const Standard_Integer        theBits)
983 {
984   Handle(Graphic3d_ShaderProgram) aProgramSrc = new Graphic3d_ShaderProgram();
985   TCollection_AsciiString aSrcVert, aSrcVertExtraOut, aSrcVertExtraMain, aSrcVertExtraFunc, aSrcGetAlpha, aSrcFrag, aSrcFragExtraOut, aSrcFragExtraMain;
986   TCollection_AsciiString aSrcFragGetColor     = EOL"vec4 getColor(void) { return occColor; }";
987   TCollection_AsciiString aSrcFragMainGetColor = EOL"  occFragColor = getColor();";
988   if ((theBits & OpenGl_PO_Point) != 0)
989   {
990   #if defined(GL_ES_VERSION_2_0)
991     aSrcVertExtraMain += EOL"  gl_PointSize = occPointSize;";
992   #endif
993
994     if ((theBits & OpenGl_PO_TextureRGB) != 0)
995     {
996       aSrcFragGetColor =
997         EOL"vec4 getColor(void) { return occTexture2D(occActiveSampler, " THE_VEC2_glPointCoord "); }";
998     }
999
1000     if (textureUsed (theBits))
1001     {
1002       aSrcGetAlpha = pointSpriteAlphaSrc (theBits);
1003
1004     #if !defined(GL_ES_VERSION_2_0)
1005       if (myContext->core11 != NULL
1006         && myContext->IsGlGreaterEqual (2, 1))
1007       {
1008         aProgramSrc->SetHeader ("#version 120"); // gl_PointCoord has been added since GLSL 1.2
1009       }
1010     #endif
1011
1012       aSrcFragMainGetColor =
1013         EOL"  vec4 aColor = getColor();"
1014         EOL"  aColor.a = getAlpha();"
1015         EOL"  if (aColor.a <= 0.1) discard;"
1016         EOL"  occFragColor = aColor;";
1017     }
1018     else
1019     {
1020       aSrcFragMainGetColor =
1021         EOL"  vec4 aColor = getColor();"
1022         EOL"  if (aColor.a <= 0.1) discard;"
1023         EOL"  occFragColor = aColor;";
1024     }
1025   }
1026   else
1027   {
1028     if ((theBits & OpenGl_PO_TextureRGB) != 0)
1029     {
1030       aSrcVertExtraOut  += THE_VARY_TexCoord_OUT;
1031       aSrcFragExtraOut  += THE_VARY_TexCoord_IN;
1032       aSrcVertExtraMain += THE_VARY_TexCoord_Trsf;
1033
1034       aSrcFragGetColor =
1035         EOL"vec4 getColor(void) { return occTexture2D(occActiveSampler, TexCoord.st / TexCoord.w); }";
1036     }
1037     else if ((theBits & OpenGl_PO_TextureEnv) != 0)
1038     {
1039       aSrcVertExtraOut += THE_VARY_TexCoord_OUT;
1040       aSrcFragExtraOut += THE_VARY_TexCoord_IN;
1041
1042       aSrcVertExtraFunc = THE_FUNC_transformNormal;
1043
1044       aSrcVertExtraMain +=
1045         EOL"  vec4 aPosition = occWorldViewMatrix * occModelWorldMatrix * occVertex;"
1046         EOL"  vec3 aNormal   = transformNormal (occNormal);"
1047         EOL"  vec3 aReflect  = reflect (normalize (aPosition.xyz), aNormal);"
1048         EOL"  aReflect.z += 1.0;"
1049         EOL"  TexCoord = vec4(aReflect.xy * inversesqrt (dot (aReflect, aReflect)) * 0.5 + vec2 (0.5), 0.0, 1.0);";
1050
1051       aSrcFragGetColor =
1052         EOL"vec4 getColor(void) { return occTexture2D (occActiveSampler, TexCoord.st); }";
1053     }
1054   }
1055   if ((theBits & OpenGl_PO_VertColor) != 0)
1056   {
1057     aSrcVertExtraOut  += EOL"THE_SHADER_OUT vec4 VertColor;";
1058     aSrcVertExtraMain += EOL"  VertColor = occVertColor;";
1059     aSrcFragExtraOut  += EOL"THE_SHADER_IN  vec4 VertColor;";
1060     aSrcFragGetColor  =  EOL"vec4 getColor(void) { return VertColor; }";
1061   }
1062   if ((theBits & OpenGl_PO_ClipPlanesN) != 0)
1063   {
1064     aSrcVertExtraOut +=
1065       EOL"THE_SHADER_OUT vec4 PositionWorld;"
1066       EOL"THE_SHADER_OUT vec4 Position;";
1067     aSrcFragExtraOut +=
1068       EOL"THE_SHADER_IN  vec4 PositionWorld;"
1069       EOL"THE_SHADER_IN  vec4 Position;";
1070     aSrcVertExtraMain +=
1071       EOL"  PositionWorld = occModelWorldMatrix * occVertex;"
1072       EOL"  Position      = occWorldViewMatrix * PositionWorld;";
1073
1074     if ((theBits & OpenGl_PO_ClipPlanes1) != 0)
1075     {
1076       aSrcFragExtraMain += THE_FRAG_CLIP_PLANES_1;
1077     }
1078     else if ((theBits & OpenGl_PO_ClipPlanes2) != 0)
1079     {
1080       aSrcFragExtraMain += THE_FRAG_CLIP_PLANES_2;
1081     }
1082     else
1083     {
1084       aSrcFragExtraMain += THE_FRAG_CLIP_PLANES_N;
1085     }
1086   }
1087
1088   TCollection_AsciiString aSrcVertEndMain;
1089   if ((theBits & OpenGl_PO_StippleLine) != 0)
1090   {
1091     bool hasGlslBitOps = false;
1092   #if defined(GL_ES_VERSION_2_0)
1093     if (myContext->IsGlGreaterEqual (3, 0))
1094     {
1095       aProgramSrc->SetHeader ("#version 300 es");
1096       hasGlslBitOps = true;
1097     }
1098   #else
1099     if (myContext->IsGlGreaterEqual (3, 0))
1100     {
1101       aProgramSrc->SetHeader ("#version 130");
1102       hasGlslBitOps = true;
1103     }
1104     else if(myContext->CheckExtension("GL_EXT_gpu_shader4"))
1105     {
1106       aProgramSrc->SetHeader ("#extension GL_EXT_gpu_shader4 : enable");
1107       hasGlslBitOps = true;
1108     }
1109   #endif
1110
1111     if (hasGlslBitOps)
1112     {
1113       aSrcVertExtraOut +=
1114         EOL"THE_SHADER_OUT vec2 ScreenSpaceCoord;";
1115       aSrcFragExtraOut +=
1116         EOL"THE_SHADER_IN  vec2 ScreenSpaceCoord;"
1117         EOL"uniform int   uPattern;"
1118         EOL"uniform float uFactor;";
1119       aSrcVertEndMain =
1120         EOL"  ScreenSpaceCoord = gl_Position.xy / gl_Position.w;";
1121       aSrcFragMainGetColor =
1122         EOL"  float anAngle      = atan (dFdx (ScreenSpaceCoord.x), dFdy (ScreenSpaceCoord.y));"
1123         EOL"  float aRotatePoint = gl_FragCoord.x * sin (anAngle) + gl_FragCoord.y * cos (anAngle);"
1124         EOL"  uint  aBit         = uint (floor (aRotatePoint / uFactor + 0.5)) & 15U;"
1125         EOL"  if ((uint (uPattern) & (1U << aBit)) == 0U) discard;"
1126         EOL"  vec4 aColor = getColor();"
1127         EOL"  if (aColor.a <= 0.1) discard;"
1128         EOL"  occFragColor = aColor;";
1129     }
1130     else
1131     {
1132       const TCollection_ExtendedString aWarnMessage =
1133         "Warning: stipple lines in GLSL will be ignored.";
1134       myContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION,
1135         GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_HIGH, aWarnMessage);
1136     }
1137   }
1138
1139   aSrcVert =
1140       aSrcVertExtraFunc
1141     + aSrcVertExtraOut
1142     + EOL"void main()"
1143       EOL"{"
1144     + aSrcVertExtraMain
1145     + EOL"  gl_Position = occProjectionMatrix * occWorldViewMatrix * occModelWorldMatrix * occVertex;"
1146     + aSrcVertEndMain
1147     + EOL"}";
1148
1149   aSrcFrag =
1150       aSrcFragExtraOut
1151     + aSrcFragGetColor
1152     + aSrcGetAlpha
1153     + EOL"void main()"
1154       EOL"{"
1155     + aSrcFragExtraMain
1156     + aSrcFragMainGetColor
1157     + EOL"}";
1158
1159 #if !defined(GL_ES_VERSION_2_0)
1160   if (myContext->core32 != NULL)
1161   {
1162     aProgramSrc->SetHeader ("#version 150");
1163   }
1164 #endif
1165   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_VERTEX,   aSrcVert));
1166   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_FRAGMENT, aSrcFrag));
1167
1168   TCollection_AsciiString aKey;
1169   if (!Create (aProgramSrc, aKey, theProgram))
1170   {
1171     theProgram = new OpenGl_ShaderProgram(); // just mark as invalid
1172     return Standard_False;
1173   }
1174   return Standard_True;
1175 }
1176
1177 // =======================================================================
1178 // function : pointSpriteShadingSrc
1179 // purpose  :
1180 // =======================================================================
1181 TCollection_AsciiString OpenGl_ShaderManager::pointSpriteShadingSrc (const TCollection_AsciiString theBaseColorSrc,
1182                                                                      const Standard_Integer theBits)
1183 {
1184   TCollection_AsciiString aSrcFragGetColor;
1185   if ((theBits & OpenGl_PO_TextureA) != 0)
1186   {
1187     aSrcFragGetColor = pointSpriteAlphaSrc (theBits) +
1188       EOL"vec4 getColor(void)"
1189       EOL"{"
1190       EOL"  vec4 aColor = " + theBaseColorSrc + ";"
1191       EOL"  aColor.a = getAlpha();"
1192       EOL"  if (aColor.a <= 0.1) discard;"
1193       EOL"  return aColor;"
1194       EOL"}";
1195   }
1196   else if ((theBits & OpenGl_PO_TextureRGB) != 0)
1197   {
1198     aSrcFragGetColor = TCollection_AsciiString() +
1199       EOL"vec4 getColor(void)"
1200       EOL"{"
1201       EOL"  vec4 aColor = " + theBaseColorSrc + ";"
1202       EOL"  aColor = occTexture2D(occActiveSampler, " THE_VEC2_glPointCoord ") * aColor;"
1203       EOL"  if (aColor.a <= 0.1) discard;"
1204       EOL"  return aColor;"
1205       EOL"}";
1206   }
1207
1208   return aSrcFragGetColor;
1209 }
1210
1211 // =======================================================================
1212 // function : stdComputeLighting
1213 // purpose  :
1214 // =======================================================================
1215 TCollection_AsciiString OpenGl_ShaderManager::stdComputeLighting (const Standard_Boolean theHasVertColor)
1216 {
1217   Standard_Integer aLightsMap[Graphic3d_TOLS_SPOT + 1] = { 0, 0, 0, 0 };
1218   TCollection_AsciiString aLightsFunc, aLightsLoop;
1219   const OpenGl_ListOfLight* aLights = myLightSourceState.LightSources();
1220   if (aLights != NULL)
1221   {
1222     Standard_Integer anIndex = 0;
1223     for (OpenGl_ListOfLight::Iterator aLightIter (*aLights); aLightIter.More(); aLightIter.Next(), ++anIndex)
1224     {
1225       switch (aLightIter.Value().Type)
1226       {
1227         case Graphic3d_TOLS_AMBIENT:
1228           --anIndex;
1229           break; // skip ambient
1230         case Graphic3d_TOLS_DIRECTIONAL:
1231           aLightsLoop = aLightsLoop + EOL"    directionalLight (" + anIndex + ", theNormal, theView, theIsFront);";
1232           break;
1233         case Graphic3d_TOLS_POSITIONAL:
1234           aLightsLoop = aLightsLoop + EOL"    pointLight (" + anIndex + ", theNormal, theView, aPoint, theIsFront);";
1235           break;
1236         case Graphic3d_TOLS_SPOT:
1237           aLightsLoop = aLightsLoop + EOL"    spotLight (" + anIndex + ", theNormal, theView, aPoint, theIsFront);";
1238           break;
1239       }
1240       aLightsMap[aLightIter.Value().Type] += 1;
1241     }
1242     const Standard_Integer aNbLoopLights = aLightsMap[Graphic3d_TOLS_DIRECTIONAL]
1243                                          + aLightsMap[Graphic3d_TOLS_POSITIONAL]
1244                                          + aLightsMap[Graphic3d_TOLS_SPOT];
1245     if (aLightsMap[Graphic3d_TOLS_DIRECTIONAL] == 1
1246      && aNbLoopLights == 1)
1247     {
1248       // use the version with hard-coded first index
1249       aLightsLoop = EOL"    directionalLightFirst(theNormal, theView, theIsFront);";
1250       aLightsFunc += THE_FUNC_directionalLightFirst;
1251     }
1252     else if (aLightsMap[Graphic3d_TOLS_DIRECTIONAL] > 0)
1253     {
1254       aLightsFunc += THE_FUNC_directionalLight;
1255     }
1256     if (aLightsMap[Graphic3d_TOLS_POSITIONAL] > 0)
1257     {
1258       aLightsFunc += THE_FUNC_pointLight;
1259     }
1260     if (aLightsMap[Graphic3d_TOLS_SPOT] > 0)
1261     {
1262       aLightsFunc += THE_FUNC_spotLight;
1263     }
1264   }
1265
1266   TCollection_AsciiString aGetMatAmbient = "theIsFront ? occFrontMaterial_Ambient()  : occBackMaterial_Ambient();";
1267   TCollection_AsciiString aGetMatDiffuse = "theIsFront ? occFrontMaterial_Diffuse()  : occBackMaterial_Diffuse();";
1268   if (theHasVertColor)
1269   {
1270     aGetMatAmbient = "getVertColor();";
1271     aGetMatDiffuse = "getVertColor();";
1272   }
1273
1274   return TCollection_AsciiString()
1275     + THE_FUNC_lightDef
1276     + aLightsFunc
1277     + EOL
1278       EOL"vec4 computeLighting (in vec3 theNormal,"
1279       EOL"                      in vec3 theView,"
1280       EOL"                      in vec4 thePoint,"
1281       EOL"                      in bool theIsFront)"
1282       EOL"{"
1283       EOL"  Ambient  = occLightAmbient.rgb;"
1284       EOL"  Diffuse  = vec3 (0.0);"
1285       EOL"  Specular = vec3 (0.0);"
1286       EOL"  vec3 aPoint = thePoint.xyz / thePoint.w;"
1287     + aLightsLoop
1288     + EOL"  vec4 aMatAmbient  = " + aGetMatAmbient
1289     + EOL"  vec4 aMatDiffuse  = " + aGetMatDiffuse
1290     + EOL"  vec4 aMatSpecular = theIsFront ? occFrontMaterial_Specular() : occBackMaterial_Specular();"
1291       EOL"  vec4 aMatEmission = theIsFront ? occFrontMaterial_Emission() : occBackMaterial_Emission();"
1292       EOL"  vec3 aColor = Ambient  * aMatAmbient.rgb"
1293       EOL"              + Diffuse  * aMatDiffuse.rgb"
1294       EOL"              + Specular * aMatSpecular.rgb"
1295       EOL"                         + aMatEmission.rgb;"
1296       EOL"  return vec4 (aColor, aMatDiffuse.a);"
1297       EOL"}";
1298 }
1299
1300 // =======================================================================
1301 // function : prepareStdProgramGouraud
1302 // purpose  :
1303 // =======================================================================
1304 Standard_Boolean OpenGl_ShaderManager::prepareStdProgramGouraud (Handle(OpenGl_ShaderProgram)& theProgram,
1305                                                                  const Standard_Integer        theBits)
1306 {
1307   Handle(Graphic3d_ShaderProgram) aProgramSrc = new Graphic3d_ShaderProgram();
1308   TCollection_AsciiString aSrcVert, aSrcVertColor, aSrcVertExtraOut, aSrcVertExtraMain, aSrcFrag, aSrcFragExtraOut, aSrcFragExtraMain;
1309   TCollection_AsciiString aSrcFragGetColor = EOL"vec4 getColor(void) { return gl_FrontFacing ? FrontColor : BackColor; }";
1310   if ((theBits & OpenGl_PO_Point) != 0)
1311   {
1312   #if defined(GL_ES_VERSION_2_0)
1313     aSrcVertExtraMain += EOL"  gl_PointSize = occPointSize;";
1314   #endif
1315
1316     if (textureUsed (theBits))
1317     {
1318       #if !defined(GL_ES_VERSION_2_0)
1319         if (myContext->core11 != NULL
1320          && myContext->IsGlGreaterEqual (2, 1))
1321         {
1322           aProgramSrc->SetHeader ("#version 120"); // gl_PointCoord has been added since GLSL 1.2
1323         }
1324       #endif
1325
1326       aSrcFragGetColor = pointSpriteShadingSrc ("gl_FrontFacing ? FrontColor : BackColor", theBits);
1327     }
1328   }
1329   else
1330   {
1331     if ((theBits & OpenGl_PO_TextureRGB) != 0)
1332     {
1333       aSrcVertExtraOut  += THE_VARY_TexCoord_OUT;
1334       aSrcFragExtraOut  += THE_VARY_TexCoord_IN;
1335       aSrcVertExtraMain += THE_VARY_TexCoord_Trsf;
1336
1337       aSrcFragGetColor =
1338         EOL"vec4 getColor(void)"
1339         EOL"{"
1340         EOL"  vec4 aColor = gl_FrontFacing ? FrontColor : BackColor;"
1341         EOL"  return occTexture2D(occActiveSampler, TexCoord.st / TexCoord.w) * aColor;"
1342         EOL"}";
1343     }
1344   }
1345
1346   if ((theBits & OpenGl_PO_VertColor) != 0)
1347   {
1348     aSrcVertColor = EOL"vec4 getVertColor(void) { return occVertColor; }";
1349   }
1350
1351   if ((theBits & OpenGl_PO_ClipPlanesN) != 0)
1352   {
1353     aSrcVertExtraOut +=
1354       EOL"THE_SHADER_OUT vec4 PositionWorld;"
1355       EOL"THE_SHADER_OUT vec4 Position;";
1356     aSrcFragExtraOut +=
1357       EOL"THE_SHADER_IN  vec4 PositionWorld;"
1358       EOL"THE_SHADER_IN  vec4 Position;";
1359     aSrcVertExtraMain +=
1360       EOL"  PositionWorld = aPositionWorld;"
1361       EOL"  Position      = aPosition;";
1362
1363     if ((theBits & OpenGl_PO_ClipPlanes1) != 0)
1364     {
1365       aSrcFragExtraMain += THE_FRAG_CLIP_PLANES_1;
1366     }
1367     else if ((theBits & OpenGl_PO_ClipPlanes2) != 0)
1368     {
1369       aSrcFragExtraMain += THE_FRAG_CLIP_PLANES_2;
1370     }
1371     else
1372     {
1373       aSrcFragExtraMain += THE_FRAG_CLIP_PLANES_N;
1374     }
1375   }
1376
1377   const TCollection_AsciiString aLights = stdComputeLighting ((theBits & OpenGl_PO_VertColor) != 0);
1378   aSrcVert = TCollection_AsciiString()
1379     + THE_FUNC_transformNormal
1380     + EOL
1381     + aSrcVertColor
1382     + aLights
1383     + EOL
1384       EOL"THE_SHADER_OUT vec4 FrontColor;"
1385       EOL"THE_SHADER_OUT vec4 BackColor;"
1386       EOL
1387     + aSrcVertExtraOut
1388     + EOL"void main()"
1389       EOL"{"
1390       EOL"  vec4 aPositionWorld = occModelWorldMatrix * occVertex;"
1391       EOL"  vec4 aPosition      = occWorldViewMatrix * aPositionWorld;"
1392       EOL"  vec3 aNormal        = transformNormal (occNormal);"
1393       EOL"  vec3 aView          = vec3 (0.0, 0.0, 1.0);"
1394       EOL"  FrontColor  = computeLighting (normalize (aNormal), normalize (aView), aPosition, true);"
1395       EOL"  BackColor   = computeLighting (normalize (aNormal), normalize (aView), aPosition, false);"
1396     + aSrcVertExtraMain
1397     + EOL"  gl_Position = occProjectionMatrix * occWorldViewMatrix * occModelWorldMatrix * occVertex;"
1398       EOL"}";
1399
1400   aSrcFrag = TCollection_AsciiString()
1401     + EOL"THE_SHADER_IN vec4 FrontColor;"
1402       EOL"THE_SHADER_IN vec4 BackColor;"
1403     + aSrcFragExtraOut
1404     + aSrcFragGetColor
1405     + EOL"void main()"
1406       EOL"{"
1407     + aSrcFragExtraMain
1408     + EOL"  occFragColor = getColor();"
1409       EOL"}";
1410
1411 #if !defined(GL_ES_VERSION_2_0)
1412   if (myContext->core32 != NULL)
1413   {
1414     aProgramSrc->SetHeader ("#version 150");
1415   }
1416 #endif
1417   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_VERTEX,   aSrcVert));
1418   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_FRAGMENT, aSrcFrag));
1419   TCollection_AsciiString aKey;
1420   if (!Create (aProgramSrc, aKey, theProgram))
1421   {
1422     theProgram = new OpenGl_ShaderProgram(); // just mark as invalid
1423     return Standard_False;
1424   }
1425   return Standard_True;
1426 }
1427
1428 // =======================================================================
1429 // function : prepareStdProgramPhong
1430 // purpose  :
1431 // =======================================================================
1432 Standard_Boolean OpenGl_ShaderManager::prepareStdProgramPhong (Handle(OpenGl_ShaderProgram)& theProgram,
1433                                                                const Standard_Integer        theBits)
1434 {
1435   #define thePhongCompLight "computeLighting (normalize (Normal), normalize (View), Position, gl_FrontFacing)"
1436
1437   Handle(Graphic3d_ShaderProgram) aProgramSrc = new Graphic3d_ShaderProgram();
1438   TCollection_AsciiString aSrcVert, aSrcVertExtraOut, aSrcVertExtraMain, aSrcFrag, aSrcFragExtraOut, aSrcFragGetVertColor, aSrcFragExtraMain;
1439   TCollection_AsciiString aSrcFragGetColor = EOL"vec4 getColor(void) { return " thePhongCompLight "; }";
1440   if ((theBits & OpenGl_PO_Point) != 0)
1441   {
1442   #if defined(GL_ES_VERSION_2_0)
1443     aSrcVertExtraMain += EOL"  gl_PointSize = occPointSize;";
1444   #endif
1445
1446     if (textureUsed (theBits))
1447     {
1448       #if !defined(GL_ES_VERSION_2_0)
1449         if (myContext->core11 != NULL
1450          && myContext->IsGlGreaterEqual (2, 1))
1451         {
1452           aProgramSrc->SetHeader ("#version 120"); // gl_PointCoord has been added since GLSL 1.2
1453         }
1454       #endif
1455
1456       aSrcFragGetColor = pointSpriteShadingSrc (thePhongCompLight, theBits);
1457     }
1458   }
1459   else
1460   {
1461     if ((theBits & OpenGl_PO_TextureRGB) != 0)
1462     {
1463       aSrcVertExtraOut  += THE_VARY_TexCoord_OUT;
1464       aSrcFragExtraOut  += THE_VARY_TexCoord_IN;
1465       aSrcVertExtraMain += THE_VARY_TexCoord_Trsf;
1466
1467       aSrcFragGetColor =
1468         EOL"vec4 getColor(void)"
1469         EOL"{"
1470         EOL"  vec4 aColor = " thePhongCompLight ";"
1471         EOL"  return occTexture2D(occActiveSampler, TexCoord.st / TexCoord.w) * aColor;"
1472         EOL"}";
1473     }
1474   }
1475
1476   if ((theBits & OpenGl_PO_VertColor) != 0)
1477   {
1478     aSrcVertExtraOut    += EOL"THE_SHADER_OUT vec4 VertColor;";
1479     aSrcVertExtraMain   += EOL"  VertColor = occVertColor;";
1480     aSrcFragGetVertColor = EOL"THE_SHADER_IN  vec4 VertColor;"
1481                            EOL"vec4 getVertColor(void) { return VertColor; }";
1482   }
1483
1484   if ((theBits & OpenGl_PO_ClipPlanesN) != 0)
1485   {
1486     if ((theBits & OpenGl_PO_ClipPlanes1) != 0)
1487     {
1488       aSrcFragExtraMain += THE_FRAG_CLIP_PLANES_1;
1489     }
1490     else if ((theBits & OpenGl_PO_ClipPlanes2) != 0)
1491     {
1492       aSrcFragExtraMain += THE_FRAG_CLIP_PLANES_2;
1493     }
1494     else
1495     {
1496       aSrcFragExtraMain += THE_FRAG_CLIP_PLANES_N;
1497     }
1498   }
1499
1500   aSrcVert = TCollection_AsciiString()
1501     + THE_FUNC_transformNormal
1502     + EOL
1503       EOL"THE_SHADER_OUT vec4 PositionWorld;"
1504       EOL"THE_SHADER_OUT vec4 Position;"
1505       EOL"THE_SHADER_OUT vec3 Normal;"
1506       EOL"THE_SHADER_OUT vec3 View;"
1507       EOL
1508     + aSrcVertExtraOut
1509     + EOL"void main()"
1510       EOL"{"
1511       EOL"  PositionWorld = occModelWorldMatrix * occVertex;"
1512       EOL"  Position      = occWorldViewMatrix * PositionWorld;"
1513       EOL"  Normal        = transformNormal (occNormal);"
1514       EOL"  View          = vec3 (0.0, 0.0, 1.0);"
1515     + aSrcVertExtraMain
1516     + EOL"  gl_Position = occProjectionMatrix * occWorldViewMatrix * occModelWorldMatrix * occVertex;"
1517       EOL"}";
1518
1519   const TCollection_AsciiString aLights = stdComputeLighting ((theBits & OpenGl_PO_VertColor) != 0);
1520   aSrcFrag = TCollection_AsciiString()
1521     + EOL"THE_SHADER_IN vec4 PositionWorld;"
1522       EOL"THE_SHADER_IN vec4 Position;"
1523       EOL"THE_SHADER_IN vec3 Normal;"
1524       EOL"THE_SHADER_IN vec3 View;"
1525     + EOL
1526     + aSrcFragExtraOut
1527     + aSrcFragGetVertColor
1528     + aLights
1529     + aSrcFragGetColor
1530     + EOL
1531       EOL"void main()"
1532       EOL"{"
1533     + aSrcFragExtraMain
1534     + EOL"  occFragColor = getColor();"
1535       EOL"}";
1536
1537 #if !defined(GL_ES_VERSION_2_0)
1538   if (myContext->core32 != NULL)
1539   {
1540     aProgramSrc->SetHeader ("#version 150");
1541   }
1542 #endif
1543   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_VERTEX,   aSrcVert));
1544   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_FRAGMENT, aSrcFrag));
1545   TCollection_AsciiString aKey;
1546   if (!Create (aProgramSrc, aKey, theProgram))
1547   {
1548     theProgram = new OpenGl_ShaderProgram(); // just mark as invalid
1549     return Standard_False;
1550   }
1551   return Standard_True;
1552 }
1553
1554 // =======================================================================
1555 // function : prepareStdProgramStereo
1556 // purpose  :
1557 // =======================================================================
1558 Standard_Boolean OpenGl_ShaderManager::prepareStdProgramStereo (Handle(OpenGl_ShaderProgram)& theProgram,
1559                                                                 const Graphic3d_StereoMode    theStereoMode)
1560 {
1561   Handle(Graphic3d_ShaderProgram) aProgramSrc = new Graphic3d_ShaderProgram();
1562   TCollection_AsciiString aSrcVert =
1563       EOL"THE_SHADER_OUT vec2 TexCoord;"
1564       EOL"void main()"
1565       EOL"{"
1566       EOL"  TexCoord    = occVertex.zw;"
1567       EOL"  gl_Position = vec4(occVertex.x, occVertex.y, 0.0, 1.0);"
1568       EOL"}";
1569
1570   TCollection_AsciiString aSrcFrag;
1571   switch (theStereoMode)
1572   {
1573     case Graphic3d_StereoMode_Anaglyph:
1574     {
1575       aSrcFrag =
1576           EOL"uniform sampler2D uLeftSampler;"
1577           EOL"uniform sampler2D uRightSampler;"
1578           EOL
1579           EOL"uniform mat4 uMultL;"
1580           EOL"uniform mat4 uMultR;"
1581           EOL
1582           EOL"const vec4 THE_POW_UP   =       vec4 (2.2, 2.2, 2.2, 1.0);"
1583           EOL"const vec4 THE_POW_DOWN = 1.0 / vec4 (2.2, 2.2, 2.2, 1.0);"
1584           EOL
1585           EOL"THE_SHADER_IN vec2 TexCoord;"
1586           EOL
1587           EOL"void main()"
1588           EOL"{"
1589           EOL"  vec4 aColorL = occTexture2D (uLeftSampler,  TexCoord);"
1590           EOL"  vec4 aColorR = occTexture2D (uRightSampler, TexCoord);"
1591           EOL"  aColorL = pow (aColorL, THE_POW_UP);" // normalize
1592           EOL"  aColorR = pow (aColorR, THE_POW_UP);"
1593           EOL"  vec4 aColor = uMultR * aColorR + uMultL * aColorL;"
1594           EOL"  occFragColor = pow (aColor, THE_POW_DOWN);"
1595           EOL"}";
1596       break;
1597     }
1598     case Graphic3d_StereoMode_RowInterlaced:
1599     {
1600       aSrcFrag =
1601           EOL"uniform sampler2D uLeftSampler;"
1602           EOL"uniform sampler2D uRightSampler;"
1603           EOL
1604           EOL"THE_SHADER_IN vec2 TexCoord;"
1605           EOL
1606           EOL"void main()"
1607           EOL"{"
1608           EOL"  vec4 aColorL = occTexture2D (uLeftSampler,  TexCoord);"
1609           EOL"  vec4 aColorR = occTexture2D (uRightSampler, TexCoord);"
1610           EOL"  if (int (mod (gl_FragCoord.y - 1023.5, 2.0)) != 1)"
1611           EOL"  {"
1612           EOL"    occFragColor = aColorL;"
1613           EOL"  }"
1614           EOL"  else"
1615           EOL"  {"
1616           EOL"    occFragColor = aColorR;"
1617           EOL"  }"
1618           EOL"}";
1619       break;
1620     }
1621     case Graphic3d_StereoMode_ColumnInterlaced:
1622     {
1623       aSrcFrag =
1624           EOL"uniform sampler2D uLeftSampler;"
1625           EOL"uniform sampler2D uRightSampler;"
1626           EOL
1627           EOL"THE_SHADER_IN vec2 TexCoord;"
1628           EOL
1629           EOL"void main()"
1630           EOL"{"
1631           EOL"  vec4 aColorL = occTexture2D (uLeftSampler,  TexCoord);"
1632           EOL"  vec4 aColorR = occTexture2D (uRightSampler, TexCoord);"
1633           EOL"  if (int (mod (gl_FragCoord.x - 1023.5, 2.0)) == 1)"
1634           EOL"  {"
1635           EOL"    occFragColor = aColorL;"
1636           EOL"  }"
1637           EOL"  else"
1638           EOL"  {"
1639           EOL"    occFragColor = aColorR;"
1640           EOL"  }"
1641           EOL"}";
1642       break;
1643     }
1644     case Graphic3d_StereoMode_ChessBoard:
1645     {
1646       aSrcFrag =
1647           EOL"uniform sampler2D uLeftSampler;"
1648           EOL"uniform sampler2D uRightSampler;"
1649           EOL
1650           EOL"THE_SHADER_IN vec2 TexCoord;"
1651           EOL
1652           EOL"void main()"
1653           EOL"{"
1654           EOL"  vec4 aColorL = occTexture2D (uLeftSampler,  TexCoord);"
1655           EOL"  vec4 aColorR = occTexture2D (uRightSampler, TexCoord);"
1656           EOL"  bool isEvenX = int(mod(floor(gl_FragCoord.x - 1023.5), 2.0)) != 1;"
1657           EOL"  bool isEvenY = int(mod(floor(gl_FragCoord.y - 1023.5), 2.0)) == 1;"
1658           EOL"  if ((isEvenX && isEvenY) || (!isEvenX && !isEvenY))"
1659           EOL"  {"
1660           EOL"    occFragColor = aColorL;"
1661           EOL"  }"
1662           EOL"  else"
1663           EOL"  {"
1664           EOL"    occFragColor = aColorR;"
1665           EOL"  }"
1666           EOL"}";
1667       break;
1668     }
1669     case Graphic3d_StereoMode_SideBySide:
1670     {
1671       aSrcFrag =
1672           EOL"uniform sampler2D uLeftSampler;"
1673           EOL"uniform sampler2D uRightSampler;"
1674           EOL
1675           EOL"THE_SHADER_IN vec2 TexCoord;"
1676           EOL
1677           EOL"void main()"
1678           EOL"{"
1679           EOL"  vec2 aTexCoord = vec2 (TexCoord.x * 2.0, TexCoord.y);"
1680           EOL"  if (TexCoord.x > 0.5)"
1681           EOL"  {"
1682           EOL"    aTexCoord.x -= 1.0;"
1683           EOL"  }"
1684           EOL"  vec4 aColorL = occTexture2D (uLeftSampler,  aTexCoord);"
1685           EOL"  vec4 aColorR = occTexture2D (uRightSampler, aTexCoord);"
1686           EOL"  if (TexCoord.x <= 0.5)"
1687           EOL"  {"
1688           EOL"    occFragColor = aColorL;"
1689           EOL"  }"
1690           EOL"  else"
1691           EOL"  {"
1692           EOL"    occFragColor = aColorR;"
1693           EOL"  }"
1694           EOL"}";
1695       break;
1696     }
1697     case Graphic3d_StereoMode_OverUnder:
1698     {
1699       aSrcFrag =
1700           EOL"uniform sampler2D uLeftSampler;"
1701           EOL"uniform sampler2D uRightSampler;"
1702           EOL
1703           EOL"THE_SHADER_IN vec2 TexCoord;"
1704           EOL
1705           EOL"void main()"
1706           EOL"{"
1707           EOL"  vec2 aTexCoord = vec2 (TexCoord.x, TexCoord.y * 2.0);"
1708           EOL"  if (TexCoord.y > 0.5)"
1709           EOL"  {"
1710           EOL"    aTexCoord.y -= 1.0;"
1711           EOL"  }"
1712           EOL"  vec4 aColorL = occTexture2D (uLeftSampler,  aTexCoord);"
1713           EOL"  vec4 aColorR = occTexture2D (uRightSampler, aTexCoord);"
1714           EOL"  if (TexCoord.y <= 0.5)"
1715           EOL"  {"
1716           EOL"    occFragColor = aColorL;"
1717           EOL"  }"
1718           EOL"  else"
1719           EOL"  {"
1720           EOL"    occFragColor = aColorR;"
1721           EOL"  }"
1722           EOL"}";
1723       break;
1724     }
1725     case Graphic3d_StereoMode_QuadBuffer:
1726     case Graphic3d_StereoMode_SoftPageFlip:
1727     default:
1728     {
1729       /*const Handle(OpenGl_ShaderProgram)& aProgram = myStereoPrograms[Graphic3d_StereoMode_QuadBuffer];
1730       if (!aProgram.IsNull())
1731       {
1732         return aProgram->IsValid();
1733       }*/
1734       aSrcFrag =
1735           EOL"uniform sampler2D uLeftSampler;"
1736           EOL"uniform sampler2D uRightSampler;"
1737           EOL
1738           EOL"THE_SHADER_IN vec2 TexCoord;"
1739           EOL
1740           EOL"void main()"
1741           EOL"{"
1742           EOL"  vec4 aColorL = occTexture2D (uLeftSampler,  TexCoord);"
1743           EOL"  vec4 aColorR = occTexture2D (uRightSampler, TexCoord);"
1744           EOL"  aColorL.b = 0.0;"
1745           EOL"  aColorL.g = 0.0;"
1746           EOL"  aColorR.r = 0.0;"
1747           EOL"  occFragColor = aColorL + aColorR;"
1748           EOL"}";
1749       break;
1750     }
1751   }
1752
1753 #if !defined(GL_ES_VERSION_2_0)
1754   if (myContext->core32 != NULL)
1755   {
1756     aProgramSrc->SetHeader ("#version 150");
1757   }
1758 #endif
1759
1760   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_VERTEX,   aSrcVert));
1761   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_FRAGMENT, aSrcFrag));
1762   TCollection_AsciiString aKey;
1763   if (!Create (aProgramSrc, aKey, theProgram))
1764   {
1765     theProgram = new OpenGl_ShaderProgram(); // just mark as invalid
1766     return Standard_False;
1767   }
1768
1769   myContext->BindProgram (theProgram);
1770   theProgram->SetSampler (myContext, "uLeftSampler",  0);
1771   theProgram->SetSampler (myContext, "uRightSampler", 1);
1772   myContext->BindProgram (NULL);
1773   return Standard_True;
1774 }
1775
1776 // =======================================================================
1777 // function : bindProgramWithState
1778 // purpose  :
1779 // =======================================================================
1780 Standard_Boolean OpenGl_ShaderManager::bindProgramWithState (const Handle(OpenGl_ShaderProgram)& theProgram)
1781 {
1782   if (!myContext->BindProgram (theProgram))
1783   {
1784     return Standard_False;
1785   }
1786   theProgram->ApplyVariables (myContext);
1787
1788   PushState (theProgram);
1789   return Standard_True;
1790 }