0024381: Visualization, TKOpenGl - revise matrices stack and usage of temporary matrices
[occt.git] / src / OpenGl / OpenGl_Workspace_5.cxx
1 // Created on: 2011-08-05
2 // Created by: Sergey ZERCHANINOV
3 // Copyright (c) 2011-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 <OpenGl_GlCore11.hxx>
17
18 #include <OpenGl_Workspace.hxx>
19
20 #include <OpenGl_AspectLine.hxx>
21 #include <OpenGl_AspectFace.hxx>
22 #include <OpenGl_AspectMarker.hxx>
23 #include <OpenGl_AspectText.hxx>
24 #include <OpenGl_Context.hxx>
25 #include <OpenGl_ShaderManager.hxx>
26 #include <OpenGl_telem_util.hxx>
27
28 /* OCC22218 NOTE: project dependency on gl2ps is specified by macro */
29 #ifdef HAVE_GL2PS
30   #include <gl2ps.h>
31   /* OCC22216 NOTE: linker dependency can be switched off by undefining macro.
32      Pragma comment for gl2ps.lib is defined only here. */
33   #ifdef _MSC_VER
34   #pragma comment( lib, "gl2ps.lib" )
35   #endif
36 #endif
37
38 #include <Aspect_PolygonOffsetMode.hxx>
39 #include <OpenGl_View.hxx>
40
41 /*----------------------------------------------------------------------*/
42
43 static void TelUpdatePolygonOffsets (const TEL_POFFSET_PARAM& theOffsetData)
44 {
45   if ((theOffsetData.mode & Aspect_POM_Fill) == Aspect_POM_Fill)
46   {
47     glEnable (GL_POLYGON_OFFSET_FILL);
48   }
49   else
50   {
51     glDisable (GL_POLYGON_OFFSET_FILL);
52   }
53
54 #if !defined(GL_ES_VERSION_2_0)
55   if ((theOffsetData.mode & Aspect_POM_Line) == Aspect_POM_Line)
56   {
57     glEnable (GL_POLYGON_OFFSET_LINE);
58   }
59   else
60   {
61     glDisable (GL_POLYGON_OFFSET_LINE);
62   }
63
64   if ((theOffsetData.mode & Aspect_POM_Point) == Aspect_POM_Point)
65   {
66     glEnable (GL_POLYGON_OFFSET_POINT);
67   }
68   else
69   {
70     glDisable (GL_POLYGON_OFFSET_POINT);
71   }
72 #endif
73
74   glPolygonOffset (theOffsetData.factor, theOffsetData.units);
75 }
76
77 /*----------------------------------------------------------------------*/
78
79 void OpenGl_Workspace::updateMaterial (const int theFlag)
80 {
81   // Case of hidden line
82   if (AspectFace_set->InteriorStyle() == Aspect_IS_HIDDENLINE)
83   {
84     myAspectFaceHl = *AspectFace_set; // copy all values including line edge aspect
85     myAspectFaceHl.ChangeIntFront().matcol     = BackgroundColor();
86     myAspectFaceHl.ChangeIntFront().color_mask = 0;
87     myAspectFaceHl.ChangeIntFront().color_mask = 0;
88
89     AspectFace_set = &myAspectFaceHl;
90     return;
91   }
92
93   const OPENGL_SURF_PROP* aProps = &AspectFace_set->IntFront();
94   GLenum aFace = GL_FRONT_AND_BACK;
95   if (theFlag == TEL_BACK_MATERIAL)
96   {
97     aFace  = GL_BACK;
98     aProps = &AspectFace_set->IntBack();
99   }
100   else if (AspectFace_set->DistinguishingMode() == TOn
101         && !(NamedStatus & OPENGL_NS_RESMAT))
102   {
103     aFace = GL_FRONT;
104   }
105
106   myMatTmp.Init (*aProps);
107
108   // handling transparency
109   if (NamedStatus & OPENGL_NS_2NDPASSDO)
110   {
111     // second pass
112     myMatTmp.Diffuse.a() = aProps->env_reflexion;
113   }
114   else
115   {
116     if (aProps->env_reflexion != 0.0f)
117     {
118       // if the material reflects the environment scene, the second pass is needed
119       NamedStatus |= OPENGL_NS_2NDPASSNEED;
120     }
121
122     if (myUseTransparency && aProps->trans != 1.0f)
123     {
124       // render transparent
125       myMatTmp.Diffuse.a() = aProps->trans;
126       glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
127       glEnable    (GL_BLEND);
128       glDepthMask (GL_FALSE);
129     }
130     else
131     {
132       // render opaque
133       if ((NamedStatus & OPENGL_NS_ANTIALIASING) == 0)
134       {
135         glBlendFunc (GL_ONE, GL_ZERO);
136         glDisable   (GL_BLEND);
137       }
138       glDepthMask (GL_TRUE);
139     }
140   }
141
142   // do not update material properties in case of zero reflection mode,
143   // because GL lighting will be disabled by OpenGl_PrimitiveArray::DrawArray() anyway.
144   if (aProps->color_mask == 0)
145   {
146     return;
147   }
148
149   // reset material
150   if (NamedStatus & OPENGL_NS_RESMAT)
151   {
152   #if !defined(GL_ES_VERSION_2_0)
153     glMaterialfv (aFace, GL_AMBIENT,   myMatTmp.Ambient.GetData());
154     glMaterialfv (aFace, GL_DIFFUSE,   myMatTmp.Diffuse.GetData());
155     glMaterialfv (aFace, GL_SPECULAR,  myMatTmp.Specular.GetData());
156     glMaterialfv (aFace, GL_EMISSION,  myMatTmp.Emission.GetData());
157     glMaterialf  (aFace, GL_SHININESS, myMatTmp.Shine());
158   #endif
159
160     if (theFlag == TEL_FRONT_MATERIAL)
161     {
162       myMatFront = myMatTmp;
163       myMatBack  = myMatTmp;
164     }
165     else
166     {
167       myMatBack = myMatTmp;
168     }
169
170     NamedStatus &= ~OPENGL_NS_RESMAT;
171     return;
172   }
173
174   // reduce updates
175   OpenGl_Material& anOld = (theFlag == TEL_FRONT_MATERIAL)
176                          ? myMatFront
177                          : myMatBack;
178 #if !defined(GL_ES_VERSION_2_0)
179   if (myMatTmp.Ambient.r() != anOld.Ambient.r()
180    || myMatTmp.Ambient.g() != anOld.Ambient.g()
181    || myMatTmp.Ambient.b() != anOld.Ambient.b())
182   {
183     glMaterialfv (aFace, GL_AMBIENT, myMatTmp.Ambient.GetData());
184   }
185   if (myMatTmp.Diffuse.r() != anOld.Diffuse.r()
186    || myMatTmp.Diffuse.g() != anOld.Diffuse.g()
187    || myMatTmp.Diffuse.b() != anOld.Diffuse.b()
188    || fabs (myMatTmp.Diffuse.a() - anOld.Diffuse.a()) > 0.01f)
189   {
190     glMaterialfv (aFace, GL_DIFFUSE, myMatTmp.Diffuse.GetData());
191   }
192   if (myMatTmp.Specular.r() != anOld.Specular.r()
193    || myMatTmp.Specular.g() != anOld.Specular.g()
194    || myMatTmp.Specular.b() != anOld.Specular.b())
195   {
196     glMaterialfv (aFace, GL_SPECULAR, myMatTmp.Specular.GetData());
197   }
198   if (myMatTmp.Emission.r() != anOld.Emission.r()
199    || myMatTmp.Emission.g() != anOld.Emission.g()
200    || myMatTmp.Emission.b() != anOld.Emission.b())
201   {
202     glMaterialfv (aFace, GL_EMISSION, myMatTmp.Emission.GetData());
203   }
204   if (myMatTmp.Shine() != anOld.Shine())
205   {
206     glMaterialf (aFace, GL_SHININESS, myMatTmp.Shine());
207   }
208 #endif
209   anOld = myMatTmp;
210   if (aFace == GL_FRONT_AND_BACK)
211   {
212     myMatBack = myMatTmp;
213   }
214 }
215
216 /*----------------------------------------------------------------------*/
217
218 const OpenGl_AspectLine * OpenGl_Workspace::SetAspectLine(const OpenGl_AspectLine *AnAspect)
219 {
220   const OpenGl_AspectLine *AspectLine_old = AspectLine_set;
221   AspectLine_set = AnAspect;
222   return AspectLine_old;
223 }
224
225 /*----------------------------------------------------------------------*/
226
227 const OpenGl_AspectFace * OpenGl_Workspace::SetAspectFace(const OpenGl_AspectFace *AnAspect)
228 {
229   const OpenGl_AspectFace *AspectFace_old = AspectFace_set;
230   AspectFace_set = AnAspect;
231   return AspectFace_old;
232 }
233
234 /*----------------------------------------------------------------------*/
235
236 const OpenGl_AspectMarker * OpenGl_Workspace::SetAspectMarker(const OpenGl_AspectMarker *AnAspect)
237 {
238   const OpenGl_AspectMarker *AspectMarker_old = AspectMarker_set;
239   AspectMarker_set = AnAspect;
240   return AspectMarker_old;
241 }
242
243 /*----------------------------------------------------------------------*/
244
245 const OpenGl_AspectText * OpenGl_Workspace::SetAspectText(const OpenGl_AspectText *AnAspect)
246 {
247   const OpenGl_AspectText *AspectText_old = AspectText_set;
248   AspectText_set = AnAspect;
249   return AspectText_old;
250 }
251
252 /*----------------------------------------------------------------------*/
253
254 const OpenGl_Matrix * OpenGl_Workspace::SetViewMatrix (const OpenGl_Matrix *AMatrix)
255 {
256   const OpenGl_Matrix *ViewMatrix_old = ViewMatrix_applied;
257   ViewMatrix_applied = AMatrix;
258
259   // Update model-view matrix with new view matrix
260   UpdateModelViewMatrix();
261
262   return ViewMatrix_old;
263 }
264
265 /*----------------------------------------------------------------------*/
266
267 const OpenGl_Matrix * OpenGl_Workspace::SetStructureMatrix (const OpenGl_Matrix *AMatrix, bool aRevert)
268 {
269   const OpenGl_Matrix *StructureMatrix_old = StructureMatrix_applied;
270   StructureMatrix_applied = AMatrix;
271
272   OpenGl_Matrix lmat;
273   OpenGl_Transposemat3( &lmat, AMatrix );
274
275   // Update model-view matrix with new structure matrix
276   UpdateModelViewMatrix();
277
278   if (!myGlContext->ShaderManager()->IsEmpty())
279   {
280     if (aRevert)
281     {
282       myGlContext->ShaderManager()->RevertModelWorldStateTo (OpenGl_Mat4::Map (*lmat.mat));
283     }
284     else
285     {
286       myGlContext->ShaderManager()->UpdateModelWorldStateTo (OpenGl_Mat4::Map (*lmat.mat));
287     }
288   }
289
290   return StructureMatrix_old;
291 }
292
293 /*----------------------------------------------------------------------*/
294
295 const void OpenGl_Workspace::UpdateModelViewMatrix()
296 {
297   OpenGl_Matrix aStructureMatT;
298   OpenGl_Transposemat3( &aStructureMatT, StructureMatrix_applied);
299   OpenGl_Multiplymat3 (&myModelViewMatrix, &aStructureMatT, ViewMatrix_applied);
300 #if !defined(GL_ES_VERSION_2_0)
301   glMatrixMode (GL_MODELVIEW);
302   glLoadMatrixf ((const GLfloat* )&myModelViewMatrix.mat);
303 #endif
304 }
305
306 /*----------------------------------------------------------------------*/
307
308 const OpenGl_AspectLine * OpenGl_Workspace::AspectLine(const Standard_Boolean WithApply)
309 {
310   if ( WithApply && (AspectLine_set != AspectLine_applied) )
311   {
312     const GLfloat* anRgb = AspectLine_set->Color().rgb;
313   #if !defined(GL_ES_VERSION_2_0)
314     glColor3fv(anRgb);
315   #endif
316
317     if ( !AspectLine_applied || (AspectLine_set->Type() != AspectLine_applied->Type() ) )
318     {
319       myLineAttribs->SetTypeOfLine (AspectLine_set->Type());
320     }
321
322     if ( !AspectLine_applied || ( AspectLine_set->Width() != AspectLine_applied->Width() ) )
323     {
324       glLineWidth( (GLfloat)AspectLine_set->Width() );
325 #ifdef HAVE_GL2PS
326       gl2psLineWidth( (GLfloat)AspectLine_set->Width() );
327 #endif
328     }
329
330     AspectLine_applied = AspectLine_set;
331   }
332   return AspectLine_set;
333 }
334
335 /*----------------------------------------------------------------------*/
336
337 const OpenGl_AspectFace* OpenGl_Workspace::AspectFace (const Standard_Boolean theToApply)
338 {
339   if (!theToApply)
340   {
341     return AspectFace_set;
342   }
343
344   if (!ActiveView()->Backfacing())
345   {
346     // manage back face culling mode, disable culling when clipping is enabled
347     TelCullMode aCullingMode = (myGlContext->Clipping().IsClippingOrCappingOn()
348                              || AspectFace_set->InteriorStyle() == Aspect_IS_HATCH)
349                              ? TelCullNone
350                              : (TelCullMode )AspectFace_set->CullingMode();
351     if (aCullingMode != TelCullNone
352      && myUseTransparency && !(NamedStatus & OPENGL_NS_2NDPASSDO))
353     {
354       // disable culling in case of translucent shading aspect
355       if (AspectFace_set->IntFront().trans != 1.0f)
356       {
357         aCullingMode = TelCullNone;
358       }
359     }
360     if (myCullingMode != aCullingMode)
361     {
362       myCullingMode = aCullingMode;
363       switch (myCullingMode)
364       {
365         case TelCullNone:
366         case TelCullUndefined:
367         {
368           glDisable (GL_CULL_FACE);
369           break;
370         }
371         case TelCullFront:
372         {
373           glCullFace (GL_FRONT);
374           glEnable (GL_CULL_FACE);
375           break;
376         }
377         case TelCullBack:
378         {
379           glCullFace (GL_BACK);
380           glEnable (GL_CULL_FACE);
381           break;
382         }
383       }
384     }
385   }
386
387   if (AspectFace_set == AspectFace_applied)
388   {
389     return AspectFace_set;
390   }
391
392 #if !defined(GL_ES_VERSION_2_0)
393   const Aspect_InteriorStyle anIntstyle = AspectFace_set->InteriorStyle();
394   if (AspectFace_applied == NULL || AspectFace_applied->InteriorStyle() != anIntstyle)
395   {
396     switch (anIntstyle)
397     {
398       case Aspect_IS_EMPTY:
399       case Aspect_IS_HOLLOW:
400       {
401         glPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
402         break;
403       }
404       case Aspect_IS_HATCH:
405       {
406         glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
407         myLineAttribs->SetTypeOfHatch (AspectFace_applied != NULL ? AspectFace_applied->Hatch() : TEL_HS_SOLID);
408         break;
409       }
410       case Aspect_IS_SOLID:
411       case Aspect_IS_HIDDENLINE:
412       {
413         glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
414         glDisable (GL_POLYGON_STIPPLE);
415         break;
416       }
417       case Aspect_IS_POINT:
418       {
419         glPolygonMode (GL_FRONT_AND_BACK, GL_POINT);
420         break;
421       }
422     }
423   }
424
425   if (anIntstyle == Aspect_IS_HATCH)
426   {
427     const Tint hatchstyle = AspectFace_set->Hatch();
428     if (AspectFace_applied == NULL || AspectFace_applied->Hatch() != hatchstyle)
429     {
430       myLineAttribs->SetTypeOfHatch (hatchstyle);
431     }
432   }
433 #endif
434
435   // Aspect_POM_None means: do not change current settings
436   if ((AspectFace_set->PolygonOffset().mode & Aspect_POM_None) != Aspect_POM_None)
437   {
438     if (PolygonOffset_applied.mode   != AspectFace_set->PolygonOffset().mode
439      || PolygonOffset_applied.factor != AspectFace_set->PolygonOffset().factor
440      || PolygonOffset_applied.units  != AspectFace_set->PolygonOffset().units)
441     {
442       SetPolygonOffset (AspectFace_set->PolygonOffset().mode,
443                         AspectFace_set->PolygonOffset().factor,
444                         AspectFace_set->PolygonOffset().units);
445     }
446   }
447
448   updateMaterial (TEL_FRONT_MATERIAL);
449   if (AspectFace_set->DistinguishingMode() == TOn)
450   {
451     updateMaterial (TEL_BACK_MATERIAL);
452   }
453
454   if ((NamedStatus & OPENGL_NS_FORBIDSETTEX) == 0)
455   {
456     if (AspectFace_set->DoTextureMap())
457     {
458       EnableTexture (AspectFace_set->TextureRes (myGlContext),
459                      AspectFace_set->TextureParams());
460     }
461     else
462     {
463       DisableTexture();
464     }
465   }
466
467   AspectFace_applied = AspectFace_set;
468   return AspectFace_set;
469 }
470
471 //=======================================================================
472 //function : SetPolygonOffset
473 //purpose  :
474 //=======================================================================
475 void OpenGl_Workspace::SetPolygonOffset (int theMode,
476                                          Standard_ShortReal theFactor,
477                                          Standard_ShortReal theUnits)
478 {
479   PolygonOffset_applied.mode   = theMode;
480   PolygonOffset_applied.factor = theFactor;
481   PolygonOffset_applied.units  = theUnits;
482
483   TelUpdatePolygonOffsets (PolygonOffset_applied);
484 }
485
486 /*----------------------------------------------------------------------*/
487
488 const OpenGl_AspectMarker* OpenGl_Workspace::AspectMarker (const Standard_Boolean theToApply)
489 {
490   if (theToApply && (AspectMarker_set != AspectMarker_applied))
491   {
492     if (!AspectMarker_applied || (AspectMarker_set->Scale() != AspectMarker_applied->Scale()))
493     {
494     #if !defined(GL_ES_VERSION_2_0)
495       glPointSize (AspectMarker_set->Scale());
496     #ifdef HAVE_GL2PS
497       gl2psPointSize (AspectMarker_set->Scale());
498     #endif
499     #endif
500     }
501     AspectMarker_applied = AspectMarker_set;
502   }
503   return AspectMarker_set;
504 }
505
506 /*----------------------------------------------------------------------*/
507
508 const OpenGl_AspectText* OpenGl_Workspace::AspectText (const Standard_Boolean theWithApply)
509 {
510   if (theWithApply)
511   {
512     AspectText_applied = AspectText_set;
513     TextParam_applied  = TextParam_set;
514   }
515
516   return AspectText_set;
517 }