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