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