0032121: Draw Harness, ViewerTest - implement -reset option for vlight command
[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 <OpenGl_ShaderManager.hxx>
17
18 #include <Graphic3d_CubeMapPacked.hxx>
19 #include <Graphic3d_TextureParams.hxx>
20 #include <OpenGl_Aspects.hxx>
21 #include <OpenGl_ClippingIterator.hxx>
22 #include <OpenGl_Context.hxx>
23 #include <OpenGl_ShadowMap.hxx>
24 #include <OpenGl_ShaderProgram.hxx>
25 #include <OpenGl_VertexBufferCompat.hxx>
26 #include <OpenGl_PointSprite.hxx>
27 #include <OpenGl_Workspace.hxx>
28
29 IMPLEMENT_STANDARD_RTTIEXT(OpenGl_ShaderManager, Graphic3d_ShaderManager)
30
31 namespace
32 {
33 #if !defined(GL_ES_VERSION_2_0)
34
35   static const GLfloat THE_DEFAULT_AMBIENT[4]    = { 0.0f, 0.0f, 0.0f, 1.0f };
36   static const GLfloat THE_DEFAULT_SPOT_DIR[3]   = { 0.0f, 0.0f, -1.0f };
37   static const GLfloat THE_DEFAULT_SPOT_EXPONENT = 0.0f;
38   static const GLfloat THE_DEFAULT_SPOT_CUTOFF   = 180.0f;
39
40   //! Bind FFP light source.
41   static void bindLight (const Graphic3d_CLight& theLight,
42                          const GLenum        theLightGlId,
43                          const OpenGl_Mat4&  theModelView,
44                          OpenGl_Context*     theCtx)
45   {
46     // the light is a headlight?
47     if (theLight.IsHeadlight())
48     {
49       theCtx->core11ffp->glMatrixMode (GL_MODELVIEW);
50       theCtx->core11ffp->glLoadIdentity();
51     }
52
53     // setup light type
54     const Graphic3d_Vec4& aLightColor = theLight.PackedColor();
55     switch (theLight.Type())
56     {
57       case Graphic3d_TypeOfLightSource_Ambient:
58       {
59         break; // handled by separate if-clause at beginning of method
60       }
61       case Graphic3d_TypeOfLightSource_Directional:
62       {
63         // if the last parameter of GL_POSITION, is zero, the corresponding light source is a Directional one
64         const OpenGl_Vec4 anInfDir = -theLight.PackedDirectionRange();
65
66         // to create a realistic effect,  set the GL_SPECULAR parameter to the same value as the GL_DIFFUSE.
67         theCtx->core11ffp->glLightfv (theLightGlId, GL_AMBIENT,               THE_DEFAULT_AMBIENT);
68         theCtx->core11ffp->glLightfv (theLightGlId, GL_DIFFUSE,               aLightColor.GetData());
69         theCtx->core11ffp->glLightfv (theLightGlId, GL_SPECULAR,              aLightColor.GetData());
70         theCtx->core11ffp->glLightfv (theLightGlId, GL_POSITION,              anInfDir.GetData());
71         theCtx->core11ffp->glLightfv (theLightGlId, GL_SPOT_DIRECTION,        THE_DEFAULT_SPOT_DIR);
72         theCtx->core11ffp->glLightf  (theLightGlId, GL_SPOT_EXPONENT,         THE_DEFAULT_SPOT_EXPONENT);
73         theCtx->core11ffp->glLightf  (theLightGlId, GL_SPOT_CUTOFF,           THE_DEFAULT_SPOT_CUTOFF);
74         break;
75       }
76       case Graphic3d_TypeOfLightSource_Positional:
77       {
78         // to create a realistic effect, set the GL_SPECULAR parameter to the same value as the GL_DIFFUSE
79         const OpenGl_Vec4 aPosition (static_cast<float>(theLight.Position().X()), static_cast<float>(theLight.Position().Y()), static_cast<float>(theLight.Position().Z()), 1.0f);
80         theCtx->core11ffp->glLightfv (theLightGlId, GL_AMBIENT,               THE_DEFAULT_AMBIENT);
81         theCtx->core11ffp->glLightfv (theLightGlId, GL_DIFFUSE,               aLightColor.GetData());
82         theCtx->core11ffp->glLightfv (theLightGlId, GL_SPECULAR,              aLightColor.GetData());
83         theCtx->core11ffp->glLightfv (theLightGlId, GL_POSITION,              aPosition.GetData());
84         theCtx->core11ffp->glLightfv (theLightGlId, GL_SPOT_DIRECTION,        THE_DEFAULT_SPOT_DIR);
85         theCtx->core11ffp->glLightf  (theLightGlId, GL_SPOT_EXPONENT,         THE_DEFAULT_SPOT_EXPONENT);
86         theCtx->core11ffp->glLightf  (theLightGlId, GL_SPOT_CUTOFF,           THE_DEFAULT_SPOT_CUTOFF);
87         theCtx->core11ffp->glLightf  (theLightGlId, GL_CONSTANT_ATTENUATION,  theLight.ConstAttenuation());
88         theCtx->core11ffp->glLightf  (theLightGlId, GL_LINEAR_ATTENUATION,    theLight.LinearAttenuation());
89         theCtx->core11ffp->glLightf  (theLightGlId, GL_QUADRATIC_ATTENUATION, 0.0f);
90         break;
91       }
92       case Graphic3d_TypeOfLightSource_Spot:
93       {
94         const OpenGl_Vec4 aPosition (static_cast<float>(theLight.Position().X()), static_cast<float>(theLight.Position().Y()), static_cast<float>(theLight.Position().Z()), 1.0f);
95         theCtx->core11ffp->glLightfv (theLightGlId, GL_AMBIENT,               THE_DEFAULT_AMBIENT);
96         theCtx->core11ffp->glLightfv (theLightGlId, GL_DIFFUSE,               aLightColor.GetData());
97         theCtx->core11ffp->glLightfv (theLightGlId, GL_SPECULAR,              aLightColor.GetData());
98         theCtx->core11ffp->glLightfv (theLightGlId, GL_POSITION,              aPosition.GetData());
99         theCtx->core11ffp->glLightfv (theLightGlId, GL_SPOT_DIRECTION,        theLight.PackedDirectionRange().GetData());
100         theCtx->core11ffp->glLightf  (theLightGlId, GL_SPOT_EXPONENT,         theLight.Concentration() * 128.0f);
101         theCtx->core11ffp->glLightf  (theLightGlId, GL_SPOT_CUTOFF,          (theLight.Angle() * 180.0f) / GLfloat(M_PI));
102         theCtx->core11ffp->glLightf  (theLightGlId, GL_CONSTANT_ATTENUATION,  theLight.ConstAttenuation());
103         theCtx->core11ffp->glLightf  (theLightGlId, GL_LINEAR_ATTENUATION,    theLight.LinearAttenuation());
104         theCtx->core11ffp->glLightf  (theLightGlId, GL_QUADRATIC_ATTENUATION, 0.0f);
105         break;
106       }
107     }
108
109     // restore matrix in case of headlight
110     if (theLight.IsHeadlight())
111     {
112       theCtx->core11ffp->glLoadMatrixf (theModelView.GetData());
113     }
114
115     glEnable (theLightGlId);
116   }
117 #endif
118 }
119
120 // =======================================================================
121 // function : OpenGl_ShaderManager
122 // purpose  : Creates new empty shader manager
123 // =======================================================================
124 OpenGl_ShaderManager::OpenGl_ShaderManager (OpenGl_Context* theContext)
125 #if defined(GL_ES_VERSION_2_0)
126 : Graphic3d_ShaderManager (Aspect_GraphicsLibrary_OpenGLES),
127 #else
128 : Graphic3d_ShaderManager (Aspect_GraphicsLibrary_OpenGL),
129 #endif
130   myFfpProgram (new OpenGl_ShaderProgramFFP()),
131   myShadingModel (Graphic3d_TOSM_VERTEX),
132   myUnlitPrograms (new OpenGl_SetOfPrograms()),
133   myContext  (theContext),
134   myHasLocalOrigin (Standard_False)
135 {
136   mySRgbState = theContext->ToRenderSRGB();
137 }
138
139 // =======================================================================
140 // function : ~OpenGl_ShaderManager
141 // purpose  : Releases resources of shader manager
142 // =======================================================================
143 OpenGl_ShaderManager::~OpenGl_ShaderManager()
144 {
145   myProgramList.Clear();
146   if (!myPBREnvironment.IsNull())
147   {
148     myPBREnvironment->Release (myContext);
149   }
150 }
151
152 // =======================================================================
153 // function : clear
154 // purpose  :
155 // =======================================================================
156 void OpenGl_ShaderManager::clear()
157 {
158   myProgramList.Clear();
159   myLightPrograms.Nullify();
160   myUnlitPrograms = new OpenGl_SetOfPrograms();
161   myOutlinePrograms.Nullify();
162   myMapOfLightPrograms.Clear();
163   myFontProgram.Nullify();
164   myBlitPrograms[0].Init (Handle(OpenGl_ShaderProgram)());
165   myBlitPrograms[1].Init (Handle(OpenGl_ShaderProgram)());
166   myBoundBoxProgram.Nullify();
167   myBoundBoxVertBuffer.Nullify();
168   for (Standard_Integer aModeIter = 0; aModeIter < Graphic3d_StereoMode_NB; ++aModeIter)
169   {
170     myStereoPrograms[aModeIter].Nullify();
171   }
172   switchLightPrograms();
173 }
174
175 // =======================================================================
176 // function : Create
177 // purpose  : Creates new shader program
178 // =======================================================================
179 Standard_Boolean OpenGl_ShaderManager::Create (const Handle(Graphic3d_ShaderProgram)& theProxy,
180                                                TCollection_AsciiString&               theShareKey,
181                                                Handle(OpenGl_ShaderProgram)&          theProgram)
182 {
183   theProgram.Nullify();
184   if (theProxy.IsNull())
185   {
186     return Standard_False;
187   }
188
189   theShareKey = theProxy->GetId();
190   if (myContext->GetResource<Handle(OpenGl_ShaderProgram)> (theShareKey, theProgram))
191   {
192     if (theProgram->Share())
193     {
194       myProgramList.Append (theProgram);
195     }
196     return Standard_True;
197   }
198
199   theProgram = new OpenGl_ShaderProgram (theProxy);
200   if (!theProgram->Initialize (myContext, theProxy->ShaderObjects()))
201   {
202     theProgram->Release (myContext);
203     theShareKey.Clear();
204     theProgram.Nullify();
205     return Standard_False;
206   }
207
208   myProgramList.Append (theProgram);
209   myContext->ShareResource (theShareKey, theProgram);
210   return Standard_True;
211 }
212
213 // =======================================================================
214 // function : Unregister
215 // purpose  : Removes specified shader program from the manager
216 // =======================================================================
217 void OpenGl_ShaderManager::Unregister (TCollection_AsciiString&      theShareKey,
218                                        Handle(OpenGl_ShaderProgram)& theProgram)
219 {
220   for (OpenGl_ShaderProgramList::Iterator anIt (myProgramList); anIt.More(); anIt.Next())
221   {
222     if (anIt.Value() == theProgram)
223     {
224       if (!theProgram->UnShare())
225       {
226         theShareKey.Clear();
227         theProgram.Nullify();
228         return;
229       }
230
231       myProgramList.Remove (anIt);
232       break;
233     }
234   }
235
236   const TCollection_AsciiString anID = theProgram->myProxy->GetId();
237   if (anID.IsEmpty())
238   {
239     myContext->DelayedRelease (theProgram);
240     theProgram.Nullify();
241   }
242   else
243   {
244     theProgram.Nullify();
245     myContext->ReleaseResource (anID, Standard_True);
246   }
247 }
248
249 // =======================================================================
250 // function : switchLightPrograms
251 // purpose  :
252 // =======================================================================
253 void OpenGl_ShaderManager::switchLightPrograms()
254 {
255   const Handle(Graphic3d_LightSet)& aLights = myLightSourceState.LightSources();
256   if (aLights.IsNull())
257   {
258     if (!myMapOfLightPrograms.Find ("unlit", myLightPrograms))
259     {
260       myLightPrograms = new OpenGl_SetOfShaderPrograms (myUnlitPrograms);
261       myMapOfLightPrograms.Bind ("unlit", myLightPrograms);
262     }
263     return;
264   }
265
266   const TCollection_AsciiString aKey = genLightKey (aLights, myLightSourceState.HasShadowMaps());
267   if (!myMapOfLightPrograms.Find (aKey, myLightPrograms))
268   {
269     myLightPrograms = new OpenGl_SetOfShaderPrograms();
270     myMapOfLightPrograms.Bind (aKey, myLightPrograms);
271   }
272 }
273
274 // =======================================================================
275 // function : UpdateSRgbState
276 // purpose  :
277 // =======================================================================
278 void OpenGl_ShaderManager::UpdateSRgbState()
279 {
280   if (mySRgbState == myContext->ToRenderSRGB())
281   {
282     return;
283   }
284
285   mySRgbState = myContext->ToRenderSRGB();
286
287   // special cases - GLSL programs dealing with sRGB/linearRGB internally
288   myStereoPrograms[Graphic3d_StereoMode_Anaglyph].Nullify();
289 }
290
291 // =======================================================================
292 // function : UpdateLightSourceStateTo
293 // purpose  : Updates state of OCCT light sources
294 // =======================================================================
295 void OpenGl_ShaderManager::UpdateLightSourceStateTo (const Handle(Graphic3d_LightSet)& theLights,
296                                                      Standard_Integer theSpecIBLMapLevels,
297                                                      const Handle(OpenGl_ShadowMapArray)& theShadowMaps)
298 {
299   myLightSourceState.Set (theLights);
300   myLightSourceState.SetSpecIBLMapLevels (theSpecIBLMapLevels);
301   myLightSourceState.SetShadowMaps (theShadowMaps);
302   myLightSourceState.Update();
303   switchLightPrograms();
304 }
305
306 // =======================================================================
307 // function : UpdateLightSourceState
308 // purpose  :
309 // =======================================================================
310 void OpenGl_ShaderManager::UpdateLightSourceState()
311 {
312   myLightSourceState.Update();
313 }
314
315 // =======================================================================
316 // function : SetShadingModel
317 // purpose  :
318 // =======================================================================
319 void OpenGl_ShaderManager::SetShadingModel (const Graphic3d_TypeOfShadingModel theModel)
320 {
321   if (theModel == Graphic3d_TOSM_DEFAULT)
322   {
323     throw Standard_ProgramError ("OpenGl_ShaderManager::SetShadingModel() - attempt to set invalid Shading Model!");
324   }
325
326   myShadingModel = theModel;
327   switchLightPrograms();
328 }
329
330 // =======================================================================
331 // function : SetProjectionState
332 // purpose  : Sets new state of OCCT projection transform
333 // =======================================================================
334 void OpenGl_ShaderManager::UpdateProjectionStateTo (const OpenGl_Mat4& theProjectionMatrix)
335 {
336   myProjectionState.Set (theProjectionMatrix);
337   myProjectionState.Update();
338 }
339
340 // =======================================================================
341 // function : SetModelWorldState
342 // purpose  : Sets new state of OCCT model-world transform
343 // =======================================================================
344 void OpenGl_ShaderManager::UpdateModelWorldStateTo (const OpenGl_Mat4& theModelWorldMatrix)
345 {
346   myModelWorldState.Set (theModelWorldMatrix);
347   myModelWorldState.Update();
348 }
349
350 // =======================================================================
351 // function : SetWorldViewState
352 // purpose  : Sets new state of OCCT world-view transform
353 // =======================================================================
354 void OpenGl_ShaderManager::UpdateWorldViewStateTo (const OpenGl_Mat4& theWorldViewMatrix)
355 {
356   myWorldViewState.Set (theWorldViewMatrix);
357   myWorldViewState.Update();
358 }
359
360 // =======================================================================
361 // function : pushLightSourceState
362 // purpose  :
363 // =======================================================================
364 void OpenGl_ShaderManager::pushLightSourceState (const Handle(OpenGl_ShaderProgram)& theProgram) const
365 {
366   theProgram->UpdateState (OpenGl_LIGHT_SOURCES_STATE, myLightSourceState.Index());
367   if (theProgram == myFfpProgram)
368   {
369   #if !defined(GL_ES_VERSION_2_0)
370     if (myContext->core11ffp == NULL)
371     {
372       return;
373     }
374
375     GLenum aLightGlId = GL_LIGHT0;
376     const OpenGl_Mat4 aModelView = myWorldViewState.WorldViewMatrix() * myModelWorldState.ModelWorldMatrix();
377     for (Graphic3d_LightSet::Iterator aLightIt (myLightSourceState.LightSources(), Graphic3d_LightSet::IterationFilter_ExcludeDisabledAndAmbient);
378          aLightIt.More(); aLightIt.Next())
379     {
380       if (aLightGlId > GL_LIGHT7) // only 8 lights in FFP...
381       {
382         myContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_MEDIUM,
383                                 "Warning: light sources limit (8) has been exceeded within Fixed-function pipeline.");
384         continue;
385       }
386
387       bindLight (*aLightIt.Value(), aLightGlId, aModelView, myContext);
388       ++aLightGlId;
389     }
390
391     // apply accumulated ambient color
392     const Graphic3d_Vec4 anAmbient = !myLightSourceState.LightSources().IsNull()
393                                     ? myLightSourceState.LightSources()->AmbientColor()
394                                     : Graphic3d_Vec4 (0.0f, 0.0f, 0.0f, 1.0f);
395     myContext->core11ffp->glLightModelfv (GL_LIGHT_MODEL_AMBIENT, anAmbient.GetData());
396
397     // GL_LIGHTING is managed by drawers to switch between shaded / no lighting output,
398     // therefore managing the state here does not have any effect - do it just for consistency.
399     if (aLightGlId != GL_LIGHT0)
400     {
401       myContext->core11fwd->glEnable (GL_LIGHTING);
402     }
403     else
404     {
405       myContext->core11fwd->glDisable (GL_LIGHTING);
406     }
407     // switch off unused lights
408     for (; aLightGlId <= GL_LIGHT7; ++aLightGlId)
409     {
410       myContext->core11fwd->glDisable (aLightGlId);
411     }
412   #endif
413     return;
414   }
415
416   const Standard_Integer aNbLightsMax = theProgram->NbLightsMax();
417   const GLint anAmbientLoc = theProgram->GetStateLocation (OpenGl_OCC_LIGHT_AMBIENT);
418   if (aNbLightsMax == 0
419    && anAmbientLoc == OpenGl_ShaderProgram::INVALID_LOCATION)
420   {
421     return;
422   }
423
424   if (myLightTypeArray.Size() < aNbLightsMax)
425   {
426     myLightTypeArray  .Resize (0, aNbLightsMax - 1, false);
427     myLightParamsArray.Resize (0, aNbLightsMax - 1, false);
428   }
429   for (Standard_Integer aLightIt = 0; aLightIt < aNbLightsMax; ++aLightIt)
430   {
431     myLightTypeArray.SetValue (aLightIt, -1);
432   }
433
434   if (myLightSourceState.LightSources().IsNull()
435    || myLightSourceState.LightSources()->IsEmpty())
436   {
437     theProgram->SetUniform (myContext,
438                             theProgram->GetStateLocation (OpenGl_OCC_LIGHT_SOURCE_COUNT),
439                             0);
440     theProgram->SetUniform (myContext,
441                             anAmbientLoc,
442                             OpenGl_Vec4 (0.0f, 0.0f, 0.0f, 0.0f));
443     theProgram->SetUniform (myContext,
444                             theProgram->GetStateLocation (OpenGl_OCC_LIGHT_SOURCE_TYPES),
445                             aNbLightsMax,
446                             &myLightTypeArray.First());
447     return;
448   }
449
450   Standard_Integer aLightsNb = 0;
451   for (Graphic3d_LightSet::Iterator anIter (myLightSourceState.LightSources(), Graphic3d_LightSet::IterationFilter_ExcludeDisabledAndAmbient);
452        anIter.More(); anIter.Next())
453   {
454     const Graphic3d_CLight& aLight = *anIter.Value();
455     if (aLightsNb >= aNbLightsMax)
456     {
457       if (aNbLightsMax != 0)
458       {
459         myContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_MEDIUM,
460                                 TCollection_AsciiString("Warning: light sources limit (") + aNbLightsMax + ") has been exceeded.");
461       }
462       continue;
463     }
464
465     Standard_Integer&             aLightType   = myLightTypeArray  .ChangeValue (aLightsNb);
466     OpenGl_ShaderLightParameters& aLightParams = myLightParamsArray.ChangeValue (aLightsNb);
467     if (!aLight.IsEnabled()) // has no affect with Graphic3d_LightSet::IterationFilter_ExcludeDisabled - here just for consistency
468     {
469       // if it is desired to keep disabled light in the same order - we can replace it with a black light so that it will have no influence on result
470       aLightType = -1; // Graphic3d_TypeOfLightSource_Ambient can be used instead
471       aLightParams.Color = OpenGl_Vec4 (0.0f, 0.0f, 0.0f, 0.0f);
472       ++aLightsNb;
473       continue;
474     }
475
476     // ignoring OpenGl_Context::ToRenderSRGB() for light colors,
477     // as non-absolute colors for lights are rare and require tuning anyway
478     aLightType = aLight.Type();
479     aLightParams.Color     = aLight.PackedColor();
480     aLightParams.Color.a() = aLight.Intensity(); // used by PBR and ignored by old shading model
481     aLightParams.Parameters = aLight.PackedParams();
482     switch (aLight.Type())
483     {
484       case Graphic3d_TypeOfLightSource_Ambient:
485       {
486         break;
487       }
488       case Graphic3d_TypeOfLightSource_Directional:
489       {
490         if (aLight.IsHeadlight())
491         {
492           const Graphic3d_Mat4& anOrientInv = myWorldViewState.WorldViewMatrixInverse();
493           aLightParams.Position = anOrientInv * Graphic3d_Vec4 (-aLight.PackedDirection(), 0.0f);
494           aLightParams.Position.SetValues (aLightParams.Position.xyz().Normalized(), 0.0f);
495         }
496         else
497         {
498           aLightParams.Position = Graphic3d_Vec4 (-aLight.PackedDirection(), 0.0f);
499         }
500         break;
501       }
502       case Graphic3d_TypeOfLightSource_Spot:
503       {
504         if (aLight.IsHeadlight())
505         {
506           const Graphic3d_Mat4& anOrientInv = myWorldViewState.WorldViewMatrixInverse();
507           aLightParams.Direction = anOrientInv * Graphic3d_Vec4 (aLight.PackedDirection(), 0.0f);
508           aLightParams.Direction.SetValues (aLightParams.Direction.xyz().Normalized(), 0.0f);
509         }
510         else
511         {
512           aLightParams.Direction = Graphic3d_Vec4 (aLight.PackedDirection(), 0.0f);
513         }
514       }
515       Standard_FALLTHROUGH
516       case Graphic3d_TypeOfLightSource_Positional:
517       {
518         if (aLight.IsHeadlight())
519         {
520           aLightParams.Position.x() = static_cast<float>(aLight.Position().X());
521           aLightParams.Position.y() = static_cast<float>(aLight.Position().Y());
522           aLightParams.Position.z() = static_cast<float>(aLight.Position().Z());
523           const Graphic3d_Mat4& anOrientInv = myWorldViewState.WorldViewMatrixInverse();
524           aLightParams.Position = anOrientInv * Graphic3d_Vec4 (aLightParams.Position.xyz(), 1.0f);
525         }
526         else
527         {
528           aLightParams.Position.x() = static_cast<float>(aLight.Position().X() - myLocalOrigin.X());
529           aLightParams.Position.y() = static_cast<float>(aLight.Position().Y() - myLocalOrigin.Y());
530           aLightParams.Position.z() = static_cast<float>(aLight.Position().Z() - myLocalOrigin.Z());
531           aLightParams.Position.w() = 0.0f;
532         }
533         aLightParams.Direction.w() = aLight.Range();
534         break;
535       }
536     }
537     ++aLightsNb;
538   }
539
540   const Graphic3d_Vec4& anAmbient = myLightSourceState.LightSources()->AmbientColor();
541   theProgram->SetUniform (myContext,
542                           theProgram->GetStateLocation (OpenGl_OCC_LIGHT_SOURCE_COUNT),
543                           aLightsNb);
544   theProgram->SetUniform (myContext,
545                           anAmbientLoc,
546                           anAmbient);
547   theProgram->SetUniform (myContext,
548                           theProgram->GetStateLocation (OpenGl_OCC_LIGHT_SOURCE_TYPES),
549                           aNbLightsMax,
550                           &myLightTypeArray.First());
551   if (aLightsNb > 0)
552   {
553     theProgram->SetUniform (myContext,
554                             theProgram->GetStateLocation (OpenGl_OCC_LIGHT_SOURCE_PARAMS),
555                             aLightsNb * OpenGl_ShaderLightParameters::NbOfVec4(),
556                             myLightParamsArray.First().Packed());
557   }
558
559   if (const OpenGl_ShaderUniformLocation aLocation = theProgram->GetStateLocation (OpenGl_OCCT_NB_SPEC_IBL_LEVELS))
560   {
561     theProgram->SetUniform (myContext, aLocation, myLightSourceState.SpecIBLMapLevels());
562   }
563
564   // update shadow map variables
565   if (const OpenGl_ShaderUniformLocation aShadowMatLoc = theProgram->GetStateLocation (OpenGl_OCC_LIGHT_SHADOWMAP_MATRICES))
566   {
567     if (myShadowMatArray.Size() < theProgram->NbShadowMaps())
568     {
569       myShadowMatArray.Resize (0, theProgram->NbShadowMaps() - 1, false);
570     }
571
572     Graphic3d_Vec2 aSizeBias;
573     if (myLightSourceState.HasShadowMaps())
574     {
575       aSizeBias.SetValues (1.0f / (float )myLightSourceState.ShadowMaps()->First()->Texture()->SizeX(),
576                            myLightSourceState.ShadowMaps()->First()->ShadowMapBias());
577       const Standard_Integer aNbShadows = Min (theProgram->NbShadowMaps(), myLightSourceState.ShadowMaps()->Size());
578       for (Standard_Integer aShadowIter = 0; aShadowIter < aNbShadows; ++aShadowIter)
579       {
580         const Handle(OpenGl_ShadowMap)& aShadow = myLightSourceState.ShadowMaps()->Value (aShadowIter);
581         myShadowMatArray[aShadowIter] = aShadow->LightSourceMatrix();
582       }
583     }
584
585     theProgram->SetUniform (myContext, aShadowMatLoc, theProgram->NbShadowMaps(), &myShadowMatArray.First());
586     theProgram->SetUniform (myContext, theProgram->GetStateLocation (OpenGl_OCC_LIGHT_SHADOWMAP_SIZE_BIAS), aSizeBias);
587   }
588 }
589
590 // =======================================================================
591 // function : pushProjectionState
592 // purpose  :
593 // =======================================================================
594 void OpenGl_ShaderManager::pushProjectionState (const Handle(OpenGl_ShaderProgram)& theProgram) const
595 {
596   theProgram->UpdateState (OpenGl_PROJECTION_STATE, myProjectionState.Index());
597   if (theProgram == myFfpProgram)
598   {
599   #if !defined(GL_ES_VERSION_2_0)
600     if (myContext->core11ffp != NULL)
601     {
602       myContext->core11ffp->glMatrixMode (GL_PROJECTION);
603       myContext->core11ffp->glLoadMatrixf (myProjectionState.ProjectionMatrix().GetData());
604     }
605   #endif
606     return;
607   }
608
609   theProgram->SetUniform (myContext,
610                           theProgram->GetStateLocation (OpenGl_OCC_PROJECTION_MATRIX),
611                           myProjectionState.ProjectionMatrix());
612
613   GLint aLocation = theProgram->GetStateLocation (OpenGl_OCC_PROJECTION_MATRIX_INVERSE);
614   if (aLocation != OpenGl_ShaderProgram::INVALID_LOCATION)
615   {
616     theProgram->SetUniform (myContext, aLocation, myProjectionState.ProjectionMatrixInverse());
617   }
618
619   theProgram->SetUniform (myContext,
620                           theProgram->GetStateLocation (OpenGl_OCC_PROJECTION_MATRIX_TRANSPOSE),
621                           myProjectionState.ProjectionMatrix(), true);
622
623   aLocation = theProgram->GetStateLocation (OpenGl_OCC_PROJECTION_MATRIX_INVERSE_TRANSPOSE);
624   if (aLocation != OpenGl_ShaderProgram::INVALID_LOCATION)
625   {
626     theProgram->SetUniform (myContext, aLocation, myProjectionState.ProjectionMatrixInverse(), true);
627   }
628 }
629
630 // =======================================================================
631 // function : pushModelWorldState
632 // purpose  :
633 // =======================================================================
634 void OpenGl_ShaderManager::pushModelWorldState (const Handle(OpenGl_ShaderProgram)& theProgram) const
635 {
636   theProgram->UpdateState (OpenGl_MODEL_WORLD_STATE, myModelWorldState.Index());
637   if (theProgram == myFfpProgram)
638   {
639   #if !defined(GL_ES_VERSION_2_0)
640     if (myContext->core11ffp != NULL)
641     {
642       const OpenGl_Mat4 aModelView = myWorldViewState.WorldViewMatrix() * myModelWorldState.ModelWorldMatrix();
643       myContext->core11ffp->glMatrixMode (GL_MODELVIEW);
644       myContext->core11ffp->glLoadMatrixf (aModelView.GetData());
645       theProgram->UpdateState (OpenGl_WORLD_VIEW_STATE, myWorldViewState.Index());
646     }
647   #endif
648     return;
649   }
650
651   theProgram->SetUniform (myContext,
652                           theProgram->GetStateLocation (OpenGl_OCC_MODEL_WORLD_MATRIX),
653                           myModelWorldState.ModelWorldMatrix());
654
655   GLint aLocation = theProgram->GetStateLocation (OpenGl_OCC_MODEL_WORLD_MATRIX_INVERSE);
656   if (aLocation != OpenGl_ShaderProgram::INVALID_LOCATION)
657   {
658     theProgram->SetUniform (myContext, aLocation, myModelWorldState.ModelWorldMatrixInverse());
659   }
660
661   theProgram->SetUniform (myContext,
662                           theProgram->GetStateLocation (OpenGl_OCC_MODEL_WORLD_MATRIX_TRANSPOSE),
663                           myModelWorldState.ModelWorldMatrix(), true);
664
665   aLocation = theProgram->GetStateLocation (OpenGl_OCC_MODEL_WORLD_MATRIX_INVERSE_TRANSPOSE);
666   if (aLocation != OpenGl_ShaderProgram::INVALID_LOCATION)
667   {
668     theProgram->SetUniform (myContext, aLocation, myModelWorldState.ModelWorldMatrixInverse(), true);
669   }
670 }
671
672 // =======================================================================
673 // function : pushWorldViewState
674 // purpose  :
675 // =======================================================================
676 void OpenGl_ShaderManager::pushWorldViewState (const Handle(OpenGl_ShaderProgram)& theProgram) const
677 {
678   if (myWorldViewState.Index() == theProgram->ActiveState (OpenGl_WORLD_VIEW_STATE))
679   {
680     return;
681   }
682
683   theProgram->UpdateState (OpenGl_WORLD_VIEW_STATE, myWorldViewState.Index());
684   if (theProgram == myFfpProgram)
685   {
686   #if !defined(GL_ES_VERSION_2_0)
687     if (myContext->core11ffp != NULL)
688     {
689       const OpenGl_Mat4 aModelView = myWorldViewState.WorldViewMatrix() * myModelWorldState.ModelWorldMatrix();
690       myContext->core11ffp->glMatrixMode (GL_MODELVIEW);
691       myContext->core11ffp->glLoadMatrixf (aModelView.GetData());
692       theProgram->UpdateState (OpenGl_MODEL_WORLD_STATE, myModelWorldState.Index());
693     }
694   #endif
695     return;
696   }
697
698   theProgram->SetUniform (myContext,
699                           theProgram->GetStateLocation (OpenGl_OCC_WORLD_VIEW_MATRIX),
700                           myWorldViewState.WorldViewMatrix());
701
702   GLint aLocation = theProgram->GetStateLocation (OpenGl_OCC_WORLD_VIEW_MATRIX_INVERSE);
703   if (aLocation != OpenGl_ShaderProgram::INVALID_LOCATION)
704   {
705     theProgram->SetUniform (myContext, aLocation, myWorldViewState.WorldViewMatrixInverse());
706   }
707
708   theProgram->SetUniform (myContext,
709                           theProgram->GetStateLocation (OpenGl_OCC_WORLD_VIEW_MATRIX_TRANSPOSE),
710                           myWorldViewState.WorldViewMatrix(), true);
711
712   aLocation = theProgram->GetStateLocation (OpenGl_OCC_WORLD_VIEW_MATRIX_INVERSE_TRANSPOSE);
713   if (aLocation != OpenGl_ShaderProgram::INVALID_LOCATION)
714   {
715     theProgram->SetUniform (myContext, aLocation, myWorldViewState.WorldViewMatrixInverse(), true);
716   }
717 }
718
719 // =======================================================================
720 // function : UpdateClippingState
721 // purpose  : Updates state of OCCT clipping planes
722 // =======================================================================
723 void OpenGl_ShaderManager::UpdateClippingState()
724 {
725   myClippingState.Update();
726 }
727
728 // =======================================================================
729 // function : RevertClippingState
730 // purpose  : Reverts state of OCCT clipping planes
731 // =======================================================================
732 void OpenGl_ShaderManager::RevertClippingState()
733 {
734   myClippingState.Revert();
735 }
736
737 // =======================================================================
738 // function : pushClippingState
739 // purpose  :
740 // =======================================================================
741 void OpenGl_ShaderManager::pushClippingState (const Handle(OpenGl_ShaderProgram)& theProgram) const
742 {
743   theProgram->UpdateState (OpenGl_CLIP_PLANES_STATE, myClippingState.Index());
744   if (theProgram == myFfpProgram)
745   {
746   #if !defined(GL_ES_VERSION_2_0)
747     if (myContext->core11ffp == NULL)
748     {
749       return;
750     }
751
752     const Standard_Integer aNbMaxPlanes = myContext->MaxClipPlanes();
753     if (myClipPlaneArrayFfp.Size() < aNbMaxPlanes)
754     {
755       myClipPlaneArrayFfp.Resize (0, aNbMaxPlanes - 1, false);
756     }
757
758     Standard_Integer aPlaneId = 0;
759     Standard_Boolean toRestoreModelView = Standard_False;
760     const Handle(Graphic3d_ClipPlane)& aCappedChain = myContext->Clipping().CappedChain();
761     for (OpenGl_ClippingIterator aPlaneIter (myContext->Clipping()); aPlaneIter.More(); aPlaneIter.Next())
762     {
763       const Handle(Graphic3d_ClipPlane)& aPlane = aPlaneIter.Value();
764       if (aPlaneIter.IsDisabled()
765        || aPlane->IsChain()
766        || (aPlane == aCappedChain
767         && myContext->Clipping().IsCappingEnableAllExcept()))
768       {
769         continue;
770       }
771       else if (aPlaneId >= aNbMaxPlanes)
772       {
773         Message::SendWarning() << "OpenGl_ShaderManager, warning: clipping planes limit (" << aNbMaxPlanes << ") has been exceeded";
774         break;
775       }
776
777       const Graphic3d_ClipPlane::Equation& anEquation = aPlane->GetEquation();
778       OpenGl_Vec4d& aPlaneEq = myClipPlaneArrayFfp.ChangeValue (aPlaneId);
779       aPlaneEq.x() = anEquation.x();
780       aPlaneEq.y() = anEquation.y();
781       aPlaneEq.z() = anEquation.z();
782       aPlaneEq.w() = anEquation.w();
783       if (myHasLocalOrigin)
784       {
785         const gp_XYZ        aPos = aPlane->ToPlane().Position().Location().XYZ() - myLocalOrigin;
786         const Standard_Real aD   = -(anEquation.x() * aPos.X() + anEquation.y() * aPos.Y() + anEquation.z() * aPos.Z());
787         aPlaneEq.w() = aD;
788       }
789
790       const GLenum anFfpPlaneID = GL_CLIP_PLANE0 + aPlaneId;
791       if (anFfpPlaneID == GL_CLIP_PLANE0)
792       {
793         // set either identity or pure view matrix
794         toRestoreModelView = Standard_True;
795         myContext->core11ffp->glMatrixMode (GL_MODELVIEW);
796         myContext->core11ffp->glLoadMatrixf (myWorldViewState.WorldViewMatrix().GetData());
797       }
798
799       myContext->core11fwd->glEnable (anFfpPlaneID);
800       myContext->core11ffp->glClipPlane (anFfpPlaneID, aPlaneEq);
801
802       ++aPlaneId;
803     }
804
805     // switch off unused lights
806     for (; aPlaneId < aNbMaxPlanes; ++aPlaneId)
807     {
808       myContext->core11fwd->glDisable (GL_CLIP_PLANE0 + aPlaneId);
809     }
810
811     // restore combined model-view matrix
812     if (toRestoreModelView)
813     {
814       const OpenGl_Mat4 aModelView = myWorldViewState.WorldViewMatrix() * myModelWorldState.ModelWorldMatrix();
815       myContext->core11ffp->glLoadMatrixf (aModelView.GetData());
816     }
817   #endif
818     return;
819   }
820
821   const GLint aLocEquations = theProgram->GetStateLocation (OpenGl_OCC_CLIP_PLANE_EQUATIONS);
822   if (aLocEquations == OpenGl_ShaderProgram::INVALID_LOCATION)
823   {
824     return;
825   }
826
827   const Standard_Integer aNbClipPlanesMax = theProgram->NbClipPlanesMax();
828   const Standard_Integer aNbPlanes = Min (myContext->Clipping().NbClippingOrCappingOn(), aNbClipPlanesMax);
829   if (aNbPlanes < 1)
830   {
831     theProgram->SetUniform (myContext, theProgram->GetStateLocation (OpenGl_OCC_CLIP_PLANE_COUNT), 0);
832     return;
833   }
834
835   if (myClipPlaneArray.Size() < aNbClipPlanesMax)
836   {
837     myClipPlaneArray.Resize (0, aNbClipPlanesMax - 1, false);
838     myClipChainArray.Resize (0, aNbClipPlanesMax - 1, false);
839   }
840
841   Standard_Integer aPlaneId = 0;
842   const Handle(Graphic3d_ClipPlane)& aCappedChain = myContext->Clipping().CappedChain();
843   for (OpenGl_ClippingIterator aPlaneIter (myContext->Clipping()); aPlaneIter.More(); aPlaneIter.Next())
844   {
845     const Handle(Graphic3d_ClipPlane)& aPlane = aPlaneIter.Value();
846     if (aPlaneIter.IsDisabled())
847     {
848       continue;
849     }
850
851     if (myContext->Clipping().IsCappingDisableAllExcept())
852     {
853       // enable only specific (sub) plane
854       if (aPlane != aCappedChain)
855       {
856         continue;
857       }
858
859       Standard_Integer aSubPlaneIndex = 1;
860       for (const Graphic3d_ClipPlane* aSubPlaneIter = aCappedChain.get(); aSubPlaneIter != NULL; aSubPlaneIter = aSubPlaneIter->ChainNextPlane().get(), ++aSubPlaneIndex)
861       {
862         if (aSubPlaneIndex == myContext->Clipping().CappedSubPlane())
863         {
864           addClippingPlane (aPlaneId, *aSubPlaneIter, aSubPlaneIter->GetEquation(), 1);
865           break;
866         }
867       }
868       break;
869     }
870     else if (aPlane == aCappedChain) // && myContext->Clipping().IsCappingEnableAllExcept()
871     {
872       // enable sub-planes within processed Chain as reversed and ORed, excluding filtered plane
873       if (aPlaneId + aPlane->NbChainNextPlanes() - 1 > aNbClipPlanesMax)
874       {
875         myContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_HIGH,
876                                 TCollection_AsciiString("Error: clipping planes limit (") + aNbClipPlanesMax + ") has been exceeded.");
877         break;
878       }
879
880       Standard_Integer aSubPlaneIndex = 1;
881       for (const Graphic3d_ClipPlane* aSubPlaneIter = aPlane.get(); aSubPlaneIter != NULL; aSubPlaneIter = aSubPlaneIter->ChainNextPlane().get(), ++aSubPlaneIndex)
882       {
883         if (aSubPlaneIndex != -myContext->Clipping().CappedSubPlane())
884         {
885           addClippingPlane (aPlaneId, *aSubPlaneIter, aSubPlaneIter->ReversedEquation(), 1);
886         }
887       }
888     }
889     else
890     {
891       // normal case
892       if (aPlaneId + aPlane->NbChainNextPlanes() > aNbClipPlanesMax)
893       {
894         myContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_HIGH,
895                                 TCollection_AsciiString("Error: clipping planes limit (") + aNbClipPlanesMax + ") has been exceeded.");
896         break;
897       }
898       for (const Graphic3d_ClipPlane* aSubPlaneIter = aPlane.get(); aSubPlaneIter != NULL; aSubPlaneIter = aSubPlaneIter->ChainNextPlane().get())
899       {
900         addClippingPlane (aPlaneId, *aSubPlaneIter, aSubPlaneIter->GetEquation(), aSubPlaneIter->NbChainNextPlanes());
901       }
902     }
903   }
904
905   theProgram->SetUniform (myContext, theProgram->GetStateLocation (OpenGl_OCC_CLIP_PLANE_COUNT), aPlaneId);
906   theProgram->SetUniform (myContext, aLocEquations, aNbClipPlanesMax, &myClipPlaneArray.First());
907   theProgram->SetUniform (myContext, theProgram->GetStateLocation (OpenGl_OCC_CLIP_PLANE_CHAINS), aNbClipPlanesMax, &myClipChainArray.First());
908 }
909
910 // =======================================================================
911 // function : pushMaterialState
912 // purpose  :
913 // =======================================================================
914 void OpenGl_ShaderManager::pushMaterialState (const Handle(OpenGl_ShaderProgram)& theProgram) const
915 {
916   const OpenGl_Material& aMat = myMaterialState.Material();
917   theProgram->UpdateState (OpenGl_MATERIAL_STATE, myMaterialState.Index());
918   if (theProgram == myFfpProgram)
919   {
920   #if !defined(GL_ES_VERSION_2_0)
921     if (myContext->core11ffp == NULL)
922     {
923       return;
924     }
925
926     if (myMaterialState.AlphaCutoff() < ShortRealLast())
927     {
928       myContext->core11fwd->glAlphaFunc (GL_GEQUAL, myMaterialState.AlphaCutoff());
929       myContext->core11fwd->glEnable (GL_ALPHA_TEST);
930     }
931     else
932     {
933       myContext->core11fwd->glDisable (GL_ALPHA_TEST);
934     }
935
936     const GLenum aFrontFace = myMaterialState.ToDistinguish() ? GL_FRONT : GL_FRONT_AND_BACK;
937     const OpenGl_MaterialCommon& aFrontMat = aMat.Common[0];
938     const OpenGl_MaterialCommon& aBackMat  = aMat.Common[1];
939     const Graphic3d_Vec4 aSpec4 (aFrontMat.SpecularShininess.rgb(), 1.0f);
940     myContext->core11ffp->glMaterialfv(aFrontFace, GL_AMBIENT,   aFrontMat.Ambient.GetData());
941     myContext->core11ffp->glMaterialfv(aFrontFace, GL_DIFFUSE,   aFrontMat.Diffuse.GetData());
942     myContext->core11ffp->glMaterialfv(aFrontFace, GL_SPECULAR,  aSpec4.GetData());
943     myContext->core11ffp->glMaterialfv(aFrontFace, GL_EMISSION,  aFrontMat.Emission.GetData());
944     myContext->core11ffp->glMaterialf (aFrontFace, GL_SHININESS, aFrontMat.Shine());
945     if (myMaterialState.ToDistinguish())
946     {
947       const Graphic3d_Vec4 aSpec4Back (aBackMat.SpecularShininess.rgb(), 1.0f);
948       myContext->core11ffp->glMaterialfv(GL_BACK, GL_AMBIENT,   aBackMat.Ambient.GetData());
949       myContext->core11ffp->glMaterialfv(GL_BACK, GL_DIFFUSE,   aBackMat.Diffuse.GetData());
950       myContext->core11ffp->glMaterialfv(GL_BACK, GL_SPECULAR,  aSpec4Back.GetData());
951       myContext->core11ffp->glMaterialfv(GL_BACK, GL_EMISSION,  aBackMat.Emission.GetData());
952       myContext->core11ffp->glMaterialf (GL_BACK, GL_SHININESS, aBackMat.Shine());
953     }
954   #endif
955     return;
956   }
957
958   theProgram->SetUniform (myContext,
959                           theProgram->GetStateLocation (OpenGl_OCCT_ALPHA_CUTOFF),
960                           myMaterialState.AlphaCutoff());
961   theProgram->SetUniform (myContext,
962                           theProgram->GetStateLocation (OpenGl_OCCT_TEXTURE_ENABLE),
963                           myMaterialState.ToMapTexture()  ? 1 : 0);
964   theProgram->SetUniform (myContext,
965                           theProgram->GetStateLocation (OpenGl_OCCT_DISTINGUISH_MODE),
966                           myMaterialState.ToDistinguish() ? 1 : 0);
967
968   if (const OpenGl_ShaderUniformLocation& aLocPbrFront = theProgram->GetStateLocation (OpenGl_OCCT_PBR_MATERIAL))
969   {
970     theProgram->SetUniform (myContext, aLocPbrFront, OpenGl_Material::NbOfVec4Pbr(), aMat.PackedPbr());
971   }
972   if (const OpenGl_ShaderUniformLocation& aLocFront = theProgram->GetStateLocation (OpenGl_OCCT_COMMON_MATERIAL))
973   {
974     theProgram->SetUniform (myContext, aLocFront, OpenGl_Material::NbOfVec4Common(), aMat.PackedCommon());
975   }
976 }
977
978 // =======================================================================
979 // function : pushOitState
980 // purpose  :
981 // =======================================================================
982 void OpenGl_ShaderManager::pushOitState (const Handle(OpenGl_ShaderProgram)& theProgram) const
983 {
984   if (const OpenGl_ShaderUniformLocation& aLocOutput = theProgram->GetStateLocation (OpenGl_OCCT_OIT_OUTPUT))
985   {
986     theProgram->SetUniform (myContext, aLocOutput, (GLint )myOitState.ActiveMode());
987   }
988   if (const OpenGl_ShaderUniformLocation& aLocDepthFactor = theProgram->GetStateLocation (OpenGl_OCCT_OIT_DEPTH_FACTOR))
989   {
990     theProgram->SetUniform (myContext, aLocDepthFactor, myOitState.DepthFactor());
991   }
992 }
993
994 // =======================================================================
995 // function : PushInteriorState
996 // purpose  :
997 // =======================================================================
998 void OpenGl_ShaderManager::PushInteriorState (const Handle(OpenGl_ShaderProgram)& theProgram,
999                                               const Handle(Graphic3d_Aspects)& theAspect) const
1000 {
1001   if (theProgram.IsNull()
1002   || !theProgram->IsValid())
1003   {
1004     return;
1005   }
1006
1007   if (const OpenGl_ShaderUniformLocation aLocLineWidth = theProgram->GetStateLocation (OpenGl_OCCT_LINE_WIDTH))
1008   {
1009     theProgram->SetUniform (myContext, aLocLineWidth, theAspect->EdgeWidth() * myContext->LineWidthScale());
1010     theProgram->SetUniform (myContext, theProgram->GetStateLocation (OpenGl_OCCT_LINE_FEATHER), myContext->LineFeather() * myContext->LineWidthScale());
1011   }
1012   if (const OpenGl_ShaderUniformLocation aLocWireframeColor = theProgram->GetStateLocation (OpenGl_OCCT_WIREFRAME_COLOR))
1013   {
1014     if (theAspect->InteriorStyle() == Aspect_IS_HOLLOW)
1015     {
1016       theProgram->SetUniform (myContext, aLocWireframeColor, OpenGl_Vec4 (-1.0f, -1.0f, -1.0f, -1.0f));
1017     }
1018     else
1019     {
1020       theProgram->SetUniform (myContext, aLocWireframeColor, myContext->Vec4FromQuantityColor (theAspect->EdgeColorRGBA()));
1021     }
1022   }
1023   if (const OpenGl_ShaderUniformLocation aLocQuadModeState = theProgram->GetStateLocation (OpenGl_OCCT_QUAD_MODE_STATE))
1024   {
1025     theProgram->SetUniform (myContext, aLocQuadModeState, theAspect->ToSkipFirstEdge() ? 1 : 0);
1026   }
1027 }
1028
1029 // =======================================================================
1030 // function : PushState
1031 // purpose  : Pushes state of OCCT graphics parameters to the program
1032 // =======================================================================
1033 void OpenGl_ShaderManager::PushState (const Handle(OpenGl_ShaderProgram)& theProgram,
1034                                       Graphic3d_TypeOfShadingModel theShadingModel) const
1035 {
1036   const Handle(OpenGl_ShaderProgram)& aProgram = !theProgram.IsNull() ? theProgram : myFfpProgram;
1037   PushClippingState    (aProgram);
1038   PushLightSourceState (aProgram); // should be before PushWorldViewState()
1039   PushWorldViewState   (aProgram);
1040   PushModelWorldState  (aProgram);
1041   PushProjectionState  (aProgram);
1042   PushMaterialState    (aProgram);
1043   PushOitState         (aProgram);
1044
1045   if (!theProgram.IsNull())
1046   {
1047     if (const OpenGl_ShaderUniformLocation& aLocViewPort = theProgram->GetStateLocation (OpenGl_OCCT_VIEWPORT))
1048     {
1049       theProgram->SetUniform (myContext, aLocViewPort, OpenGl_Vec4 ((float )myContext->Viewport()[0], (float )myContext->Viewport()[1],
1050                                                                     (float )myContext->Viewport()[2], (float )myContext->Viewport()[3]));
1051     }
1052   }
1053 #if !defined(GL_ES_VERSION_2_0)
1054   else if (myContext->core11ffp != NULL)
1055   {
1056     // manage FFP lighting
1057     myContext->SetShadeModel (theShadingModel);
1058     if (theShadingModel == Graphic3d_TOSM_UNLIT)
1059     {
1060       myContext->core11fwd->glDisable (GL_LIGHTING);
1061     }
1062     else
1063     {
1064       myContext->core11fwd->glEnable (GL_LIGHTING);
1065     }
1066   }
1067 #else
1068   (void )theShadingModel;
1069 #endif
1070 }
1071
1072 // =======================================================================
1073 // function : BindFontProgram
1074 // purpose  :
1075 // =======================================================================
1076 Standard_Boolean OpenGl_ShaderManager::BindFontProgram (const Handle(OpenGl_ShaderProgram)& theCustomProgram)
1077 {
1078   if (!theCustomProgram.IsNull()
1079     || myContext->caps->ffpEnable)
1080   {
1081     return bindProgramWithState (theCustomProgram, Graphic3d_TOSM_UNLIT);
1082   }
1083
1084   if (myFontProgram.IsNull())
1085   {
1086     Handle(Graphic3d_ShaderProgram) aProgramSrc = getStdProgramFont();
1087     TCollection_AsciiString aKey;
1088     if (!Create (aProgramSrc, aKey, myFontProgram))
1089     {
1090       myFontProgram = new OpenGl_ShaderProgram(); // just mark as invalid
1091       return false;
1092     }
1093   }
1094
1095   return bindProgramWithState (myFontProgram, Graphic3d_TOSM_UNLIT);
1096 }
1097
1098 // =======================================================================
1099 // function : BindFboBlitProgram
1100 // purpose  :
1101 // =======================================================================
1102 Standard_Boolean OpenGl_ShaderManager::BindFboBlitProgram (Standard_Integer theNbSamples,
1103                                                            Standard_Boolean theIsFallback_sRGB)
1104 {
1105   NCollection_Array1<Handle(OpenGl_ShaderProgram)>& aList = myBlitPrograms[theIsFallback_sRGB ? 1 : 0];
1106   Standard_Integer aNbSamples = Max (theNbSamples, 1);
1107   if (aNbSamples > aList.Upper())
1108   {
1109     aList.Resize (1, aNbSamples, true);
1110   }
1111
1112   Handle(OpenGl_ShaderProgram)& aProg = aList[aNbSamples];
1113   if (!aProg.IsNull())
1114   {
1115     return myContext->BindProgram (aProg);
1116   }
1117
1118   Handle(Graphic3d_ShaderProgram) aProgramSrc = getStdProgramFboBlit (aNbSamples, theIsFallback_sRGB);
1119   TCollection_AsciiString aKey;
1120   if (!Create (aProgramSrc, aKey, aProg))
1121   {
1122     aProg = new OpenGl_ShaderProgram(); // just mark as invalid
1123     return false;
1124   }
1125
1126   myContext->BindProgram (aProg);
1127   aProg->SetSampler (myContext, "uColorSampler", Graphic3d_TextureUnit_0);
1128   aProg->SetSampler (myContext, "uDepthSampler", Graphic3d_TextureUnit_1);
1129   return true;
1130 }
1131
1132 // =======================================================================
1133 // function : BindOitCompositingProgram
1134 // purpose  :
1135 // =======================================================================
1136 Standard_Boolean OpenGl_ShaderManager::BindOitCompositingProgram (Standard_Boolean theIsMSAAEnabled)
1137 {
1138   const Standard_Integer aProgramIdx = theIsMSAAEnabled ? 1 : 0;
1139   Handle(OpenGl_ShaderProgram)& aProgram = myOitCompositingProgram[aProgramIdx];
1140   if (!aProgram.IsNull())
1141   {
1142     return myContext->BindProgram (aProgram);
1143   }
1144
1145   Handle(Graphic3d_ShaderProgram) aProgramSrc = getStdProgramOitCompositing (theIsMSAAEnabled);
1146   TCollection_AsciiString aKey;
1147   if (!Create (aProgramSrc, aKey, aProgram))
1148   {
1149     aProgram = new OpenGl_ShaderProgram(); // just mark as invalid
1150     return false;
1151   }
1152
1153   myContext->BindProgram (aProgram);
1154   aProgram->SetSampler (myContext, "uAccumTexture",  Graphic3d_TextureUnit_0);
1155   aProgram->SetSampler (myContext, "uWeightTexture", Graphic3d_TextureUnit_1);
1156   return true;
1157 }
1158
1159 // =======================================================================
1160 // function : BindOitDepthPeelingBlendProgram
1161 // purpose  :
1162 // =======================================================================
1163 Standard_Boolean OpenGl_ShaderManager::BindOitDepthPeelingBlendProgram (bool theIsMSAAEnabled)
1164 {
1165   const Standard_Integer aProgramIdx = theIsMSAAEnabled ? 1 : 0;
1166   Handle(OpenGl_ShaderProgram)& aProgram = myOitDepthPeelingBlendProgram [aProgramIdx];
1167   if (!aProgram.IsNull())
1168   {
1169     return myContext->BindProgram (aProgram);
1170   }
1171
1172   Handle(Graphic3d_ShaderProgram) aProgramSrc = getStdProgramOitDepthPeelingBlend (theIsMSAAEnabled);
1173   TCollection_AsciiString aKey;
1174   if (!Create (aProgramSrc, aKey, aProgram))
1175   {
1176     aProgram = new OpenGl_ShaderProgram(); // just mark as invalid
1177     return false;
1178   }
1179
1180   myContext->BindProgram (aProgram);
1181   aProgram->SetSampler (myContext, "uDepthPeelingBackColor", Graphic3d_TextureUnit_0);
1182   return true;
1183 }
1184
1185 // =======================================================================
1186 // function : BindOitDepthPeelingFlushProgram
1187 // purpose  :
1188 // =======================================================================
1189 Standard_Boolean OpenGl_ShaderManager::BindOitDepthPeelingFlushProgram (bool theIsMSAAEnabled)
1190 {
1191   const Standard_Integer aProgramIdx = theIsMSAAEnabled ? 1 : 0;
1192   Handle(OpenGl_ShaderProgram)& aProgram = myOitDepthPeelingFlushProgram [aProgramIdx];
1193   if (!aProgram.IsNull())
1194   {
1195     return myContext->BindProgram (aProgram);
1196   }
1197
1198   Handle(Graphic3d_ShaderProgram) aProgramSrc = getStdProgramOitDepthPeelingFlush (theIsMSAAEnabled);
1199   TCollection_AsciiString aKey;
1200   if (!Create (aProgramSrc, aKey, aProgram))
1201   {
1202     aProgram = new OpenGl_ShaderProgram(); // just mark as invalid
1203     return false;
1204   }
1205
1206   myContext->BindProgram (aProgram);
1207   aProgram->SetSampler (myContext, "uDepthPeelingFrontColor", Graphic3d_TextureUnit_0);
1208   aProgram->SetSampler (myContext, "uDepthPeelingBackColor",  Graphic3d_TextureUnit_1);
1209   return true;
1210 }
1211
1212 // =======================================================================
1213 // function : prepareStdProgramUnlit
1214 // purpose  :
1215 // =======================================================================
1216 Standard_Boolean OpenGl_ShaderManager::prepareStdProgramUnlit (Handle(OpenGl_ShaderProgram)& theProgram,
1217                                                                Standard_Integer theBits,
1218                                                                Standard_Boolean theIsOutline)
1219 {
1220   Handle(Graphic3d_ShaderProgram) aProgramSrc = getStdProgramUnlit (theBits, theIsOutline);
1221   TCollection_AsciiString aKey;
1222   if (!Create (aProgramSrc, aKey, theProgram))
1223   {
1224     theProgram = new OpenGl_ShaderProgram(); // just mark as invalid
1225     return Standard_False;
1226   }
1227   return Standard_True;
1228 }
1229
1230 // =======================================================================
1231 // function : prepareStdProgramGouraud
1232 // purpose  :
1233 // =======================================================================
1234 Standard_Boolean OpenGl_ShaderManager::prepareStdProgramGouraud (Handle(OpenGl_ShaderProgram)& theProgram,
1235                                                                  const Standard_Integer        theBits)
1236 {
1237   Handle(Graphic3d_ShaderProgram) aProgramSrc = getStdProgramGouraud (myLightSourceState.LightSources(), theBits);
1238   TCollection_AsciiString aKey;
1239   if (!Create (aProgramSrc, aKey, theProgram))
1240   {
1241     theProgram = new OpenGl_ShaderProgram(); // just mark as invalid
1242     return Standard_False;
1243   }
1244   return Standard_True;
1245 }
1246
1247 // =======================================================================
1248 // function : prepareStdProgramPhong
1249 // purpose  :
1250 // =======================================================================
1251 Standard_Boolean OpenGl_ShaderManager::prepareStdProgramPhong (Handle(OpenGl_ShaderProgram)& theProgram,
1252                                                                const Standard_Integer        theBits,
1253                                                                const Standard_Boolean        theIsFlatNormal,
1254                                                                const Standard_Boolean        theIsPBR)
1255 {
1256   Standard_Integer aNbShadowMaps = myLightSourceState.HasShadowMaps()
1257                                  ? myLightSourceState.LightSources()->NbCastShadows()
1258                                  : 0;
1259   Handle(Graphic3d_ShaderProgram) aProgramSrc = getStdProgramPhong (myLightSourceState.LightSources(), theBits, theIsFlatNormal, theIsPBR, aNbShadowMaps);
1260   TCollection_AsciiString aKey;
1261   if (!Create (aProgramSrc, aKey, theProgram))
1262   {
1263     theProgram = new OpenGl_ShaderProgram(); // just mark as invalid
1264     return Standard_False;
1265   }
1266   return Standard_True;
1267 }
1268
1269 // =======================================================================
1270 // function : BindStereoProgram
1271 // purpose  :
1272 // =======================================================================
1273 Standard_Boolean OpenGl_ShaderManager::BindStereoProgram (Graphic3d_StereoMode theStereoMode)
1274 {
1275   if (theStereoMode < 0 || theStereoMode >= Graphic3d_StereoMode_NB)
1276   {
1277     return false;
1278   }
1279
1280   Handle(OpenGl_ShaderProgram)& aProgram = myStereoPrograms[theStereoMode];
1281   if (!aProgram.IsNull())
1282   {
1283     return myContext->BindProgram (aProgram);
1284   }
1285
1286   Handle(Graphic3d_ShaderProgram) aProgramSrc = getStdProgramStereo (theStereoMode);
1287   TCollection_AsciiString aKey;
1288   if (!Create (aProgramSrc, aKey, aProgram))
1289   {
1290     aProgram = new OpenGl_ShaderProgram(); // just mark as invalid
1291     return false;
1292   }
1293
1294   myContext->BindProgram (aProgram);
1295   aProgram->SetSampler (myContext, "uLeftSampler",  Graphic3d_TextureUnit_0);
1296   aProgram->SetSampler (myContext, "uRightSampler", Graphic3d_TextureUnit_1);
1297   return true;
1298 }
1299
1300 // =======================================================================
1301 // function : prepareStdProgramBoundBox
1302 // purpose  :
1303 // =======================================================================
1304 Standard_Boolean OpenGl_ShaderManager::prepareStdProgramBoundBox()
1305 {
1306   Handle(Graphic3d_ShaderProgram) aProgramSrc = Graphic3d_ShaderManager::getStdProgramBoundBox();
1307   TCollection_AsciiString aKey;
1308   if (!Create (aProgramSrc, aKey, myBoundBoxProgram))
1309   {
1310     myBoundBoxProgram = new OpenGl_ShaderProgram(); // just mark as invalid
1311     return Standard_False;
1312   }
1313
1314   const OpenGl_Vec4 aMin (-0.5f, -0.5f, -0.5f, 1.0f);
1315   const OpenGl_Vec4 anAxisShifts[3] =
1316   {
1317     OpenGl_Vec4 (1.0f, 0.0f, 0.0f, 0.0f),
1318     OpenGl_Vec4 (0.0f, 1.0f, 0.0f, 0.0f),
1319     OpenGl_Vec4 (0.0f, 0.0f, 1.0f, 0.0f)
1320   };
1321
1322   const OpenGl_Vec4 aLookup1 (0.0f, 1.0f, 0.0f, 1.0f);
1323   const OpenGl_Vec4 aLookup2 (0.0f, 0.0f, 1.0f, 1.0f);
1324   OpenGl_Vec4 aLinesVertices[24];
1325   for (int anAxis = 0, aVertex = 0; anAxis < 3; ++anAxis)
1326   {
1327     for (int aCompIter = 0; aCompIter < 4; ++aCompIter)
1328     {
1329       aLinesVertices[aVertex++] = aMin
1330         + anAxisShifts[(anAxis + 1) % 3] * aLookup1[aCompIter]
1331         + anAxisShifts[(anAxis + 2) % 3] * aLookup2[aCompIter];
1332
1333       aLinesVertices[aVertex++] = aMin
1334         + anAxisShifts[anAxis]
1335         + anAxisShifts[(anAxis + 1) % 3] * aLookup1[aCompIter]
1336         + anAxisShifts[(anAxis + 2) % 3] * aLookup2[aCompIter];
1337     }
1338   }
1339   if (myContext->ToUseVbo())
1340   {
1341     myBoundBoxVertBuffer = new OpenGl_VertexBuffer();
1342     if (myBoundBoxVertBuffer->Init (myContext, 4, 24, aLinesVertices[0].GetData()))
1343     {
1344       myContext->ShareResource ("OpenGl_ShaderManager_BndBoxVbo", myBoundBoxVertBuffer);
1345       return Standard_True;
1346     }
1347   }
1348   myBoundBoxVertBuffer = new OpenGl_VertexBufferCompat();
1349   myBoundBoxVertBuffer->Init (myContext, 4, 24, aLinesVertices[0].GetData());
1350   myContext->ShareResource ("OpenGl_ShaderManager_BndBoxVbo", myBoundBoxVertBuffer);
1351   return Standard_True;
1352 }
1353
1354 // =======================================================================
1355 // function : preparePBREnvBakingProgram
1356 // purpose  :
1357 // =======================================================================
1358 Standard_Boolean OpenGl_ShaderManager::preparePBREnvBakingProgram (Standard_Integer theIndex)
1359 {
1360   Handle(Graphic3d_ShaderProgram) aProgramSrc = getPBREnvBakingProgram (theIndex);
1361   TCollection_AsciiString aKey;
1362   if (!Create (aProgramSrc, aKey, myPBREnvBakingProgram[theIndex]))
1363   {
1364     myPBREnvBakingProgram[theIndex] = new OpenGl_ShaderProgram(); // just mark as invalid
1365     return Standard_False;
1366   }
1367
1368   if (theIndex == 0
1369    || theIndex == 2)
1370   {
1371     // workaround for old GLSL - load constants as uniform
1372     myContext->BindProgram (myPBREnvBakingProgram[theIndex]);
1373     const float aSHBasisFuncCoeffs[9] =
1374     {
1375       0.282095f * 0.282095f, 0.488603f * 0.488603f, 0.488603f * 0.488603f, 0.488603f * 0.488603f,
1376       1.092548f * 1.092548f, 1.092548f * 1.092548f, 1.092548f * 1.092548f, 0.315392f * 0.315392f, 0.546274f * 0.546274f
1377     };
1378     const float aSHCosCoeffs[9] = { 3.141593f, 2.094395f, 2.094395f, 2.094395f, 0.785398f, 0.785398f, 0.785398f, 0.785398f, 0.785398f };
1379     myPBREnvBakingProgram[theIndex]->SetUniform (myContext, myPBREnvBakingProgram[theIndex]->GetUniformLocation (myContext, "aSHBasisFuncCoeffs"), 9, aSHBasisFuncCoeffs);
1380     myPBREnvBakingProgram[theIndex]->SetUniform (myContext, myPBREnvBakingProgram[theIndex]->GetUniformLocation (myContext, "aSHCosCoeffs"), 9, aSHCosCoeffs);
1381     myContext->BindProgram (NULL);
1382   }
1383
1384   return Standard_True;
1385 }
1386
1387 // =======================================================================
1388 // function : GetBgCubeMapProgram
1389 // purpose  :
1390 // =======================================================================
1391 const Handle(Graphic3d_ShaderProgram)& OpenGl_ShaderManager::GetBgCubeMapProgram ()
1392 {
1393   if (myBgCubeMapProgram.IsNull())
1394   {
1395     myBgCubeMapProgram = getBgCubeMapProgram();
1396   }
1397   return myBgCubeMapProgram;
1398 }
1399
1400 // =======================================================================
1401 // function : bindProgramWithState
1402 // purpose  :
1403 // =======================================================================
1404 Standard_Boolean OpenGl_ShaderManager::bindProgramWithState (const Handle(OpenGl_ShaderProgram)& theProgram,
1405                                                              Graphic3d_TypeOfShadingModel theShadingModel)
1406 {
1407   const Standard_Boolean isBound = myContext->BindProgram (theProgram);
1408   if (isBound
1409   && !theProgram.IsNull())
1410   {
1411     theProgram->ApplyVariables (myContext);
1412   }
1413   PushState (theProgram, theShadingModel);
1414   return isBound;
1415 }
1416
1417 // =======================================================================
1418 // function : BindMarkerProgram
1419 // purpose  :
1420 // =======================================================================
1421 Standard_Boolean OpenGl_ShaderManager::BindMarkerProgram (const Handle(OpenGl_TextureSet)& theTextures,
1422                                                           Graphic3d_TypeOfShadingModel theShadingModel,
1423                                                           Graphic3d_AlphaMode theAlphaMode,
1424                                                           Standard_Boolean theHasVertColor,
1425                                                           const Handle(OpenGl_ShaderProgram)& theCustomProgram)
1426 {
1427   if (!theCustomProgram.IsNull()
1428     || myContext->caps->ffpEnable)
1429   {
1430     return bindProgramWithState (theCustomProgram, theShadingModel);
1431   }
1432
1433   Standard_Integer aBits = getProgramBits (theTextures, theAlphaMode, Aspect_IS_SOLID, theHasVertColor, false, false);
1434   if (!theTextures.IsNull()
1435     && theTextures->HasPointSprite())
1436   {
1437     aBits |= theTextures->Last()->IsAlpha() ? Graphic3d_ShaderFlags_PointSpriteA : Graphic3d_ShaderFlags_PointSprite;
1438   }
1439   else
1440   {
1441     aBits |= Graphic3d_ShaderFlags_PointSimple;
1442   }
1443   Handle(OpenGl_ShaderProgram)& aProgram = getStdProgram (theShadingModel, aBits);
1444   return bindProgramWithState (aProgram, theShadingModel);
1445 }