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