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