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