0032143: Visualization - add option excluding transparent object from sorting
[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_Aspects.hxx>
20 #include <OpenGl_Context.hxx>
21 #include <OpenGl_Element.hxx>
22 #include <OpenGl_FrameBuffer.hxx>
23 #include <OpenGl_GlCore15.hxx>
24 #include <OpenGl_SceneGeometry.hxx>
25 #include <OpenGl_Structure.hxx>
26 #include <OpenGl_Sampler.hxx>
27 #include <OpenGl_ShaderManager.hxx>
28 #include <OpenGl_Texture.hxx>
29 #include <OpenGl_View.hxx>
30 #include <OpenGl_Window.hxx>
31
32 #include <Graphic3d_TextureParams.hxx>
33 #include <Graphic3d_TransformUtils.hxx>
34
35 IMPLEMENT_STANDARD_RTTIEXT(OpenGl_Workspace,Standard_Transient)
36
37 namespace
38 {
39   static const OpenGl_Vec4 THE_WHITE_COLOR (1.0f, 1.0f, 1.0f, 1.0f);
40   static const OpenGl_Vec4 THE_BLACK_COLOR (0.0f, 0.0f, 0.0f, 1.0f);
41
42   static const OpenGl_Matrix myDefaultMatrix =
43   {
44     {{ 1.0F, 0.0F, 0.0F, 0.0F },
45      { 0.0F, 1.0F, 0.0F, 0.0F },
46      { 0.0F, 0.0F, 1.0F, 0.0F },
47      { 0.0F, 0.0F, 0.0F, 1.0F }}
48   };
49
50 }
51
52 // =======================================================================
53 // function : Init
54 // purpose  :
55 // =======================================================================
56 void OpenGl_Material::Init (const OpenGl_Context& theCtx,
57                             const Graphic3d_MaterialAspect& theMat,
58                             const Quantity_Color& theInteriorColor)
59 {
60   Common.ChangeShine()        = 128.0f * theMat.Shininess();
61   Common.ChangeTransparency() = theMat.Alpha();
62
63   Pbr.ChangeMetallic()  = theMat.PBRMaterial().Metallic();
64   Pbr.ChangeRoughness() = theMat.PBRMaterial().NormalizedRoughness();
65   Pbr.EmissionIOR = Graphic3d_Vec4 (theMat.PBRMaterial().Emission(), theMat.PBRMaterial().IOR());
66
67   const OpenGl_Vec3& aSrcAmb = theMat.AmbientColor();
68   const OpenGl_Vec3& aSrcDif = theMat.DiffuseColor();
69   const OpenGl_Vec3& aSrcSpe = theMat.SpecularColor();
70   const OpenGl_Vec3& aSrcEms = theMat.EmissiveColor();
71   Common.Specular.SetValues (aSrcSpe, 1.0f); // interior color is ignored for Specular
72   switch (theMat.MaterialType())
73   {
74     case Graphic3d_MATERIAL_ASPECT:
75     {
76       Common.Ambient .SetValues (aSrcAmb * theInteriorColor, 1.0f);
77       Common.Diffuse .SetValues (aSrcDif * theInteriorColor, 1.0f);
78       Common.Emission.SetValues (aSrcEms * theInteriorColor, 1.0f);
79       Pbr  .BaseColor.SetValues (theInteriorColor, theMat.Alpha());
80       break;
81     }
82     case Graphic3d_MATERIAL_PHYSIC:
83     {
84       Common.Ambient .SetValues (aSrcAmb, 1.0f);
85       Common.Diffuse .SetValues (aSrcDif, 1.0f);
86       Common.Emission.SetValues (aSrcEms, 1.0f);
87       Pbr.BaseColor = theMat.PBRMaterial().Color();
88       break;
89     }
90   }
91
92   Common.Ambient  = theCtx.Vec4FromQuantityColor (Common.Ambient);
93   Common.Diffuse  = theCtx.Vec4FromQuantityColor (Common.Diffuse);
94   Common.Specular = theCtx.Vec4FromQuantityColor (Common.Specular);
95   Common.Emission = theCtx.Vec4FromQuantityColor (Common.Emission);
96 }
97
98 // =======================================================================
99 // function : OpenGl_Workspace
100 // purpose  :
101 // =======================================================================
102 OpenGl_Workspace::OpenGl_Workspace (OpenGl_View* theView, const Handle(OpenGl_Window)& theWindow)
103 : myView (theView),
104   myWindow (theWindow),
105   myGlContext (!theWindow.IsNull() ? theWindow->GetGlContext() : NULL),
106   myUseZBuffer    (Standard_True),
107   myUseDepthWrite (Standard_True),
108   //
109   myNbSkippedTranspElems (0),
110   myRenderFilter (OpenGl_RenderFilter_Empty),
111   //
112   myAspectsSet (&myDefaultAspects),
113   //
114   ViewMatrix_applied (&myDefaultMatrix),
115   StructureMatrix_applied (&myDefaultMatrix),
116   myToAllowFaceCulling (false),
117   myModelViewMatrix (myDefaultMatrix)
118 {
119   if (!myGlContext.IsNull() && myGlContext->MakeCurrent())
120   {
121     myGlContext->core11fwd->glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
122
123     // General initialization of the context
124   #if !defined(GL_ES_VERSION_2_0)
125     if (myGlContext->core11 != NULL)
126     {
127       // enable two-side lighting by default
128       glLightModeli ((GLenum )GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
129       glHint (GL_POINT_SMOOTH_HINT, GL_FASTEST);
130       if (myGlContext->caps->ffpEnable)
131       {
132         glHint (GL_FOG_HINT, GL_FASTEST);
133       }
134     }
135
136     glHint (GL_LINE_SMOOTH_HINT,    GL_FASTEST);
137     glHint (GL_POLYGON_SMOOTH_HINT, GL_FASTEST);
138     if (myGlContext->Vendor() == "microsoft corporation"
139     && !myGlContext->IsGlGreaterEqual (1, 2))
140     {
141       // this software implementation causes too slow rendering into GL_FRONT on modern Windows
142       theView->SetImmediateModeDrawToFront (false);
143     }
144   #endif
145   }
146
147   myNoneCulling .Aspect()->SetSuppressBackFaces (false);
148   myNoneCulling .Aspect()->SetDrawEdges (false);
149   myNoneCulling .Aspect()->SetAlphaMode (Graphic3d_AlphaMode_Opaque);
150
151   myFrontCulling.Aspect()->SetSuppressBackFaces (true);
152   myFrontCulling.Aspect()->SetDrawEdges (false);
153   myFrontCulling.Aspect()->SetAlphaMode (Graphic3d_AlphaMode_Opaque);
154 }
155
156 // =======================================================================
157 // function : Activate
158 // purpose  :
159 // =======================================================================
160 Standard_Boolean OpenGl_Workspace::Activate()
161 {
162   if (myWindow.IsNull() || !myWindow->Activate())
163   {
164     return Standard_False;
165   }
166
167   ViewMatrix_applied      = &myDefaultMatrix;
168   StructureMatrix_applied = &myDefaultMatrix;
169
170   if (myGlContext->core11 == NULL)
171   {
172     if (myGlContext->caps->ffpEnable)
173     {
174     #if defined(GL_ES_VERSION_2_0)
175       Message::SendWarning ("Warning: FFP is unsupported by OpenGL ES");
176     #else
177       Message::SendWarning ("Warning: FFP is unsupported by OpenGL Core Profile");
178     #endif
179       myGlContext->caps->ffpEnable = false;
180     }
181   }
182
183   ResetAppliedAspect();
184
185   // reset state for safety
186   myGlContext->BindProgram (Handle(OpenGl_ShaderProgram)());
187   if (myGlContext->core20fwd != NULL)
188   {
189     myGlContext->core20fwd->glUseProgram (OpenGl_ShaderProgram::NO_PROGRAM);
190   }
191   if (myGlContext->caps->ffpEnable)
192   {
193     myGlContext->ShaderManager()->PushState (Handle(OpenGl_ShaderProgram)());
194   }
195   return Standard_True;
196 }
197
198 //=======================================================================
199 //function : ResetAppliedAspect
200 //purpose  : Sets default values of GL parameters in accordance with default aspects
201 //=======================================================================
202 void OpenGl_Workspace::ResetAppliedAspect()
203 {
204   myGlContext->BindDefaultVao();
205
206   myHighlightStyle.Nullify();
207   myToAllowFaceCulling  = false;
208   myAspectsSet = &myDefaultAspects;
209   myAspectsApplied.Nullify();
210   myGlContext->SetPolygonOffset (Graphic3d_PolygonOffset());
211
212   ApplyAspects();
213   myGlContext->SetLineStipple(myDefaultAspects.Aspect()->LinePattern());
214   myGlContext->SetLineWidth  (myDefaultAspects.Aspect()->LineWidth());
215   if (myGlContext->core15fwd != NULL)
216   {
217     myGlContext->core15fwd->glActiveTexture (GL_TEXTURE0);
218   }
219 }
220
221 // =======================================================================
222 // function : SetDefaultPolygonOffset
223 // purpose  :
224 // =======================================================================
225 Graphic3d_PolygonOffset OpenGl_Workspace::SetDefaultPolygonOffset (const Graphic3d_PolygonOffset& theOffset)
226 {
227   Graphic3d_PolygonOffset aPrev = myDefaultAspects.Aspect()->PolygonOffset();
228   myDefaultAspects.Aspect()->SetPolygonOffset (theOffset);
229   if (myAspectsApplied == myDefaultAspects.Aspect()
230    || myAspectsApplied.IsNull()
231    || (myAspectsApplied->PolygonOffset().Mode & Aspect_POM_None) == Aspect_POM_None)
232   {
233     myGlContext->SetPolygonOffset (theOffset);
234   }
235   return aPrev;
236 }
237
238 // =======================================================================
239 // function : SetAspects
240 // purpose  :
241 // =======================================================================
242 const OpenGl_Aspects* OpenGl_Workspace::SetAspects (const OpenGl_Aspects* theAspect)
243 {
244   const OpenGl_Aspects* aPrevAspects = myAspectsSet;
245   myAspectsSet = theAspect;
246   return aPrevAspects;
247 }
248
249 // =======================================================================
250 // function : ApplyAspects
251 // purpose  :
252 // =======================================================================
253 const OpenGl_Aspects* OpenGl_Workspace::ApplyAspects (bool theToBindTextures)
254 {
255   if (myView->BackfacingModel() == Graphic3d_TOBM_AUTOMATIC)
256   {
257     bool toSuppressBackFaces = myToAllowFaceCulling
258                             && myAspectsSet->Aspect()->ToSuppressBackFaces();
259     if (toSuppressBackFaces)
260     {
261       if (myAspectsSet->Aspect()->InteriorStyle() == Aspect_IS_HATCH
262        || myAspectsSet->Aspect()->AlphaMode() == Graphic3d_AlphaMode_Blend
263        || myAspectsSet->Aspect()->AlphaMode() == Graphic3d_AlphaMode_Mask
264        || myAspectsSet->Aspect()->AlphaMode() == Graphic3d_AlphaMode_MaskBlend
265        || (myAspectsSet->Aspect()->AlphaMode() == Graphic3d_AlphaMode_BlendAuto
266         && myAspectsSet->Aspect()->FrontMaterial().Transparency() != 0.0f))
267       {
268         // disable culling in case of translucent shading aspect
269         toSuppressBackFaces = false;
270       }
271     }
272     myGlContext->SetCullBackFaces (toSuppressBackFaces);
273   }
274
275   if (myAspectsSet->Aspect() == myAspectsApplied
276    && myHighlightStyle == myAspectFaceAppliedWithHL)
277   {
278     return myAspectsSet;
279   }
280   myAspectFaceAppliedWithHL = myHighlightStyle;
281
282   // Aspect_POM_None means: do not change current settings
283   if ((myAspectsSet->Aspect()->PolygonOffset().Mode & Aspect_POM_None) != Aspect_POM_None)
284   {
285     myGlContext->SetPolygonOffset (myAspectsSet->Aspect()->PolygonOffset());
286   }
287
288   const Aspect_InteriorStyle anIntstyle = myAspectsSet->Aspect()->InteriorStyle();
289   if (myAspectsApplied.IsNull()
290    || myAspectsApplied->InteriorStyle() != anIntstyle)
291   {
292   #if !defined(GL_ES_VERSION_2_0)
293     myGlContext->SetPolygonMode (anIntstyle == Aspect_IS_POINT ? GL_POINT : GL_FILL);
294     myGlContext->SetPolygonHatchEnabled (anIntstyle == Aspect_IS_HATCH);
295   #endif
296   }
297
298 #if !defined(GL_ES_VERSION_2_0)
299   if (anIntstyle == Aspect_IS_HATCH)
300   {
301     myGlContext->SetPolygonHatchStyle (myAspectsSet->Aspect()->HatchStyle());
302   }
303 #endif
304
305   // Case of hidden line
306   if (anIntstyle == Aspect_IS_HIDDENLINE)
307   {
308     // copy all values including line edge aspect
309     *myAspectFaceHl.Aspect() = *myAspectsSet->Aspect();
310     myAspectFaceHl.Aspect()->SetShadingModel (Graphic3d_TOSM_UNLIT);
311     myAspectFaceHl.Aspect()->SetInteriorColor (myView->BackgroundColor().GetRGB());
312     myAspectFaceHl.Aspect()->SetDistinguish (false);
313     myAspectFaceHl.SetNoLighting();
314     myAspectsSet = &myAspectFaceHl;
315   }
316   else
317   {
318     myGlContext->SetShadingMaterial (myAspectsSet, myHighlightStyle);
319   }
320
321   if (theToBindTextures)
322   {
323     const Handle(OpenGl_TextureSet)& aTextureSet = TextureSet();
324     myGlContext->BindTextures (aTextureSet, Handle(OpenGl_ShaderProgram)());
325   }
326
327   if ((myView->myShadingModel == Graphic3d_TOSM_PBR
328     || myView->myShadingModel == Graphic3d_TOSM_PBR_FACET)
329    && !myView->myPBREnvironment.IsNull()
330    &&  myView->myPBREnvironment->IsNeededToBeBound())
331   {
332     myView->myPBREnvironment->Bind (myGlContext);
333   }
334
335   myAspectsApplied = myAspectsSet->Aspect();
336   return myAspectsSet;
337 }
338
339 // =======================================================================
340 // function : Width
341 // purpose  :
342 // =======================================================================
343 Standard_Integer OpenGl_Workspace::Width()  const
344 {
345   return !myView->GlWindow().IsNull() ? myView->GlWindow()->Width() : 0;
346 }
347
348 // =======================================================================
349 // function : Height
350 // purpose  :
351 // =======================================================================
352 Standard_Integer OpenGl_Workspace::Height() const
353 {
354   return !myView->GlWindow().IsNull() ? myView->GlWindow()->Height() : 0;
355 }
356
357 // =======================================================================
358 // function : FBOCreate
359 // purpose  :
360 // =======================================================================
361 Handle(OpenGl_FrameBuffer) OpenGl_Workspace::FBOCreate (const Standard_Integer theWidth,
362                                                         const Standard_Integer theHeight)
363 {
364   // activate OpenGL context
365   if (!Activate())
366     return Handle(OpenGl_FrameBuffer)();
367
368   // create the FBO
369   const Handle(OpenGl_Context)& aCtx = GetGlContext();
370   aCtx->BindTextures (Handle(OpenGl_TextureSet)(), Handle(OpenGl_ShaderProgram)());
371   Handle(OpenGl_FrameBuffer) aFrameBuffer = new OpenGl_FrameBuffer();
372   if (!aFrameBuffer->Init (aCtx, theWidth, theHeight, GL_SRGB8_ALPHA8, GL_DEPTH24_STENCIL8, 0))
373   {
374     aFrameBuffer->Release (aCtx.operator->());
375     return Handle(OpenGl_FrameBuffer)();
376   }
377   return aFrameBuffer;
378 }
379
380 // =======================================================================
381 // function : FBORelease
382 // purpose  :
383 // =======================================================================
384 void OpenGl_Workspace::FBORelease (Handle(OpenGl_FrameBuffer)& theFbo)
385 {
386   // activate OpenGL context
387   if (!Activate()
388    || theFbo.IsNull())
389   {
390     return;
391   }
392
393   theFbo->Release (GetGlContext().operator->());
394   theFbo.Nullify();
395 }
396
397 // =======================================================================
398 // function : BufferDump
399 // purpose  :
400 // =======================================================================
401 Standard_Boolean OpenGl_Workspace::BufferDump (const Handle(OpenGl_FrameBuffer)& theFbo,
402                                                Image_PixMap&                     theImage,
403                                                const Graphic3d_BufferType&       theBufferType)
404 {
405   return !theImage.IsEmpty()
406       && Activate()
407       && OpenGl_FrameBuffer::BufferDump (GetGlContext(), theFbo, theImage, theBufferType);
408 }
409
410 // =======================================================================
411 // function : ShouldRender
412 // purpose  :
413 // =======================================================================
414 bool OpenGl_Workspace::ShouldRender (const OpenGl_Element* theElement,
415                                      const OpenGl_Group*   theGroup)
416 {
417   // render only non-raytracable elements when RayTracing is enabled
418   if ((myRenderFilter & OpenGl_RenderFilter_NonRaytraceableOnly) != 0)
419   {
420     if (!theGroup->HasPersistence() && OpenGl_Raytrace::IsRaytracedElement (theElement))
421     {
422       return false;
423     }
424   }
425   else if ((myRenderFilter & OpenGl_RenderFilter_FillModeOnly) != 0)
426   {
427     if (!theElement->IsFillDrawMode())
428     {
429       return false;
430     }
431   }
432
433   // handle opaque/transparency render passes
434   if ((myRenderFilter & OpenGl_RenderFilter_OpaqueOnly) != 0)
435   {
436     if (!theElement->IsFillDrawMode())
437     {
438       return true;
439     }
440
441     if (OpenGl_Context::CheckIsTransparent (myAspectsSet, myHighlightStyle))
442     {
443       ++myNbSkippedTranspElems;
444       return false;
445     }
446   }
447   else if ((myRenderFilter & OpenGl_RenderFilter_TransparentOnly) != 0)
448   {
449     if (!theElement->IsFillDrawMode())
450     {
451       if (dynamic_cast<const OpenGl_Aspects*> (theElement) == NULL)
452       {
453         return false;
454       }
455     }
456     else if (!OpenGl_Context::CheckIsTransparent (myAspectsSet, myHighlightStyle))
457     {
458       return false;
459     }
460   }
461   return true;
462 }
463
464 // =======================================================================
465 // function : DumpJson
466 // purpose  :
467 // =======================================================================
468 void OpenGl_Workspace::DumpJson (Standard_OStream& theOStream, Standard_Integer theDepth) const
469 {
470   OCCT_DUMP_TRANSIENT_CLASS_BEGIN (theOStream)
471
472   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myUseZBuffer)
473   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myUseDepthWrite)
474
475   OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &myNoneCulling)
476   OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &myFrontCulling)
477
478   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myNbSkippedTranspElems)
479   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myRenderFilter)
480
481   OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &myDefaultAspects)
482
483   OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, myAspectsSet)
484   OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, myAspectsApplied.get())
485
486   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myToAllowFaceCulling)
487
488   OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &myAspectFaceHl)
489 }