0025442: Visualization, TKOpenGl - prevent inclusion of system header glxext.h
[occt.git] / src / OpenGl / OpenGl_ShaderManager.cxx
1 // Created on: 2013-09-26
2 // Created by: Denis BOGOLEPOV
3 // Copyright (c) 2013-2014 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15
16 #include <typeinfo>
17
18 #include <OpenGl_AspectFace.hxx>
19 #include <OpenGl_AspectLine.hxx>
20 #include <OpenGl_AspectMarker.hxx>
21 #include <OpenGl_AspectText.hxx>
22 #include <OpenGl_Clipping.hxx>
23 #include <OpenGl_Context.hxx>
24 #include <OpenGl_ShaderManager.hxx>
25 #include <OpenGl_ShaderProgram.hxx>
26 #include <OpenGl_Workspace.hxx>
27
28 IMPLEMENT_STANDARD_HANDLE (OpenGl_SetOfShaderPrograms, Standard_Transient)
29 IMPLEMENT_STANDARD_RTTIEXT(OpenGl_SetOfShaderPrograms, Standard_Transient)
30
31 IMPLEMENT_STANDARD_HANDLE (OpenGl_ShaderManager, Standard_Transient)
32 IMPLEMENT_STANDARD_RTTIEXT(OpenGl_ShaderManager, Standard_Transient)
33
34 namespace
35 {
36
37 #define EOL "\n"
38
39 //! Auxiliary function to transform normal
40 const char THE_FUNC_transformNormal[] =
41   EOL"vec3 transformNormal (in vec3 theNormal)"
42   EOL"{"
43   EOL"  vec4 aResult = occWorldViewMatrixInverseTranspose"
44   EOL"               * occModelWorldMatrixInverseTranspose"
45   EOL"               * vec4 (theNormal, 0.0);"
46   EOL"  return normalize (aResult.xyz);"
47   EOL"}";
48
49 //! Global shader variable for color definition with lighting enabled.
50 const char THE_FUNC_lightDef[] =
51   EOL"vec3 Ambient;"   //!< Ambient  contribution of light sources
52   EOL"vec3 Diffuse;"   //!< Diffuse  contribution of light sources
53   EOL"vec3 Specular;"; //!< Specular contribution of light sources
54
55 //! Function computes contribution of isotropic point light source
56 const char THE_FUNC_pointLight[] =
57   EOL"void pointLight (in int  theId,"
58   EOL"                 in vec3 theNormal,"
59   EOL"                 in vec3 theView,"
60   EOL"                 in vec3 thePoint,"
61   EOL"                 in bool theIsFront)"
62   EOL"{"
63   EOL"  vec3 aLight = occLight_Position (theId).xyz;"
64   EOL"  if (occLight_IsHeadlight (theId) == 0)"
65   EOL"  {"
66   EOL"    aLight = vec3 (occWorldViewMatrix * occModelWorldMatrix * vec4 (aLight, 1.0));"
67   EOL"  }"
68   EOL"  aLight -= thePoint;"
69   EOL
70   EOL"  float aDist = length (aLight);"
71   EOL"  aLight = aLight * (1.0 / aDist);"
72   EOL
73   EOL"  float anAtten = 1.0 / (occLight_ConstAttenuation  (theId)"
74   EOL"                       + occLight_LinearAttenuation (theId) * aDist);"
75   EOL
76   EOL"  vec3 aHalf = normalize (aLight + theView);"
77   EOL
78   EOL"  vec3  aFaceSideNormal = theIsFront ? theNormal : -theNormal;"
79   EOL"  float aNdotL = max (0.0, dot (aFaceSideNormal, aLight));"
80   EOL"  float aNdotH = max (0.0, dot (aFaceSideNormal, aHalf ));"
81   EOL
82   EOL"  float aSpecl = 0.0;"
83   EOL"  if (aNdotL > 0.0)"
84   EOL"  {"
85   EOL"    aSpecl = pow (aNdotH, theIsFront ? occFrontMaterial_Shininess() : occBackMaterial_Shininess());"
86   EOL"  }"
87   EOL
88   EOL"Diffuse  += occLight_Diffuse  (theId).rgb * aNdotL * anAtten;"
89   EOL"Specular += occLight_Specular (theId).rgb * aSpecl * anAtten;"
90   EOL"}";
91
92 //! Function computes contribution of spotlight source
93 const char THE_FUNC_spotLight[] =
94   EOL"void spotLight (in int  theId,"
95   EOL"                in vec3 theNormal,"
96   EOL"                in vec3 theView,"
97   EOL"                in vec3 thePoint,"
98   EOL"                in bool theIsFront)"
99   EOL"{"
100   EOL"  vec3 aLight   = occLight_Position      (theId).xyz;"
101   EOL"  vec3 aSpotDir = occLight_SpotDirection (theId).xyz;"
102   EOL"  if (occLight_IsHeadlight (theId) == 0)"
103   EOL"  {"
104   EOL"    aLight   = vec3 (occWorldViewMatrix * occModelWorldMatrix * vec4 (aLight,   1.0));"
105   EOL"    aSpotDir = vec3 (occWorldViewMatrix * occModelWorldMatrix * vec4 (aSpotDir, 0.0));"
106   EOL"  }"
107   EOL"  aLight -= thePoint;"
108   EOL
109   EOL"  float aDist = length (aLight);"
110   EOL"  aLight = aLight * (1.0 / aDist);"
111   EOL
112   EOL"  aSpotDir = normalize (aSpotDir);"
113   // light cone
114   EOL"  float aCosA = dot (aSpotDir, -aLight);"
115   EOL"  if (aCosA >= 1.0 || aCosA < cos (occLight_SpotCutOff (theId)))"
116   EOL"  {"
117   EOL"    return;"
118   EOL"  }"
119   EOL
120   EOL"  float anExponent = occLight_SpotExponent (theId);"
121   EOL"  float anAtten    = 1.0 / (occLight_ConstAttenuation  (theId)"
122   EOL"                          + occLight_LinearAttenuation (theId) * aDist);"
123   EOL"  if (anExponent > 0.0)"
124   EOL"  {"
125   EOL"    anAtten *= pow (aCosA, anExponent * 128.0);"
126   EOL"  }"
127   EOL
128   EOL"  vec3 aHalf = normalize (aLight + theView);"
129   EOL
130   EOL"  vec3  aFaceSideNormal = theIsFront ? theNormal : -theNormal;"
131   EOL"  float aNdotL = max (0.0, dot (aFaceSideNormal, aLight));"
132   EOL"  float aNdotH = max (0.0, dot (aFaceSideNormal, aHalf ));"
133   EOL
134   EOL"  float aSpecl = 0.0;"
135   EOL"  if (aNdotL > 0.0)"
136   EOL"  {"
137   EOL"    aSpecl = pow (aNdotH, theIsFront ? occFrontMaterial_Shininess() : occBackMaterial_Shininess());"
138   EOL"  }"
139   EOL
140   EOL"  Diffuse  += occLight_Diffuse  (theId).rgb * aNdotL * anAtten;"
141   EOL"  Specular += occLight_Specular (theId).rgb * aSpecl * anAtten;"
142   EOL"}";
143
144 //! Function computes contribution of directional light source
145 const char THE_FUNC_directionalLight[] =
146   EOL"void directionalLight (in int  theId,"
147   EOL"                       in vec3 theNormal,"
148   EOL"                       in vec3 theView,"
149   EOL"                       in bool theIsFront)"
150   EOL"{"
151   EOL"  vec3 aLight = normalize (occLight_Position (theId).xyz);"
152   EOL"  if (occLight_IsHeadlight (theId) == 0)"
153   EOL"  {"
154   EOL"    aLight = vec3 (occWorldViewMatrix * occModelWorldMatrix * vec4 (aLight, 0.0));"
155   EOL"  }"
156   EOL
157   EOL"  vec3 aHalf = normalize (aLight + theView);"
158   EOL
159   EOL"  vec3  aFaceSideNormal = theIsFront ? theNormal : -theNormal;"
160   EOL"  float aNdotL = max (0.0, dot (aFaceSideNormal, aLight));"
161   EOL"  float aNdotH = max (0.0, dot (aFaceSideNormal, aHalf ));"
162   EOL
163   EOL"  float aSpecl = 0.0;"
164   EOL"  if (aNdotL > 0.0)"
165   EOL"  {"
166   EOL"    aSpecl = pow (aNdotH, theIsFront ? occFrontMaterial_Shininess() : occBackMaterial_Shininess());"
167   EOL"  }"
168   EOL
169   EOL"  Diffuse  += occLight_Diffuse  (theId).rgb * aNdotL;"
170   EOL"  Specular += occLight_Specular (theId).rgb * aSpecl;"
171   EOL"}";
172
173 //! Process clipping planes in Fragment Shader.
174 //! Should be added at the beginning of the main() function.
175 const char THE_FRAG_CLIP_PLANES[] =
176   EOL"  for (int aPlaneIter = 0; aPlaneIter < occClipPlaneCount; ++aPlaneIter)"
177   EOL"  {"
178   EOL"    vec4 aClipEquation = occClipPlaneEquations[aPlaneIter];"
179   EOL"    int  aClipSpace    = occClipPlaneSpaces[aPlaneIter];"
180   EOL"    if (aClipSpace == OccEquationCoords_World)"
181   EOL"    {"
182   EOL"      if (dot (aClipEquation.xyz, PositionWorld.xyz) + aClipEquation.w < 0.0)"
183   EOL"      {"
184   EOL"        discard;"
185   EOL"      }"
186   EOL"    }"
187   EOL"    else if (aClipSpace == OccEquationCoords_View)"
188   EOL"    {"
189   EOL"      if (dot (aClipEquation.xyz, Position.xyz) + aClipEquation.w < 0.0)"
190   EOL"      {"
191   EOL"        discard;"
192   EOL"      }"
193   EOL"    }"
194   EOL"  }";
195
196 }
197
198 // =======================================================================
199 // function : OpenGl_ShaderManager
200 // purpose  : Creates new empty shader manager
201 // =======================================================================
202 OpenGl_ShaderManager::OpenGl_ShaderManager (OpenGl_Context* theContext)
203 : myShadingModel (Visual3d_TOM_VERTEX),
204   myContext  (theContext),
205   myLastView (NULL)
206 {
207   //
208 }
209
210 // =======================================================================
211 // function : ~OpenGl_ShaderManager
212 // purpose  : Releases resources of shader manager
213 // =======================================================================
214 OpenGl_ShaderManager::~OpenGl_ShaderManager()
215 {
216   myProgramList.Clear();
217 }
218
219 // =======================================================================
220 // function : clear
221 // purpose  :
222 // =======================================================================
223 void OpenGl_ShaderManager::clear()
224 {
225   myProgramList.Clear();
226   myLightPrograms.Nullify();
227   myFlatPrograms = OpenGl_SetOfShaderPrograms();
228   myMapOfLightPrograms.Clear();
229   myFontProgram.Nullify();
230   switchLightPrograms();
231 }
232
233 // =======================================================================
234 // function : Create
235 // purpose  : Creates new shader program
236 // =======================================================================
237 Standard_Boolean OpenGl_ShaderManager::Create (const Handle(Graphic3d_ShaderProgram)& theProxy,
238                                                TCollection_AsciiString&               theShareKey,
239                                                Handle(OpenGl_ShaderProgram)&          theProgram)
240 {
241   theProgram.Nullify();
242   if (theProxy.IsNull())
243   {
244     return Standard_False;
245   }
246
247   theShareKey = theProxy->GetId();
248   if (myContext->GetResource<Handle(OpenGl_ShaderProgram)> (theShareKey, theProgram))
249   {
250     if (theProgram->Share())
251     {
252       myProgramList.Append (theProgram);
253     }
254     return Standard_True;
255   }
256
257   theProgram = new OpenGl_ShaderProgram (theProxy);
258   if (!theProgram->Initialize (myContext, theProxy->ShaderObjects()))
259   {
260     theProgram->Release (myContext);
261     theShareKey.Clear();
262     theProgram.Nullify();
263     return Standard_False;
264   }
265
266   myProgramList.Append (theProgram);
267   myContext->ShareResource (theShareKey, theProgram);
268   return Standard_True;
269 }
270
271 // =======================================================================
272 // function : Unregister
273 // purpose  : Removes specified shader program from the manager
274 // =======================================================================
275 void OpenGl_ShaderManager::Unregister (TCollection_AsciiString&      theShareKey,
276                                        Handle(OpenGl_ShaderProgram)& theProgram)
277 {
278   for (OpenGl_ShaderProgramList::Iterator anIt (myProgramList); anIt.More(); anIt.Next())
279   {
280     if (anIt.Value() == theProgram)
281     {
282       if (!theProgram->UnShare())
283       {
284         theShareKey.Clear();
285         theProgram.Nullify();
286         return;
287       }
288
289       myProgramList.Remove (anIt);
290       myMaterialStates.UnBind (theProgram);
291       break;
292     }
293   }
294
295   const TCollection_AsciiString anID = theProgram->myProxy->GetId();
296   if (anID.IsEmpty())
297   {
298     myContext->DelayedRelease (theProgram);
299     theProgram.Nullify();
300   }
301   else
302   {
303     theProgram.Nullify();
304     myContext->ReleaseResource (anID, Standard_True);
305   }
306 }
307
308 // =======================================================================
309 // function : ShaderPrograms
310 // purpose  : Returns list of registered shader programs
311 // =======================================================================
312 const OpenGl_ShaderProgramList& OpenGl_ShaderManager::ShaderPrograms() const
313 {
314   return myProgramList;
315 }
316
317 // =======================================================================
318 // function : Empty
319 // purpose  : Returns true if no program objects are attached
320 // =======================================================================
321 Standard_Boolean OpenGl_ShaderManager::IsEmpty() const
322 {
323   return myProgramList.IsEmpty();
324 }
325
326 // =======================================================================
327 // function : switchLightPrograms
328 // purpose  :
329 // =======================================================================
330 void OpenGl_ShaderManager::switchLightPrograms()
331 {
332   TCollection_AsciiString aKey (myShadingModel == Visual3d_TOM_FRAGMENT ? "p_" : "g_");
333   const OpenGl_ListOfLight* aLights = myLightSourceState.LightSources();
334   if (aLights != NULL)
335   {
336     for (OpenGl_ListOfLight::Iterator aLightIter (*aLights); aLightIter.More(); aLightIter.Next())
337     {
338       switch (aLightIter.Value().Type)
339       {
340         case Visual3d_TOLS_AMBIENT:
341           break; // skip ambient
342         case Visual3d_TOLS_DIRECTIONAL:
343           aKey += "d";
344           break;
345         case Visual3d_TOLS_POSITIONAL:
346           aKey += "p";
347           break;
348         case Visual3d_TOLS_SPOT:
349           aKey += "s";
350           break;
351       }
352     }
353   }
354
355   if (!myMapOfLightPrograms.Find (aKey, myLightPrograms))
356   {
357     myLightPrograms = new OpenGl_SetOfShaderPrograms();
358     myMapOfLightPrograms.Bind (aKey, myLightPrograms);
359   }
360 }
361
362 // =======================================================================
363 // function : UpdateLightSourceStateTo
364 // purpose  : Updates state of OCCT light sources
365 // =======================================================================
366 void OpenGl_ShaderManager::UpdateLightSourceStateTo (const OpenGl_ListOfLight* theLights)
367 {
368   myLightSourceState.Set (theLights);
369   myLightSourceState.Update();
370   switchLightPrograms();
371 }
372
373 // =======================================================================
374 // function : SetShadingModel
375 // purpose  :
376 // =======================================================================
377 void OpenGl_ShaderManager::SetShadingModel (const Visual3d_TypeOfModel theModel)
378 {
379   myShadingModel = theModel;
380   switchLightPrograms();
381 }
382
383 // =======================================================================
384 // function : SetProjectionState
385 // purpose  : Sets new state of OCCT projection transform
386 // =======================================================================
387 void OpenGl_ShaderManager::UpdateProjectionStateTo (const Tmatrix3* theProjectionMatrix)
388 {
389   myProjectionState.Set (theProjectionMatrix);
390   myProjectionState.Update();
391 }
392
393 // =======================================================================
394 // function : SetModelWorldState
395 // purpose  : Sets new state of OCCT model-world transform
396 // =======================================================================
397 void OpenGl_ShaderManager::UpdateModelWorldStateTo (const Tmatrix3* theModelWorldMatrix)
398 {
399   myModelWorldState.Set (theModelWorldMatrix);
400   myModelWorldState.Update();
401 }
402
403 // =======================================================================
404 // function : SetWorldViewState
405 // purpose  : Sets new state of OCCT world-view transform
406 // =======================================================================
407 void OpenGl_ShaderManager::UpdateWorldViewStateTo (const Tmatrix3* theWorldViewMatrix)
408 {
409   myWorldViewState.Set (theWorldViewMatrix);
410   myWorldViewState.Update();
411 }
412
413 // =======================================================================
414 // function : RevertProjectionStateTo
415 // purpose  : Reverts state of OCCT projection transform
416 // =======================================================================
417 void OpenGl_ShaderManager::RevertProjectionStateTo (const Tmatrix3* theProjectionMatrix)
418 {
419   myProjectionState.Set (theProjectionMatrix);
420   myProjectionState.Revert();
421 }
422
423 // =======================================================================
424 // function : RevertModelWorldStateTo
425 // purpose  : Reverts state of OCCT model-world transform
426 // =======================================================================
427 void OpenGl_ShaderManager::RevertModelWorldStateTo (const Tmatrix3* theModelWorldMatrix)
428 {
429   myModelWorldState.Set (theModelWorldMatrix);
430   myModelWorldState.Revert();
431 }
432
433 // =======================================================================
434 // function : RevertWorldViewStateTo
435 // purpose  : Reverts state of OCCT world-view transform
436 // =======================================================================
437 void OpenGl_ShaderManager::RevertWorldViewStateTo (const Tmatrix3* theWorldViewMatrix)
438 {
439   myWorldViewState.Set (theWorldViewMatrix);
440   myWorldViewState.Revert();
441 }
442
443 // =======================================================================
444 // function : LightSourceState
445 // purpose  : Returns current state of OCCT light sources
446 // =======================================================================
447 const OpenGl_LightSourceState& OpenGl_ShaderManager::LightSourceState() const
448 {
449   return myLightSourceState;
450 }
451
452 // =======================================================================
453 // function : ProjectionState
454 // purpose  : Returns current state of OCCT projection transform
455 // =======================================================================
456 const OpenGl_ProjectionState& OpenGl_ShaderManager::ProjectionState() const
457 {
458   return myProjectionState;
459 }
460
461 // =======================================================================
462 // function : ModelWorldState
463 // purpose  : Returns current state of OCCT model-world transform
464 // =======================================================================
465 const OpenGl_ModelWorldState& OpenGl_ShaderManager::ModelWorldState() const
466 {
467   return myModelWorldState;
468 }
469
470 // =======================================================================
471 // function : WorldViewState
472 // purpose  : Returns current state of OCCT world-view transform
473 // =======================================================================
474 const OpenGl_WorldViewState& OpenGl_ShaderManager::WorldViewState() const
475 {
476   return myWorldViewState;
477 }
478
479 //! Packed properties of light source
480 class OpenGl_ShaderLightParameters
481 {
482 public:
483
484   OpenGl_Vec4 Color;
485   OpenGl_Vec4 Position;
486   OpenGl_Vec4 Direction;
487   OpenGl_Vec4 Parameters;
488
489   //! Returns packed (serialized) representation of light source properties
490   const OpenGl_Vec4* Packed() const { return reinterpret_cast<const OpenGl_Vec4*> (this); }
491   static Standard_Integer NbOfVec4() { return 4; }
492
493 };
494
495 //! Packed light source type information
496 class OpenGl_ShaderLightType
497 {
498 public:
499
500   Standard_Integer Type;
501   Standard_Integer IsHeadlight;
502
503   //! Returns packed (serialized) representation of light source type
504   const OpenGl_Vec2i* Packed() const { return reinterpret_cast<const OpenGl_Vec2i*> (this); }
505   static Standard_Integer NbOfVec2i() { return 1; }
506
507 };
508
509 // =======================================================================
510 // function : PushLightSourceState
511 // purpose  : Pushes state of OCCT light sources to the program
512 // =======================================================================
513 void OpenGl_ShaderManager::PushLightSourceState (const Handle(OpenGl_ShaderProgram)& theProgram) const
514 {
515   if (myLightSourceState.Index() == theProgram->ActiveState (OpenGl_LIGHT_SOURCES_STATE)
516    || !theProgram->IsValid())
517   {
518     return;
519   }
520
521   OpenGl_ShaderLightType* aLightTypeArray = new OpenGl_ShaderLightType[OpenGLMaxLights];
522   for (Standard_Integer aLightIt = 0; aLightIt < OpenGLMaxLights; ++aLightIt)
523   {
524     aLightTypeArray[aLightIt].Type = -1;
525   }
526
527   const Standard_Integer aLightsDefNb = Min (myLightSourceState.LightSources()->Size(), OpenGLMaxLights);
528   if (aLightsDefNb < 1)
529   {
530     theProgram->SetUniform (myContext,
531                             theProgram->GetStateLocation (OpenGl_OCC_LIGHT_SOURCE_COUNT),
532                             0);
533     theProgram->SetUniform (myContext,
534                             theProgram->GetStateLocation (OpenGl_OCC_LIGHT_AMBIENT),
535                             OpenGl_Vec4 (0.0f, 0.0f, 0.0f, 0.0f));
536     theProgram->SetUniform (myContext,
537                             theProgram->GetStateLocation (OpenGl_OCC_LIGHT_SOURCE_TYPES),
538                             OpenGLMaxLights * OpenGl_ShaderLightType::NbOfVec2i(),
539                             aLightTypeArray[0].Packed());
540     theProgram->UpdateState (OpenGl_LIGHT_SOURCES_STATE, myLightSourceState.Index());
541     delete[] aLightTypeArray;
542     return;
543   }
544
545   OpenGl_ShaderLightParameters* aLightParamsArray = new OpenGl_ShaderLightParameters[aLightsDefNb];
546
547   OpenGl_Vec4 anAmbient (0.0f, 0.0f, 0.0f, 0.0f);
548   Standard_Integer aLightsNb = 0;
549   for (OpenGl_ListOfLight::Iterator anIter (*myLightSourceState.LightSources()); anIter.More(); anIter.Next())
550   {
551     const OpenGl_Light& aLight = anIter.Value();
552     if (aLight.Type == Visual3d_TOLS_AMBIENT)
553     {
554       anAmbient += aLight.Color;
555       continue;
556     }
557     else if (aLightsNb >= OpenGLMaxLights)
558     {
559       continue;
560     }
561
562     OpenGl_ShaderLightType& aLightType = aLightTypeArray[aLightsNb];
563     aLightType.Type        = aLight.Type;
564     aLightType.IsHeadlight = aLight.IsHeadlight;
565
566     OpenGl_ShaderLightParameters& aLightParams = aLightParamsArray[aLightsNb];
567     aLightParams.Color    = aLight.Color;
568     aLightParams.Position = aLight.Type == Visual3d_TOLS_DIRECTIONAL
569                          ? -aLight.Direction
570                          :  aLight.Position;
571     if (aLight.Type == Visual3d_TOLS_SPOT)
572     {
573       aLightParams.Direction = aLight.Direction;
574     }
575     aLightParams.Parameters = aLight.Params;
576     ++aLightsNb;
577   }
578
579   theProgram->SetUniform (myContext,
580                           theProgram->GetStateLocation (OpenGl_OCC_LIGHT_SOURCE_COUNT),
581                           aLightsNb);
582   theProgram->SetUniform (myContext,
583                           theProgram->GetStateLocation (OpenGl_OCC_LIGHT_AMBIENT),
584                           anAmbient);
585   theProgram->SetUniform (myContext,
586                           theProgram->GetStateLocation (OpenGl_OCC_LIGHT_SOURCE_TYPES),
587                           OpenGLMaxLights * OpenGl_ShaderLightType::NbOfVec2i(),
588                           aLightTypeArray[0].Packed());
589   if (aLightsNb > 0)
590   {
591     theProgram->SetUniform (myContext,
592                             theProgram->GetStateLocation (OpenGl_OCC_LIGHT_SOURCE_PARAMS),
593                             aLightsNb * OpenGl_ShaderLightParameters::NbOfVec4(),
594                             aLightParamsArray[0].Packed());
595   }
596   delete[] aLightParamsArray;
597   delete[] aLightTypeArray;
598
599   theProgram->UpdateState (OpenGl_LIGHT_SOURCES_STATE, myLightSourceState.Index());
600 }
601
602 // =======================================================================
603 // function : PushProjectionState
604 // purpose  : Pushes state of OCCT projection transform to the program
605 // =======================================================================
606 void OpenGl_ShaderManager::PushProjectionState (const Handle(OpenGl_ShaderProgram)& theProgram) const
607 {
608   if (myProjectionState.Index() == theProgram->ActiveState (OpenGl_PROJECTION_STATE))
609   {
610     return;
611   }
612
613   theProgram->SetUniform (myContext,
614                           theProgram->GetStateLocation (OpenGl_OCC_PROJECTION_MATRIX),
615                           myProjectionState.ProjectionMatrix());
616
617   GLint aLocation = theProgram->GetStateLocation (OpenGl_OCC_PROJECTION_MATRIX_INVERSE);
618   if (aLocation != OpenGl_ShaderProgram::INVALID_LOCATION)
619   {
620     theProgram->SetUniform (myContext, aLocation, myProjectionState.ProjectionMatrixInverse());
621   }
622
623   theProgram->SetUniform (myContext,
624                           theProgram->GetStateLocation (OpenGl_OCC_PROJECTION_MATRIX_TRANSPOSE),
625                           myProjectionState.ProjectionMatrix(), true);
626
627   aLocation = theProgram->GetStateLocation (OpenGl_OCC_PROJECTION_MATRIX_INVERSE_TRANSPOSE);
628   if (aLocation != OpenGl_ShaderProgram::INVALID_LOCATION)
629   {
630     theProgram->SetUniform (myContext, aLocation, myProjectionState.ProjectionMatrixInverse(), true);
631   }
632
633   theProgram->UpdateState (OpenGl_PROJECTION_STATE, myProjectionState.Index());
634 }
635
636 // =======================================================================
637 // function : PushModelWorldState
638 // purpose  : Pushes state of OCCT model-world transform to the program
639 // =======================================================================
640 void OpenGl_ShaderManager::PushModelWorldState (const Handle(OpenGl_ShaderProgram)& theProgram) const
641 {
642   if (myModelWorldState.Index() == theProgram->ActiveState (OpenGl_MODEL_WORLD_STATE))
643   {
644     return;
645   }
646
647   theProgram->SetUniform (myContext,
648                           theProgram->GetStateLocation (OpenGl_OCC_MODEL_WORLD_MATRIX),
649                           myModelWorldState.ModelWorldMatrix());
650
651   GLint aLocation = theProgram->GetStateLocation (OpenGl_OCC_MODEL_WORLD_MATRIX_INVERSE);
652   if (aLocation != OpenGl_ShaderProgram::INVALID_LOCATION)
653   {
654     theProgram->SetUniform (myContext, aLocation, myModelWorldState.ModelWorldMatrixInverse());
655   }
656
657   theProgram->SetUniform (myContext,
658                           theProgram->GetStateLocation (OpenGl_OCC_MODEL_WORLD_MATRIX_TRANSPOSE),
659                           myModelWorldState.ModelWorldMatrix(), true);
660
661   aLocation = theProgram->GetStateLocation (OpenGl_OCC_MODEL_WORLD_MATRIX_INVERSE_TRANSPOSE);
662   if (aLocation != OpenGl_ShaderProgram::INVALID_LOCATION)
663   {
664     theProgram->SetUniform (myContext, aLocation, myModelWorldState.ModelWorldMatrixInverse(), true);
665   }
666
667   theProgram->UpdateState (OpenGl_MODEL_WORLD_STATE, myModelWorldState.Index());
668 }
669
670 // =======================================================================
671 // function : PushWorldViewState
672 // purpose  : Pushes state of OCCT world-view transform to the program
673 // =======================================================================
674 void OpenGl_ShaderManager::PushWorldViewState (const Handle(OpenGl_ShaderProgram)& theProgram) const
675 {
676   if (myWorldViewState.Index() == theProgram->ActiveState (OpenGl_WORLD_VIEW_STATE))
677   {
678     return;
679   }
680
681   theProgram->SetUniform (myContext,
682                           theProgram->GetStateLocation (OpenGl_OCC_WORLD_VIEW_MATRIX),
683                           myWorldViewState.WorldViewMatrix());
684
685   GLint aLocation = theProgram->GetStateLocation (OpenGl_OCC_WORLD_VIEW_MATRIX_INVERSE);
686   if (aLocation != OpenGl_ShaderProgram::INVALID_LOCATION)
687   {
688     theProgram->SetUniform (myContext, aLocation, myWorldViewState.WorldViewMatrixInverse());
689   }
690
691   theProgram->SetUniform (myContext,
692                           theProgram->GetStateLocation (OpenGl_OCC_WORLD_VIEW_MATRIX_TRANSPOSE),
693                           myWorldViewState.WorldViewMatrix(), true);
694
695   aLocation = theProgram->GetStateLocation (OpenGl_OCC_WORLD_VIEW_MATRIX_INVERSE_TRANSPOSE);
696   if (aLocation != OpenGl_ShaderProgram::INVALID_LOCATION)
697   {
698     theProgram->SetUniform (myContext, aLocation, myWorldViewState.WorldViewMatrixInverse(), true);
699   }
700
701   theProgram->UpdateState (OpenGl_WORLD_VIEW_STATE, myWorldViewState.Index());
702 }
703
704 // =======================================================================
705 // function : UpdateClippingState
706 // purpose  : Updates state of OCCT clipping planes
707 // =======================================================================
708 void OpenGl_ShaderManager::UpdateClippingState()
709 {
710   myClippingState.Update();
711 }
712
713 // =======================================================================
714 // function : RevertClippingState
715 // purpose  : Reverts state of OCCT clipping planes
716 // =======================================================================
717 void OpenGl_ShaderManager::RevertClippingState()
718 {
719   myClippingState.Revert();
720 }
721
722 // =======================================================================
723 // function : PushClippingState
724 // purpose  : Pushes state of OCCT clipping planes to the program
725 // =======================================================================
726 void OpenGl_ShaderManager::PushClippingState (const Handle(OpenGl_ShaderProgram)& theProgram) const
727 {
728   if (myClippingState.Index() == theProgram->ActiveState (OpenGl_CLIP_PLANES_STATE))
729   {
730     return;
731   }
732
733   theProgram->UpdateState (OpenGl_CLIP_PLANES_STATE, myClippingState.Index());
734   const GLint aLocEquations = theProgram->GetStateLocation (OpenGl_OCC_CLIP_PLANE_EQUATIONS);
735   const GLint aLocSpaces    = theProgram->GetStateLocation (OpenGl_OCC_CLIP_PLANE_SPACES);
736   if (aLocEquations == OpenGl_ShaderProgram::INVALID_LOCATION
737    && aLocSpaces    == OpenGl_ShaderProgram::INVALID_LOCATION)
738   {
739     return;
740   }
741
742   GLint aPlanesNb = 0;
743   for (Graphic3d_SequenceOfHClipPlane::Iterator anIter (myContext->Clipping().Planes());
744        anIter.More(); anIter.Next())
745   {
746     const Handle(Graphic3d_ClipPlane)& aPlane = anIter.Value();
747     if (!myContext->Clipping().IsEnabled (aPlane))
748     {
749       continue;
750     }
751
752     ++aPlanesNb;
753   }
754   if (aPlanesNb < 1)
755   {
756     return;
757   }
758
759   const Standard_Size MAX_CLIP_PLANES = 8;
760   OpenGl_Vec4* anEquations = new OpenGl_Vec4[MAX_CLIP_PLANES];
761   GLint*       aSpaces     = new GLint      [MAX_CLIP_PLANES];
762   GLuint aPlaneId = 0;
763   for (Graphic3d_SequenceOfHClipPlane::Iterator anIter (myContext->Clipping().Planes());
764        anIter.More(); anIter.Next())
765   {
766     const Handle(Graphic3d_ClipPlane)& aPlane = anIter.Value();
767     if (!myContext->Clipping().IsEnabled (aPlane))
768     {
769       continue;
770     }
771
772     const Graphic3d_ClipPlane::Equation& anEquation = aPlane->GetEquation();
773     anEquations[aPlaneId] = OpenGl_Vec4 ((float) anEquation.x(),
774                                          (float) anEquation.y(),
775                                          (float) anEquation.z(),
776                                          (float) anEquation.w());
777     aSpaces[aPlaneId] = myContext->Clipping().GetEquationSpace (aPlane);
778     ++aPlaneId;
779   }
780
781   theProgram->SetUniform (myContext,
782                           theProgram->GetStateLocation (OpenGl_OCC_CLIP_PLANE_COUNT),
783                           aPlanesNb);
784   theProgram->SetUniform (myContext, aLocEquations, MAX_CLIP_PLANES, anEquations);
785   theProgram->SetUniform (myContext, aLocSpaces,    MAX_CLIP_PLANES, aSpaces);
786
787   delete[] anEquations;
788   delete[] aSpaces;
789 }
790
791 // =======================================================================
792 // function : UpdateMaterialStateTo
793 // purpose  : Updates state of OCCT material for specified program
794 // =======================================================================
795 void OpenGl_ShaderManager::UpdateMaterialStateTo (const Handle(OpenGl_ShaderProgram)& theProgram,
796                                                   const OpenGl_Element*               theAspect)
797 {
798   if (myMaterialStates.IsBound (theProgram))
799   {
800     OpenGl_MaterialState& aState = myMaterialStates.ChangeFind (theProgram);
801     aState.Set (theAspect);
802     aState.Update();
803   }
804   else
805   {
806     myMaterialStates.Bind       (theProgram, OpenGl_MaterialState (theAspect));
807     myMaterialStates.ChangeFind (theProgram).Update();
808   }
809 }
810
811 // =======================================================================
812 // function : ResetMaterialStates
813 // purpose  : Resets state of OCCT material for all programs
814 // =======================================================================
815 void OpenGl_ShaderManager::ResetMaterialStates()
816 {
817   for (OpenGl_ShaderProgramList::Iterator anIt (myProgramList); anIt.More(); anIt.Next())
818   {
819     anIt.Value()->UpdateState (OpenGl_MATERIALS_STATE, 0);
820   }
821 }
822
823 // =======================================================================
824 // function : MaterialState
825 // purpose  : Returns state of OCCT material for specified program
826 // =======================================================================
827 const OpenGl_MaterialState* OpenGl_ShaderManager::MaterialState (const Handle(OpenGl_ShaderProgram)& theProgram) const
828 {
829   if (!myMaterialStates.IsBound (theProgram))
830     return NULL;
831
832   return &myMaterialStates.Find (theProgram);
833 }
834
835 namespace
836 {
837
838 static const OpenGl_Vec4 THE_COLOR_BLACK_VEC4 (0.0f, 0.0f, 0.0f, 0.0f);
839
840 // =======================================================================
841 // function : PushAspectFace
842 // purpose  :
843 // =======================================================================
844 static void PushAspectFace (const Handle(OpenGl_Context)&       theCtx,
845                             const Handle(OpenGl_ShaderProgram)& theProgram,
846                             const OpenGl_AspectFace*            theAspect)
847 {
848   theProgram->SetUniform (theCtx,
849                           theProgram->GetStateLocation (OpenGl_OCCT_TEXTURE_ENABLE),
850                           theAspect->DoTextureMap());
851   theProgram->SetUniform (theCtx,
852                           theProgram->GetStateLocation (OpenGl_OCCT_ACTIVE_SAMPLER),
853                           0 /* GL_TEXTURE0 */);
854   theProgram->SetUniform (theCtx,
855                           theProgram->GetStateLocation (OpenGl_OCCT_DISTINGUISH_MODE),
856                           theAspect->DistinguishingMode());
857
858   OpenGl_Material aParams;
859   for (Standard_Integer anIndex = 0; anIndex < 2; ++anIndex)
860   {
861     const GLint aLoc = theProgram->GetStateLocation (anIndex == 0
862                                                    ? OpenGl_OCCT_FRONT_MATERIAL
863                                                    : OpenGl_OCCT_BACK_MATERIAL);
864     if (aLoc == OpenGl_ShaderProgram::INVALID_LOCATION)
865     {
866       continue;
867     }
868
869     aParams.Init (anIndex == 0 ? theAspect->IntFront() : theAspect->IntBack());
870     theProgram->SetUniform (theCtx, aLoc, OpenGl_Material::NbOfVec4(),
871                             aParams.Packed());
872   }
873 }
874
875 // =======================================================================
876 // function : PushAspectLine
877 // purpose  :
878 // =======================================================================
879 static void PushAspectLine (const Handle(OpenGl_Context)&       theCtx,
880                             const Handle(OpenGl_ShaderProgram)& theProgram,
881                             const OpenGl_AspectLine*            theAspect)
882 {
883   theProgram->SetUniform (theCtx, theProgram->GetStateLocation (OpenGl_OCCT_TEXTURE_ENABLE),   TOff);
884   theProgram->SetUniform (theCtx, theProgram->GetStateLocation (OpenGl_OCCT_DISTINGUISH_MODE), TOff);
885
886   const OpenGl_Vec4 aDiffuse (theAspect->Color().rgb[0],
887                               theAspect->Color().rgb[1],
888                               theAspect->Color().rgb[2],
889                               theAspect->Color().rgb[3]);
890   OpenGl_Vec4 aParams[5];
891   aParams[0] = THE_COLOR_BLACK_VEC4;
892   aParams[1] = THE_COLOR_BLACK_VEC4;
893   aParams[2] = aDiffuse;
894   aParams[3] = THE_COLOR_BLACK_VEC4;
895   aParams[4].x() = 0.0f; // shininess
896   aParams[4].y() = 0.0f; // transparency
897   theProgram->SetUniform (theCtx, theProgram->GetStateLocation (OpenGl_OCCT_FRONT_MATERIAL),
898                           5, aParams);
899 }
900
901 // =======================================================================
902 // function : PushAspectText
903 // purpose  :
904 // =======================================================================
905 static void PushAspectText (const Handle(OpenGl_Context)&       theCtx,
906                             const Handle(OpenGl_ShaderProgram)& theProgram,
907                             const OpenGl_AspectText*            theAspect)
908 {
909   theProgram->SetUniform (theCtx, theProgram->GetStateLocation (OpenGl_OCCT_TEXTURE_ENABLE),   TOn);
910   theProgram->SetUniform (theCtx, theProgram->GetStateLocation (OpenGl_OCCT_DISTINGUISH_MODE), TOff);
911   theProgram->SetUniform (theCtx, theProgram->GetStateLocation (OpenGl_OCCT_ACTIVE_SAMPLER),   0 /* GL_TEXTURE0 */);
912
913   OpenGl_Vec4 aDiffuse (theAspect->Color().rgb[0],
914                         theAspect->Color().rgb[1],
915                         theAspect->Color().rgb[2],
916                         theAspect->Color().rgb[3]);
917   if (theAspect->DisplayType() == Aspect_TODT_DEKALE
918    || theAspect->DisplayType() == Aspect_TODT_SUBTITLE)
919   {
920     aDiffuse = OpenGl_Vec4 (theAspect->SubtitleColor().rgb[0],
921                             theAspect->SubtitleColor().rgb[1],
922                             theAspect->SubtitleColor().rgb[2],
923                             theAspect->SubtitleColor().rgb[3]);
924   }
925
926   OpenGl_Vec4 aParams[5];
927   aParams[0] = THE_COLOR_BLACK_VEC4;
928   aParams[1] = THE_COLOR_BLACK_VEC4;
929   aParams[2] = aDiffuse;
930   aParams[3] = THE_COLOR_BLACK_VEC4;
931   aParams[4].x() = 0.0f; // shininess
932   aParams[4].y() = 0.0f; // transparency
933   theProgram->SetUniform (theCtx, theProgram->GetStateLocation (OpenGl_OCCT_FRONT_MATERIAL),
934                           5, aParams);
935 }
936
937 // =======================================================================
938 // function : PushAspectMarker
939 // purpose  :
940 // =======================================================================
941 static void PushAspectMarker (const Handle(OpenGl_Context)&       theCtx,
942                               const Handle(OpenGl_ShaderProgram)& theProgram,
943                               const OpenGl_AspectMarker*          theAspect)
944 {
945   theProgram->SetUniform (theCtx, theProgram->GetStateLocation (OpenGl_OCCT_TEXTURE_ENABLE),   TOn);
946   theProgram->SetUniform (theCtx, theProgram->GetStateLocation (OpenGl_OCCT_DISTINGUISH_MODE), TOff);
947   theProgram->SetUniform (theCtx, theProgram->GetStateLocation (OpenGl_OCCT_ACTIVE_SAMPLER),   0 /* GL_TEXTURE0 */);
948
949   const OpenGl_Vec4 aDiffuse (theAspect->Color().rgb[0],
950                               theAspect->Color().rgb[1],
951                               theAspect->Color().rgb[2],
952                               theAspect->Color().rgb[3]);
953   OpenGl_Vec4 aParams[5];
954   aParams[0] = THE_COLOR_BLACK_VEC4;
955   aParams[1] = THE_COLOR_BLACK_VEC4;
956   aParams[2] = aDiffuse;
957   aParams[3] = THE_COLOR_BLACK_VEC4;
958   aParams[4].x() = 0.0f; // shininess
959   aParams[4].y() = 0.0f; // transparency
960   theProgram->SetUniform (theCtx, theProgram->GetStateLocation (OpenGl_OCCT_FRONT_MATERIAL),
961                           5, aParams);
962 }
963
964 }; // nameless namespace
965
966 // =======================================================================
967 // function : PushMaterialState
968 // purpose  : Pushes current state of OCCT material to the program
969 // =======================================================================
970 void OpenGl_ShaderManager::PushMaterialState (const Handle(OpenGl_ShaderProgram)& theProgram) const
971 {
972   if (!myMaterialStates.IsBound (theProgram))
973   {
974     return;
975   }
976
977   const OpenGl_MaterialState& aState = myMaterialStates.Find (theProgram);
978   if (aState.Index() == theProgram->ActiveState (OpenGl_MATERIALS_STATE))
979   {
980     return;
981   }
982
983   if (typeid (*aState.Aspect()) == typeid (OpenGl_AspectFace))
984   {
985     PushAspectFace   (myContext, theProgram, dynamic_cast<const OpenGl_AspectFace*> (aState.Aspect()));
986   }
987   else if (typeid (*aState.Aspect()) == typeid (OpenGl_AspectLine))
988   {
989     PushAspectLine   (myContext, theProgram, dynamic_cast<const OpenGl_AspectLine*> (aState.Aspect()));
990   }
991   else if (typeid (*aState.Aspect()) == typeid (OpenGl_AspectText))
992   {
993     PushAspectText   (myContext, theProgram, dynamic_cast<const OpenGl_AspectText*> (aState.Aspect()));
994   }
995   else if (typeid (*aState.Aspect()) == typeid (OpenGl_AspectMarker))
996   {
997     PushAspectMarker (myContext, theProgram, dynamic_cast<const OpenGl_AspectMarker*> (aState.Aspect()));
998   }
999
1000   theProgram->UpdateState (OpenGl_MATERIALS_STATE, aState.Index());
1001 }
1002
1003 // =======================================================================
1004 // function : PushWorldViewState
1005 // purpose  : Pushes state of OCCT graphics parameters to the program
1006 // =======================================================================
1007 void OpenGl_ShaderManager::PushState (const Handle(OpenGl_ShaderProgram)& theProgram) const
1008 {
1009   PushClippingState    (theProgram);
1010   PushMaterialState    (theProgram);
1011   PushWorldViewState   (theProgram);
1012   PushModelWorldState  (theProgram);
1013   PushProjectionState  (theProgram);
1014   PushLightSourceState (theProgram);
1015 }
1016
1017 // =======================================================================
1018 // function : prepareStdProgramFont
1019 // purpose  :
1020 // =======================================================================
1021 Standard_Boolean OpenGl_ShaderManager::prepareStdProgramFont()
1022 {
1023   Handle(Graphic3d_ShaderProgram) aProgramSrc = new Graphic3d_ShaderProgram();
1024   TCollection_AsciiString aSrcVert =
1025       EOL"void main()"
1026       EOL"{"
1027       EOL"  gl_Position = occProjectionMatrix * occWorldViewMatrix * occModelWorldMatrix * occVertex;"
1028       EOL"}";
1029
1030   TCollection_AsciiString aSrcFrag =
1031       EOL"float getAlpha(void) { return texture2D(occActiveSampler, gl_PointCoord).a; }"
1032       EOL"void main()"
1033       EOL"{"
1034       EOL"  vec4 aColor = occColor;"
1035       EOL"  aColor.a *= getAlpha();"
1036       EOL"  if (aColor.a <= 0.285) discard;"
1037       EOL"  gl_FragColor = aColor;"
1038       EOL"}";
1039
1040   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_VERTEX,   aSrcVert));
1041   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_FRAGMENT, aSrcFrag));
1042   TCollection_AsciiString aKey;
1043   if (!Create (aProgramSrc, aKey, myFontProgram))
1044   {
1045     myFontProgram = new OpenGl_ShaderProgram(); // just mark as invalid
1046     return Standard_False;
1047   }
1048   return Standard_True;
1049 }
1050
1051 // =======================================================================
1052 // function : prepareStdProgramFlat
1053 // purpose  :
1054 // =======================================================================
1055 Standard_Boolean OpenGl_ShaderManager::prepareStdProgramFlat (Handle(OpenGl_ShaderProgram)& theProgram,
1056                                                               const Standard_Integer        theBits)
1057 {
1058   Handle(Graphic3d_ShaderProgram) aProgramSrc = new Graphic3d_ShaderProgram();
1059   TCollection_AsciiString aSrcVert, aSrcVertExtraOut, aSrcVertExtraMain, aSrcFrag, aSrcFragExtraOut, aSrcFragExtraMain;
1060   TCollection_AsciiString aSrcFragGetColor     = EOL"vec4 getColor(void) { return occColor; }";
1061   TCollection_AsciiString aSrcFragMainGetColor = EOL"  gl_FragColor = getColor();";
1062   if ((theBits & OpenGl_PO_Point) != 0)
1063   {
1064   #if defined(GL_ES_VERSION_2_0)
1065     aSrcVertExtraMain += EOL"  gl_PointSize = occPointSize;";
1066   #endif
1067     if ((theBits & OpenGl_PO_TextureA) != 0)
1068     {
1069       aSrcFragGetColor =
1070         EOL"float getAlpha(void) { return texture2D(occActiveSampler, gl_PointCoord).a; }"
1071         EOL"vec4  getColor(void)"
1072         EOL"{"
1073         EOL"  vec4 aColor = occColor;"
1074         EOL"  aColor.a *= getAlpha();"
1075         EOL"  return aColor;"
1076         EOL"}";
1077
1078       aSrcFragMainGetColor =
1079         EOL"  vec4 aColor = getColor();"
1080         EOL"  if (aColor.a <= 0.1) discard;"
1081         EOL"  gl_FragColor = aColor;";
1082     }
1083     else if ((theBits & OpenGl_PO_TextureRGB) != 0)
1084     {
1085       aSrcFragGetColor =
1086         EOL"vec4 getColor(void) { return texture2D(occActiveSampler, gl_PointCoord); }";
1087       aSrcFragMainGetColor =
1088         EOL"  vec4 aColor = getColor();"
1089         EOL"  if (aColor.a <= 0.1) discard;"
1090         EOL"  gl_FragColor = aColor;";
1091     }
1092   }
1093   if ((theBits & OpenGl_PO_VertColor) != 0)
1094   {
1095     aSrcVertExtraOut  += EOL"varying vec4 VertColor;";
1096     aSrcVertExtraMain += EOL"  VertColor = occVertColor;";
1097     aSrcFragExtraOut  += EOL"varying vec4 VertColor;";
1098     aSrcFragGetColor  =  EOL"vec4 getColor(void) { return VertColor; }";
1099   }
1100   if ((theBits & OpenGl_PO_ClipPlanes) != 0)
1101   {
1102     const char THE_POS_VARY[] =
1103       EOL"varying vec4 PositionWorld;"
1104       EOL"varying vec4 Position;";
1105
1106     aSrcVertExtraOut  += THE_POS_VARY;
1107     aSrcFragExtraOut  += THE_POS_VARY;
1108     aSrcVertExtraMain +=
1109       EOL"  PositionWorld = occModelWorldMatrix * occVertex;"
1110       EOL"  Position      = occWorldViewMatrix * PositionWorld;";
1111     aSrcFragExtraMain += THE_FRAG_CLIP_PLANES;
1112   }
1113
1114   aSrcVert =
1115       aSrcVertExtraOut
1116     + EOL"void main()"
1117       EOL"{"
1118     + aSrcVertExtraMain
1119     + EOL"  gl_Position = occProjectionMatrix * occWorldViewMatrix * occModelWorldMatrix * occVertex;"
1120       EOL"}";
1121
1122   aSrcFrag =
1123       aSrcFragExtraOut
1124     + aSrcFragGetColor
1125     + EOL"void main()"
1126       EOL"{"
1127     + aSrcFragExtraMain
1128     + aSrcFragMainGetColor
1129     + EOL"}";
1130
1131   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_VERTEX,   aSrcVert));
1132   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_FRAGMENT, aSrcFrag));
1133
1134   TCollection_AsciiString aKey;
1135   if (!Create (aProgramSrc, aKey, theProgram))
1136   {
1137     theProgram = new OpenGl_ShaderProgram(); // just mark as invalid
1138     return Standard_False;
1139   }
1140   return Standard_True;
1141 }
1142
1143 // =======================================================================
1144 // function : stdComputeLighting
1145 // purpose  :
1146 // =======================================================================
1147 TCollection_AsciiString OpenGl_ShaderManager::stdComputeLighting()
1148 {
1149   bool aLightsMap[Visual3d_TOLS_SPOT + 1] = { false, false, false, false };
1150   TCollection_AsciiString aLightsFunc, aLightsLoop;
1151   const OpenGl_ListOfLight* aLights = myLightSourceState.LightSources();
1152   if (aLights != NULL)
1153   {
1154     Standard_Integer anIndex = 0;
1155     for (OpenGl_ListOfLight::Iterator aLightIter (*aLights); aLightIter.More(); aLightIter.Next(), ++anIndex)
1156     {
1157       switch (aLightIter.Value().Type)
1158       {
1159         case Visual3d_TOLS_AMBIENT:
1160           --anIndex;
1161           break; // skip ambient
1162         case Visual3d_TOLS_DIRECTIONAL:
1163           aLightsLoop = aLightsLoop + EOL"    directionalLight (" + anIndex + ", theNormal, theView, theIsFront);";
1164           break;
1165         case Visual3d_TOLS_POSITIONAL:
1166           aLightsLoop = aLightsLoop + EOL"    pointLight (" + anIndex + ", theNormal, theView, aPoint, theIsFront);";
1167           break;
1168         case Visual3d_TOLS_SPOT:
1169           aLightsLoop = aLightsLoop + EOL"    spotLight (" + anIndex + ", theNormal, theView, aPoint, theIsFront);";
1170           break;
1171       }
1172
1173       bool& aTypeBit = aLightsMap[aLightIter.Value().Type];
1174       if (aTypeBit)
1175       {
1176         continue;
1177       }
1178
1179       aTypeBit = true;
1180       switch (aLightIter.Value().Type)
1181       {
1182         case Visual3d_TOLS_AMBIENT:     break;
1183         case Visual3d_TOLS_DIRECTIONAL: aLightsFunc += THE_FUNC_directionalLight; break;
1184         case Visual3d_TOLS_POSITIONAL:  aLightsFunc += THE_FUNC_pointLight;       break;
1185         case Visual3d_TOLS_SPOT:        aLightsFunc += THE_FUNC_spotLight;        break;
1186       }
1187     }
1188   }
1189
1190   return TCollection_AsciiString()
1191     + THE_FUNC_lightDef
1192     + aLightsFunc
1193     + EOL
1194       EOL"vec4 computeLighting (in vec3 theNormal,"
1195       EOL"                      in vec3 theView,"
1196       EOL"                      in vec4 thePoint,"
1197       EOL"                      in bool theIsFront)"
1198       EOL"{"
1199       EOL"  Ambient  = occLightAmbient.rgb;"
1200       EOL"  Diffuse  = vec3 (0.0);"
1201       EOL"  Specular = vec3 (0.0);"
1202       EOL"  vec3 aPoint = thePoint.xyz / thePoint.w;"
1203     + aLightsLoop
1204     + EOL"  vec4 aMaterialAmbient  = theIsFront ? occFrontMaterial_Ambient()  : occBackMaterial_Ambient();"
1205       EOL"  vec4 aMaterialDiffuse  = theIsFront ? occFrontMaterial_Diffuse()  : occBackMaterial_Diffuse();"
1206       EOL"  vec4 aMaterialSpecular = theIsFront ? occFrontMaterial_Specular() : occBackMaterial_Specular();"
1207       EOL"  vec4 aMaterialEmission = theIsFront ? occFrontMaterial_Emission() : occBackMaterial_Emission();"
1208       EOL"  return vec4 (Ambient,  1.0) * aMaterialAmbient"
1209       EOL"       + vec4 (Diffuse,  1.0) * aMaterialDiffuse"
1210       EOL"       + vec4 (Specular, 1.0) * aMaterialSpecular"
1211       EOL"                              + aMaterialEmission;"
1212       EOL"}";
1213 }
1214
1215 // =======================================================================
1216 // function : prepareStdProgramGouraud
1217 // purpose  :
1218 // =======================================================================
1219 Standard_Boolean OpenGl_ShaderManager::prepareStdProgramGouraud (Handle(OpenGl_ShaderProgram)& theProgram,
1220                                                                  const Standard_Integer        theBits)
1221 {
1222   Handle(Graphic3d_ShaderProgram) aProgramSrc = new Graphic3d_ShaderProgram();
1223   TCollection_AsciiString aSrcVert, aSrcVertExtraOut, aSrcVertExtraMain, aSrcFrag, aSrcFragExtraOut, aSrcFragExtraMain;
1224   if ((theBits & OpenGl_PO_Point) != 0)
1225   {
1226   #if defined(GL_ES_VERSION_2_0)
1227     aSrcVertExtraMain += EOL"  gl_PointSize = occPointSize;";
1228   #endif
1229   }
1230   if ((theBits & OpenGl_PO_ClipPlanes) != 0)
1231   {
1232     const char THE_POS_VARY[] =
1233       EOL"varying vec4 PositionWorld;"
1234       EOL"varying vec4 Position;";
1235
1236     aSrcVertExtraOut  += THE_POS_VARY;
1237     aSrcFragExtraOut  += THE_POS_VARY;
1238     aSrcVertExtraMain +=
1239       EOL"  PositionWorld = aPositionWorld;"
1240       EOL"  Position      = aPosition;";
1241     aSrcFragExtraMain += THE_FRAG_CLIP_PLANES;
1242   }
1243
1244   const TCollection_AsciiString aLights = stdComputeLighting();
1245   aSrcVert = TCollection_AsciiString()
1246     + THE_FUNC_transformNormal
1247     + EOL
1248     + aLights
1249     + EOL
1250       EOL"varying vec4 FrontColor;"
1251       EOL"varying vec4 BackColor;"
1252       EOL
1253     + aSrcVertExtraOut
1254     + EOL"void main()"
1255       EOL"{"
1256       EOL"  vec4 aPositionWorld = occModelWorldMatrix * occVertex;"
1257       EOL"  vec4 aPosition      = occWorldViewMatrix * aPositionWorld;"
1258       EOL"  vec3 aNormal        = transformNormal (occNormal);"
1259       EOL"  vec3 aView          = vec3 (0.0, 0.0, 1.0);"
1260       EOL"  FrontColor  = computeLighting (normalize (aNormal), normalize (aView), aPosition, true);"
1261       EOL"  BackColor   = computeLighting (normalize (aNormal), normalize (aView), aPosition, false);"
1262     + aSrcVertExtraMain
1263     + EOL"  gl_Position = occProjectionMatrix * occWorldViewMatrix * occModelWorldMatrix * occVertex;"
1264       EOL"}";
1265
1266   aSrcFrag = TCollection_AsciiString()
1267     + EOL"varying vec4 FrontColor;"
1268       EOL"varying vec4 BackColor;"
1269     + aSrcFragExtraOut
1270     + EOL"void main()"
1271       EOL"{"
1272     + aSrcFragExtraMain
1273     + EOL"  gl_FragColor = gl_FrontFacing ? FrontColor : BackColor;"
1274       EOL"}";
1275
1276   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_VERTEX,   aSrcVert));
1277   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_FRAGMENT, aSrcFrag));
1278   TCollection_AsciiString aKey;
1279   if (!Create (aProgramSrc, aKey, theProgram))
1280   {
1281     theProgram = new OpenGl_ShaderProgram(); // just mark as invalid
1282     return Standard_False;
1283   }
1284   return Standard_True;
1285 }
1286
1287 // =======================================================================
1288 // function : prepareStdProgramPhong
1289 // purpose  :
1290 // =======================================================================
1291 Standard_Boolean OpenGl_ShaderManager::prepareStdProgramPhong (Handle(OpenGl_ShaderProgram)& theProgram,
1292                                                                const Standard_Integer        theBits)
1293 {
1294   Handle(Graphic3d_ShaderProgram) aProgramSrc = new Graphic3d_ShaderProgram();
1295   TCollection_AsciiString aSrcVert, aSrcVertExtraOut, aSrcVertExtraMain, aSrcFrag, aSrcFragExtraMain;
1296   if ((theBits & OpenGl_PO_Point) != 0)
1297   {
1298   #if defined(GL_ES_VERSION_2_0)
1299     aSrcVertExtraMain += EOL"  gl_PointSize = occPointSize;";
1300   #endif
1301   }
1302   if ((theBits & OpenGl_PO_ClipPlanes) != 0)
1303   {
1304     aSrcFragExtraMain += THE_FRAG_CLIP_PLANES;
1305   }
1306
1307   aSrcVert = TCollection_AsciiString()
1308     + THE_FUNC_transformNormal
1309     + EOL
1310       EOL"varying vec4 PositionWorld;"
1311       EOL"varying vec4 Position;"
1312       EOL"varying vec3 Normal;"
1313       EOL"varying vec3 View;"
1314       EOL
1315     + aSrcVertExtraOut
1316     + EOL"void main()"
1317       EOL"{"
1318       EOL"  PositionWorld = occModelWorldMatrix * occVertex;"
1319       EOL"  Position      = occWorldViewMatrix * PositionWorld;"
1320       EOL"  Normal        = transformNormal (occNormal);"
1321       EOL"  View          = vec3 (0.0, 0.0, 1.0);"
1322     + aSrcVertExtraMain
1323     + EOL"  gl_Position = occProjectionMatrix * occWorldViewMatrix * occModelWorldMatrix * occVertex;"
1324       EOL"}";
1325
1326   const TCollection_AsciiString aLights = stdComputeLighting();
1327   aSrcFrag = TCollection_AsciiString()
1328     + EOL"varying vec4 PositionWorld;"
1329       EOL"varying vec4 Position;"
1330       EOL"varying vec3 Normal;"
1331       EOL"varying vec3 View;"
1332     + EOL
1333     + aLights
1334     + EOL
1335       EOL"void main()"
1336       EOL"{"
1337     + aSrcFragExtraMain
1338     + EOL"  gl_FragColor = computeLighting (normalize (Normal), normalize (View), Position, gl_FrontFacing);"
1339       EOL"}";
1340
1341   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_VERTEX,   aSrcVert));
1342   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_FRAGMENT, aSrcFrag));
1343   TCollection_AsciiString aKey;
1344   if (!Create (aProgramSrc, aKey, theProgram))
1345   {
1346     theProgram = new OpenGl_ShaderProgram(); // just mark as invalid
1347     return Standard_False;
1348   }
1349   return Standard_True;
1350 }
1351
1352 // =======================================================================
1353 // function : bindProgramWithState
1354 // purpose  :
1355 // =======================================================================
1356 Standard_Boolean OpenGl_ShaderManager::bindProgramWithState (const Handle(OpenGl_ShaderProgram)& theProgram,
1357                                                              const OpenGl_Element*               theAspect)
1358 {
1359   if (!myContext->BindProgram (theProgram))
1360   {
1361     return Standard_False;
1362   }
1363   theProgram->ApplyVariables (myContext);
1364
1365   const OpenGl_MaterialState* aMaterialState = MaterialState (theProgram);
1366   if (aMaterialState == NULL || aMaterialState->Aspect() != theAspect)
1367   {
1368     UpdateMaterialStateTo (theProgram, theAspect);
1369   }
1370
1371   PushState (theProgram);
1372   return Standard_True;
1373 }