92a4c2d15bb64f73f2552a7cd7c7364efe57fd3e
[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_ShaderManager, Standard_Transient)
29 IMPLEMENT_STANDARD_RTTIEXT(OpenGl_ShaderManager, Standard_Transient)
30
31 // =======================================================================
32 // function : OpenGl_ShaderManager
33 // purpose  : Creates new empty shader manager
34 // =======================================================================
35 OpenGl_ShaderManager::OpenGl_ShaderManager (OpenGl_Context* theContext)
36 : myContext (theContext),
37   myIsPP    (Standard_False)
38 {
39   //
40 }
41
42 // =======================================================================
43 // function : ~OpenGl_ShaderManager
44 // purpose  : Releases resources of shader manager
45 // =======================================================================
46 OpenGl_ShaderManager::~OpenGl_ShaderManager()
47 {
48   myProgramList.Clear();
49 }
50
51 // =======================================================================
52 // function : Create
53 // purpose  : Creates new shader program
54 // =======================================================================
55 void OpenGl_ShaderManager::Create (const Handle(Graphic3d_ShaderProgram)& theProxy,
56                                    TCollection_AsciiString&               theShareKey,
57                                    Handle(OpenGl_ShaderProgram)&          theProgram)
58 {
59   theProgram.Nullify();
60   if (theProxy.IsNull())
61   {
62     return;
63   }
64
65   theShareKey = theProxy->GetId();
66   if (myContext->GetResource<Handle(OpenGl_ShaderProgram)> (theShareKey, theProgram))
67   {
68     if (theProgram->Share())
69     {
70       myProgramList.Append (theProgram);
71     }
72     return;
73   }
74
75   theProgram = new OpenGl_ShaderProgram (theProxy);
76   if (!theProgram->Initialize (myContext, theProxy->ShaderObjects()))
77   {
78     theProgram->Release (myContext);
79     theShareKey.Clear();
80     theProgram.Nullify();
81     return;
82   }
83
84   myProgramList.Append (theProgram);
85   myContext->ShareResource (theShareKey, theProgram);
86 }
87
88 // =======================================================================
89 // function : Unregister
90 // purpose  : Removes specified shader program from the manager
91 // =======================================================================
92 void OpenGl_ShaderManager::Unregister (TCollection_AsciiString&      theShareKey,
93                                        Handle(OpenGl_ShaderProgram)& theProgram)
94 {
95   for (OpenGl_ShaderProgramList::Iterator anIt (myProgramList); anIt.More(); anIt.Next())
96   {
97     if (anIt.Value() == theProgram)
98     {
99       if (!theProgram->UnShare())
100       {
101         theShareKey.Clear();
102         theProgram.Nullify();
103         return;
104       }
105
106       myProgramList.Remove (anIt);
107       myMaterialStates.UnBind (theProgram);
108       break;
109     }
110   }
111
112   const TCollection_AsciiString anID = theProgram->myProxy->GetId();
113   if (anID.IsEmpty())
114   {
115     myContext->DelayedRelease (theProgram);
116     theProgram.Nullify();
117   }
118   else
119   {
120     theProgram.Nullify();
121     myContext->ReleaseResource (anID, Standard_True);
122   }
123 }
124
125 // =======================================================================
126 // function : ShaderPrograms
127 // purpose  : Returns list of registered shader programs
128 // =======================================================================
129 const OpenGl_ShaderProgramList& OpenGl_ShaderManager::ShaderPrograms() const
130 {
131   return myProgramList;
132 }
133
134 // =======================================================================
135 // function : Empty
136 // purpose  : Returns true if no program objects are attached
137 // =======================================================================
138 Standard_Boolean OpenGl_ShaderManager::IsEmpty() const
139 {
140   return myProgramList.IsEmpty();
141 }
142
143 // =======================================================================
144 // function : UpdateLightSourceStateTo
145 // purpose  : Updates state of OCCT light sources
146 // =======================================================================
147 void OpenGl_ShaderManager::UpdateLightSourceStateTo (const OpenGl_ListOfLight* theLights)
148 {
149   myLightSourceState.Set (theLights);
150   myLightSourceState.Update();
151 }
152
153 // =======================================================================
154 // function : SetProjectionState
155 // purpose  : Sets new state of OCCT projection transform
156 // =======================================================================
157 void OpenGl_ShaderManager::UpdateProjectionStateTo (const Tmatrix3* theProjectionMatrix)
158 {
159   myProjectionState.Set (theProjectionMatrix);
160   myProjectionState.Update();
161 }
162
163 // =======================================================================
164 // function : SetModelWorldState
165 // purpose  : Sets new state of OCCT model-world transform
166 // =======================================================================
167 void OpenGl_ShaderManager::UpdateModelWorldStateTo (const Tmatrix3* theModelWorldMatrix)
168 {
169   myModelWorldState.Set (theModelWorldMatrix);
170   myModelWorldState.Update();
171 }
172
173 // =======================================================================
174 // function : SetWorldViewState
175 // purpose  : Sets new state of OCCT world-view transform
176 // =======================================================================
177 void OpenGl_ShaderManager::UpdateWorldViewStateTo (const Tmatrix3* theWorldViewMatrix)
178 {
179   myWorldViewState.Set (theWorldViewMatrix);
180   myWorldViewState.Update();
181 }
182
183 // =======================================================================
184 // function : RevertProjectionStateTo
185 // purpose  : Reverts state of OCCT projection transform
186 // =======================================================================
187 void OpenGl_ShaderManager::RevertProjectionStateTo (const Tmatrix3* theProjectionMatrix)
188 {
189   myProjectionState.Set (theProjectionMatrix);
190   myProjectionState.Revert();
191 }
192
193 // =======================================================================
194 // function : RevertModelWorldStateTo
195 // purpose  : Reverts state of OCCT model-world transform
196 // =======================================================================
197 void OpenGl_ShaderManager::RevertModelWorldStateTo (const Tmatrix3* theModelWorldMatrix)
198 {
199   myModelWorldState.Set (theModelWorldMatrix);
200   myModelWorldState.Revert();
201 }
202
203 // =======================================================================
204 // function : RevertWorldViewStateTo
205 // purpose  : Reverts state of OCCT world-view transform
206 // =======================================================================
207 void OpenGl_ShaderManager::RevertWorldViewStateTo (const Tmatrix3* theWorldViewMatrix)
208 {
209   myWorldViewState.Set (theWorldViewMatrix);
210   myWorldViewState.Revert();
211 }
212
213 // =======================================================================
214 // function : LightSourceState
215 // purpose  : Returns current state of OCCT light sources
216 // =======================================================================
217 const OpenGl_LightSourceState& OpenGl_ShaderManager::LightSourceState() const
218 {
219   return myLightSourceState;
220 }
221
222 // =======================================================================
223 // function : ProjectionState
224 // purpose  : Returns current state of OCCT projection transform
225 // =======================================================================
226 const OpenGl_ProjectionState& OpenGl_ShaderManager::ProjectionState() const
227 {
228   return myProjectionState;
229 }
230
231 // =======================================================================
232 // function : ModelWorldState
233 // purpose  : Returns current state of OCCT model-world transform
234 // =======================================================================
235 const OpenGl_ModelWorldState& OpenGl_ShaderManager::ModelWorldState() const
236 {
237   return myModelWorldState;
238 }
239
240 // =======================================================================
241 // function : WorldViewState
242 // purpose  : Returns current state of OCCT world-view transform
243 // =======================================================================
244 const OpenGl_WorldViewState& OpenGl_ShaderManager::WorldViewState() const
245 {
246   return myWorldViewState;
247 }
248
249 //! Packed properties of light source
250 class OpenGl_ShaderLightParameters
251 {
252 public:
253
254   OpenGl_Vec4 Color;
255   OpenGl_Vec4 Position;
256   OpenGl_Vec4 Direction;
257   OpenGl_Vec4 Parameters;
258
259   //! Returns packed (serialized) representation of light source properties
260   const OpenGl_Vec4* Packed() const { return reinterpret_cast<const OpenGl_Vec4*> (this); }
261   static Standard_Integer NbOfVec4() { return 4; }
262
263 };
264
265 //! Packed light source type information
266 class OpenGl_ShaderLightType
267 {
268 public:
269
270   Standard_Integer Type;
271   Standard_Integer IsHeadlight;
272
273   //! Returns packed (serialized) representation of light source type
274   const OpenGl_Vec2i* Packed() const { return reinterpret_cast<const OpenGl_Vec2i*> (this); }
275   static Standard_Integer NbOfVec2i() { return 1; }
276
277 };
278
279 // =======================================================================
280 // function : PushLightSourceState
281 // purpose  : Pushes state of OCCT light sources to the program
282 // =======================================================================
283 void OpenGl_ShaderManager::PushLightSourceState (const Handle(OpenGl_ShaderProgram)& theProgram) const
284 {
285   if (myLightSourceState.Index() == theProgram->ActiveState (OpenGl_LIGHT_SOURCES_STATE)
286    || !theProgram->IsValid())
287   {
288     return;
289   }
290
291   OpenGl_ShaderLightType* aLightTypeArray = new OpenGl_ShaderLightType[OpenGLMaxLights];
292   for (Standard_Integer aLightIt = 0; aLightIt < OpenGLMaxLights; ++aLightIt)
293   {
294     aLightTypeArray[aLightIt].Type = -1;
295   }
296
297   const Standard_Integer aLightsDefNb = Min (myLightSourceState.LightSources()->Size(), OpenGLMaxLights);
298   if (aLightsDefNb < 1)
299   {
300     theProgram->SetUniform (myContext,
301                             theProgram->GetStateLocation (OpenGl_OCC_LIGHT_SOURCE_COUNT),
302                             0);
303     theProgram->SetUniform (myContext,
304                             theProgram->GetStateLocation (OpenGl_OCC_LIGHT_AMBIENT),
305                             OpenGl_Vec4 (0.0f, 0.0f, 0.0f, 0.0f));
306     theProgram->SetUniform (myContext,
307                             theProgram->GetStateLocation (OpenGl_OCC_LIGHT_SOURCE_TYPES),
308                             OpenGLMaxLights * OpenGl_ShaderLightType::NbOfVec2i(),
309                             aLightTypeArray[0].Packed());
310     theProgram->UpdateState (OpenGl_LIGHT_SOURCES_STATE, myLightSourceState.Index());
311     delete[] aLightTypeArray;
312     return;
313   }
314
315   OpenGl_ShaderLightParameters* aLightParamsArray = new OpenGl_ShaderLightParameters[aLightsDefNb];
316
317   OpenGl_Vec4 anAmbient (0.0f, 0.0f, 0.0f, 0.0f);
318   Standard_Integer aLightsNb = 0;
319   for (OpenGl_ListOfLight::Iterator anIter (*myLightSourceState.LightSources()); anIter.More(); anIter.Next())
320   {
321     const OpenGl_Light& aLight = anIter.Value();
322     if (aLight.Type == Visual3d_TOLS_AMBIENT)
323     {
324       anAmbient += aLight.Color;
325       continue;
326     }
327     else if (aLightsNb >= OpenGLMaxLights)
328     {
329       continue;
330     }
331
332     OpenGl_ShaderLightType& aLightType = aLightTypeArray[aLightsNb];
333     aLightType.Type        = aLight.Type;
334     aLightType.IsHeadlight = aLight.IsHeadlight;
335
336     OpenGl_ShaderLightParameters& aLightParams = aLightParamsArray[aLightsNb];
337     aLightParams.Color    = aLight.Color;
338     aLightParams.Position = aLight.Type == Visual3d_TOLS_DIRECTIONAL
339                          ? -aLight.Direction
340                          :  aLight.Position;
341     if (aLight.Type == Visual3d_TOLS_SPOT)
342     {
343       aLightParams.Direction = aLight.Direction;
344     }
345     aLightParams.Parameters = aLight.Params;
346     ++aLightsNb;
347   }
348
349   theProgram->SetUniform (myContext,
350                           theProgram->GetStateLocation (OpenGl_OCC_LIGHT_SOURCE_COUNT),
351                           aLightsNb);
352   theProgram->SetUniform (myContext,
353                           theProgram->GetStateLocation (OpenGl_OCC_LIGHT_AMBIENT),
354                           anAmbient);
355   theProgram->SetUniform (myContext,
356                           theProgram->GetStateLocation (OpenGl_OCC_LIGHT_SOURCE_TYPES),
357                           OpenGLMaxLights * OpenGl_ShaderLightType::NbOfVec2i(),
358                           aLightTypeArray[0].Packed());
359   if (aLightsNb > 0)
360   {
361     theProgram->SetUniform (myContext,
362                             theProgram->GetStateLocation (OpenGl_OCC_LIGHT_SOURCE_PARAMS),
363                             aLightsNb * OpenGl_ShaderLightParameters::NbOfVec4(),
364                             aLightParamsArray[0].Packed());
365   }
366   delete[] aLightParamsArray;
367   delete[] aLightTypeArray;
368
369   theProgram->UpdateState (OpenGl_LIGHT_SOURCES_STATE, myLightSourceState.Index());
370 }
371
372 // =======================================================================
373 // function : PushProjectionState
374 // purpose  : Pushes state of OCCT projection transform to the program
375 // =======================================================================
376 void OpenGl_ShaderManager::PushProjectionState (const Handle(OpenGl_ShaderProgram)& theProgram) const
377 {
378   if (myProjectionState.Index() == theProgram->ActiveState (OpenGl_PROJECTION_STATE))
379   {
380     return;
381   }
382
383   theProgram->SetUniform (myContext,
384                           theProgram->GetStateLocation (OpenGl_OCC_PROJECTION_MATRIX),
385                           myProjectionState.ProjectionMatrix());
386
387   GLint aLocation = theProgram->GetStateLocation (OpenGl_OCC_PROJECTION_MATRIX_INVERSE);
388   if (aLocation != OpenGl_ShaderProgram::INVALID_LOCATION)
389   {
390     theProgram->SetUniform (myContext, aLocation, myProjectionState.ProjectionMatrixInverse());
391   }
392
393   theProgram->SetUniform (myContext,
394                           theProgram->GetStateLocation (OpenGl_OCC_PROJECTION_MATRIX_TRANSPOSE),
395                           myProjectionState.ProjectionMatrix(), true);
396
397   aLocation = theProgram->GetStateLocation (OpenGl_OCC_PROJECTION_MATRIX_INVERSE_TRANSPOSE);
398   if (aLocation != OpenGl_ShaderProgram::INVALID_LOCATION)
399   {
400     theProgram->SetUniform (myContext, aLocation, myProjectionState.ProjectionMatrixInverse(), true);
401   }
402
403   theProgram->UpdateState (OpenGl_PROJECTION_STATE, myProjectionState.Index());
404 }
405
406 // =======================================================================
407 // function : PushModelWorldState
408 // purpose  : Pushes state of OCCT model-world transform to the program
409 // =======================================================================
410 void OpenGl_ShaderManager::PushModelWorldState (const Handle(OpenGl_ShaderProgram)& theProgram) const
411 {
412   if (myModelWorldState.Index() == theProgram->ActiveState (OpenGl_MODEL_WORLD_STATE))
413   {
414     return;
415   }
416
417   theProgram->SetUniform (myContext,
418                           theProgram->GetStateLocation (OpenGl_OCC_MODEL_WORLD_MATRIX),
419                           myModelWorldState.ModelWorldMatrix());
420
421   GLint aLocation = theProgram->GetStateLocation (OpenGl_OCC_MODEL_WORLD_MATRIX_INVERSE);
422   if (aLocation != OpenGl_ShaderProgram::INVALID_LOCATION)
423   {
424     theProgram->SetUniform (myContext, aLocation, myModelWorldState.ModelWorldMatrixInverse());
425   }
426
427   theProgram->SetUniform (myContext,
428                           theProgram->GetStateLocation (OpenGl_OCC_MODEL_WORLD_MATRIX_TRANSPOSE),
429                           myModelWorldState.ModelWorldMatrix(), true);
430
431   aLocation = theProgram->GetStateLocation (OpenGl_OCC_MODEL_WORLD_MATRIX_INVERSE_TRANSPOSE);
432   if (aLocation != OpenGl_ShaderProgram::INVALID_LOCATION)
433   {
434     theProgram->SetUniform (myContext, aLocation, myModelWorldState.ModelWorldMatrixInverse(), true);
435   }
436
437   theProgram->UpdateState (OpenGl_MODEL_WORLD_STATE, myModelWorldState.Index());
438 }
439
440 // =======================================================================
441 // function : PushWorldViewState
442 // purpose  : Pushes state of OCCT world-view transform to the program
443 // =======================================================================
444 void OpenGl_ShaderManager::PushWorldViewState (const Handle(OpenGl_ShaderProgram)& theProgram) const
445 {
446   if (myWorldViewState.Index() == theProgram->ActiveState (OpenGl_WORLD_VIEW_STATE))
447   {
448     return;
449   }
450
451   theProgram->SetUniform (myContext,
452                           theProgram->GetStateLocation (OpenGl_OCC_WORLD_VIEW_MATRIX),
453                           myWorldViewState.WorldViewMatrix());
454
455   GLint aLocation = theProgram->GetStateLocation (OpenGl_OCC_WORLD_VIEW_MATRIX_INVERSE);
456   if (aLocation != OpenGl_ShaderProgram::INVALID_LOCATION)
457   {
458     theProgram->SetUniform (myContext, aLocation, myWorldViewState.WorldViewMatrixInverse());
459   }
460
461   theProgram->SetUniform (myContext,
462                           theProgram->GetStateLocation (OpenGl_OCC_WORLD_VIEW_MATRIX_TRANSPOSE),
463                           myWorldViewState.WorldViewMatrix(), true);
464
465   aLocation = theProgram->GetStateLocation (OpenGl_OCC_WORLD_VIEW_MATRIX_INVERSE_TRANSPOSE);
466   if (aLocation != OpenGl_ShaderProgram::INVALID_LOCATION)
467   {
468     theProgram->SetUniform (myContext, aLocation, myWorldViewState.WorldViewMatrixInverse(), true);
469   }
470
471   theProgram->UpdateState (OpenGl_WORLD_VIEW_STATE, myWorldViewState.Index());
472 }
473
474 // =======================================================================
475 // function : UpdateClippingState
476 // purpose  : Updates state of OCCT clipping planes
477 // =======================================================================
478 void OpenGl_ShaderManager::UpdateClippingState()
479 {
480   myClippingState.Update();
481 }
482
483 // =======================================================================
484 // function : RevertClippingState
485 // purpose  : Reverts state of OCCT clipping planes
486 // =======================================================================
487 void OpenGl_ShaderManager::RevertClippingState()
488 {
489   myClippingState.Revert();
490 }
491
492 // =======================================================================
493 // function : PushClippingState
494 // purpose  : Pushes state of OCCT clipping planes to the program
495 // =======================================================================
496 void OpenGl_ShaderManager::PushClippingState (const Handle(OpenGl_ShaderProgram)& theProgram) const
497 {
498   if (myClippingState.Index() == theProgram->ActiveState (OpenGl_CLIP_PLANES_STATE))
499   {
500     return;
501   }
502
503   theProgram->UpdateState (OpenGl_CLIP_PLANES_STATE, myClippingState.Index());
504   const GLint aLocEquations = theProgram->GetStateLocation (OpenGl_OCC_CLIP_PLANE_EQUATIONS);
505   const GLint aLocSpaces    = theProgram->GetStateLocation (OpenGl_OCC_CLIP_PLANE_SPACES);
506   if (aLocEquations == OpenGl_ShaderProgram::INVALID_LOCATION
507    && aLocSpaces    == OpenGl_ShaderProgram::INVALID_LOCATION)
508   {
509     return;
510   }
511
512   GLint aPlanesNb = 0;
513   for (Graphic3d_SequenceOfHClipPlane::Iterator anIter (myContext->Clipping().Planes());
514        anIter.More(); anIter.Next())
515   {
516     const Handle(Graphic3d_ClipPlane)& aPlane = anIter.Value();
517     if (!myContext->Clipping().IsEnabled (aPlane))
518     {
519       continue;
520     }
521
522     ++aPlanesNb;
523   }
524   if (aPlanesNb < 1)
525   {
526     return;
527   }
528
529   const Standard_Size MAX_CLIP_PLANES = 8;
530   OpenGl_Vec4* anEquations = new OpenGl_Vec4[MAX_CLIP_PLANES];
531   GLint*       aSpaces     = new GLint      [MAX_CLIP_PLANES];
532   GLuint aPlaneId = 0;
533   for (Graphic3d_SequenceOfHClipPlane::Iterator anIter (myContext->Clipping().Planes());
534        anIter.More(); anIter.Next())
535   {
536     const Handle(Graphic3d_ClipPlane)& aPlane = anIter.Value();
537     if (!myContext->Clipping().IsEnabled (aPlane))
538     {
539       continue;
540     }
541
542     const Graphic3d_ClipPlane::Equation& anEquation = aPlane->GetEquation();
543     anEquations[aPlaneId] = OpenGl_Vec4 ((float) anEquation.x(),
544                                          (float) anEquation.y(),
545                                          (float) anEquation.z(),
546                                          (float) anEquation.w());
547     aSpaces[aPlaneId] = myContext->Clipping().GetEquationSpace (aPlane);
548     ++aPlaneId;
549   }
550
551   theProgram->SetUniform (myContext,
552                           theProgram->GetStateLocation (OpenGl_OCC_CLIP_PLANE_COUNT),
553                           aPlanesNb);
554   theProgram->SetUniform (myContext, aLocEquations, MAX_CLIP_PLANES, anEquations);
555   theProgram->SetUniform (myContext, aLocSpaces,    MAX_CLIP_PLANES, aSpaces);
556
557   delete[] anEquations;
558   delete[] aSpaces;
559 }
560
561 // =======================================================================
562 // function : UpdateMaterialStateTo
563 // purpose  : Updates state of OCCT material for specified program
564 // =======================================================================
565 void OpenGl_ShaderManager::UpdateMaterialStateTo (const Handle(OpenGl_ShaderProgram)& theProgram,
566                                                   const OpenGl_Element*               theAspect)
567 {
568   if (myMaterialStates.IsBound (theProgram))
569   {
570     myMaterialStates.ChangeFind (theProgram).Set (theAspect);
571   }
572   else
573   {
574     myMaterialStates.Bind (theProgram, OpenGl_MaterialState (theAspect));
575   }
576
577   myMaterialStates.ChangeFind (theProgram).Update();
578 }
579
580 // =======================================================================
581 // function : ResetMaterialStates
582 // purpose  : Resets state of OCCT material for all programs
583 // =======================================================================
584 void OpenGl_ShaderManager::ResetMaterialStates()
585 {
586   for (OpenGl_ShaderProgramList::Iterator anIt (myProgramList); anIt.More(); anIt.Next())
587   {
588     anIt.Value()->UpdateState (OpenGl_MATERIALS_STATE, 0);
589   }
590 }
591
592 // =======================================================================
593 // function : MaterialState
594 // purpose  : Returns state of OCCT material for specified program
595 // =======================================================================
596 const OpenGl_MaterialState* OpenGl_ShaderManager::MaterialState (const Handle(OpenGl_ShaderProgram)& theProgram) const
597 {
598   if (!myMaterialStates.IsBound (theProgram))
599     return NULL;
600
601   return &myMaterialStates.Find (theProgram);
602 }
603
604 namespace
605 {
606
607 static const OpenGl_Vec4 THE_COLOR_BLACK_VEC4 (0.0f, 0.0f, 0.0f, 0.0f);
608
609 // =======================================================================
610 // function : PushAspectFace
611 // purpose  :
612 // =======================================================================
613 static void PushAspectFace (const Handle(OpenGl_Context)&       theCtx,
614                             const Handle(OpenGl_ShaderProgram)& theProgram,
615                             const OpenGl_AspectFace*            theAspect)
616 {
617   theProgram->SetUniform (theCtx,
618                           theProgram->GetStateLocation (OpenGl_OCCT_TEXTURE_ENABLE),
619                           theAspect->DoTextureMap());
620   theProgram->SetUniform (theCtx,
621                           theProgram->GetStateLocation (OpenGl_OCCT_ACTIVE_SAMPLER),
622                           0 /* GL_TEXTURE0 */);
623   theProgram->SetUniform (theCtx,
624                           theProgram->GetStateLocation (OpenGl_OCCT_DISTINGUISH_MODE),
625                           theAspect->DistinguishingMode());
626
627   OpenGl_Material aParams;
628   for (Standard_Integer anIndex = 0; anIndex < 2; ++anIndex)
629   {
630     const GLint aLoc = theProgram->GetStateLocation (anIndex == 0
631                                                    ? OpenGl_OCCT_FRONT_MATERIAL
632                                                    : OpenGl_OCCT_BACK_MATERIAL);
633     if (aLoc == OpenGl_ShaderProgram::INVALID_LOCATION)
634     {
635       continue;
636     }
637
638     aParams.Init (anIndex == 0 ? theAspect->IntFront() : theAspect->IntBack());
639     theProgram->SetUniform (theCtx, aLoc, OpenGl_Material::NbOfVec4(),
640                             aParams.Packed());
641   }
642 }
643
644 // =======================================================================
645 // function : PushAspectLine
646 // purpose  :
647 // =======================================================================
648 static void PushAspectLine (const Handle(OpenGl_Context)&       theCtx,
649                             const Handle(OpenGl_ShaderProgram)& theProgram,
650                             const OpenGl_AspectLine*            theAspect)
651 {
652   theProgram->SetUniform (theCtx, theProgram->GetStateLocation (OpenGl_OCCT_TEXTURE_ENABLE),   TOff);
653   theProgram->SetUniform (theCtx, theProgram->GetStateLocation (OpenGl_OCCT_DISTINGUISH_MODE), TOff);
654
655   const OpenGl_Vec4 aDiffuse (theAspect->Color().rgb[0],
656                               theAspect->Color().rgb[1],
657                               theAspect->Color().rgb[2],
658                               theAspect->Color().rgb[3]);
659   OpenGl_Vec4 aParams[5];
660   aParams[0] = THE_COLOR_BLACK_VEC4;
661   aParams[1] = THE_COLOR_BLACK_VEC4;
662   aParams[2] = aDiffuse;
663   aParams[3] = THE_COLOR_BLACK_VEC4;
664   aParams[4].x() = 0.0f; // shininess
665   aParams[4].y() = 0.0f; // transparency
666   theProgram->SetUniform (theCtx, theProgram->GetStateLocation (OpenGl_OCCT_FRONT_MATERIAL),
667                           5, aParams);
668 }
669
670 // =======================================================================
671 // function : PushAspectText
672 // purpose  :
673 // =======================================================================
674 static void PushAspectText (const Handle(OpenGl_Context)&       theCtx,
675                             const Handle(OpenGl_ShaderProgram)& theProgram,
676                             const OpenGl_AspectText*            theAspect)
677 {
678   theProgram->SetUniform (theCtx, theProgram->GetStateLocation (OpenGl_OCCT_TEXTURE_ENABLE),   TOn);
679   theProgram->SetUniform (theCtx, theProgram->GetStateLocation (OpenGl_OCCT_DISTINGUISH_MODE), TOff);
680   theProgram->SetUniform (theCtx, theProgram->GetStateLocation (OpenGl_OCCT_ACTIVE_SAMPLER),   0 /* GL_TEXTURE0 */);
681
682   OpenGl_Vec4 aDiffuse (theAspect->Color().rgb[0],
683                         theAspect->Color().rgb[1],
684                         theAspect->Color().rgb[2],
685                         theAspect->Color().rgb[3]);
686   if (theAspect->DisplayType() == Aspect_TODT_DEKALE
687    || theAspect->DisplayType() == Aspect_TODT_SUBTITLE)
688   {
689     aDiffuse = OpenGl_Vec4 (theAspect->SubtitleColor().rgb[0],
690                             theAspect->SubtitleColor().rgb[1],
691                             theAspect->SubtitleColor().rgb[2],
692                             theAspect->SubtitleColor().rgb[3]);
693   }
694
695   OpenGl_Vec4 aParams[5];
696   aParams[0] = THE_COLOR_BLACK_VEC4;
697   aParams[1] = THE_COLOR_BLACK_VEC4;
698   aParams[2] = aDiffuse;
699   aParams[3] = THE_COLOR_BLACK_VEC4;
700   aParams[4].x() = 0.0f; // shininess
701   aParams[4].y() = 0.0f; // transparency
702   theProgram->SetUniform (theCtx, theProgram->GetStateLocation (OpenGl_OCCT_FRONT_MATERIAL),
703                           5, aParams);
704 }
705
706 // =======================================================================
707 // function : PushAspectMarker
708 // purpose  :
709 // =======================================================================
710 static void PushAspectMarker (const Handle(OpenGl_Context)&       theCtx,
711                               const Handle(OpenGl_ShaderProgram)& theProgram,
712                               const OpenGl_AspectMarker*          theAspect)
713 {
714   theProgram->SetUniform (theCtx, theProgram->GetStateLocation (OpenGl_OCCT_TEXTURE_ENABLE),   TOn);
715   theProgram->SetUniform (theCtx, theProgram->GetStateLocation (OpenGl_OCCT_DISTINGUISH_MODE), TOff);
716   theProgram->SetUniform (theCtx, theProgram->GetStateLocation (OpenGl_OCCT_ACTIVE_SAMPLER),   0 /* GL_TEXTURE0 */);
717
718   const OpenGl_Vec4 aDiffuse (theAspect->Color().rgb[0],
719                               theAspect->Color().rgb[1],
720                               theAspect->Color().rgb[2],
721                               theAspect->Color().rgb[3]);
722   OpenGl_Vec4 aParams[5];
723   aParams[0] = THE_COLOR_BLACK_VEC4;
724   aParams[1] = THE_COLOR_BLACK_VEC4;
725   aParams[2] = aDiffuse;
726   aParams[3] = THE_COLOR_BLACK_VEC4;
727   aParams[4].x() = 0.0f; // shininess
728   aParams[4].y() = 0.0f; // transparency
729   theProgram->SetUniform (theCtx, theProgram->GetStateLocation (OpenGl_OCCT_FRONT_MATERIAL),
730                           5, aParams);
731 }
732
733 }; // nameless namespace
734
735 // =======================================================================
736 // function : PushMaterialState
737 // purpose  : Pushes current state of OCCT material to the program
738 // =======================================================================
739 void OpenGl_ShaderManager::PushMaterialState (const Handle(OpenGl_ShaderProgram)& theProgram) const
740 {
741   if (!myMaterialStates.IsBound (theProgram))
742   {
743     return;
744   }
745
746   const OpenGl_MaterialState& aState = myMaterialStates.Find (theProgram);
747   if (aState.Index() == theProgram->ActiveState (OpenGl_MATERIALS_STATE))
748   {
749     return;
750   }
751
752   if (typeid (*aState.Aspect()) == typeid (OpenGl_AspectFace))
753   {
754     PushAspectFace   (myContext, theProgram, dynamic_cast<const OpenGl_AspectFace*> (aState.Aspect()));
755   }
756   else if (typeid (*aState.Aspect()) == typeid (OpenGl_AspectLine))
757   {
758     PushAspectLine   (myContext, theProgram, dynamic_cast<const OpenGl_AspectLine*> (aState.Aspect()));
759   }
760   else if (typeid (*aState.Aspect()) == typeid (OpenGl_AspectText))
761   {
762     PushAspectText   (myContext, theProgram, dynamic_cast<const OpenGl_AspectText*> (aState.Aspect()));
763   }
764   else if (typeid (*aState.Aspect()) == typeid (OpenGl_AspectMarker))
765   {
766     PushAspectMarker (myContext, theProgram, dynamic_cast<const OpenGl_AspectMarker*> (aState.Aspect()));
767   }
768
769   theProgram->UpdateState (OpenGl_MATERIALS_STATE, aState.Index());
770 }
771
772 // =======================================================================
773 // function : PushWorldViewState
774 // purpose  : Pushes state of OCCT graphics parameters to the program
775 // =======================================================================
776 void OpenGl_ShaderManager::PushState (const Handle(OpenGl_ShaderProgram)& theProgram) const
777 {
778   PushClippingState    (theProgram);
779   PushMaterialState    (theProgram);
780   PushWorldViewState   (theProgram);
781   PushModelWorldState  (theProgram);
782   PushProjectionState  (theProgram);  
783   PushLightSourceState (theProgram);
784 }