0030434: Visualization, TKV3d - add "NoUpdate" state of frustum culling optimization
[occt.git] / src / OpenGl / OpenGl_Workspace.cxx
1 // Created on: 2011-09-20
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_Workspace.hxx>
17
18 #include <OpenGl_ArbFBO.hxx>
19 #include <OpenGl_AspectLine.hxx>
20 #include <OpenGl_AspectFace.hxx>
21 #include <OpenGl_AspectMarker.hxx>
22 #include <OpenGl_AspectText.hxx>
23 #include <OpenGl_Context.hxx>
24 #include <OpenGl_Element.hxx>
25 #include <OpenGl_FrameBuffer.hxx>
26 #include <OpenGl_GlCore15.hxx>
27 #include <OpenGl_SceneGeometry.hxx>
28 #include <OpenGl_Structure.hxx>
29 #include <OpenGl_Sampler.hxx>
30 #include <OpenGl_ShaderManager.hxx>
31 #include <OpenGl_Texture.hxx>
32 #include <OpenGl_View.hxx>
33 #include <OpenGl_Window.hxx>
34
35 #include <Graphic3d_TextureParams.hxx>
36 #include <Graphic3d_TransformUtils.hxx>
37 #include <NCollection_AlignedAllocator.hxx>
38
39 IMPLEMENT_STANDARD_RTTIEXT(OpenGl_Workspace,Standard_Transient)
40
41 namespace
42 {
43   static const OpenGl_Vec4 THE_WHITE_COLOR (1.0f, 1.0f, 1.0f, 1.0f);
44   static const OpenGl_Vec4 THE_BLACK_COLOR (0.0f, 0.0f, 0.0f, 1.0f);
45
46   static const OpenGl_Matrix myDefaultMatrix =
47   {
48     {{ 1.0F, 0.0F, 0.0F, 0.0F },
49      { 0.0F, 1.0F, 0.0F, 0.0F },
50      { 0.0F, 0.0F, 1.0F, 0.0F },
51      { 0.0F, 0.0F, 0.0F, 1.0F }}
52   };
53
54 }
55
56 // =======================================================================
57 // function : Init
58 // purpose  :
59 // =======================================================================
60 void OpenGl_Material::Init (const Graphic3d_MaterialAspect& theMat,
61                             const Quantity_Color&           theInteriorColor)
62 {
63   const bool isPhysic = theMat.MaterialType (Graphic3d_MATERIAL_PHYSIC);
64   ChangeShine()        = 128.0f * theMat.Shininess();
65   ChangeTransparency() = theMat.Alpha();
66
67   // ambient component
68   if (theMat.ReflectionMode (Graphic3d_TOR_AMBIENT))
69   {
70     const OpenGl_Vec3& aSrcAmb = isPhysic ? theMat.AmbientColor() : theInteriorColor;
71     Ambient = OpenGl_Vec4 (aSrcAmb * theMat.Ambient(), 1.0f);
72   }
73   else
74   {
75     Ambient = THE_BLACK_COLOR;
76   }
77
78   // diffusion component
79   if (theMat.ReflectionMode (Graphic3d_TOR_DIFFUSE))
80   {
81     const OpenGl_Vec3& aSrcDif = isPhysic ? theMat.DiffuseColor() : theInteriorColor;
82     Diffuse = OpenGl_Vec4 (aSrcDif * theMat.Diffuse(), 1.0f);
83   }
84   else
85   {
86     Diffuse = THE_BLACK_COLOR;
87   }
88
89   // specular component
90   if (theMat.ReflectionMode (Graphic3d_TOR_SPECULAR))
91   {
92     const OpenGl_Vec3& aSrcSpe = isPhysic ? (const OpenGl_Vec3& )theMat.SpecularColor() : THE_WHITE_COLOR.rgb();
93     Specular = OpenGl_Vec4 (aSrcSpe * theMat.Specular(), 1.0f);
94   }
95   else
96   {
97     Specular = THE_BLACK_COLOR;
98   }
99
100   // emission component
101   if (theMat.ReflectionMode (Graphic3d_TOR_EMISSION))
102   {
103     const OpenGl_Vec3& aSrcEms = isPhysic ? theMat.EmissiveColor() : theInteriorColor;
104     Emission = OpenGl_Vec4 (aSrcEms * theMat.Emissive(), 1.0f);
105   }
106   else
107   {
108     Emission = THE_BLACK_COLOR;
109   }
110 }
111
112 // =======================================================================
113 // function : OpenGl_Workspace
114 // purpose  :
115 // =======================================================================
116 OpenGl_Workspace::OpenGl_Workspace (OpenGl_View* theView, const Handle(OpenGl_Window)& theWindow)
117 : myView (theView),
118   myWindow (theWindow),
119   myGlContext (!theWindow.IsNull() ? theWindow->GetGlContext() : NULL),
120   myUseZBuffer    (Standard_True),
121   myUseDepthWrite (Standard_True),
122   //
123   myNbSkippedTranspElems (0),
124   myRenderFilter (OpenGl_RenderFilter_Empty),
125   //
126   myAspectLineSet (&myDefaultAspectLine),
127   myAspectFaceSet (&myDefaultAspectFace),
128   myAspectMarkerSet (&myDefaultAspectMarker),
129   myAspectTextSet (&myDefaultAspectText),
130   //
131   ViewMatrix_applied (&myDefaultMatrix),
132   StructureMatrix_applied (&myDefaultMatrix),
133   myToAllowFaceCulling (false),
134   myModelViewMatrix (myDefaultMatrix)
135 {
136   if (!myGlContext.IsNull() && myGlContext->MakeCurrent())
137   {
138     myGlContext->core11fwd->glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
139
140     // General initialization of the context
141   #if !defined(GL_ES_VERSION_2_0)
142     if (myGlContext->core11 != NULL)
143     {
144       // enable two-side lighting by default
145       glLightModeli ((GLenum )GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
146       glHint (GL_POINT_SMOOTH_HINT, GL_FASTEST);
147       if (myGlContext->caps->ffpEnable)
148       {
149         glHint (GL_FOG_HINT, GL_FASTEST);
150       }
151     }
152
153     glHint (GL_LINE_SMOOTH_HINT,    GL_FASTEST);
154     glHint (GL_POLYGON_SMOOTH_HINT, GL_FASTEST);
155   #endif
156   }
157
158   myFontFaceAspect.Aspect()->SetAlphaMode (Graphic3d_AlphaMode_Mask, 0.285f);
159   myFontFaceAspect.Aspect()->SetShadingModel (Graphic3d_TOSM_UNLIT);
160
161   myNoneCulling .Aspect()->SetSuppressBackFaces (false);
162   myNoneCulling .Aspect()->SetDrawEdges (false);
163   myNoneCulling .Aspect()->SetAlphaMode (Graphic3d_AlphaMode_Opaque);
164
165   myFrontCulling.Aspect()->SetSuppressBackFaces (true);
166   myFrontCulling.Aspect()->SetDrawEdges (false);
167   myFrontCulling.Aspect()->SetAlphaMode (Graphic3d_AlphaMode_Opaque);
168 }
169
170 // =======================================================================
171 // function : Activate
172 // purpose  :
173 // =======================================================================
174 Standard_Boolean OpenGl_Workspace::Activate()
175 {
176   if (myWindow.IsNull() || !myWindow->Activate())
177   {
178     return Standard_False;
179   }
180
181   ViewMatrix_applied      = &myDefaultMatrix;
182   StructureMatrix_applied = &myDefaultMatrix;
183
184   ResetAppliedAspect();
185
186   // reset state for safety
187   myGlContext->BindProgram (Handle(OpenGl_ShaderProgram)());
188   if (myGlContext->core20fwd != NULL)
189   {
190     myGlContext->core20fwd->glUseProgram (OpenGl_ShaderProgram::NO_PROGRAM);
191   }
192   if (myGlContext->caps->ffpEnable)
193   {
194     myGlContext->ShaderManager()->PushState (Handle(OpenGl_ShaderProgram)());
195   }
196   return Standard_True;
197 }
198
199 //=======================================================================
200 //function : ResetAppliedAspect
201 //purpose  : Sets default values of GL parameters in accordance with default aspects
202 //=======================================================================
203 void OpenGl_Workspace::ResetAppliedAspect()
204 {
205   myGlContext->BindDefaultVao();
206
207   myHighlightStyle.Nullify();
208   myToAllowFaceCulling  = false;
209   myAspectLineSet       = &myDefaultAspectLine;
210   myAspectFaceSet       = &myDefaultAspectFace;
211   myAspectFaceApplied.Nullify();
212   myAspectMarkerSet     = &myDefaultAspectMarker;
213   myAspectMarkerApplied.Nullify();
214   myAspectTextSet       = &myDefaultAspectText;
215   myGlContext->SetPolygonOffset (Graphic3d_PolygonOffset());
216
217   ApplyAspectLine();
218   ApplyAspectFace();
219   ApplyAspectMarker();
220   ApplyAspectText();
221
222   myGlContext->SetTypeOfLine (myDefaultAspectLine.Aspect()->Type());
223   myGlContext->SetLineWidth  (myDefaultAspectLine.Aspect()->Width());
224 }
225
226 // =======================================================================
227 // function : SetDefaultPolygonOffset
228 // purpose  :
229 // =======================================================================
230 Graphic3d_PolygonOffset OpenGl_Workspace::SetDefaultPolygonOffset (const Graphic3d_PolygonOffset& theOffset)
231 {
232   Graphic3d_PolygonOffset aPrev = myDefaultAspectFace.Aspect()->PolygonOffset();
233   myDefaultAspectFace.Aspect()->SetPolygonOffset (theOffset);
234   if (myAspectFaceApplied == myDefaultAspectFace.Aspect()
235    || myAspectFaceApplied.IsNull()
236    || (myAspectFaceApplied->PolygonOffset().Mode & Aspect_POM_None) == Aspect_POM_None)
237   {
238     myGlContext->SetPolygonOffset (theOffset);
239   }
240   return aPrev;
241 }
242
243 // =======================================================================
244 // function : SetAspectLine
245 // purpose  :
246 // =======================================================================
247 const OpenGl_AspectLine* OpenGl_Workspace::SetAspectLine (const OpenGl_AspectLine* theAspect)
248 {
249   const OpenGl_AspectLine* aPrevAspectLine = myAspectLineSet;
250   myAspectLineSet = theAspect;
251   return aPrevAspectLine;
252 }
253
254 // =======================================================================
255 // function : SetAspectFace
256 // purpose  :
257 // =======================================================================
258 const OpenGl_AspectFace * OpenGl_Workspace::SetAspectFace (const OpenGl_AspectFace* theAspect)
259 {
260   const OpenGl_AspectFace* aPrevAspectFace = myAspectFaceSet;
261   myAspectFaceSet = theAspect;
262   return aPrevAspectFace;
263 }
264
265 // =======================================================================
266 // function : SetAspectMarker
267 // purpose  :
268 // =======================================================================
269 const OpenGl_AspectMarker* OpenGl_Workspace::SetAspectMarker (const OpenGl_AspectMarker* theAspect)
270 {
271   const OpenGl_AspectMarker* aPrevAspectMarker = myAspectMarkerSet;
272   myAspectMarkerSet = theAspect;
273   return aPrevAspectMarker;
274 }
275
276 // =======================================================================
277 // function : SetAspectText
278 // purpose  :
279 // =======================================================================
280 const OpenGl_AspectText * OpenGl_Workspace::SetAspectText (const OpenGl_AspectText* theAspect)
281 {
282   const OpenGl_AspectText* aPrevAspectText = myAspectTextSet;
283   myAspectTextSet = theAspect;
284   return aPrevAspectText;
285 }
286
287 // =======================================================================
288 // function : ApplyAspectFace
289 // purpose  :
290 // =======================================================================
291 const OpenGl_AspectFace* OpenGl_Workspace::ApplyAspectFace()
292 {
293   if (myView->BackfacingModel() == Graphic3d_TOBM_AUTOMATIC)
294   {
295     bool toSuppressBackFaces = myToAllowFaceCulling
296                             && myAspectFaceSet->Aspect()->ToSuppressBackFaces();
297     if (toSuppressBackFaces)
298     {
299       if (myAspectFaceSet->Aspect()->InteriorStyle() == Aspect_IS_HATCH
300        || myAspectFaceSet->Aspect()->AlphaMode() == Graphic3d_AlphaMode_Blend
301        || myAspectFaceSet->Aspect()->AlphaMode() == Graphic3d_AlphaMode_Mask
302        || (myAspectFaceSet->Aspect()->AlphaMode() == Graphic3d_AlphaMode_BlendAuto
303         && myAspectFaceSet->Aspect()->FrontMaterial().Transparency() != 0.0f))
304       {
305         // disable culling in case of translucent shading aspect
306         toSuppressBackFaces = false;
307       }
308     }
309     myGlContext->SetCullBackFaces (toSuppressBackFaces);
310   }
311
312   if (myAspectFaceSet->Aspect() == myAspectFaceApplied
313    && myHighlightStyle == myAspectFaceAppliedWithHL)
314   {
315     return myAspectFaceSet;
316   }
317   myAspectFaceAppliedWithHL = myHighlightStyle;
318
319 #if !defined(GL_ES_VERSION_2_0)
320   const Aspect_InteriorStyle anIntstyle = myAspectFaceSet->Aspect()->InteriorStyle();
321   if (myAspectFaceApplied.IsNull()
322    || myAspectFaceApplied->InteriorStyle() != anIntstyle)
323   {
324     switch (anIntstyle)
325     {
326       case Aspect_IS_EMPTY:
327       case Aspect_IS_HOLLOW:
328       {
329         myGlContext->SetPolygonMode (GL_LINE);
330         break;
331       }
332       case Aspect_IS_HATCH:
333       {
334         myGlContext->SetPolygonMode (GL_FILL);
335         myGlContext->SetPolygonHatchEnabled (true);
336         break;
337       }
338       case Aspect_IS_SOLID:
339       case Aspect_IS_HIDDENLINE:
340       {
341         myGlContext->SetPolygonMode (GL_FILL);
342         myGlContext->SetPolygonHatchEnabled (false);
343         break;
344       }
345       case Aspect_IS_POINT:
346       {
347         myGlContext->SetPolygonMode (GL_POINT);
348         break;
349       }
350     }
351   }
352
353   if (anIntstyle == Aspect_IS_HATCH)
354   {
355     myGlContext->SetPolygonHatchStyle (myAspectFaceSet->Aspect()->HatchStyle());
356   }
357 #endif
358
359   // Aspect_POM_None means: do not change current settings
360   if ((myAspectFaceSet->Aspect()->PolygonOffset().Mode & Aspect_POM_None) != Aspect_POM_None)
361   {
362     myGlContext->SetPolygonOffset (myAspectFaceSet->Aspect()->PolygonOffset());
363   }
364
365   // Case of hidden line
366   if (myAspectFaceSet->Aspect()->InteriorStyle() == Aspect_IS_HIDDENLINE)
367   {
368     // copy all values including line edge aspect
369     *myAspectFaceHl.Aspect() = *myAspectFaceSet->Aspect();
370     myAspectFaceHl.SetAspectEdge (myAspectFaceSet->AspectEdge());
371     myAspectFaceHl.Aspect()->SetShadingModel (Graphic3d_TOSM_UNLIT);
372     myAspectFaceHl.Aspect()->SetInteriorColor (myView->BackgroundColor().GetRGB());
373     myAspectFaceHl.SetNoLighting();
374     myAspectFaceSet = &myAspectFaceHl;
375   }
376   else
377   {
378     myGlContext->SetShadingMaterial (myAspectFaceSet, myHighlightStyle);
379   }
380
381   if (myAspectFaceSet->Aspect()->ToMapTexture())
382   {
383     myGlContext->BindTextures (myAspectFaceSet->TextureSet (myGlContext));
384   }
385   else
386   {
387     myGlContext->BindTextures (myEnvironmentTexture);
388   }
389
390   myAspectFaceApplied = myAspectFaceSet->Aspect();
391   return myAspectFaceSet;
392 }
393
394 // =======================================================================
395 // function : ApplyAspectMarker
396 // purpose  :
397 // =======================================================================
398 const OpenGl_AspectMarker* OpenGl_Workspace::ApplyAspectMarker()
399 {
400   if (myAspectMarkerSet->Aspect() != myAspectMarkerApplied)
401   {
402     if (myAspectMarkerApplied.IsNull()
403     || (myAspectMarkerSet->Aspect()->Scale() != myAspectMarkerApplied->Scale()))
404     {
405     #if !defined(GL_ES_VERSION_2_0)
406       glPointSize (myAspectMarkerSet->Aspect()->Scale());
407     #endif
408     }
409     myAspectMarkerApplied = myAspectMarkerSet->Aspect();
410   }
411   return myAspectMarkerSet;
412 }
413
414 // =======================================================================
415 // function : Width
416 // purpose  :
417 // =======================================================================
418 Standard_Integer OpenGl_Workspace::Width()  const
419 {
420   return !myView->GlWindow().IsNull() ? myView->GlWindow()->Width() : 0;
421 }
422
423 // =======================================================================
424 // function : Height
425 // purpose  :
426 // =======================================================================
427 Standard_Integer OpenGl_Workspace::Height() const
428 {
429   return !myView->GlWindow().IsNull() ? myView->GlWindow()->Height() : 0;
430 }
431
432 // =======================================================================
433 // function : FBOCreate
434 // purpose  :
435 // =======================================================================
436 Handle(OpenGl_FrameBuffer) OpenGl_Workspace::FBOCreate (const Standard_Integer theWidth,
437                                                         const Standard_Integer theHeight)
438 {
439   // activate OpenGL context
440   if (!Activate())
441     return Handle(OpenGl_FrameBuffer)();
442
443   // create the FBO
444   const Handle(OpenGl_Context)& aCtx = GetGlContext();
445   aCtx->BindTextures (Handle(OpenGl_TextureSet)());
446   Handle(OpenGl_FrameBuffer) aFrameBuffer = new OpenGl_FrameBuffer();
447   if (!aFrameBuffer->Init (aCtx, theWidth, theHeight, GL_RGBA8, GL_DEPTH24_STENCIL8, 0))
448   {
449     aFrameBuffer->Release (aCtx.operator->());
450     return Handle(OpenGl_FrameBuffer)();
451   }
452   return aFrameBuffer;
453 }
454
455 // =======================================================================
456 // function : FBORelease
457 // purpose  :
458 // =======================================================================
459 void OpenGl_Workspace::FBORelease (Handle(OpenGl_FrameBuffer)& theFbo)
460 {
461   // activate OpenGL context
462   if (!Activate()
463    || theFbo.IsNull())
464   {
465     return;
466   }
467
468   theFbo->Release (GetGlContext().operator->());
469   theFbo.Nullify();
470 }
471
472 // =======================================================================
473 // function : BufferDump
474 // purpose  :
475 // =======================================================================
476 Standard_Boolean OpenGl_Workspace::BufferDump (const Handle(OpenGl_FrameBuffer)& theFbo,
477                                                Image_PixMap&                     theImage,
478                                                const Graphic3d_BufferType&       theBufferType)
479 {
480   return !theImage.IsEmpty()
481       && Activate()
482       && OpenGl_FrameBuffer::BufferDump (GetGlContext(), theFbo, theImage, theBufferType);
483 }
484
485 // =======================================================================
486 // function : ShouldRender
487 // purpose  :
488 // =======================================================================
489 bool OpenGl_Workspace::ShouldRender (const OpenGl_Element* theElement)
490 {
491   // render only non-raytracable elements when RayTracing is enabled
492   if ((myRenderFilter & OpenGl_RenderFilter_NonRaytraceableOnly) != 0)
493   {
494     if (OpenGl_Raytrace::IsRaytracedElement (theElement))
495     {
496       return false;
497     }
498   }
499   else if ((myRenderFilter & OpenGl_RenderFilter_FillModeOnly) != 0)
500   {
501     if (!theElement->IsFillDrawMode())
502     {
503       return false;
504     }
505   }
506
507   // handle opaque/transparency render passes
508   if ((myRenderFilter & OpenGl_RenderFilter_OpaqueOnly) != 0)
509   {
510     if (!theElement->IsFillDrawMode())
511     {
512       return true;
513     }
514
515     if (OpenGl_Context::CheckIsTransparent (myAspectFaceSet, myHighlightStyle))
516     {
517       ++myNbSkippedTranspElems;
518       return false;
519     }
520   }
521   else if ((myRenderFilter & OpenGl_RenderFilter_TransparentOnly) != 0)
522   {
523     if (!theElement->IsFillDrawMode())
524     {
525       if (dynamic_cast<const OpenGl_AspectFace*> (theElement) == NULL)
526       {
527         return false;
528       }
529     }
530     else if (!OpenGl_Context::CheckIsTransparent (myAspectFaceSet, myHighlightStyle))
531     {
532       return false;
533     }
534   }
535   return true;
536 }