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