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