0029520: Visualization - drop deprecated V3d_View::Export() functionality and depende...
[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     // manage back face culling mode, disable culling when clipping is enabled
284     bool toSuppressBackFaces = myToAllowFaceCulling
285                             && myAspectFaceSet->Aspect()->ToSuppressBackFaces();
286     if (toSuppressBackFaces)
287     {
288       if (myGlContext->Clipping().IsClippingOrCappingOn()
289        || myAspectFaceSet->Aspect()->InteriorStyle() == Aspect_IS_HATCH)
290       {
291         toSuppressBackFaces = false;
292       }
293     }
294     if (toSuppressBackFaces)
295     {
296       if (myAspectFaceSet->Aspect()->AlphaMode() == Graphic3d_AlphaMode_Blend
297        || myAspectFaceSet->Aspect()->AlphaMode() == Graphic3d_AlphaMode_Mask
298        || (myAspectFaceSet->Aspect()->AlphaMode() == Graphic3d_AlphaMode_BlendAuto
299         && myAspectFaceSet->Aspect()->FrontMaterial().Transparency() != 0.0f))
300       {
301         // disable culling in case of translucent shading aspect
302         toSuppressBackFaces = false;
303       }
304     }
305     myGlContext->SetCullBackFaces (toSuppressBackFaces);
306   }
307
308   if (myAspectFaceSet->Aspect() == myAspectFaceApplied
309    && myHighlightStyle == myAspectFaceAppliedWithHL)
310   {
311     return myAspectFaceSet;
312   }
313   myAspectFaceAppliedWithHL = myHighlightStyle;
314
315 #if !defined(GL_ES_VERSION_2_0)
316   const Aspect_InteriorStyle anIntstyle = myAspectFaceSet->Aspect()->InteriorStyle();
317   if (myAspectFaceApplied.IsNull()
318    || myAspectFaceApplied->InteriorStyle() != anIntstyle)
319   {
320     switch (anIntstyle)
321     {
322       case Aspect_IS_EMPTY:
323       case Aspect_IS_HOLLOW:
324       {
325         myGlContext->SetPolygonMode (GL_LINE);
326         break;
327       }
328       case Aspect_IS_HATCH:
329       {
330         myGlContext->SetPolygonMode (GL_FILL);
331         myGlContext->SetPolygonHatchEnabled (true);
332         break;
333       }
334       case Aspect_IS_SOLID:
335       case Aspect_IS_HIDDENLINE:
336       {
337         myGlContext->SetPolygonMode (GL_FILL);
338         myGlContext->SetPolygonHatchEnabled (false);
339         break;
340       }
341       case Aspect_IS_POINT:
342       {
343         myGlContext->SetPolygonMode (GL_POINT);
344         break;
345       }
346     }
347   }
348
349   if (anIntstyle == Aspect_IS_HATCH)
350   {
351     myGlContext->SetPolygonHatchStyle (myAspectFaceSet->Aspect()->HatchStyle());
352   }
353 #endif
354
355   // Aspect_POM_None means: do not change current settings
356   if ((myAspectFaceSet->Aspect()->PolygonOffset().Mode & Aspect_POM_None) != Aspect_POM_None)
357   {
358     myGlContext->SetPolygonOffset (myAspectFaceSet->Aspect()->PolygonOffset());
359   }
360
361   // Case of hidden line
362   if (myAspectFaceSet->Aspect()->InteriorStyle() == Aspect_IS_HIDDENLINE)
363   {
364     // copy all values including line edge aspect
365     *myAspectFaceHl.Aspect() = *myAspectFaceSet->Aspect();
366     myAspectFaceHl.SetAspectEdge (myAspectFaceSet->AspectEdge());
367     myAspectFaceHl.Aspect()->SetShadingModel (Graphic3d_TOSM_UNLIT);
368     myAspectFaceHl.Aspect()->SetInteriorColor (myView->BackgroundColor().GetRGB());
369     myAspectFaceHl.SetNoLighting();
370     myAspectFaceSet = &myAspectFaceHl;
371   }
372   else
373   {
374     myGlContext->SetShadingMaterial (myAspectFaceSet, myHighlightStyle);
375   }
376
377   if (myAspectFaceSet->Aspect()->ToMapTexture())
378   {
379     myGlContext->BindTextures (myAspectFaceSet->TextureSet (myGlContext));
380   }
381   else
382   {
383     myGlContext->BindTextures (myEnvironmentTexture);
384   }
385
386   myAspectFaceApplied = myAspectFaceSet->Aspect();
387   return myAspectFaceSet;
388 }
389
390 // =======================================================================
391 // function : ApplyAspectMarker
392 // purpose  :
393 // =======================================================================
394 const OpenGl_AspectMarker* OpenGl_Workspace::ApplyAspectMarker()
395 {
396   if (myAspectMarkerSet->Aspect() != myAspectMarkerApplied)
397   {
398     if (myAspectMarkerApplied.IsNull()
399     || (myAspectMarkerSet->Aspect()->Scale() != myAspectMarkerApplied->Scale()))
400     {
401     #if !defined(GL_ES_VERSION_2_0)
402       glPointSize (myAspectMarkerSet->Aspect()->Scale());
403     #endif
404     }
405     myAspectMarkerApplied = myAspectMarkerSet->Aspect();
406   }
407   return myAspectMarkerSet;
408 }
409
410 // =======================================================================
411 // function : Width
412 // purpose  :
413 // =======================================================================
414 Standard_Integer OpenGl_Workspace::Width()  const
415 {
416   return !myView->GlWindow().IsNull() ? myView->GlWindow()->Width() : 0;
417 }
418
419 // =======================================================================
420 // function : Height
421 // purpose  :
422 // =======================================================================
423 Standard_Integer OpenGl_Workspace::Height() const
424 {
425   return !myView->GlWindow().IsNull() ? myView->GlWindow()->Height() : 0;
426 }
427
428 // =======================================================================
429 // function : IsCullingEnabled
430 // purpose  :
431 // =======================================================================
432 Standard_Boolean OpenGl_Workspace::IsCullingEnabled() const
433 {
434   return myView->IsCullingEnabled();
435 }
436
437 // =======================================================================
438 // function : FBOCreate
439 // purpose  :
440 // =======================================================================
441 Handle(OpenGl_FrameBuffer) OpenGl_Workspace::FBOCreate (const Standard_Integer theWidth,
442                                                         const Standard_Integer theHeight)
443 {
444   // activate OpenGL context
445   if (!Activate())
446     return Handle(OpenGl_FrameBuffer)();
447
448   // create the FBO
449   const Handle(OpenGl_Context)& aCtx = GetGlContext();
450   aCtx->BindTextures (Handle(OpenGl_TextureSet)());
451   Handle(OpenGl_FrameBuffer) aFrameBuffer = new OpenGl_FrameBuffer();
452   if (!aFrameBuffer->Init (aCtx, theWidth, theHeight, GL_RGBA8, GL_DEPTH24_STENCIL8, 0))
453   {
454     aFrameBuffer->Release (aCtx.operator->());
455     return Handle(OpenGl_FrameBuffer)();
456   }
457   return aFrameBuffer;
458 }
459
460 // =======================================================================
461 // function : FBORelease
462 // purpose  :
463 // =======================================================================
464 void OpenGl_Workspace::FBORelease (Handle(OpenGl_FrameBuffer)& theFbo)
465 {
466   // activate OpenGL context
467   if (!Activate()
468    || theFbo.IsNull())
469   {
470     return;
471   }
472
473   theFbo->Release (GetGlContext().operator->());
474   theFbo.Nullify();
475 }
476
477 // =======================================================================
478 // function : BufferDump
479 // purpose  :
480 // =======================================================================
481 Standard_Boolean OpenGl_Workspace::BufferDump (const Handle(OpenGl_FrameBuffer)& theFbo,
482                                                Image_PixMap&                     theImage,
483                                                const Graphic3d_BufferType&       theBufferType)
484 {
485   return !theImage.IsEmpty()
486       && Activate()
487       && OpenGl_FrameBuffer::BufferDump (GetGlContext(), theFbo, theImage, theBufferType);
488 }
489
490 // =======================================================================
491 // function : ShouldRender
492 // purpose  :
493 // =======================================================================
494 Standard_Boolean OpenGl_RaytraceFilter::ShouldRender (const Handle(OpenGl_Workspace)& theWorkspace,
495                                                       const OpenGl_Element*           theElement)
496 {
497   Standard_Boolean aPrevFilterResult = Standard_True;
498   if (!myPrevRenderFilter.IsNull())
499   {
500     aPrevFilterResult = myPrevRenderFilter->ShouldRender (theWorkspace, theElement);
501   }
502   return aPrevFilterResult &&
503     !OpenGl_Raytrace::IsRaytracedElement (theElement);
504 }