2e82f08374cda461b7e7b116076506cc908e200c
[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   #endif
150   }
151
152   myNoneCulling .Aspect()->SetSuppressBackFaces (false);
153   myNoneCulling .Aspect()->SetDrawEdges (false);
154   myNoneCulling .Aspect()->SetAlphaMode (Graphic3d_AlphaMode_Opaque);
155
156   myFrontCulling.Aspect()->SetSuppressBackFaces (true);
157   myFrontCulling.Aspect()->SetDrawEdges (false);
158   myFrontCulling.Aspect()->SetAlphaMode (Graphic3d_AlphaMode_Opaque);
159 }
160
161 // =======================================================================
162 // function : Activate
163 // purpose  :
164 // =======================================================================
165 Standard_Boolean OpenGl_Workspace::Activate()
166 {
167   if (myWindow.IsNull() || !myWindow->Activate())
168   {
169     return Standard_False;
170   }
171
172   ViewMatrix_applied      = &myDefaultMatrix;
173   StructureMatrix_applied = &myDefaultMatrix;
174
175   ResetAppliedAspect();
176
177   // reset state for safety
178   myGlContext->BindProgram (Handle(OpenGl_ShaderProgram)());
179   if (myGlContext->core20fwd != NULL)
180   {
181     myGlContext->core20fwd->glUseProgram (OpenGl_ShaderProgram::NO_PROGRAM);
182   }
183   if (myGlContext->caps->ffpEnable)
184   {
185     myGlContext->ShaderManager()->PushState (Handle(OpenGl_ShaderProgram)());
186   }
187   return Standard_True;
188 }
189
190 //=======================================================================
191 //function : ResetAppliedAspect
192 //purpose  : Sets default values of GL parameters in accordance with default aspects
193 //=======================================================================
194 void OpenGl_Workspace::ResetAppliedAspect()
195 {
196   myGlContext->BindDefaultVao();
197
198   myHighlightStyle.Nullify();
199   myToAllowFaceCulling  = false;
200   myAspectsSet = &myDefaultAspects;
201   myAspectsApplied.Nullify();
202   myGlContext->SetPolygonOffset (Graphic3d_PolygonOffset());
203
204   ApplyAspects();
205   myGlContext->SetTypeOfLine (myDefaultAspects.Aspect()->LineType());
206   myGlContext->SetLineWidth  (myDefaultAspects.Aspect()->LineWidth());
207 }
208
209 // =======================================================================
210 // function : SetDefaultPolygonOffset
211 // purpose  :
212 // =======================================================================
213 Graphic3d_PolygonOffset OpenGl_Workspace::SetDefaultPolygonOffset (const Graphic3d_PolygonOffset& theOffset)
214 {
215   Graphic3d_PolygonOffset aPrev = myDefaultAspects.Aspect()->PolygonOffset();
216   myDefaultAspects.Aspect()->SetPolygonOffset (theOffset);
217   if (myAspectsApplied == myDefaultAspects.Aspect()
218    || myAspectsApplied.IsNull()
219    || (myAspectsApplied->PolygonOffset().Mode & Aspect_POM_None) == Aspect_POM_None)
220   {
221     myGlContext->SetPolygonOffset (theOffset);
222   }
223   return aPrev;
224 }
225
226 // =======================================================================
227 // function : SetAspects
228 // purpose  :
229 // =======================================================================
230 const OpenGl_Aspects* OpenGl_Workspace::SetAspects (const OpenGl_Aspects* theAspect)
231 {
232   const OpenGl_Aspects* aPrevAspects = myAspectsSet;
233   myAspectsSet = theAspect;
234   return aPrevAspects;
235 }
236
237 // =======================================================================
238 // function : ApplyAspects
239 // purpose  :
240 // =======================================================================
241 const OpenGl_Aspects* OpenGl_Workspace::ApplyAspects()
242 {
243   if (myView->BackfacingModel() == Graphic3d_TOBM_AUTOMATIC)
244   {
245     bool toSuppressBackFaces = myToAllowFaceCulling
246                             && myAspectsSet->Aspect()->ToSuppressBackFaces();
247     if (toSuppressBackFaces)
248     {
249       if (myAspectsSet->Aspect()->InteriorStyle() == Aspect_IS_HATCH
250        || myAspectsSet->Aspect()->AlphaMode() == Graphic3d_AlphaMode_Blend
251        || myAspectsSet->Aspect()->AlphaMode() == Graphic3d_AlphaMode_Mask
252        || (myAspectsSet->Aspect()->AlphaMode() == Graphic3d_AlphaMode_BlendAuto
253         && myAspectsSet->Aspect()->FrontMaterial().Transparency() != 0.0f))
254       {
255         // disable culling in case of translucent shading aspect
256         toSuppressBackFaces = false;
257       }
258     }
259     myGlContext->SetCullBackFaces (toSuppressBackFaces);
260   }
261
262   if (myAspectsSet->Aspect() == myAspectsApplied
263    && myHighlightStyle == myAspectFaceAppliedWithHL)
264   {
265     return myAspectsSet;
266   }
267   myAspectFaceAppliedWithHL = myHighlightStyle;
268
269   // Aspect_POM_None means: do not change current settings
270   if ((myAspectsSet->Aspect()->PolygonOffset().Mode & Aspect_POM_None) != Aspect_POM_None)
271   {
272     myGlContext->SetPolygonOffset (myAspectsSet->Aspect()->PolygonOffset());
273   }
274
275   const Aspect_InteriorStyle anIntstyle = myAspectsSet->Aspect()->InteriorStyle();
276   if (myAspectsApplied.IsNull()
277    || myAspectsApplied->InteriorStyle() != anIntstyle)
278   {
279   #if !defined(GL_ES_VERSION_2_0)
280     myGlContext->SetPolygonMode (anIntstyle == Aspect_IS_POINT ? GL_POINT : GL_FILL);
281     myGlContext->SetPolygonHatchEnabled (anIntstyle == Aspect_IS_HATCH);
282   #endif
283   }
284
285 #if !defined(GL_ES_VERSION_2_0)
286   if (anIntstyle == Aspect_IS_HATCH)
287   {
288     myGlContext->SetPolygonHatchStyle (myAspectsSet->Aspect()->HatchStyle());
289   }
290 #endif
291
292   // Case of hidden line
293   if (anIntstyle == Aspect_IS_HIDDENLINE)
294   {
295     // copy all values including line edge aspect
296     *myAspectFaceHl.Aspect() = *myAspectsSet->Aspect();
297     myAspectFaceHl.Aspect()->SetShadingModel (Graphic3d_TOSM_UNLIT);
298     myAspectFaceHl.Aspect()->SetInteriorColor (myView->BackgroundColor().GetRGB());
299     myAspectFaceHl.Aspect()->SetDistinguish (false);
300     myAspectFaceHl.SetNoLighting();
301     myAspectsSet = &myAspectFaceHl;
302   }
303   else
304   {
305     myGlContext->SetShadingMaterial (myAspectsSet, myHighlightStyle);
306   }
307
308   if (myAspectsSet->Aspect()->ToMapTexture())
309   {
310     myGlContext->BindTextures (myAspectsSet->TextureSet (myGlContext));
311   }
312   else
313   {
314     myGlContext->BindTextures (myEnvironmentTexture);
315   }
316
317   myAspectsApplied = myAspectsSet->Aspect();
318   return myAspectsSet;
319 }
320
321 // =======================================================================
322 // function : Width
323 // purpose  :
324 // =======================================================================
325 Standard_Integer OpenGl_Workspace::Width()  const
326 {
327   return !myView->GlWindow().IsNull() ? myView->GlWindow()->Width() : 0;
328 }
329
330 // =======================================================================
331 // function : Height
332 // purpose  :
333 // =======================================================================
334 Standard_Integer OpenGl_Workspace::Height() const
335 {
336   return !myView->GlWindow().IsNull() ? myView->GlWindow()->Height() : 0;
337 }
338
339 // =======================================================================
340 // function : FBOCreate
341 // purpose  :
342 // =======================================================================
343 Handle(OpenGl_FrameBuffer) OpenGl_Workspace::FBOCreate (const Standard_Integer theWidth,
344                                                         const Standard_Integer theHeight)
345 {
346   // activate OpenGL context
347   if (!Activate())
348     return Handle(OpenGl_FrameBuffer)();
349
350   // create the FBO
351   const Handle(OpenGl_Context)& aCtx = GetGlContext();
352   aCtx->BindTextures (Handle(OpenGl_TextureSet)());
353   Handle(OpenGl_FrameBuffer) aFrameBuffer = new OpenGl_FrameBuffer();
354   if (!aFrameBuffer->Init (aCtx, theWidth, theHeight, GL_RGBA8, GL_DEPTH24_STENCIL8, 0))
355   {
356     aFrameBuffer->Release (aCtx.operator->());
357     return Handle(OpenGl_FrameBuffer)();
358   }
359   return aFrameBuffer;
360 }
361
362 // =======================================================================
363 // function : FBORelease
364 // purpose  :
365 // =======================================================================
366 void OpenGl_Workspace::FBORelease (Handle(OpenGl_FrameBuffer)& theFbo)
367 {
368   // activate OpenGL context
369   if (!Activate()
370    || theFbo.IsNull())
371   {
372     return;
373   }
374
375   theFbo->Release (GetGlContext().operator->());
376   theFbo.Nullify();
377 }
378
379 // =======================================================================
380 // function : BufferDump
381 // purpose  :
382 // =======================================================================
383 Standard_Boolean OpenGl_Workspace::BufferDump (const Handle(OpenGl_FrameBuffer)& theFbo,
384                                                Image_PixMap&                     theImage,
385                                                const Graphic3d_BufferType&       theBufferType)
386 {
387   return !theImage.IsEmpty()
388       && Activate()
389       && OpenGl_FrameBuffer::BufferDump (GetGlContext(), theFbo, theImage, theBufferType);
390 }
391
392 // =======================================================================
393 // function : ShouldRender
394 // purpose  :
395 // =======================================================================
396 bool OpenGl_Workspace::ShouldRender (const OpenGl_Element* theElement)
397 {
398   // render only non-raytracable elements when RayTracing is enabled
399   if ((myRenderFilter & OpenGl_RenderFilter_NonRaytraceableOnly) != 0)
400   {
401     if (OpenGl_Raytrace::IsRaytracedElement (theElement))
402     {
403       return false;
404     }
405   }
406   else if ((myRenderFilter & OpenGl_RenderFilter_FillModeOnly) != 0)
407   {
408     if (!theElement->IsFillDrawMode())
409     {
410       return false;
411     }
412   }
413
414   // handle opaque/transparency render passes
415   if ((myRenderFilter & OpenGl_RenderFilter_OpaqueOnly) != 0)
416   {
417     if (!theElement->IsFillDrawMode())
418     {
419       return true;
420     }
421
422     if (OpenGl_Context::CheckIsTransparent (myAspectsSet, myHighlightStyle))
423     {
424       ++myNbSkippedTranspElems;
425       return false;
426     }
427   }
428   else if ((myRenderFilter & OpenGl_RenderFilter_TransparentOnly) != 0)
429   {
430     if (!theElement->IsFillDrawMode())
431     {
432       if (dynamic_cast<const OpenGl_Aspects*> (theElement) == NULL)
433       {
434         return false;
435       }
436     }
437     else if (!OpenGl_Context::CheckIsTransparent (myAspectsSet, myHighlightStyle))
438     {
439       return false;
440     }
441   }
442   return true;
443 }