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