0025305: Visualization, TKOpenGl - support stipple line aspects within built-in GLSL...
[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 (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       if (myUseDepthWrite)
129       {
130         glDepthMask (GL_FALSE);
131       }
132     }
133     else
134     {
135       // render opaque
136       if ((NamedStatus & OPENGL_NS_ANTIALIASING) == 0)
137       {
138         glBlendFunc (GL_ONE, GL_ZERO);
139         glDisable   (GL_BLEND);
140       }
141       if (myUseDepthWrite)
142       {
143         glDepthMask (GL_TRUE);
144       }
145     }
146   }
147
148   // do not update material properties in case of zero reflection mode,
149   // because GL lighting will be disabled by OpenGl_PrimitiveArray::DrawArray() anyway.
150   if (aProps->color_mask == 0)
151   {
152     return;
153   }
154
155   // reset material
156   if (NamedStatus & OPENGL_NS_RESMAT)
157   {
158   #if !defined(GL_ES_VERSION_2_0)
159     if (myGlContext->core11 != NULL)
160     {
161       myGlContext->core11->glMaterialfv (aFace, GL_AMBIENT,   myMatTmp.Ambient.GetData());
162       myGlContext->core11->glMaterialfv (aFace, GL_DIFFUSE,   myMatTmp.Diffuse.GetData());
163       myGlContext->core11->glMaterialfv (aFace, GL_SPECULAR,  myMatTmp.Specular.GetData());
164       myGlContext->core11->glMaterialfv (aFace, GL_EMISSION,  myMatTmp.Emission.GetData());
165       myGlContext->core11->glMaterialf  (aFace, GL_SHININESS, myMatTmp.Shine());
166     }
167   #endif
168
169     if (theFlag == TEL_FRONT_MATERIAL)
170     {
171       myMatFront = myMatTmp;
172       myMatBack  = myMatTmp;
173     }
174     else
175     {
176       myMatBack = myMatTmp;
177     }
178
179     NamedStatus &= ~OPENGL_NS_RESMAT;
180     return;
181   }
182
183   // reduce updates
184   OpenGl_Material& anOld = (theFlag == TEL_FRONT_MATERIAL)
185                          ? myMatFront
186                          : myMatBack;
187 #if !defined(GL_ES_VERSION_2_0)
188   if (myGlContext->core11 != NULL)
189   {
190     if (myMatTmp.Ambient.r() != anOld.Ambient.r()
191      || myMatTmp.Ambient.g() != anOld.Ambient.g()
192      || myMatTmp.Ambient.b() != anOld.Ambient.b())
193     {
194       myGlContext->core11->glMaterialfv (aFace, GL_AMBIENT, myMatTmp.Ambient.GetData());
195     }
196     if (myMatTmp.Diffuse.r() != anOld.Diffuse.r()
197      || myMatTmp.Diffuse.g() != anOld.Diffuse.g()
198      || myMatTmp.Diffuse.b() != anOld.Diffuse.b()
199      || fabs (myMatTmp.Diffuse.a() - anOld.Diffuse.a()) > 0.01f)
200     {
201       myGlContext->core11->glMaterialfv (aFace, GL_DIFFUSE, myMatTmp.Diffuse.GetData());
202     }
203     if (myMatTmp.Specular.r() != anOld.Specular.r()
204      || myMatTmp.Specular.g() != anOld.Specular.g()
205      || myMatTmp.Specular.b() != anOld.Specular.b())
206     {
207       myGlContext->core11->glMaterialfv (aFace, GL_SPECULAR, myMatTmp.Specular.GetData());
208     }
209     if (myMatTmp.Emission.r() != anOld.Emission.r()
210      || myMatTmp.Emission.g() != anOld.Emission.g()
211      || myMatTmp.Emission.b() != anOld.Emission.b())
212     {
213       myGlContext->core11->glMaterialfv (aFace, GL_EMISSION, myMatTmp.Emission.GetData());
214     }
215     if (myMatTmp.Shine() != anOld.Shine())
216     {
217       myGlContext->core11->glMaterialf (aFace, GL_SHININESS, myMatTmp.Shine());
218     }
219   }
220 #endif
221   anOld = myMatTmp;
222   if (aFace == GL_FRONT_AND_BACK)
223   {
224     myMatBack = myMatTmp;
225   }
226 }
227
228 /*----------------------------------------------------------------------*/
229
230 const OpenGl_AspectLine * OpenGl_Workspace::SetAspectLine(const OpenGl_AspectLine *AnAspect)
231 {
232   const OpenGl_AspectLine *AspectLine_old = AspectLine_set;
233   AspectLine_set = AnAspect;
234   return AspectLine_old;
235 }
236
237 /*----------------------------------------------------------------------*/
238
239 const OpenGl_AspectFace * OpenGl_Workspace::SetAspectFace(const OpenGl_AspectFace *AnAspect)
240 {
241   const OpenGl_AspectFace *AspectFace_old = AspectFace_set;
242   AspectFace_set = AnAspect;
243   return AspectFace_old;
244 }
245
246 /*----------------------------------------------------------------------*/
247
248 const OpenGl_AspectMarker * OpenGl_Workspace::SetAspectMarker(const OpenGl_AspectMarker *AnAspect)
249 {
250   const OpenGl_AspectMarker *AspectMarker_old = AspectMarker_set;
251   AspectMarker_set = AnAspect;
252   return AspectMarker_old;
253 }
254
255 /*----------------------------------------------------------------------*/
256
257 const OpenGl_AspectText * OpenGl_Workspace::SetAspectText(const OpenGl_AspectText *AnAspect)
258 {
259   const OpenGl_AspectText *AspectText_old = AspectText_set;
260   AspectText_set = AnAspect;
261   return AspectText_old;
262 }
263
264 /*----------------------------------------------------------------------*/
265
266 const OpenGl_AspectLine * OpenGl_Workspace::AspectLine(const Standard_Boolean theWithApply)
267 {
268   if (theWithApply)
269   {
270     AspectLine_applied = AspectLine_set;
271   }
272
273   return AspectLine_set;
274 }
275
276 /*----------------------------------------------------------------------*/
277
278 const OpenGl_AspectFace* OpenGl_Workspace::AspectFace (const Standard_Boolean theToApply)
279 {
280   if (!theToApply)
281   {
282     return AspectFace_set;
283   }
284
285   if (!ActiveView()->Backfacing())
286   {
287     // manage back face culling mode, disable culling when clipping is enabled
288     TelCullMode aCullingMode = (myGlContext->Clipping().IsClippingOrCappingOn()
289                              || AspectFace_set->InteriorStyle() == Aspect_IS_HATCH)
290                              ? TelCullNone
291                              : (TelCullMode )AspectFace_set->CullingMode();
292     if (aCullingMode != TelCullNone
293      && !(NamedStatus & OPENGL_NS_2NDPASSDO))
294     {
295       // disable culling in case of translucent shading aspect
296       if (AspectFace_set->IntFront().trans != 1.0f)
297       {
298         aCullingMode = TelCullNone;
299       }
300     }
301     if (myCullingMode != aCullingMode)
302     {
303       myCullingMode = aCullingMode;
304       switch (myCullingMode)
305       {
306         case TelCullNone:
307         case TelCullUndefined:
308         {
309           glDisable (GL_CULL_FACE);
310           break;
311         }
312         case TelCullFront:
313         {
314           glCullFace (GL_FRONT);
315           glEnable (GL_CULL_FACE);
316           break;
317         }
318         case TelCullBack:
319         {
320           glCullFace (GL_BACK);
321           glEnable (GL_CULL_FACE);
322           break;
323         }
324       }
325     }
326   }
327
328   if (AspectFace_set == AspectFace_applied)
329   {
330     return AspectFace_set;
331   }
332
333 #if !defined(GL_ES_VERSION_2_0)
334   const Aspect_InteriorStyle anIntstyle = AspectFace_set->InteriorStyle();
335   if (AspectFace_applied == NULL || AspectFace_applied->InteriorStyle() != anIntstyle)
336   {
337     switch (anIntstyle)
338     {
339       case Aspect_IS_EMPTY:
340       case Aspect_IS_HOLLOW:
341       {
342         glPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
343         break;
344       }
345       case Aspect_IS_HATCH:
346       {
347         glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
348         myLineAttribs->SetTypeOfHatch (AspectFace_applied != NULL ? AspectFace_applied->Hatch() : TEL_HS_SOLID);
349         break;
350       }
351       case Aspect_IS_SOLID:
352       case Aspect_IS_HIDDENLINE:
353       {
354         glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
355         if (myGlContext->core11 != NULL)
356         {
357           glDisable (GL_POLYGON_STIPPLE);
358         }
359         break;
360       }
361       case Aspect_IS_POINT:
362       {
363         glPolygonMode (GL_FRONT_AND_BACK, GL_POINT);
364         break;
365       }
366     }
367   }
368
369   if (anIntstyle == Aspect_IS_HATCH)
370   {
371     const Tint hatchstyle = AspectFace_set->Hatch();
372     if (AspectFace_applied == NULL || AspectFace_applied->Hatch() != hatchstyle)
373     {
374       myLineAttribs->SetTypeOfHatch (hatchstyle);
375     }
376   }
377 #endif
378
379   // Aspect_POM_None means: do not change current settings
380   if ((AspectFace_set->PolygonOffset().mode & Aspect_POM_None) != Aspect_POM_None)
381   {
382     if (PolygonOffset_applied.mode   != AspectFace_set->PolygonOffset().mode
383      || PolygonOffset_applied.factor != AspectFace_set->PolygonOffset().factor
384      || PolygonOffset_applied.units  != AspectFace_set->PolygonOffset().units)
385     {
386       SetPolygonOffset (AspectFace_set->PolygonOffset().mode,
387                         AspectFace_set->PolygonOffset().factor,
388                         AspectFace_set->PolygonOffset().units);
389     }
390   }
391
392   updateMaterial (TEL_FRONT_MATERIAL);
393   if (AspectFace_set->DistinguishingMode() == TOn)
394   {
395     updateMaterial (TEL_BACK_MATERIAL);
396   }
397
398   if ((NamedStatus & OPENGL_NS_FORBIDSETTEX) == 0)
399   {
400     if (AspectFace_set->DoTextureMap())
401     {
402       EnableTexture (AspectFace_set->TextureRes (myGlContext),
403                      AspectFace_set->TextureParams());
404     }
405     else
406     {
407       DisableTexture();
408     }
409   }
410
411   AspectFace_applied = AspectFace_set;
412   return AspectFace_set;
413 }
414
415 //=======================================================================
416 //function : SetPolygonOffset
417 //purpose  :
418 //=======================================================================
419 void OpenGl_Workspace::SetPolygonOffset (int theMode,
420                                          Standard_ShortReal theFactor,
421                                          Standard_ShortReal theUnits)
422 {
423   PolygonOffset_applied.mode   = theMode;
424   PolygonOffset_applied.factor = theFactor;
425   PolygonOffset_applied.units  = theUnits;
426
427   TelUpdatePolygonOffsets (PolygonOffset_applied);
428 }
429
430 /*----------------------------------------------------------------------*/
431
432 const OpenGl_AspectMarker* OpenGl_Workspace::AspectMarker (const Standard_Boolean theToApply)
433 {
434   if (theToApply && (AspectMarker_set != AspectMarker_applied))
435   {
436     if (!AspectMarker_applied || (AspectMarker_set->Scale() != AspectMarker_applied->Scale()))
437     {
438     #if !defined(GL_ES_VERSION_2_0)
439       glPointSize (AspectMarker_set->Scale());
440     #ifdef HAVE_GL2PS
441       gl2psPointSize (AspectMarker_set->Scale());
442     #endif
443     #endif
444     }
445     AspectMarker_applied = AspectMarker_set;
446   }
447   return AspectMarker_set;
448 }
449
450 /*----------------------------------------------------------------------*/
451
452 const OpenGl_AspectText* OpenGl_Workspace::AspectText (const Standard_Boolean theWithApply)
453 {
454   if (theWithApply)
455   {
456     AspectText_applied = AspectText_set;
457     TextParam_applied  = TextParam_set;
458   }
459
460   return AspectText_set;
461 }