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