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