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