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