adfc4902da40f0e58f79e3d5d79c8467b7bce669
[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   if (myGlContext->core15fwd != NULL)
208   {
209     myGlContext->core15fwd->glActiveTexture (GL_TEXTURE0);
210   }
211 }
212
213 // =======================================================================
214 // function : SetDefaultPolygonOffset
215 // purpose  :
216 // =======================================================================
217 Graphic3d_PolygonOffset OpenGl_Workspace::SetDefaultPolygonOffset (const Graphic3d_PolygonOffset& theOffset)
218 {
219   Graphic3d_PolygonOffset aPrev = myDefaultAspects.Aspect()->PolygonOffset();
220   myDefaultAspects.Aspect()->SetPolygonOffset (theOffset);
221   if (myAspectsApplied == myDefaultAspects.Aspect()
222    || myAspectsApplied.IsNull()
223    || (myAspectsApplied->PolygonOffset().Mode & Aspect_POM_None) == Aspect_POM_None)
224   {
225     myGlContext->SetPolygonOffset (theOffset);
226   }
227   return aPrev;
228 }
229
230 // =======================================================================
231 // function : SetAspects
232 // purpose  :
233 // =======================================================================
234 const OpenGl_Aspects* OpenGl_Workspace::SetAspects (const OpenGl_Aspects* theAspect)
235 {
236   const OpenGl_Aspects* aPrevAspects = myAspectsSet;
237   myAspectsSet = theAspect;
238   return aPrevAspects;
239 }
240
241 // =======================================================================
242 // function : ApplyAspects
243 // purpose  :
244 // =======================================================================
245 const OpenGl_Aspects* OpenGl_Workspace::ApplyAspects()
246 {
247   if (myView->BackfacingModel() == Graphic3d_TOBM_AUTOMATIC)
248   {
249     bool toSuppressBackFaces = myToAllowFaceCulling
250                             && myAspectsSet->Aspect()->ToSuppressBackFaces();
251     if (toSuppressBackFaces)
252     {
253       if (myAspectsSet->Aspect()->InteriorStyle() == Aspect_IS_HATCH
254        || myAspectsSet->Aspect()->AlphaMode() == Graphic3d_AlphaMode_Blend
255        || myAspectsSet->Aspect()->AlphaMode() == Graphic3d_AlphaMode_Mask
256        || (myAspectsSet->Aspect()->AlphaMode() == Graphic3d_AlphaMode_BlendAuto
257         && myAspectsSet->Aspect()->FrontMaterial().Transparency() != 0.0f))
258       {
259         // disable culling in case of translucent shading aspect
260         toSuppressBackFaces = false;
261       }
262     }
263     myGlContext->SetCullBackFaces (toSuppressBackFaces);
264   }
265
266   if (myAspectsSet->Aspect() == myAspectsApplied
267    && myHighlightStyle == myAspectFaceAppliedWithHL)
268   {
269     return myAspectsSet;
270   }
271   myAspectFaceAppliedWithHL = myHighlightStyle;
272
273   // Aspect_POM_None means: do not change current settings
274   if ((myAspectsSet->Aspect()->PolygonOffset().Mode & Aspect_POM_None) != Aspect_POM_None)
275   {
276     myGlContext->SetPolygonOffset (myAspectsSet->Aspect()->PolygonOffset());
277   }
278
279   const Aspect_InteriorStyle anIntstyle = myAspectsSet->Aspect()->InteriorStyle();
280   if (myAspectsApplied.IsNull()
281    || myAspectsApplied->InteriorStyle() != anIntstyle)
282   {
283   #if !defined(GL_ES_VERSION_2_0)
284     myGlContext->SetPolygonMode (anIntstyle == Aspect_IS_POINT ? GL_POINT : GL_FILL);
285     myGlContext->SetPolygonHatchEnabled (anIntstyle == Aspect_IS_HATCH);
286   #endif
287   }
288
289 #if !defined(GL_ES_VERSION_2_0)
290   if (anIntstyle == Aspect_IS_HATCH)
291   {
292     myGlContext->SetPolygonHatchStyle (myAspectsSet->Aspect()->HatchStyle());
293   }
294 #endif
295
296   // Case of hidden line
297   if (anIntstyle == Aspect_IS_HIDDENLINE)
298   {
299     // copy all values including line edge aspect
300     *myAspectFaceHl.Aspect() = *myAspectsSet->Aspect();
301     myAspectFaceHl.Aspect()->SetShadingModel (Graphic3d_TOSM_UNLIT);
302     myAspectFaceHl.Aspect()->SetInteriorColor (myView->BackgroundColor().GetRGB());
303     myAspectFaceHl.Aspect()->SetDistinguish (false);
304     myAspectFaceHl.SetNoLighting();
305     myAspectsSet = &myAspectFaceHl;
306   }
307   else
308   {
309     myGlContext->SetShadingMaterial (myAspectsSet, myHighlightStyle);
310   }
311
312   const Handle(OpenGl_TextureSet)& aTextureSet = myAspectsSet->TextureSet (myGlContext, ToHighlight());
313   if (!aTextureSet.IsNull()
314    || myAspectsSet->Aspect()->ToMapTexture())
315   {
316     myGlContext->BindTextures (aTextureSet);
317   }
318   else
319   {
320     myGlContext->BindTextures (myEnvironmentTexture);
321   }
322
323   myAspectsApplied = myAspectsSet->Aspect();
324   return myAspectsSet;
325 }
326
327 // =======================================================================
328 // function : Width
329 // purpose  :
330 // =======================================================================
331 Standard_Integer OpenGl_Workspace::Width()  const
332 {
333   return !myView->GlWindow().IsNull() ? myView->GlWindow()->Width() : 0;
334 }
335
336 // =======================================================================
337 // function : Height
338 // purpose  :
339 // =======================================================================
340 Standard_Integer OpenGl_Workspace::Height() const
341 {
342   return !myView->GlWindow().IsNull() ? myView->GlWindow()->Height() : 0;
343 }
344
345 // =======================================================================
346 // function : FBOCreate
347 // purpose  :
348 // =======================================================================
349 Handle(OpenGl_FrameBuffer) OpenGl_Workspace::FBOCreate (const Standard_Integer theWidth,
350                                                         const Standard_Integer theHeight)
351 {
352   // activate OpenGL context
353   if (!Activate())
354     return Handle(OpenGl_FrameBuffer)();
355
356   // create the FBO
357   const Handle(OpenGl_Context)& aCtx = GetGlContext();
358   aCtx->BindTextures (Handle(OpenGl_TextureSet)());
359   Handle(OpenGl_FrameBuffer) aFrameBuffer = new OpenGl_FrameBuffer();
360   if (!aFrameBuffer->Init (aCtx, theWidth, theHeight, GL_RGBA8, GL_DEPTH24_STENCIL8, 0))
361   {
362     aFrameBuffer->Release (aCtx.operator->());
363     return Handle(OpenGl_FrameBuffer)();
364   }
365   return aFrameBuffer;
366 }
367
368 // =======================================================================
369 // function : FBORelease
370 // purpose  :
371 // =======================================================================
372 void OpenGl_Workspace::FBORelease (Handle(OpenGl_FrameBuffer)& theFbo)
373 {
374   // activate OpenGL context
375   if (!Activate()
376    || theFbo.IsNull())
377   {
378     return;
379   }
380
381   theFbo->Release (GetGlContext().operator->());
382   theFbo.Nullify();
383 }
384
385 // =======================================================================
386 // function : BufferDump
387 // purpose  :
388 // =======================================================================
389 Standard_Boolean OpenGl_Workspace::BufferDump (const Handle(OpenGl_FrameBuffer)& theFbo,
390                                                Image_PixMap&                     theImage,
391                                                const Graphic3d_BufferType&       theBufferType)
392 {
393   return !theImage.IsEmpty()
394       && Activate()
395       && OpenGl_FrameBuffer::BufferDump (GetGlContext(), theFbo, theImage, theBufferType);
396 }
397
398 // =======================================================================
399 // function : ShouldRender
400 // purpose  :
401 // =======================================================================
402 bool OpenGl_Workspace::ShouldRender (const OpenGl_Element* theElement)
403 {
404   // render only non-raytracable elements when RayTracing is enabled
405   if ((myRenderFilter & OpenGl_RenderFilter_NonRaytraceableOnly) != 0)
406   {
407     if (OpenGl_Raytrace::IsRaytracedElement (theElement))
408     {
409       return false;
410     }
411   }
412   else if ((myRenderFilter & OpenGl_RenderFilter_FillModeOnly) != 0)
413   {
414     if (!theElement->IsFillDrawMode())
415     {
416       return false;
417     }
418   }
419
420   // handle opaque/transparency render passes
421   if ((myRenderFilter & OpenGl_RenderFilter_OpaqueOnly) != 0)
422   {
423     if (!theElement->IsFillDrawMode())
424     {
425       return true;
426     }
427
428     if (OpenGl_Context::CheckIsTransparent (myAspectsSet, myHighlightStyle))
429     {
430       ++myNbSkippedTranspElems;
431       return false;
432     }
433   }
434   else if ((myRenderFilter & OpenGl_RenderFilter_TransparentOnly) != 0)
435   {
436     if (!theElement->IsFillDrawMode())
437     {
438       if (dynamic_cast<const OpenGl_Aspects*> (theElement) == NULL)
439       {
440         return false;
441       }
442     }
443     else if (!OpenGl_Context::CheckIsTransparent (myAspectsSet, myHighlightStyle))
444     {
445       return false;
446     }
447   }
448   return true;
449 }