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