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