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