0027925: Visualization - implement order-independent transparency algorithm within...
authorapl <apl@opencascade.com>
Tue, 25 Apr 2017 12:10:15 +0000 (15:10 +0300)
committerbugmaster <bugmaster@opencascade.com>
Fri, 5 May 2017 08:27:47 +0000 (11:27 +0300)
Weighted, Blended Order-Independent Transparency algorithm has been added rasterization pipeline.
In contrast to classical blending transparency it makes transparent objects look independent
from point of view. It also gives better depth occlusion when being used together with a weight factor
based on value of a GL depth buffer. The feature supports desktop OpenGL, OpenGL ES 3.0, ANGLE
and can be used together with MSAA on desktop GL.

To be used it require availability of:
1) Shaders pipeline.
2) Floating point color format for framebuffer (GL_ARB_color_buffer_float).
3) Multiple render targets (GL_ARB_draw_buffers).

Patch does not modify API and does not require application porting.
It adds new rendering options to Graphic3d_RenderingParams structure:
a) Transparency method from enumeration.
b) Scalar factor [0-1] controlling influence of a fragment's depth to its visibility.

Patch also simplifies processing of transparent objects for standard method:
rendering priority of transparent graphical structures is managed automatically,
therefore there is no need to care about it at application's side.

41 files changed:
src/AIS/AIS_Shape.cxx
src/AIS/AIS_Triangulation.cxx
src/D3DHost/D3DHost_FrameBuffer.cxx
src/Graphic3d/FILES
src/Graphic3d/Graphic3d_RenderTransparentMethod.hxx [new file with mode: 0644]
src/Graphic3d/Graphic3d_RenderingParams.hxx
src/Graphic3d/Graphic3d_TypeOfLimit.hxx
src/OpenGl/OpenGl_CappingAlgo.cxx
src/OpenGl/OpenGl_CappingAlgo.hxx
src/OpenGl/OpenGl_Context.cxx
src/OpenGl/OpenGl_Context.hxx
src/OpenGl/OpenGl_Element.hxx
src/OpenGl/OpenGl_FrameBuffer.cxx
src/OpenGl/OpenGl_FrameBuffer.hxx
src/OpenGl/OpenGl_GlFunctions.hxx
src/OpenGl/OpenGl_GraphicDriver.cxx
src/OpenGl/OpenGl_Layer.cxx
src/OpenGl/OpenGl_LayerList.cxx
src/OpenGl/OpenGl_LayerList.hxx
src/OpenGl/OpenGl_PrimitiveArray.hxx
src/OpenGl/OpenGl_RenderFilter.hxx
src/OpenGl/OpenGl_SetOfShaderPrograms.hxx
src/OpenGl/OpenGl_ShaderManager.cxx
src/OpenGl/OpenGl_ShaderManager.hxx
src/OpenGl/OpenGl_ShaderProgram.cxx
src/OpenGl/OpenGl_ShaderProgram.hxx
src/OpenGl/OpenGl_ShaderStates.hxx
src/OpenGl/OpenGl_Texture.cxx
src/OpenGl/OpenGl_View.cxx
src/OpenGl/OpenGl_View.hxx
src/OpenGl/OpenGl_View_Redraw.cxx
src/OpenGl/OpenGl_Workspace.cxx
src/OpenGl/OpenGl_Workspace.hxx
src/Shaders/Declarations.glsl
src/Shaders/PhongShading.fs
src/Shaders/Shaders_Declarations_glsl.pxx
src/ViewerTest/ViewerTest_ViewerCommands.cxx
tests/v3d/grids.list [changed mode: 0644->0755]
tests/v3d/transparency/begin [new file with mode: 0644]
tests/v3d/transparency/blend [new file with mode: 0644]
tests/v3d/transparency/highlight [new file with mode: 0644]

index f0a4dd6..715cc45 100644 (file)
@@ -981,7 +981,6 @@ void AIS_Shape::SetTransparency (const Standard_Real theValue)
     }
 
     const Handle(Prs3d_Presentation)& aPrs = aPrsModed.Presentation()->Presentation();
-    aPrs->SetDisplayPriority (10); // force highest priority for translucent objects
     for (Graphic3d_SequenceOfGroup::Iterator aGroupIt (aPrs->Groups()); aGroupIt.More(); aGroupIt.Next())
     {
       const Handle(Graphic3d_Group)& aGroup = aGroupIt.Value();
@@ -1037,7 +1036,6 @@ void AIS_Shape::UnsetTransparency()
         aGroup->SetGroupPrimitivesAspect (anAreaAsp);
       }
     }
-    aPrs->ResetDisplayPriority();
   }
 
   myRecomputeEveryPrs = Standard_False; // no mode to recalculate :only viewer update
index f4df8e4..3374b05 100644 (file)
@@ -105,11 +105,6 @@ void AIS_Triangulation::updatePresentation()
 
       const Handle(Prs3d_Presentation)& aPrs = aPrsModed.Presentation()->Presentation();
 
-      if (IsTransparent())
-      {
-        aPrs->SetDisplayPriority (10); // force highest priority for translucent objects
-      }
-
       for (Graphic3d_SequenceOfGroup::Iterator aGroupIt (aPrs->Groups()); aGroupIt.More(); aGroupIt.Next())
       {
         const Handle(Graphic3d_Group)& aGroup = aGroupIt.Value();
@@ -118,11 +113,6 @@ void AIS_Triangulation::updatePresentation()
           aGroup->SetGroupPrimitivesAspect (anAreaAsp);
         }
       }
-
-      if (!IsTransparent())
-      {
-        aPrs->ResetDisplayPriority();
-      }
     }
 
     myRecomputeEveryPrs = Standard_False; // no mode to recalculate - only viewer update
index 75e5f11..dc4f97d 100644 (file)
@@ -194,12 +194,12 @@ Standard_Boolean D3DHost_FrameBuffer::registerD3dBuffer (const Handle(OpenGl_Con
     return Standard_False;
   }
 
-  myColorTexture->Release (theCtx.operator->());
-  myColorTexture->Create  (theCtx);
+  myColorTextures (0)->Release (theCtx.operator->());
+  myColorTextures (0)->Create  (theCtx);
 
   myGlD3dSurf = aFuncs->wglDXRegisterObjectNV (myGlD3dDevice,
                                                myD3dSurf,
-                                               myColorTexture->TextureId(),
+                                               myColorTextures (0)->TextureId(),
                                                GL_TEXTURE_2D,
                                                WGL_ACCESS_WRITE_DISCARD_NV);
 
@@ -226,7 +226,7 @@ void D3DHost_FrameBuffer::BindBuffer (const Handle(OpenGl_Context)& theCtx)
 
   OpenGl_FrameBuffer::BindBuffer (theCtx);
   theCtx->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
-                                          GL_TEXTURE_2D, myColorTexture->TextureId(), 0);
+                                          GL_TEXTURE_2D, myColorTextures (0)->TextureId(), 0);
   theCtx->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
                                           GL_TEXTURE_2D, myDepthStencilTexture->TextureId(), 0);
   if (theCtx->arbFBO->glCheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
index 321015c..5ae409a 100755 (executable)
@@ -88,6 +88,7 @@ Graphic3d_PolygonOffset.hxx
 Graphic3d_PriorityDefinitionError.hxx
 Graphic3d_RenderingMode.hxx
 Graphic3d_RenderingParams.hxx
+Graphic3d_RenderTransparentMethod.hxx
 Graphic3d_SequenceOfGroup.hxx
 Graphic3d_SequenceOfHClipPlane.hxx
 Graphic3d_SequenceOfStructure.hxx
diff --git a/src/Graphic3d/Graphic3d_RenderTransparentMethod.hxx b/src/Graphic3d/Graphic3d_RenderTransparentMethod.hxx
new file mode 100644 (file)
index 0000000..5066f09
--- /dev/null
@@ -0,0 +1,26 @@
+// Created on: 2017-04-25
+// Created by: Anton POLETAEV
+// Copyright (c) 2017 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#ifndef _Graphic3d_RenderTransparentMethod_HeaderFile
+#define _Graphic3d_RenderTransparentMethod_HeaderFile
+
+//! Enumerates transparency rendering methods supported by rasterization mode.
+enum Graphic3d_RenderTransparentMethod
+{
+  Graphic3d_RTM_BLEND_UNORDERED, //!< Basic blend transparency with non-commuting blend operator without sorting
+  Graphic3d_RTM_BLEND_OIT        //!< Weighted Blended Order-Independent Transparency with depth weight factor
+};
+
+#endif // _Graphic3d_RenderTransparentMethod_HeaderFile
index 0ba2b79..afc678f 100644 (file)
 #ifndef _Graphic3d_RenderingParams_HeaderFile
 #define _Graphic3d_RenderingParams_HeaderFile
 
+#include <Graphic3d_Mat4.hxx>
+#include <Graphic3d_RenderTransparentMethod.hxx>
 #include <Graphic3d_RenderingMode.hxx>
 #include <Graphic3d_StereoMode.hxx>
-#include <Graphic3d_Mat4.hxx>
 #include <Graphic3d_Vec4.hxx>
 
 //! Helper class to store rendering parameters.
@@ -47,6 +48,8 @@ public:
   //! Creates default rendering parameters.
   Graphic3d_RenderingParams()
   : Method                      (Graphic3d_RM_RASTERIZATION),
+    TransparencyMethod          (Graphic3d_RTM_BLEND_UNORDERED),
+    OitDepthFactor              (0.0f),
     NbMsaaSamples               (0),
     RenderResolutionScale       (1.0f),
     // ray tracing parameters
@@ -90,39 +93,40 @@ public:
 
 public:
 
-  Graphic3d_RenderingMode Method;                      //!< specifies rendering mode, Graphic3d_RM_RASTERIZATION by default
-  Standard_Integer        NbMsaaSamples;               //!< number of MSAA samples (should be within 0..GL_MAX_SAMPLES, power-of-two number), 0 by default
-  Standard_ShortReal      RenderResolutionScale;       //!< rendering resolution scale factor, 1 by default;
-                                                       //!  incompatible with MSAA (e.g. NbMsaaSamples should be set to 0)
-
-  Standard_Boolean        IsGlobalIlluminationEnabled; //!< enables/disables global illumination effects (path tracing)
-  Standard_Integer        SamplesPerPixel;             //!< number of samples per pixel (SPP)
-  Standard_Integer        RaytracingDepth;             //!< maximum ray-tracing depth, 3 by default
-  Standard_Boolean        IsShadowEnabled;             //!< enables/disables shadows rendering, True by default
-  Standard_Boolean        IsReflectionEnabled;         //!< enables/disables specular reflections, False by default
-  Standard_Boolean        IsAntialiasingEnabled;       //!< enables/disables adaptive anti-aliasing, False by default
-  Standard_Boolean        IsTransparentShadowEnabled;  //!< enables/disables light propagation through transparent media, False by default
-  Standard_Boolean        UseEnvironmentMapBackground; //!< enables/disables environment map background
-  Standard_Boolean        CoherentPathTracingMode;     //!< enables/disables 'coherent' tracing mode (single RNG seed within 16x16 image blocks)
-  Standard_Boolean        AdaptiveScreenSampling;      //!< enables/disables adaptive screen sampling mode for path tracing, FALSE by default
-  Standard_Boolean        ShowSamplingTiles;           //!< enables/disables debug mode for adaptive screen sampling, FALSE by default
-  Standard_Boolean        TwoSidedBsdfModels;          //!< forces path tracing to use two-sided versions of original one-sided scattering models
-  Standard_ShortReal      RadianceClampingValue;       //!< maximum radiance value used for clamping radiance estimation.
-  Standard_Boolean        RebuildRayTracingShaders;    //!< forces rebuilding ray tracing shaders at the next frame
-  Standard_Integer        NbRayTracingTiles;           //!< total number of screen tiles used in adaptive sampling mode (PT only)
-
-  Graphic3d_StereoMode    StereoMode;                  //!< stereoscopic output mode, Graphic3d_StereoMode_QuadBuffer by default
-  Anaglyph                AnaglyphFilter;              //!< filter for anaglyph output, Anaglyph_RedCyan_Optimized by default
-  Graphic3d_Mat4          AnaglyphLeft;                //!< left  anaglyph filter (in normalized colorspace), Color = AnaglyphRight * theColorRight + AnaglyphLeft * theColorLeft;
-  Graphic3d_Mat4          AnaglyphRight;               //!< right anaglyph filter (in normalized colorspace), Color = AnaglyphRight * theColorRight + AnaglyphLeft * theColorLeft;
-  Standard_Boolean        ToReverseStereo;             //!< flag to reverse stereo pair, FALSE by default
-
-  unsigned int            Resolution;                  //!< Pixels density (PPI), defines scaling factor for parameters like text size
-                                                       //!  (when defined in screen-space units rather than in 3D) to be properly displayed
-                                                       //!  on device (screen / printer). 72 is default value.
-                                                       //!  Note that using difference resolution in different Views in same Viewer
-                                                       //!  will lead to performance regression (for example, text will be recreated every time).
-
+  Graphic3d_RenderingMode           Method;                      //!< specifies rendering mode, Graphic3d_RM_RASTERIZATION by default
+  Graphic3d_RenderTransparentMethod TransparencyMethod;          //!< specifies rendering method for transparent graphics
+  Standard_ShortReal                OitDepthFactor;              //!< scalar factor [0-1] controlling influence of depth of a fragment to its final coverage
+  Standard_Integer                  NbMsaaSamples;               //!< number of MSAA samples (should be within 0..GL_MAX_SAMPLES, power-of-two number), 0 by default
+  Standard_ShortReal                RenderResolutionScale;       //!< rendering resolution scale factor, 1 by default;
+                                                                 //!  incompatible with MSAA (e.g. NbMsaaSamples should be set to 0)
+
+  Standard_Boolean                  IsGlobalIlluminationEnabled; //!< enables/disables global illumination effects (path tracing)
+  Standard_Integer                  SamplesPerPixel;             //!< number of samples per pixel (SPP)
+  Standard_Integer                  RaytracingDepth;             //!< maximum ray-tracing depth, 3 by default
+  Standard_Boolean                  IsShadowEnabled;             //!< enables/disables shadows rendering, True by default
+  Standard_Boolean                  IsReflectionEnabled;         //!< enables/disables specular reflections, False by default
+  Standard_Boolean                  IsAntialiasingEnabled;       //!< enables/disables adaptive anti-aliasing, False by default
+  Standard_Boolean                  IsTransparentShadowEnabled;  //!< enables/disables light propagation through transparent media, False by default
+  Standard_Boolean                  UseEnvironmentMapBackground; //!< enables/disables environment map background
+  Standard_Boolean                  CoherentPathTracingMode;     //!< enables/disables 'coherent' tracing mode (single RNG seed within 16x16 image blocks)
+  Standard_Boolean                  AdaptiveScreenSampling;      //!< enables/disables adaptive screen sampling mode for path tracing, FALSE by default
+  Standard_Boolean                  ShowSamplingTiles;           //!< enables/disables debug mode for adaptive screen sampling, FALSE by default
+  Standard_Boolean                  TwoSidedBsdfModels;          //!< forces path tracing to use two-sided versions of original one-sided scattering models
+  Standard_ShortReal                RadianceClampingValue;       //!< maximum radiance value used for clamping radiance estimation.
+  Standard_Boolean                  RebuildRayTracingShaders;    //!< forces rebuilding ray tracing shaders at the next frame
+  Standard_Integer                  NbRayTracingTiles;           //!< total number of screen tiles used in adaptive sampling mode (PT only)
+
+  Graphic3d_StereoMode              StereoMode;                  //!< stereoscopic output mode, Graphic3d_StereoMode_QuadBuffer by default
+  Anaglyph                          AnaglyphFilter;              //!< filter for anaglyph output, Anaglyph_RedCyan_Optimized by default
+  Graphic3d_Mat4                    AnaglyphLeft;                //!< left  anaglyph filter (in normalized colorspace), Color = AnaglyphRight * theColorRight + AnaglyphLeft * theColorLeft;
+  Graphic3d_Mat4                    AnaglyphRight;               //!< right anaglyph filter (in normalized colorspace), Color = AnaglyphRight * theColorRight + AnaglyphLeft * theColorLeft;
+  Standard_Boolean                  ToReverseStereo;             //!< flag to reverse stereo pair, FALSE by default
+
+  unsigned int                      Resolution;                  //!< Pixels density (PPI), defines scaling factor for parameters like text size
+                                                                 //!  (when defined in screen-space units rather than in 3D) to be properly displayed
+                                                                 //!  on device (screen / printer). 72 is default value.
+                                                                 //!  Note that using difference resolution in different Views in same Viewer
+                                                                 //!  will lead to performance regression (for example, text will be recreated every time).
 };
 
 #endif // _Graphic3d_RenderingParams_HeaderFile
index beaefd9..9a8de15 100644 (file)
@@ -25,6 +25,8 @@ enum Graphic3d_TypeOfLimit
   Graphic3d_TypeOfLimit_HasRayTracing,                  //!< indicates whether ray tracing is supported
   Graphic3d_TypeOfLimit_HasRayTracingTextures,          //!< indicates whether ray tracing textures are supported
   Graphic3d_TypeOfLimit_HasRayTracingAdaptiveSampling,  //!< indicates whether adaptive screen sampling is supported
+  Graphic3d_TypeOfLimit_HasBlendedOit,                  //!< indicates whether necessary GL extensions for Weighted, Blended OIT available (without MSAA).
+  Graphic3d_TypeOfLimit_HasBlendedOitMsaa,              //!< indicates whether necessary GL extensions for Weighted, Blended OIT available (with MSAA).
   Graphic3d_TypeOfLimit_NB                              //!< number of elements in this enumeration
 };
 
index f0bfb66..3ba9545 100755 (executable)
@@ -27,14 +27,6 @@ IMPLEMENT_STANDARD_RTTIEXT(OpenGl_CappingAlgoFilter,OpenGl_RenderFilter)
 
 namespace
 {
-#if !defined(GL_ES_VERSION_2_0)
-  static const GLint THE_FILLPRIM_FROM = GL_TRIANGLES;
-  static const GLint THE_FILLPRIM_TO   = GL_POLYGON;
-#else
-  static const GLint THE_FILLPRIM_FROM = GL_TRIANGLES;
-  static const GLint THE_FILLPRIM_TO   = GL_TRIANGLE_FAN;
-#endif
-
   //! Render infinite capping plane.
   //! @param theWorkspace [in] the GL workspace, context state.
   //! @param thePlane [in] the graphical plane, for which the capping surface is rendered.
@@ -88,8 +80,14 @@ namespace
       theWorkspace->ApplyAspectFace();
 
       // evaluate number of pair faces
-      glDisable (GL_DEPTH_TEST);
-      glDepthMask (GL_FALSE);
+      if (theWorkspace->UseZBuffer())
+      {
+        glDisable (GL_DEPTH_TEST);
+      }
+      if (theWorkspace->UseDepthWrite())
+      {
+        glDepthMask (GL_FALSE);
+      }
       glStencilFunc (GL_ALWAYS, 1, 0x01);
       glStencilOp (GL_KEEP, GL_INVERT, GL_INVERT);
 
@@ -119,10 +117,16 @@ namespace
 
       // render capping plane using the generated stencil mask
       glColorMask (GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
-      glDepthMask (GL_TRUE);
+      if (theWorkspace->UseDepthWrite())
+      {
+        glDepthMask (GL_TRUE);
+      }
       glStencilFunc (GL_EQUAL, 1, 0x01);
       glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP);
-      glEnable (GL_DEPTH_TEST);
+      if (theWorkspace->UseZBuffer())
+      {
+        glEnable (GL_DEPTH_TEST);
+      }
 
       renderPlane (theWorkspace, thePlane, aRenderPlane->ToUseObjectProperties()
                                          ? aGroupIter.Value()->AspectFace()
@@ -160,7 +164,9 @@ void OpenGl_CappingAlgo::RenderCapping (const Handle(OpenGl_Workspace)& theWorks
 
   // replace primitive groups rendering filter
   Handle(OpenGl_RenderFilter) aRenderFilter = theWorkspace->GetRenderFilter();
-  theWorkspace->SetRenderFilter (theWorkspace->DefaultCappingAlgoFilter());
+  Handle(OpenGl_CappingAlgoFilter) aCappingFilter = theWorkspace->DefaultCappingAlgoFilter();
+  aCappingFilter->SetPreviousFilter (aRenderFilter);
+  theWorkspace->SetRenderFilter (aCappingFilter);
 
   // prepare for rendering the clip planes
   glEnable (GL_STENCIL_TEST);
@@ -214,10 +220,16 @@ void OpenGl_CappingAlgo::RenderCapping (const Handle(OpenGl_Workspace)& theWorks
 // function : CanRender
 // purpose  :
 // =======================================================================
-Standard_Boolean OpenGl_CappingAlgoFilter::CanRender (const OpenGl_Element* theElement)
+Standard_Boolean OpenGl_CappingAlgoFilter::ShouldRender (const Handle(OpenGl_Workspace)& theWorkspace,
+                                                         const OpenGl_Element* theGlElement)
 {
-  const OpenGl_PrimitiveArray* aPArray = dynamic_cast<const OpenGl_PrimitiveArray*> (theElement);
+  if (!myFilter.IsNull() && !myFilter->ShouldRender (theWorkspace, theGlElement))
+  {
+    return Standard_False;
+  }
+
+  const OpenGl_PrimitiveArray* aPArray = dynamic_cast<const OpenGl_PrimitiveArray*> (theGlElement);
   return aPArray != NULL
-      && aPArray->DrawMode() >= THE_FILLPRIM_FROM
-      && aPArray->DrawMode() <= THE_FILLPRIM_TO;
+      && aPArray->DrawMode() >= OpenGl_PrimitiveArray::THE_FILLPRIM_FROM
+      && aPArray->DrawMode() <= OpenGl_PrimitiveArray::THE_FILLPRIM_TO;
 }
index 7fc7881..e936779 100755 (executable)
@@ -41,7 +41,7 @@ public:
 };
 
 //! Graphical capping rendering algorithm filter.
-//! Filters out everything excepth shaded primitives.
+//! Filters out everything except shaded primitives.
 class OpenGl_CappingAlgoFilter : public OpenGl_RenderFilter
 {
 public:
@@ -49,10 +49,19 @@ public:
   //! Default constructor.
   OpenGl_CappingAlgoFilter() {}
 
+  //! Sets the current active filter in workspace.
+  //! @param thePrevFilter [in] the previously active filter that should have additive effect.
+  void SetPreviousFilter (const Handle(OpenGl_RenderFilter)& thePrevFitler) { myFilter = thePrevFitler; }
+
   //! Checks whether the element can be rendered or not.
   //! @param theElement [in] the element to check.
   //! @return True if element can be rendered.
-  virtual Standard_Boolean CanRender (const OpenGl_Element* theElement) Standard_OVERRIDE;
+  virtual Standard_Boolean ShouldRender (const Handle(OpenGl_Workspace)& theWorkspace,
+                                         const OpenGl_Element* theGlElement) Standard_OVERRIDE;
+
+private:
+
+  Handle(OpenGl_RenderFilter) myFilter; //!< Previous active filter that should be combined.
 
 public:
 
index 603157d..65f1d78 100644 (file)
@@ -125,6 +125,11 @@ OpenGl_Context::OpenGl_Context (const Handle(OpenGl_Caps)& theCaps)
   hasUintIndex(Standard_True),
   hasTexRGBA8(Standard_True),
 #endif
+  hasDrawBuffers     (OpenGl_FeatureNotAvailable),
+  hasFloatBuffer     (OpenGl_FeatureNotAvailable),
+  hasHalfFloatBuffer (OpenGl_FeatureNotAvailable),
+  hasSampleVariables (OpenGl_FeatureNotAvailable),
+  arbDrawBuffers (Standard_False),
   arbNPTW  (Standard_False),
   arbTexRG (Standard_False),
   arbTexFloat (Standard_False),
@@ -135,13 +140,16 @@ OpenGl_Context::OpenGl_Context (const Handle(OpenGl_Caps)& theCaps)
   arbDbg (NULL),
   arbFBO (NULL),
   arbFBOBlit (NULL),
+  arbSampleShading (Standard_False),
   extFragDepth (Standard_False),
+  extDrawBuffers (Standard_False),
   extGS  (NULL),
   extBgra(Standard_False),
   extAnis(Standard_False),
   extPDS (Standard_False),
   atiMem (Standard_False),
   nvxMem (Standard_False),
+  oesSampleVariables (Standard_False),
   mySharedResources (new OpenGl_ResourcesMap()),
   myDelayed         (new OpenGl_DelayReleaseMap()),
   myUnusedResources (new OpenGl_ResourcesStack()),
@@ -153,6 +161,8 @@ OpenGl_Context::OpenGl_Context (const Handle(OpenGl_Caps)& theCaps)
   myMaxTexDim  (1024),
   myMaxClipPlanes (6),
   myMaxMsaaSamples(0),
+  myMaxDrawBuffers (1),
+  myMaxColorAttachments (1),
   myGlVerMajor (0),
   myGlVerMinor (0),
   myIsInitialized (Standard_False),
@@ -172,7 +182,7 @@ OpenGl_Context::OpenGl_Context (const Handle(OpenGl_Caps)& theCaps)
 #endif
   myToCullBackFaces (false),
   myReadBuffer (0),
-  myDrawBuffer (0),
+  myDrawBuffers (1),
   myDefaultVao (0),
   myIsGlDebugCtx (Standard_False),
   myResolution (Graphic3d_RenderingParams::THE_DEFAULT_RESOLUTION),
@@ -394,18 +404,60 @@ void OpenGl_Context::SetReadBuffer (const Standard_Integer theReadBuffer)
 void OpenGl_Context::SetDrawBuffer (const Standard_Integer theDrawBuffer)
 {
 #if !defined(GL_ES_VERSION_2_0)
-  myDrawBuffer = !myIsStereoBuffers ? stereoToMonoBuffer (theDrawBuffer) : theDrawBuffer;
-  if (myDrawBuffer < GL_COLOR_ATTACHMENT0
+  const Standard_Integer aDrawBuffer = !myIsStereoBuffers ? stereoToMonoBuffer (theDrawBuffer) : theDrawBuffer;
+  if (aDrawBuffer < GL_COLOR_ATTACHMENT0
    && arbFBO != NULL)
   {
     arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, OpenGl_FrameBuffer::NO_FRAMEBUFFER);
   }
-  ::glDrawBuffer (myDrawBuffer);
+  ::glDrawBuffer (aDrawBuffer);
+
+  myDrawBuffers.Clear();
+
+  if (aDrawBuffer != GL_NONE)
+  {
+    myDrawBuffers.SetValue (0, aDrawBuffer);
+  }
 #else
   (void )theDrawBuffer;
 #endif
 }
 
+// =======================================================================
+// function : SetDrawBuffers
+// purpose  :
+// =======================================================================
+void OpenGl_Context::SetDrawBuffers (const Standard_Integer theNb, const Standard_Integer* theDrawBuffers)
+{
+  Standard_ASSERT_RETURN (hasDrawBuffers, "Multiple draw buffers feature is not supported by the context", Standard_ASSERT_DO_NOTHING());
+
+  myDrawBuffers.Clear();
+
+  Standard_Boolean useDefaultFbo = Standard_False;
+  for (Standard_Integer anI = 0; anI < theNb; ++anI)
+  {
+#if !defined(GL_ES_VERSION_2_0)
+    const Standard_Integer aDrawBuffer = !myIsStereoBuffers ? stereoToMonoBuffer (theDrawBuffers[anI]) : theDrawBuffers[anI];
+#else
+    const Standard_Integer aDrawBuffer = theDrawBuffers[anI];
+#endif
+    if (aDrawBuffer < GL_COLOR_ATTACHMENT0 && aDrawBuffer != GL_NONE)
+    {
+      useDefaultFbo = Standard_True;
+    }
+    else if (aDrawBuffer != GL_NONE)
+    {
+      myDrawBuffers.SetValue (anI, aDrawBuffer);
+    }
+  }
+  if (arbFBO != NULL && useDefaultFbo)
+  {
+    arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, OpenGl_FrameBuffer::NO_FRAMEBUFFER);
+  }
+
+  myFuncs->glDrawBuffers (theNb, (const GLenum*)theDrawBuffers);
+}
+
 // =======================================================================
 // function : SetCullBackFaces
 // purpose  :
@@ -442,9 +494,37 @@ void OpenGl_Context::FetchState()
     ::glGetIntegerv (GL_RENDER_MODE, &myRenderMode);
   }
 
-  // cache buffers state
+  // cache read buffers state
   ::glGetIntegerv (GL_READ_BUFFER, &myReadBuffer);
-  ::glGetIntegerv (GL_DRAW_BUFFER, &myDrawBuffer);
+
+  // cache draw buffers state
+  myDrawBuffers.Clear();
+
+  if (myMaxDrawBuffers == 1)
+  {
+    Standard_Integer aDrawBuffer;
+
+    ::glGetIntegerv (GL_DRAW_BUFFER, &aDrawBuffer);
+
+    if (aDrawBuffer != GL_NONE)
+    {
+      myDrawBuffers.SetValue (0, aDrawBuffer);
+    }
+  }
+  else
+  {
+    Standard_Integer aDrawBuffer;
+
+    for (Standard_Integer anI = 0; anI < myMaxDrawBuffers; ++anI)
+    {
+      ::glGetIntegerv (GL_DRAW_BUFFER0 + anI, &aDrawBuffer);
+
+      if (aDrawBuffer != GL_NONE)
+      {
+        myDrawBuffers.SetValue (anI, aDrawBuffer);
+      }
+    }
+  }
 #endif
 }
 
@@ -1119,6 +1199,8 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile)
   myGlVerMajor = 0;
   myGlVerMinor = 0;
   myMaxMsaaSamples = 0;
+  myMaxDrawBuffers = 1;
+  myMaxColorAttachments = 1;
   ReadGlVersion (myGlVerMajor, myGlVerMinor);
   myVendor = (const char* )::glGetString (GL_VENDOR);
   if (!caps->ffpEnable
@@ -1292,19 +1374,56 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile)
     }
   }
 
+  extDrawBuffers = CheckExtension ("GL_EXT_draw_buffers") && FindProc ("glDrawBuffersEXT", myFuncs->glDrawBuffers);
+  arbDrawBuffers = CheckExtension ("GL_ARB_draw_buffers") && FindProc ("glDrawBuffersARB", myFuncs->glDrawBuffers);
+
+  if (IsGlGreaterEqual (3, 0) && FindProc ("glDrawBuffers", myFuncs->glDrawBuffers))
+  {
+    hasDrawBuffers = OpenGl_FeatureInCore;
+  }
+  else if (extDrawBuffers || arbDrawBuffers)
+  {
+    hasDrawBuffers = OpenGl_FeatureInExtensions;
+  }
+
+  hasFloatBuffer     = IsGlGreaterEqual (3, 2) ? OpenGl_FeatureInCore :
+                       CheckExtension ("GL_EXT_color_buffer_float") ? OpenGl_FeatureInExtensions 
+                                                                    : OpenGl_FeatureNotAvailable;
+  hasHalfFloatBuffer = IsGlGreaterEqual (3, 2) ? OpenGl_FeatureInCore :
+                       CheckExtension ("GL_EXT_color_buffer_half_float") ? OpenGl_FeatureInExtensions 
+                                                                         : OpenGl_FeatureNotAvailable;
+
+  oesSampleVariables = CheckExtension ("GL_OES_sample_variables");
+  hasSampleVariables = IsGlGreaterEqual (3, 2) ? OpenGl_FeatureInCore :
+                       oesSampleVariables ? OpenGl_FeatureInExtensions
+                                          : OpenGl_FeatureNotAvailable;
 #else
 
   myTexClamp = IsGlGreaterEqual (1, 2) ? GL_CLAMP_TO_EDGE : GL_CLAMP;
 
   hasTexRGBA8 = Standard_True;
-  arbNPTW     = CheckExtension ("GL_ARB_texture_non_power_of_two");
-  arbTexFloat = IsGlGreaterEqual (3, 0)
-             || CheckExtension ("GL_ARB_texture_float");
-  extBgra     = CheckExtension ("GL_EXT_bgra");
-  extAnis     = CheckExtension ("GL_EXT_texture_filter_anisotropic");
-  extPDS      = CheckExtension ("GL_EXT_packed_depth_stencil");
-  atiMem      = CheckExtension ("GL_ATI_meminfo");
-  nvxMem      = CheckExtension ("GL_NVX_gpu_memory_info");
+  arbDrawBuffers   = CheckExtension ("GL_ARB_draw_buffers");
+  arbNPTW          = CheckExtension ("GL_ARB_texture_non_power_of_two");
+  arbTexFloat      = IsGlGreaterEqual (3, 0)
+                  || CheckExtension ("GL_ARB_texture_float");
+  arbSampleShading = CheckExtension ("GL_ARB_sample_shading");
+  extBgra          = CheckExtension ("GL_EXT_bgra");
+  extAnis          = CheckExtension ("GL_EXT_texture_filter_anisotropic");
+  extPDS           = CheckExtension ("GL_EXT_packed_depth_stencil");
+  atiMem           = CheckExtension ("GL_ATI_meminfo");
+  nvxMem           = CheckExtension ("GL_NVX_gpu_memory_info");
+
+  hasDrawBuffers = IsGlGreaterEqual (2, 0) ? OpenGl_FeatureInCore :
+                   arbDrawBuffers ? OpenGl_FeatureInExtensions 
+                                  : OpenGl_FeatureNotAvailable;
+
+  hasFloatBuffer = hasHalfFloatBuffer =  IsGlGreaterEqual (3, 0) ? OpenGl_FeatureInCore :
+                                         CheckExtension ("GL_ARB_color_buffer_float") ? OpenGl_FeatureInExtensions
+                                                                                      : OpenGl_FeatureNotAvailable;
+
+  hasSampleVariables = IsGlGreaterEqual (4, 0) ? OpenGl_FeatureInCore :
+                        arbSampleShading ? OpenGl_FeatureInExtensions
+                                         : OpenGl_FeatureNotAvailable;
 
   GLint aStereo = GL_FALSE;
   glGetIntegerv (GL_STEREO, &aStereo);
@@ -1314,6 +1433,12 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile)
   glGetIntegerv (GL_MAX_CLIP_PLANES,  &myMaxClipPlanes);
 #endif
 
+  if (hasDrawBuffers)
+  {
+    glGetIntegerv (GL_MAX_DRAW_BUFFERS,      &myMaxDrawBuffers);
+    glGetIntegerv (GL_MAX_COLOR_ATTACHMENTS, &myMaxColorAttachments);
+  }
+
   glGetIntegerv (GL_MAX_TEXTURE_SIZE, &myMaxTexDim);
 
   if (extAnis)
@@ -2892,8 +3017,7 @@ Handle(OpenGl_FrameBuffer) OpenGl_Context::SetDefaultFrameBuffer (const Handle(O
 // purpose  :
 // =======================================================================
 void OpenGl_Context::SetShadingMaterial (const OpenGl_AspectFace* theAspect,
-                                         const Handle(Graphic3d_PresentationAttributes)& theHighlight,
-                                         const Standard_Boolean theUseDepthWrite)
+                                         const Handle(Graphic3d_PresentationAttributes)& theHighlight)
 {
   const Handle(Graphic3d_AspectFillArea3d)& anAspect = (!theHighlight.IsNull() && !theHighlight->BasicFillAreaAspect().IsNull())
                                                       ?  theHighlight->BasicFillAreaAspect()
@@ -2920,39 +3044,19 @@ void OpenGl_Context::SetShadingMaterial (const OpenGl_AspectFace* theAspect,
     myMatBack = myMatFront;
   }
 
-  // handling transparency
-  float aTranspFront = aMatFrontSrc.Transparency();
-  float aTranspBack  = aMatBackSrc .Transparency();
   if (!theHighlight.IsNull()
     && theHighlight->BasicFillAreaAspect().IsNull())
   {
     myMatFront.SetColor (theHighlight->ColorRGBA());
     myMatBack .SetColor (theHighlight->ColorRGBA());
-    aTranspFront = theHighlight->Transparency();
-    aTranspBack  = theHighlight->Transparency();
   }
+
+  Standard_ShortReal aTranspFront = 0.f;
+  Standard_ShortReal aTranspBack  = 0.f;
+  if (CheckIsTransparent (theAspect, theHighlight, aTranspFront, aTranspBack))
   {
-    GLboolean aDepthMask = GL_TRUE;
-    if (aTranspFront != 0.0f
-     || aTranspBack  != 0.0f)
-    {
-      // render transparent
-      myMatFront.Diffuse.a() = 1.0f - aTranspFront;
-      myMatBack .Diffuse.a() = 1.0f - aTranspBack;
-      glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-      glEnable (GL_BLEND);
-      aDepthMask = GL_FALSE;
-    }
-    else
-    {
-      // render opaque
-      glBlendFunc (GL_ONE, GL_ZERO);
-      glDisable (GL_BLEND);
-    }
-    if (theUseDepthWrite)
-    {
-      glDepthMask (aDepthMask);
-    }
+    myMatFront.Diffuse.a() = 1.0f - aTranspFront;
+    myMatBack .Diffuse.a() = 1.0f - aTranspBack;
   }
 
   // do not update material properties in case of zero reflection mode,
@@ -2973,6 +3077,39 @@ void OpenGl_Context::SetShadingMaterial (const OpenGl_AspectFace* theAspect,
   myShaderManager->UpdateMaterialStateTo (myMatFront, myMatBack, toDistinguish, toMapTexture);
 }
 
+// =======================================================================
+// function : CheckIsTransparent
+// purpose  :
+// =======================================================================
+Standard_Boolean OpenGl_Context::CheckIsTransparent (const OpenGl_AspectFace* theAspect,
+                                                     const Handle(Graphic3d_PresentationAttributes)& theHighlight,
+                                                     Standard_ShortReal& theTranspFront,
+                                                     Standard_ShortReal& theTranspBack)
+{
+  const Handle(Graphic3d_AspectFillArea3d)& anAspect = (!theHighlight.IsNull() && !theHighlight->BasicFillAreaAspect().IsNull())
+                                                      ?  theHighlight->BasicFillAreaAspect()
+                                                      :  theAspect->Aspect();
+
+  const bool toDistinguish = anAspect->Distinguish();
+  const Graphic3d_MaterialAspect& aMatFrontSrc = anAspect->FrontMaterial();
+  const Graphic3d_MaterialAspect& aMatBackSrc  = toDistinguish
+                                               ? anAspect->BackMaterial()
+                                               : aMatFrontSrc;
+
+  // handling transparency
+  theTranspFront = aMatFrontSrc.Transparency();
+  theTranspBack  = aMatBackSrc .Transparency();
+  if (!theHighlight.IsNull()
+    && theHighlight->BasicFillAreaAspect().IsNull())
+  {
+    theTranspFront = theHighlight->Transparency();
+    theTranspBack  = theHighlight->Transparency();
+  }
+
+  return theTranspFront != 0.f
+      || theTranspBack  != 0.f;
+}
+
 // =======================================================================
 // function : SetColor4fv
 // purpose  :
index 8a26551..064c01e 100644 (file)
@@ -27,6 +27,7 @@
 #include <NCollection_Map.hxx>
 #include <NCollection_Handle.hxx>
 #include <NCollection_List.hxx>
+#include <NCollection_SparseArray.hxx>
 #include <Message.hxx>
 #include <OpenGl_Caps.hxx>
 #include <OpenGl_LineAttributes.hxx>
@@ -135,6 +136,13 @@ class OpenGl_FrameBuffer;
 class OpenGl_AspectFace;
 class Graphic3d_PresentationAttributes;
 
+enum OpenGl_FeatureFlag
+{
+  OpenGl_FeatureNotAvailable = 0, //!< Feature is not supported by OpenGl implementation.
+  OpenGl_FeatureInExtensions = 1, //!< Feature is supported as extension.
+  OpenGl_FeatureInCore       = 2  //!< Feature is supported as part of core profile.
+};
+
 DEFINE_STANDARD_HANDLE(OpenGl_Context, Standard_Transient)
 
 //! This class generalize access to the GL context and available extensions.
@@ -456,6 +464,12 @@ public:
   //! @return value for GL_MAX_SAMPLES
   Standard_Integer MaxMsaaSamples() const { return myMaxMsaaSamples; }
 
+  //! @return value for GL_MAX_DRAW_BUFFERS
+  Standard_Integer MaxDrawBuffers() const { return myMaxDrawBuffers; }
+
+  //! @return value for GL_MAX_COLOR_ATTACHMENTS
+  Standard_Integer MaxColorAttachments() const { return myMaxColorAttachments; }
+
   //! Get maximum number of clip planes supported by OpenGl.
   //! This value is implementation dependent. At least 6
   //! planes should be supported by OpenGl (see specs).
@@ -586,12 +600,18 @@ public: //! @name methods to alter or retrieve current state
   //! Switch read buffer, wrapper for ::glReadBuffer().
   Standard_EXPORT void SetReadBuffer (const Standard_Integer theReadBuffer);
 
-  //! Return active draw buffer.
-  Standard_Integer DrawBuffer() { return myDrawBuffer; }
+  //! Return active draw buffer attached to a render target referred by index (layout location).
+  Standard_Integer DrawBuffer (const Standard_Integer theIndex = 0)
+  {
+    return myDrawBuffers.IsBound (theIndex) ? myDrawBuffers.Value (theIndex) : GL_NONE;
+  }
 
   //! Switch draw buffer, wrapper for ::glDrawBuffer().
   Standard_EXPORT void SetDrawBuffer (const Standard_Integer theDrawBuffer);
 
+  //! Switch draw buffer, wrapper for ::glDrawBuffers (GLsizei, const GLenum*).
+  Standard_EXPORT void SetDrawBuffers (const Standard_Integer theNb, const Standard_Integer* theDrawBuffers);
+
   //! Switch read/draw buffers.
   void SetReadDrawBuffer (const Standard_Integer theBuffer)
   {
@@ -630,8 +650,13 @@ public: //! @name methods to alter or retrieve current state
 
   //! Setup current shading material.
   Standard_EXPORT void SetShadingMaterial (const OpenGl_AspectFace* theAspect,
-                                           const Handle(Graphic3d_PresentationAttributes)& theHighlight,
-                                           const Standard_Boolean theUseDepthWrite);
+                                           const Handle(Graphic3d_PresentationAttributes)& theHighlight);
+
+  //! Checks if transparency is required for the given aspect and highlight style.
+  Standard_EXPORT static Standard_Boolean CheckIsTransparent (const OpenGl_AspectFace* theAspect,
+                                                              const Handle(Graphic3d_PresentationAttributes)& theHighlight,
+                                                              Standard_ShortReal& theTranspFront,
+                                                              Standard_ShortReal& theTranspBack);
 
   //! Setup current color.
   Standard_EXPORT void SetColor4fv (const OpenGl_Vec4& theColor);
@@ -754,26 +779,34 @@ public: //! @name core profiles
 
 public: //! @name extensions
 
-  Standard_Boolean       hasHighp;       //!< highp in GLSL ES fragment shader is supported
-  Standard_Boolean       hasUintIndex;   //!< GLuint for index buffer is supported (always available on desktop; on OpenGL ES - since 3.0 or as extension GL_OES_element_index_uint)
-  Standard_Boolean       hasTexRGBA8;    //!< always available on desktop; on OpenGL ES - since 3.0 or as extension GL_OES_rgb8_rgba8
-  Standard_Boolean       arbNPTW;        //!< GL_ARB_texture_non_power_of_two
-  Standard_Boolean       arbTexRG;       //!< GL_ARB_texture_rg
-  Standard_Boolean       arbTexFloat;    //!< GL_ARB_texture_float (on desktop OpenGL - since 3.0 or as extension GL_ARB_texture_float; on OpenGL ES - since 3.0)
-  OpenGl_ArbTexBindless* arbTexBindless; //!< GL_ARB_bindless_texture
-  OpenGl_ArbTBO*         arbTBO;         //!< GL_ARB_texture_buffer_object
-  Standard_Boolean       arbTboRGB32;    //!< GL_ARB_texture_buffer_object_rgb32 (3-component TBO), in core since 4.0
-  OpenGl_ArbIns*         arbIns;         //!< GL_ARB_draw_instanced
-  OpenGl_ArbDbg*         arbDbg;         //!< GL_ARB_debug_output
-  OpenGl_ArbFBO*         arbFBO;         //!< GL_ARB_framebuffer_object
-  OpenGl_ArbFBOBlit*     arbFBOBlit;     //!< glBlitFramebuffer function, moved out from OpenGl_ArbFBO structure for compatibility with OpenGL ES 2.0
-  Standard_Boolean       extFragDepth;   //!< GL_EXT_frag_depth on OpenGL ES 2.0 (gl_FragDepthEXT built-in variable, before OpenGL ES 3.0)
-  OpenGl_ExtGS*          extGS;          //!< GL_EXT_geometry_shader4
-  Standard_Boolean       extBgra;        //!< GL_EXT_bgra or GL_EXT_texture_format_BGRA8888 on OpenGL ES
-  Standard_Boolean       extAnis;        //!< GL_EXT_texture_filter_anisotropic
-  Standard_Boolean       extPDS;         //!< GL_EXT_packed_depth_stencil
-  Standard_Boolean       atiMem;         //!< GL_ATI_meminfo
-  Standard_Boolean       nvxMem;         //!< GL_NVX_gpu_memory_info
+  Standard_Boolean       hasHighp;           //!< highp in GLSL ES fragment shader is supported
+  Standard_Boolean       hasUintIndex;       //!< GLuint for index buffer is supported (always available on desktop; on OpenGL ES - since 3.0 or as extension GL_OES_element_index_uint)
+  Standard_Boolean       hasTexRGBA8;        //!< always available on desktop; on OpenGL ES - since 3.0 or as extension GL_OES_rgb8_rgba8
+  OpenGl_FeatureFlag     hasDrawBuffers;     //!< Complex flag indicating support of multiple draw buffers (desktop OpenGL 2.0, OpenGL ES 3.0, GL_ARB_draw_buffers, GL_EXT_draw_buffers)
+  OpenGl_FeatureFlag     hasFloatBuffer;     //!< Complex flag indicating support of float color buffer format (desktop OpenGL 3.0, GL_ARB_color_buffer_float, GL_EXT_color_buffer_float)
+  OpenGl_FeatureFlag     hasHalfFloatBuffer; //!< Complex flag indicating support of half-float color buffer format (desktop OpenGL 3.0, GL_ARB_color_buffer_float, GL_EXT_color_buffer_half_float)
+  OpenGl_FeatureFlag     hasSampleVariables; //!< Complex flag indicating support of MSAA variables in GLSL shader (desktop OpenGL 4.0, GL_ARB_sample_shading)
+  Standard_Boolean       arbDrawBuffers;     //!< GL_ARB_draw_buffers
+  Standard_Boolean       arbNPTW;            //!< GL_ARB_texture_non_power_of_two
+  Standard_Boolean       arbTexRG;           //!< GL_ARB_texture_rg
+  Standard_Boolean       arbTexFloat;        //!< GL_ARB_texture_float (on desktop OpenGL - since 3.0 or as extension GL_ARB_texture_float; on OpenGL ES - since 3.0)
+  OpenGl_ArbTexBindless* arbTexBindless;     //!< GL_ARB_bindless_texture
+  OpenGl_ArbTBO*         arbTBO;             //!< GL_ARB_texture_buffer_object
+  Standard_Boolean       arbTboRGB32;        //!< GL_ARB_texture_buffer_object_rgb32 (3-component TBO), in core since 4.0
+  OpenGl_ArbIns*         arbIns;             //!< GL_ARB_draw_instanced
+  OpenGl_ArbDbg*         arbDbg;             //!< GL_ARB_debug_output
+  OpenGl_ArbFBO*         arbFBO;             //!< GL_ARB_framebuffer_object
+  OpenGl_ArbFBOBlit*     arbFBOBlit;         //!< glBlitFramebuffer function, moved out from OpenGl_ArbFBO structure for compatibility with OpenGL ES 2.0
+  Standard_Boolean       arbSampleShading;   //!< GL_ARB_sample_shading
+  Standard_Boolean       extFragDepth;       //!< GL_EXT_frag_depth on OpenGL ES 2.0 (gl_FragDepthEXT built-in variable, before OpenGL ES 3.0)
+  Standard_Boolean       extDrawBuffers;     //!< GL_EXT_draw_buffers
+  OpenGl_ExtGS*          extGS;              //!< GL_EXT_geometry_shader4
+  Standard_Boolean       extBgra;            //!< GL_EXT_bgra or GL_EXT_texture_format_BGRA8888 on OpenGL ES
+  Standard_Boolean       extAnis;            //!< GL_EXT_texture_filter_anisotropic
+  Standard_Boolean       extPDS;             //!< GL_EXT_packed_depth_stencil
+  Standard_Boolean       atiMem;             //!< GL_ATI_meminfo
+  Standard_Boolean       nvxMem;             //!< GL_NVX_gpu_memory_info
+  Standard_Boolean       oesSampleVariables; //!< GL_OES_sample_variables
 
 public: //! @name public properties tracking current state
 
@@ -808,6 +841,7 @@ private: // context info
   typedef NCollection_Shared< NCollection_DataMap<TCollection_AsciiString, Standard_Integer> > OpenGl_DelayReleaseMap;
   typedef NCollection_Shared< NCollection_DataMap<TCollection_AsciiString, Handle(OpenGl_Resource)> > OpenGl_ResourcesMap;
   typedef NCollection_Shared< NCollection_List<Handle(OpenGl_Resource)> > OpenGl_ResourcesStack;
+  typedef NCollection_SparseArray<Standard_Integer> OpenGl_DrawBuffers;
 
   Handle(OpenGl_ResourcesMap)    mySharedResources; //!< shared resources with unique identification key
   Handle(OpenGl_DelayReleaseMap) myDelayed;         //!< shared resources for delayed release
@@ -823,6 +857,8 @@ private: // context info
   Standard_Integer myMaxTexDim;            //!< value for GL_MAX_TEXTURE_SIZE
   Standard_Integer myMaxClipPlanes;        //!< value for GL_MAX_CLIP_PLANES
   Standard_Integer myMaxMsaaSamples;       //!< value for GL_MAX_SAMPLES
+  Standard_Integer myMaxDrawBuffers;       //!< value for GL_MAX_DRAW_BUFFERS
+  Standard_Integer myMaxColorAttachments;  //!< value for GL_MAX_COLOR_ATTACHMENTS
   Standard_Integer myGlVerMajor;           //!< cached GL version major number
   Standard_Integer myGlVerMinor;           //!< cached GL version minor number
   Standard_Boolean myIsInitialized;        //!< flag indicates initialization state
@@ -849,7 +885,7 @@ private: //! @name fields tracking current state
   Standard_Integer              myPolygonMode;     //!< currently used polygon rasterization mode (glPolygonMode)
   bool                          myToCullBackFaces; //!< back face culling mode enabled state (glIsEnabled (GL_CULL_FACE))
   Standard_Integer              myReadBuffer;      //!< current read buffer
-  Standard_Integer              myDrawBuffer;      //!< current draw buffer
+  OpenGl_DrawBuffers            myDrawBuffers;     //!< current draw buffers
   unsigned int                  myDefaultVao;      //!< default Vertex Array Object
   Standard_Boolean              myIsGlDebugCtx;    //!< debug context initialization state
   TCollection_AsciiString       myVendor;          //!< Graphics Driver's vendor
index b335421..74890ee 100644 (file)
@@ -63,12 +63,12 @@ public:
   //! @param theWorkspace [in] the rendering workspace.
   //! @param theFilter [in] the rendering filter to check whether the element
   //! should be rendered or not.
-  //! @return True if element passes the filering check and is rendered.
+  //! @return True if element passes the check and renders,
   inline Standard_Boolean
     RenderFiltered (const Handle(OpenGl_Workspace)& theWorkspace,
                     const Handle(OpenGl_RenderFilter)& theFilter) const
   {
-    if (!theFilter.IsNull() && !theFilter->CanRender (this))
+    if (!theFilter.IsNull() && !theFilter->ShouldRender (theWorkspace, this))
     {
       return Standard_False;
     }
index 30b1284..4572949 100644 (file)
@@ -64,6 +64,68 @@ namespace
     return false;
   }
 
+  //! Determine data type from texture sized format.
+  static bool getColorDataFormat (GLint   theTextFormat,
+                                  GLenum& thePixelFormat,
+                                  GLenum& theDataType)
+  {
+    switch (theTextFormat)
+    {
+      case GL_RGBA32F:
+      {
+        thePixelFormat = GL_RGBA;
+        theDataType    = GL_FLOAT;
+        return true;
+      }
+      case GL_R32F:
+      {
+        thePixelFormat = GL_RED;
+        theDataType    = GL_FLOAT;
+        return true;
+      }
+      case GL_RGBA16F:
+      {
+        thePixelFormat = GL_RGBA;
+        theDataType    = GL_HALF_FLOAT;
+        return true;
+      }
+      case GL_R16F:
+      {
+        thePixelFormat = GL_RED;
+        theDataType    = GL_HALF_FLOAT;
+        return true;
+      }
+      case GL_RGBA8:
+      {
+        thePixelFormat = GL_RGBA;
+        theDataType    = GL_UNSIGNED_INT;
+        return true;
+      }
+      case GL_RGBA:
+      {
+        thePixelFormat = GL_RGBA;
+        theDataType    = GL_UNSIGNED_BYTE;
+        return true;
+      }
+    }
+    return false;
+  }
+
+  //! Checks whether two format arrays are equal or not.
+  static bool operator== (const OpenGl_ColorFormats& theFmt1,
+                          const OpenGl_ColorFormats& theFmt2)
+  {
+    if (theFmt1.Length() != theFmt2.Length())
+      return false;
+    OpenGl_ColorFormats::Iterator anIt1 (theFmt1);
+    OpenGl_ColorFormats::Iterator anIt2 (theFmt1);
+    for (; anIt1.More(); anIt1.Next(), anIt2.Next())
+    {
+      if (anIt1.Value() != anIt2.Value())
+        return false;
+    }
+    return true;
+  }
 }
 
 // =======================================================================
@@ -74,16 +136,15 @@ OpenGl_FrameBuffer::OpenGl_FrameBuffer()
 : myVPSizeX (0),
   myVPSizeY (0),
   myNbSamples (0),
-  myColorFormat (GL_RGBA8),
   myDepthFormat (GL_DEPTH24_STENCIL8),
   myGlFBufferId (NO_FRAMEBUFFER),
   myGlColorRBufferId (NO_RENDERBUFFER),
   myGlDepthRBufferId (NO_RENDERBUFFER),
   myIsOwnBuffer  (false),
-  myColorTexture (new OpenGl_Texture()),
   myDepthStencilTexture (new OpenGl_Texture())
 {
-  //
+  myColorFormats.Append (GL_RGBA8);
+  myColorTextures.Append (new OpenGl_Texture());
 }
 
 // =======================================================================
@@ -100,13 +161,169 @@ OpenGl_FrameBuffer::~OpenGl_FrameBuffer()
 // purpose  :
 // =======================================================================
 Standard_Boolean OpenGl_FrameBuffer::Init (const Handle(OpenGl_Context)& theGlContext,
-                                           const GLsizei   theSizeX,
-                                           const GLsizei   theSizeY,
-                                           const GLint     theColorFormat,
-                                           const GLint     theDepthFormat,
-                                           const GLsizei   theNbSamples)
+                                           const GLsizei                 theSizeX,
+                                           const GLsizei                 theSizeY,
+                                           const GLint                   theColorFormat,
+                                           const GLint                   theDepthFormat,
+                                           const GLsizei                 theNbSamples)
 {
-  myColorFormat = theColorFormat;
+  OpenGl_ColorFormats aColorFormats;
+
+  aColorFormats.Append (theColorFormat);
+
+  return Init (theGlContext, theSizeX, theSizeY, aColorFormats, theDepthFormat, theNbSamples);
+}
+
+// =======================================================================
+// function : Init
+// purpose  :
+// =======================================================================
+Standard_Boolean OpenGl_FrameBuffer::Init (const Handle(OpenGl_Context)& theGlContext,
+                                           const GLsizei                 theSizeX,
+                                           const GLsizei                 theSizeY,
+                                           const OpenGl_ColorFormats&    theColorFormats,
+                                           const Handle(OpenGl_Texture)& theDepthStencilTexture,
+                                           const GLsizei                 theNbSamples)
+{
+  myColorFormats = theColorFormats;
+
+  OpenGl_TextureArray aTextures (myColorTextures);
+  if (!myColorTextures.IsEmpty())
+  {
+    for (OpenGl_TextureArray::Iterator aTextureIt (myColorTextures); aTextureIt.More(); aTextureIt.Next())
+    {
+      aTextureIt.Value()->Release (theGlContext.operator->());
+    }
+    myColorTextures.Clear();
+  }
+  for (Standard_Integer aLength = 0; aLength < myColorFormats.Length(); ++aLength)
+  {
+    myColorTextures.Append (aLength < aTextures.Length() ? aTextures.Value (aLength) : new OpenGl_Texture());
+  }
+
+  myDepthFormat = theDepthStencilTexture->GetFormat();
+  myNbSamples   = theNbSamples;
+  if (theGlContext->arbFBO == NULL)
+  {
+    return Standard_False;
+  }
+
+  // clean up previous state
+  Release (theGlContext.operator->());
+  if (myColorFormats.IsEmpty()
+   && myDepthFormat == 0)
+  {
+    return Standard_False;
+  }
+
+  myDepthStencilTexture = theDepthStencilTexture;
+  myIsOwnDepth  = false;
+  myIsOwnBuffer = true;
+
+  // setup viewport sizes as is
+  myVPSizeX = theSizeX;
+  myVPSizeY = theSizeY;
+  const Standard_Integer aSizeX = theSizeX > 0 ? theSizeX : 2;
+  const Standard_Integer aSizeY = theSizeY > 0 ? theSizeY : 2;
+
+  // Create the textures (will be used as color buffer and depth-stencil buffer)
+  if (theNbSamples != 0)
+  {
+    for (Standard_Integer aColorBufferIdx = 0; aColorBufferIdx < myColorTextures.Length(); ++aColorBufferIdx)
+    {
+      const Handle(OpenGl_Texture)& aColorTexture = myColorTextures (aColorBufferIdx);
+      const GLint                   aColorFormat  = myColorFormats  (aColorBufferIdx);
+      if (aColorFormat != 0
+      && !aColorTexture->Init2DMultisample (theGlContext, theNbSamples,
+                                            aColorFormat, aSizeX, aSizeY))
+      {
+        Release (theGlContext.operator->());
+        return Standard_False;
+      }
+    }
+  }
+  else
+  {
+    for (Standard_Integer aColorBufferIdx = 0; aColorBufferIdx < myColorTextures.Length(); ++aColorBufferIdx)
+    {
+      GLenum aPixelFormat = 0;
+      GLenum aDataType    = 0;
+      const Handle(OpenGl_Texture)& aColorTexture = myColorTextures (aColorBufferIdx);
+      const GLint                   aColorFormat  = myColorFormats  (aColorBufferIdx);
+      if (aColorFormat != 0
+      &&  getColorDataFormat (aColorFormat, aPixelFormat, aDataType)
+      && !aColorTexture->Init (theGlContext, aColorFormat,
+                               aPixelFormat, aDataType,
+                               aSizeX, aSizeY, Graphic3d_TOT_2D))
+      {
+        Release (theGlContext.operator->());
+        return Standard_False;
+      }
+    }
+  }
+
+  // Build FBO and setup it as texture
+  theGlContext->arbFBO->glGenFramebuffers (1, &myGlFBufferId);
+  theGlContext->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, myGlFBufferId);
+
+  for (Standard_Integer aColorBufferIdx = 0; aColorBufferIdx < myColorTextures.Length(); ++aColorBufferIdx)
+  {
+    const Handle(OpenGl_Texture)& aColorTexture = myColorTextures (aColorBufferIdx);
+    if (aColorTexture->IsValid())
+    {
+      theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + aColorBufferIdx,
+                                                    aColorTexture->GetTarget(), aColorTexture->TextureId(), 0);
+    }
+  }
+  if (myDepthStencilTexture->IsValid())
+  {
+  #ifdef GL_DEPTH_STENCIL_ATTACHMENT
+    theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
+                                                  myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
+  #else
+    theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
+                                                  myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
+    theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
+                                                  myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
+  #endif
+  }
+  if (theGlContext->arbFBO->glCheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
+  {
+    Release (theGlContext.operator->());
+    return Standard_False;
+  }
+
+  UnbindBuffer (theGlContext);
+  return Standard_True;
+}
+
+// =======================================================================
+// function : Init
+// purpose  :
+// =======================================================================
+Standard_Boolean OpenGl_FrameBuffer::Init (const Handle(OpenGl_Context)& theGlContext,
+                                           const GLsizei                 theSizeX,
+                                           const GLsizei                 theSizeY,
+                                           const OpenGl_ColorFormats&    theColorFormats,
+                                           const GLint                   theDepthFormat,
+                                           const GLsizei                 theNbSamples)
+{
+  myColorFormats = theColorFormats;
+
+  OpenGl_TextureArray aTextures (myColorTextures);
+  if (!myColorTextures.IsEmpty())
+  {
+    for (OpenGl_TextureArray::Iterator aTextureIt (myColorTextures); aTextureIt.More(); aTextureIt.Next())
+    {
+      aTextureIt.Value()->Release (theGlContext.operator->());
+    }
+    myColorTextures.Clear();
+  }
+  for (Standard_Integer aLength = 0; aLength < myColorFormats.Length(); ++aLength)
+  {
+    myColorTextures.Append (aLength < aTextures.Length() ? aTextures.Value (aLength) : new OpenGl_Texture());
+  }
+
   myDepthFormat = theDepthFormat;
   myNbSamples   = theNbSamples;
   if (theGlContext->arbFBO == NULL)
@@ -116,13 +333,14 @@ Standard_Boolean OpenGl_FrameBuffer::Init (const Handle(OpenGl_Context)& theGlCo
 
   // clean up previous state
   Release (theGlContext.operator->());
-  if (myColorFormat == 0
+  if (myColorFormats.IsEmpty()
    && myDepthFormat == 0)
   {
     return Standard_False;
   }
 
   myIsOwnBuffer = true;
+  myIsOwnDepth  = true;
 
   // setup viewport sizes as is
   myVPSizeX = theSizeX;
@@ -134,11 +352,16 @@ Standard_Boolean OpenGl_FrameBuffer::Init (const Handle(OpenGl_Context)& theGlCo
   // Create the textures (will be used as color buffer and depth-stencil buffer)
   if (theNbSamples != 0)
   {
-    if (myColorFormat != 0
-    && !myColorTexture       ->Init2DMultisample (theGlContext, theNbSamples, myColorFormat, aSizeX, aSizeY))
+    for (Standard_Integer aColorBufferIdx = 0; aColorBufferIdx < myColorTextures.Length(); ++aColorBufferIdx)
     {
-      Release (theGlContext.operator->());
-      return Standard_False;
+      const Handle(OpenGl_Texture)& aColorTexture = myColorTextures (aColorBufferIdx);
+      const GLint                   aColorFormat  = myColorFormats  (aColorBufferIdx);
+      if (aColorFormat != 0
+      && !aColorTexture->Init2DMultisample (theGlContext, theNbSamples, aColorFormat, aSizeX, aSizeY))
+      {
+        Release (theGlContext.operator->());
+        return Standard_False;
+      }
     }
     if (myDepthFormat != 0
     && !myDepthStencilTexture->Init2DMultisample (theGlContext, theNbSamples, myDepthFormat, aSizeX, aSizeY))
@@ -149,19 +372,26 @@ Standard_Boolean OpenGl_FrameBuffer::Init (const Handle(OpenGl_Context)& theGlCo
   }
   else
   {
-    if (myColorFormat != 0
-    && !myColorTexture->Init (theGlContext, myColorFormat,
-                              GL_RGBA, GL_UNSIGNED_BYTE,
-                              aSizeX, aSizeY, Graphic3d_TOT_2D))
+    GLenum aPixelFormat = 0;
+    GLenum aDataType    = 0;
+
+    for (Standard_Integer aColorBufferIdx = 0; aColorBufferIdx < myColorTextures.Length(); ++aColorBufferIdx)
     {
-      Release (theGlContext.operator->());
-      return Standard_False;
+      const Handle(OpenGl_Texture)& aColorTexture = myColorTextures (aColorBufferIdx);
+      const GLint                   aColorFormat  = myColorFormats  (aColorBufferIdx);
+      if (aColorFormat != 0
+      &&  getColorDataFormat (aColorFormat, aPixelFormat, aDataType)
+      && !aColorTexture->Init (theGlContext, aColorFormat,
+                               aPixelFormat, aDataType,
+                               aSizeX, aSizeY, Graphic3d_TOT_2D))
+      {
+        Release (theGlContext.operator->());
+        return Standard_False;
+      }
     }
 
     // extensions (GL_OES_packed_depth_stencil, GL_OES_depth_texture) + GL version might be used to determine supported formats
     // instead of just trying to create such texture
-    GLenum aPixelFormat = 0;
-    GLenum aDataType    = 0;
     if (myDepthFormat != 0
     &&  getDepthDataFormat (myDepthFormat, aPixelFormat, aDataType)
     && !myDepthStencilTexture->Init (theGlContext, myDepthFormat,
@@ -192,10 +422,14 @@ Standard_Boolean OpenGl_FrameBuffer::Init (const Handle(OpenGl_Context)& theGlCo
   // Build FBO and setup it as texture
   theGlContext->arbFBO->glGenFramebuffers (1, &myGlFBufferId);
   theGlContext->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, myGlFBufferId);
-  if (myColorTexture->IsValid())
+  for (Standard_Integer aColorBufferIdx = 0; aColorBufferIdx < myColorTextures.Length(); ++aColorBufferIdx)
   {
-    theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
-                                                  myColorTexture->GetTarget(), myColorTexture->TextureId(), 0);
+    const Handle(OpenGl_Texture)& aColorTexture = myColorTextures (aColorBufferIdx);
+    if (aColorTexture->IsValid())
+    {
+      theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + aColorBufferIdx,
+                                                    aColorTexture->GetTarget(), aColorTexture->TextureId(), 0);
+    }
   }
   if (myDepthStencilTexture->IsValid())
   {
@@ -235,7 +469,7 @@ Standard_Boolean OpenGl_FrameBuffer::Init (const Handle(OpenGl_Context)& theGlCo
 }
 
 // =======================================================================
-// function : Init
+// function : InitLazy
 // purpose  :
 // =======================================================================
 Standard_Boolean OpenGl_FrameBuffer::InitLazy (const Handle(OpenGl_Context)& theGlContext,
@@ -245,16 +479,34 @@ Standard_Boolean OpenGl_FrameBuffer::InitLazy (const Handle(OpenGl_Context)& the
                                                const GLint                   theDepthFormat,
                                                const GLsizei                 theNbSamples)
 {
-  if (myVPSizeX     == theViewportSizeX
-   && myVPSizeY     == theViewportSizeY
-   && myColorFormat == theColorFormat
-   && myDepthFormat == theDepthFormat
-   && myNbSamples   == theNbSamples)
+  OpenGl_ColorFormats aColorFormats;
+
+  aColorFormats.Append (theColorFormat);
+
+  return InitLazy (theGlContext, theViewportSizeX, theViewportSizeY, aColorFormats, theDepthFormat, theNbSamples);
+}
+
+// =======================================================================
+// function : InitLazy
+// purpose  :
+// =======================================================================
+Standard_Boolean OpenGl_FrameBuffer::InitLazy (const Handle(OpenGl_Context)& theGlContext,
+                                               const GLsizei                 theViewportSizeX,
+                                               const GLsizei                 theViewportSizeY,
+                                               const OpenGl_ColorFormats&    theColorFormats,
+                                               const GLint                   theDepthFormat,
+                                               const GLsizei                 theNbSamples)
+{
+  if (myVPSizeX      == theViewportSizeX
+   && myVPSizeY      == theViewportSizeY
+   && myColorFormats == theColorFormats
+   && myDepthFormat  == theDepthFormat
+   && myNbSamples    == theNbSamples)
   {
     return IsValid();
   }
 
-  return Init (theGlContext, theViewportSizeX, theViewportSizeY, theColorFormat, theDepthFormat, theNbSamples);
+  return Init (theGlContext, theViewportSizeX, theViewportSizeY, theColorFormats, theDepthFormat, theNbSamples);
 }
 
 // =======================================================================
@@ -268,7 +520,19 @@ Standard_Boolean OpenGl_FrameBuffer::InitWithRB (const Handle(OpenGl_Context)& t
                                                  const GLint                   theDepthFormat,
                                                  const GLuint                  theColorRBufferFromWindow)
 {
-  myColorFormat = theColorFormat;
+  myColorFormats.Clear();
+  myColorFormats.Append (theColorFormat);
+  if (!myColorTextures.IsEmpty())
+  {
+    Handle(OpenGl_Texture) aTexutre = myColorTextures.First();
+    for (OpenGl_TextureArray::Iterator aTextureIt (myColorTextures); aTextureIt.More(); aTextureIt.Next())
+    {
+      aTextureIt.Value()->Release (theGlCtx.operator->());
+    }
+    myColorTextures.Clear();
+    myColorTextures.Append (aTexutre);
+  }
+
   myDepthFormat = theDepthFormat;
   myNbSamples   = 0;
   if (theGlCtx->arbFBO == NULL)
@@ -280,6 +544,7 @@ Standard_Boolean OpenGl_FrameBuffer::InitWithRB (const Handle(OpenGl_Context)& t
   Release (theGlCtx.operator->());
 
   myIsOwnBuffer = true;
+  myIsOwnDepth  = true;
 
   // setup viewport sizes as is
   myVPSizeX = theSizeX;
@@ -292,11 +557,11 @@ Standard_Boolean OpenGl_FrameBuffer::InitWithRB (const Handle(OpenGl_Context)& t
   {
     myGlColorRBufferId = theColorRBufferFromWindow;
   }
-  else if (myColorFormat != 0)
+  else if (theColorFormat != 0)
   {
     theGlCtx->arbFBO->glGenRenderbuffers (1, &myGlColorRBufferId);
     theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, myGlColorRBufferId);
-    theGlCtx->arbFBO->glRenderbufferStorage (GL_RENDERBUFFER, myColorFormat, aSizeX, aSizeY);
+    theGlCtx->arbFBO->glRenderbufferStorage (GL_RENDERBUFFER, theColorFormat, aSizeX, aSizeY);
   }
 
   bool hasStencilRB = false;
@@ -375,6 +640,7 @@ Standard_Boolean OpenGl_FrameBuffer::InitWrapper (const Handle(OpenGl_Context)&
 
   myGlFBufferId = GLuint(anFbo);
   myIsOwnBuffer = false;
+  myIsOwnDepth  = false;
   if (aColorType == GL_RENDERBUFFER)
   {
     theGlCtx->arbFBO->glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &aColorId);
@@ -448,8 +714,16 @@ void OpenGl_FrameBuffer::Release (OpenGl_Context* theGlCtx)
     myIsOwnBuffer      = false;
   }
 
-  myColorTexture->Release (theGlCtx);
-  myDepthStencilTexture->Release (theGlCtx);
+  for (Standard_Integer aColorBufferIdx = 0; aColorBufferIdx < myColorTextures.Length(); ++aColorBufferIdx)
+  {
+    myColorTextures (aColorBufferIdx)->Release (theGlCtx);
+  }
+
+  if (myIsOwnDepth)
+  {
+    myDepthStencilTexture->Release (theGlCtx);
+    myIsOwnDepth = false;
+  }
 
   myVPSizeX = 0;
   myVPSizeY = 0;
index 6baf4ff..1ef79d0 100644 (file)
 #include <OpenGl_Resource.hxx>
 #include <OpenGl_Texture.hxx>
 
+#include <NCollection_Vector.hxx>
+
 class OpenGl_FrameBuffer;
 DEFINE_STANDARD_HANDLE(OpenGl_FrameBuffer, OpenGl_Resource)
 
+//! Short declaration of useful collection types.
+typedef NCollection_Vector<GLint> OpenGl_ColorFormats;
+
 //! Class implements FrameBuffer Object (FBO) resource
 //! intended for off-screen rendering.
 class OpenGl_FrameBuffer : public OpenGl_Resource
@@ -50,10 +55,16 @@ public:
     return myNbSamples;
   }
 
+  //! Number of color buffers.
+  GLsizei NbColorBuffers() const
+  {
+    return myColorTextures.Length();
+  }
+
   //! Return true if FBO has been created with color attachment.
   bool HasColor() const
   {
-    return myColorFormat != 0;
+    return !myColorFormats.IsEmpty();
   }
 
   //! Return true if FBO has been created with depth attachment.
@@ -65,13 +76,13 @@ public:
   //! Textures width.
   GLsizei GetSizeX() const
   {
-    return myColorTexture->SizeX();
+    return myColorTextures (0)->SizeX();
   }
 
   //! Textures height.
   GLsizei GetSizeY() const
   {
-    return myColorTexture->SizeY();
+    return myColorTextures (0)->SizeY();
   }
 
   //! Viewport width.
@@ -92,6 +103,21 @@ public:
     return isValidFrameBuffer();
   }
 
+  //! Initialize FBO for rendering into single/multiple color buffer and depth textures.
+  //! @param theGlCtx               currently bound OpenGL context
+  //! @param theSizeX               texture width
+  //! @param theSizeY               texture height
+  //! @param theColorFormats        list of color texture sized format (0 means no color attachment), e.g. GL_RGBA8
+  //! @param theDepthStencilTexture depth-stencil texture
+  //! @param theNbSamples           MSAA number of samples (0 means normal texture)
+  //! @return true on success
+  Standard_EXPORT Standard_Boolean Init (const Handle(OpenGl_Context)& theGlCtx,
+                                         const GLsizei                 theSizeX,
+                                         const GLsizei                 theSizeY,
+                                         const OpenGl_ColorFormats&    theColorFormats,
+                                         const Handle(OpenGl_Texture)& theDepthStencilTexture,
+                                         const GLsizei                 theNbSamples = 0);
+
   //! Initialize FBO for rendering into textures.
   //! @param theGlCtx       currently bound OpenGL context
   //! @param theSizeX       texture width
@@ -107,6 +133,21 @@ public:
                                          const GLint                   theDepthFormat,
                                          const GLsizei                 theNbSamples = 0);
 
+  //! Initialize FBO for rendering into single/multiple color buffer and depth textures.
+  //! @param theGlCtx        currently bound OpenGL context
+  //! @param theSizeX        texture width
+  //! @param theSizeY        texture height
+  //! @param theColorFormats list of color texture sized format (0 means no color attachment), e.g. GL_RGBA8
+  //! @param theDepthFormat  depth-stencil texture sized format (0 means no depth attachment), e.g. GL_DEPTH24_STENCIL8
+  //! @param theNbSamples    MSAA number of samples (0 means normal texture)
+  //! @return true on success
+  Standard_EXPORT Standard_Boolean Init (const Handle(OpenGl_Context)& theGlCtx,
+                                         const GLsizei                 theSizeX,
+                                         const GLsizei                 theSizeY,
+                                         const OpenGl_ColorFormats&    theColorFormats,
+                                         const GLint                   theDepthFormat,
+                                         const GLsizei                 theNbSamples = 0);
+
   //! (Re-)initialize FBO with specified dimensions.
   Standard_EXPORT Standard_Boolean InitLazy (const Handle(OpenGl_Context)& theGlCtx,
                                              const GLsizei                 theViewportSizeX,
@@ -115,11 +156,19 @@ public:
                                              const GLint                   theDepthFormat,
                                              const GLsizei                 theNbSamples = 0);
 
+  //! (Re-)initialize FBO with specified dimensions.
+  Standard_EXPORT Standard_Boolean InitLazy (const Handle(OpenGl_Context)& theGlCtx,
+                                             const GLsizei                 theViewportSizeX,
+                                             const GLsizei                 theViewportSizeY,
+                                             const OpenGl_ColorFormats&    theColorFormats,
+                                             const GLint                   theDepthFormat,
+                                             const GLsizei                 theNbSamples = 0);
+
   //! (Re-)initialize FBO with properties taken from another FBO.
   Standard_Boolean InitLazy (const Handle(OpenGl_Context)& theGlCtx,
                              const OpenGl_FrameBuffer&     theFbo)
   {
-    return InitLazy (theGlCtx, theFbo.myVPSizeX, theFbo.myVPSizeY, theFbo.myColorFormat, theFbo.myDepthFormat, theFbo.myNbSamples);
+    return InitLazy (theGlCtx, theFbo.myVPSizeX, theFbo.myVPSizeY, theFbo.myColorFormats, theFbo.myDepthFormat, theFbo.myNbSamples);
   }
 
   //! (Re-)initialize FBO with specified dimensions.
@@ -160,10 +209,10 @@ public:
   //! Unbind frame buffer.
   Standard_EXPORT virtual void UnbindBuffer (const Handle(OpenGl_Context)& theGlCtx);
 
-  //! Returns the color texture.
-  inline const Handle(OpenGl_Texture)& ColorTexture() const
+  //! Returns the color texture for the given color buffer index.
+  inline const Handle(OpenGl_Texture)& ColorTexture (const GLint theColorBufferIndex = 0) const
   {
-    return myColorTexture;
+    return myColorTextures (theColorBufferIndex);
   }
 
   //! Returns the depth-stencil texture.
@@ -191,18 +240,23 @@ protected:
     return myGlFBufferId != NO_FRAMEBUFFER;
   }
 
+protected:
+
+  typedef NCollection_Vector<Handle(OpenGl_Texture)> OpenGl_TextureArray;
+
 protected:
 
   GLsizei                myVPSizeX;             //!< viewport width  (should be <= texture width)
   GLsizei                myVPSizeY;             //!< viewport height (should be <= texture height)
   GLsizei                myNbSamples;           //!< number of MSAA samples
-  GLint                  myColorFormat;         //!< sized format for color         texture, GL_RGBA8 by default
+  OpenGl_ColorFormats    myColorFormats;        //!< sized format for color         texture, GL_RGBA8 by default
   GLint                  myDepthFormat;         //!< sized format for depth-stencil texture, GL_DEPTH24_STENCIL8 by default
   GLuint                 myGlFBufferId;         //!< FBO object ID
   GLuint                 myGlColorRBufferId;    //!< color         Render Buffer object (alternative to myColorTexture)
   GLuint                 myGlDepthRBufferId;    //!< depth-stencil Render Buffer object (alternative to myDepthStencilTexture)
   bool                   myIsOwnBuffer;         //!< flag indicating that FBO should be deallocated by this class
-  Handle(OpenGl_Texture) myColorTexture;        //!< color texture object
+  bool                   myIsOwnDepth;          //!< flag indicating that FBO should be deallocated by this class
+  OpenGl_TextureArray    myColorTextures;       //!< color texture objects
   Handle(OpenGl_Texture) myDepthStencilTexture; //!< depth-stencil texture object
 
 public:
index cfb31ce..daebf8e 100644 (file)
   #define GL_DEBUG_SEVERITY_HIGH        0x9146
   #define GL_DEBUG_SEVERITY_MEDIUM      0x9147
   #define GL_DEBUG_SEVERITY_LOW         0x9148
+
+  // GL_ARB_draw_buffers (GL_EXT_draw_buffers) extension
+  #define GL_MAX_COLOR_ATTACHMENTS      0x8CDF
+  #define GL_MAX_DRAW_BUFFERS           0x8824
+
+  // OES_texture_half_float
+  #define GL_HALF_FLOAT                 0x8D61
 #endif
 
 #if !defined(HAVE_EGL) && (defined(__ANDROID__) || defined(__QNX__) || defined(HAVE_GLES2) || defined(OCCT_UWP))
@@ -752,6 +759,9 @@ public: //! @name OpenGL ES 3.0
   typedef void (*glTexImage3D_t)(GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid* data);
   glTexImage3D_t glTexImage3D;
 
+  typedef void (*glDrawBuffers_t)(GLsizei n, const GLenum* bufs);
+  glDrawBuffers_t glDrawBuffers;
+
 public: //! @name OpenGL ES 3.1
 
   typedef void (*glTexStorage2DMultisample_t)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations);
index a305748..d3c178a 100644 (file)
@@ -415,6 +415,10 @@ Standard_Integer OpenGl_GraphicDriver::InquireLimit (const Graphic3d_TypeOfLimit
       return (!aCtx.IsNull() && aCtx->HasRayTracingTextures()) ? 1 : 0;
     case Graphic3d_TypeOfLimit_HasRayTracingAdaptiveSampling:
       return (!aCtx.IsNull() && aCtx->HasRayTracingAdaptiveSampling()) ? 1 : 0;
+    case Graphic3d_TypeOfLimit_HasBlendedOit:
+      return (!aCtx.IsNull() && aCtx->hasDrawBuffers && (aCtx->hasFloatBuffer || aCtx->hasHalfFloatBuffer)) ? 1 : 0;
+    case Graphic3d_TypeOfLimit_HasBlendedOitMsaa:
+      return (!aCtx.IsNull() && aCtx->hasSampleVariables && (InquireLimit (Graphic3d_TypeOfLimit_HasBlendedOit) == 1)) ? 1 : 0;
     case Graphic3d_TypeOfLimit_NB:
       return 0;
   }
index c9bb46b..d1487d1 100644 (file)
@@ -687,7 +687,7 @@ void OpenGl_Layer::Render (const Handle(OpenGl_Workspace)&   theWorkspace,
   theWorkspace->SetPolygonOffset (myLayerSettings.PolygonOffset());
 
   // handle depth write
-  theWorkspace->UseDepthWrite() = myLayerSettings.ToEnableDepthWrite();
+  theWorkspace->UseDepthWrite() = myLayerSettings.ToEnableDepthWrite() && theDefaultSettings.DepthMask == GL_TRUE;
   glDepthMask (theWorkspace->UseDepthWrite() ? GL_TRUE : GL_FALSE);
 
   const Standard_Boolean hasLocalCS = !myLayerSettings.OriginTransformation().IsNull();
index 5f6c619..f022bcf 100644 (file)
 // Alternatively, this file may be used under the terms of Open CASCADE
 // commercial license or contractual agreement.
 
-#include <OpenGl_GlCore11.hxx>
+#include <OpenGl_GlCore15.hxx>
 
+#include <OpenGl_FrameBuffer.hxx>
 #include <OpenGl_LayerList.hxx>
+#include <OpenGl_ShaderManager.hxx>
 #include <OpenGl_Structure.hxx>
+#include <OpenGl_VertexBuffer.hxx>
+#include <OpenGl_View.hxx>
 #include <OpenGl_Workspace.hxx>
 
 #include <Graphic3d_GraphicDriver.hxx>
@@ -31,7 +35,9 @@ OpenGl_LayerList::OpenGl_LayerList (const Standard_Integer theNbPriorities)
   myNbPriorities (theNbPriorities),
   myNbStructures (0),
   myImmediateNbStructures (0),
-  myModifStateOfRaytraceable (0)
+  myModifStateOfRaytraceable (0),
+  myRenderOpaqueFilter (new OpenGl_OpaqueFilter()),
+  myRenderTranspFilter (new OpenGl_TransparentFilter())
 {
   // insert default priority layers
   myLayers.Append (OpenGl_Layer (myNbPriorities));
@@ -50,6 +56,8 @@ OpenGl_LayerList::OpenGl_LayerList (const Standard_Integer theNbPriorities)
   myLayerIds.Bind (Graphic3d_ZLayerId_TopOSD,  myLayers.Upper());
 
   myDefaultLayerIndex = myLayerIds.Find (Graphic3d_ZLayerId_Default);
+
+  myTransparentToProcess.Allocate (myLayers.Length());
 }
 
 //=======================================================================
@@ -76,6 +84,8 @@ void OpenGl_LayerList::AddLayer (const Graphic3d_ZLayerId theLayerId)
   // add the new layer
   myLayers.Append (OpenGl_Layer (myNbPriorities));
   myLayerIds.Bind (theLayerId, myLayers.Length());
+
+  myTransparentToProcess.Allocate (myLayers.Length());
 }
 
 //=======================================================================
@@ -128,6 +138,8 @@ void OpenGl_LayerList::RemoveLayer (const Graphic3d_ZLayerId theLayerId)
   }
 
   myDefaultLayerIndex = myLayerIds.Find (Graphic3d_ZLayerId_Default);
+
+  myTransparentToProcess.Allocate (myLayers.Length());
 }
 
 //=======================================================================
@@ -378,17 +390,38 @@ void OpenGl_LayerList::SetLayerSettings (const Graphic3d_ZLayerId        theLaye
 //=======================================================================
 void OpenGl_LayerList::Render (const Handle(OpenGl_Workspace)& theWorkspace,
                                const Standard_Boolean          theToDrawImmediate,
-                               const OpenGl_LayerFilter        theLayersToProcess) const
+                               const OpenGl_LayerFilter        theLayersToProcess,
+                               OpenGl_FrameBuffer*             theReadDrawFbo,
+                               OpenGl_FrameBuffer*             theOitAccumFbo) const
 {
+  // Remember global settings for glDepth function and write mask.
   OpenGl_GlobalLayerSettings aDefaultSettings;
 
   const Handle(OpenGl_Context)& aCtx = theWorkspace->GetGlContext();
   aCtx->core11fwd->glGetIntegerv (GL_DEPTH_FUNC,      &aDefaultSettings.DepthFunc);
   aCtx->core11fwd->glGetBooleanv (GL_DEPTH_WRITEMASK, &aDefaultSettings.DepthMask);
 
+  // Two render filters are used to support transparency draw. Opaque filter accepts
+  // only non-transparent OpenGl elements of a layer and counts number of skipped
+  // transparent ones. If the counter has positive value the layer is added into
+  // transparency post-processing stack. At the end of drawing or once the depth
+  // buffer is to be cleared the layers in the stack should be drawn using
+  // blending and depth mask settings and another transparency filter which accepts
+  // only transparent OpenGl elements of a layer. The stack <myTransparentToProcess>
+  // was preallocated before going into this method and has enough space to keep
+  // maximum number of references to layers, therefore it will not increase memory
+  // fragmentation during regular rendering.
+  const Handle(OpenGl_RenderFilter) aPrevFilter = theWorkspace->GetRenderFilter();
+  myRenderOpaqueFilter->SetPreviousFilter (aPrevFilter);
+  myRenderTranspFilter->SetPreviousFilter (aPrevFilter);
+  theWorkspace->SetRenderFilter (myRenderOpaqueFilter);
+
+  myTransparentToProcess.Clear();
+
+  OpenGl_LayerStack::iterator aStackIter (myTransparentToProcess.Origin());
   Standard_Integer aSeqId = myLayers.Lower();
   bool toClearDepth = false;
-  for (OpenGl_SequenceOfLayers::Iterator anIts (myLayers); anIts.More(); anIts.Next(), ++aSeqId)
+  for (OpenGl_SequenceOfLayers::Iterator aLayerIter (myLayers); aLayerIter.More(); aLayerIter.Next(), ++aSeqId)
   {
     if (theLayersToProcess == OpenGl_LF_Bottom)
     {
@@ -403,28 +436,54 @@ void OpenGl_LayerList::Render (const Handle(OpenGl_Workspace)& theWorkspace,
       if (aSeqId != myDefaultLayerIndex) continue;
     }
 
-    const OpenGl_Layer& aLayer = anIts.Value();
+    const OpenGl_Layer& aLayer = aLayerIter.Value();
     if (aLayer.IsImmediate() != theToDrawImmediate)
     {
       continue;
     }
     else if (aLayer.NbStructures() < 1)
     {
-      // make sure to clear depth of previous layers even if layer has no structures
+      // Make sure to clear depth of previous layers even if layer has no structures.
       toClearDepth = toClearDepth || aLayer.LayerSettings().ToClearDepth();
       continue;
     }
 
-    // depth buffers
+    // At this point the depth buffer may be set to clear by
+    // previous configuration of layers or configuration of the
+    // current layer. Additional rendering pass to handle transparent
+    // elements of recently drawn layers require use of current depth
+    // buffer so we put remaining layers for processing as one bunch before
+    // erasing the depth buffer.
     if (toClearDepth
      || aLayer.LayerSettings().ToClearDepth())
     {
+      if (!myTransparentToProcess.IsEmpty())
+      {
+        renderTransparent (theWorkspace, aStackIter, aDefaultSettings, theReadDrawFbo, theOitAccumFbo);
+      }
+
       toClearDepth = false;
       glDepthMask (GL_TRUE);
       glClear (GL_DEPTH_BUFFER_BIT);
     }
 
+    // Render opaque OpenGl elements of a layer and count the number of skipped.
+    // If a layer has skipped (e.g. transparent) elements it should be added into
+    // the transparency post-processing stack.
+    myRenderOpaqueFilter->SetSkippedCounter (0);
+
     aLayer.Render (theWorkspace, aDefaultSettings);
+
+    if (myRenderOpaqueFilter->NbSkipped() > 0)
+    {
+      myTransparentToProcess.Push (&aLayer);
+    }
+  }
+
+  // Before finishing process the remaining collected layers with transparency.
+  if (!myTransparentToProcess.IsEmpty())
+  {
+    renderTransparent (theWorkspace, aStackIter, aDefaultSettings, theReadDrawFbo, theOitAccumFbo);
   }
 
   if (toClearDepth)
@@ -435,4 +494,206 @@ void OpenGl_LayerList::Render (const Handle(OpenGl_Workspace)& theWorkspace,
 
   aCtx->core11fwd->glDepthMask (aDefaultSettings.DepthMask);
   aCtx->core11fwd->glDepthFunc (aDefaultSettings.DepthFunc);
+
+  theWorkspace->SetRenderFilter (aPrevFilter);
+}
+
+//=======================================================================
+//function : renderTransparent
+//purpose  : Render transparent objects using blending operator.
+//=======================================================================
+void OpenGl_LayerList::renderTransparent (const Handle(OpenGl_Workspace)&   theWorkspace,
+                                          OpenGl_LayerStack::iterator&      theLayerIter,
+                                          const OpenGl_GlobalLayerSettings& theGlobalSettings,
+                                          OpenGl_FrameBuffer*               theReadDrawFbo,
+                                          OpenGl_FrameBuffer*               theOitAccumFbo) const
+{
+  // Blended order-independent transparency algorithm require several preconditions
+  // to be enabled. It should be requested by user, at least two outputs from
+  // fragment shader should be supported by GPU, so is the given framebuffer
+  // should contain two additional color buffers to handle accumulated color channels,
+  // blended alpha channel and weight factors - these accumulation buffers are required
+  // to implement commuting blend operator (at least OpenGl 2.0 should be available).
+  const bool isEnabledOit = theOitAccumFbo != NULL
+                         && theOitAccumFbo->NbColorBuffers() >= 2
+                         && theOitAccumFbo->ColorTexture (0)->IsValid()
+                         && theOitAccumFbo->ColorTexture (1)->IsValid();
+
+  // Check if current iterator has already reached the end of the stack.
+  // This should happen if no additional layers has been added to
+  // the processing stack after last transparency pass.
+  if (theLayerIter == myTransparentToProcess.Back())
+  {
+    return;
+  }
+
+  const Handle(OpenGl_Context) aCtx            = theWorkspace->GetGlContext();
+  const Handle(OpenGl_ShaderManager)& aManager = aCtx->ShaderManager();
+  OpenGl_View* aView = theWorkspace->View();
+  const float aDepthFactor =  aView != NULL ? aView->RenderingParams().OitDepthFactor : 0.0f;
+
+  theWorkspace->SetRenderFilter (myRenderTranspFilter);
+
+  aCtx->core11fwd->glEnable (GL_BLEND);
+
+  if (isEnabledOit)
+  {
+    aManager->SetOitState (true, aDepthFactor);
+
+    theOitAccumFbo->BindBuffer (aCtx);
+
+    static const Standard_Integer aDrawBuffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT0 + 1 };
+    aCtx->SetDrawBuffers (2, aDrawBuffers);
+    aCtx->core11fwd->glClearColor (0.0f, 0.0f, 0.0f, 1.0f);
+    aCtx->core11fwd->glClear (GL_COLOR_BUFFER_BIT);
+    aCtx->core15fwd->glBlendFuncSeparate (GL_ONE, GL_ONE, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA);
+  }
+  else
+  {
+    aCtx->core11fwd->glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+  }
+
+  // During blended order-independent transparency pass the depth test
+  // should be enabled to discard fragments covered by opaque geometry
+  // and depth writing should be disabled, because transparent fragments
+  // overal each other with non unitary coverage factor.
+  OpenGl_GlobalLayerSettings aGlobalSettings = theGlobalSettings;
+  aGlobalSettings.DepthMask   = GL_FALSE;
+  aCtx->core11fwd->glDepthMask (GL_FALSE);
+
+  for (; theLayerIter != myTransparentToProcess.Back(); ++theLayerIter)
+  {
+    (*theLayerIter)->Render (theWorkspace, aGlobalSettings);
+  }
+
+  // Revert state of rendering.
+  if (isEnabledOit)
+  {
+    aManager->SetOitState (false, aDepthFactor);
+    theOitAccumFbo->UnbindBuffer (aCtx);
+    if (theReadDrawFbo)
+    {
+      theReadDrawFbo->BindBuffer (aCtx);
+    }
+
+    static const Standard_Integer aDrawBuffers[] = { GL_COLOR_ATTACHMENT0 };
+    aCtx->SetDrawBuffers (1, aDrawBuffers);
+  }
+
+  theWorkspace->SetRenderFilter (myRenderOpaqueFilter);
+  if (isEnabledOit)
+  {
+    const Standard_Boolean isMSAA = theReadDrawFbo && theReadDrawFbo->NbSamples() > 0;
+    OpenGl_VertexBuffer*   aVerts = theWorkspace->View()->initBlitQuad (Standard_False);
+    if (aVerts->IsValid() && aManager->BindOitCompositingProgram (isMSAA))
+    {
+      aCtx->core11fwd->glDepthFunc (GL_ALWAYS);
+      aCtx->core11fwd->glDepthMask (GL_FALSE);
+
+      // Bind full screen quad buffer and framebuffer resources.
+      aVerts->BindVertexAttrib (aCtx, Graphic3d_TOA_POS);
+
+      const Handle(OpenGl_Texture) aTextureBack = theWorkspace->DisableTexture();
+
+      theOitAccumFbo->ColorTexture (0)->Bind (aCtx, GL_TEXTURE0 + 0);
+      theOitAccumFbo->ColorTexture (1)->Bind (aCtx, GL_TEXTURE0 + 1);
+
+      // Draw full screen quad with special shader to compose the buffers.
+      aCtx->core11fwd->glBlendFunc (GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA);
+      aCtx->core11fwd->glDrawArrays (GL_TRIANGLE_STRIP, 0, 4);
+
+      // Unbind OpenGL texture objects and shader program.
+      aVerts->UnbindVertexAttrib (aCtx, Graphic3d_TOA_POS);
+      theOitAccumFbo->ColorTexture (0)->Unbind (aCtx, GL_TEXTURE0 + 0);
+      theOitAccumFbo->ColorTexture (1)->Unbind (aCtx, GL_TEXTURE0 + 1);
+      aCtx->BindProgram (NULL);
+
+      if (!aTextureBack.IsNull())
+      {
+        theWorkspace->EnableTexture (aTextureBack);
+      }
+    }
+    else
+    {
+      aCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
+                         "Initialization of OIT compositing pass has failed.\n"
+                         "  Blended order-independent transparency will not be available.\n");
+      if (aView != NULL)
+      {
+        Standard_Boolean& aOITFlag = isMSAA ? aView->myToDisableOITMSAA : aView->myToDisableOIT;
+        aOITFlag = Standard_True;
+      }
+    }
+  }
+
+  aCtx->core11fwd->glDisable (GL_BLEND);
+  aCtx->core11fwd->glBlendFunc (GL_ONE, GL_ZERO);
+  aCtx->core11fwd->glDepthMask (theGlobalSettings.DepthMask);
+  aCtx->core11fwd->glDepthFunc (theGlobalSettings.DepthFunc);
+}
+
+//=======================================================================
+//class    : OpenGl_OpaqueFilter
+//function : ShouldRender
+//purpose  : Checks whether the element should be rendered or skipped.
+//=======================================================================
+Standard_Boolean OpenGl_LayerList::OpenGl_OpaqueFilter::ShouldRender (const Handle(OpenGl_Workspace)& theWorkspace,
+                                                                      const OpenGl_Element*           theGlElement)
+{
+  if (!myFilter.IsNull()
+   && !myFilter->ShouldRender (theWorkspace, theGlElement))
+  {
+    return Standard_False;
+  }
+
+  const OpenGl_PrimitiveArray* aPArray = dynamic_cast<const OpenGl_PrimitiveArray*> (theGlElement);
+  if (aPArray == NULL
+   || aPArray->DrawMode() < OpenGl_PrimitiveArray::THE_FILLPRIM_FROM
+   || aPArray->DrawMode() > OpenGl_PrimitiveArray::THE_FILLPRIM_TO)
+  {
+    return Standard_True;
+  }
+
+  Standard_ShortReal aFront = 0.f;
+  Standard_ShortReal aBack  = 0.f;
+
+  if (OpenGl_Context::CheckIsTransparent (theWorkspace->AspectFace(),
+                                          theWorkspace->HighlightStyle(),
+                                          aFront, aBack))
+  {
+    ++mySkippedCounter;
+    return Standard_False;
+  }
+
+  return Standard_True;
+}
+
+//=======================================================================
+//class    : OpenGl_TransparentFilter
+//function : ShouldRender
+//purpose  : Checks whether the element should be rendered or skipped.
+//=======================================================================
+Standard_Boolean OpenGl_LayerList::OpenGl_TransparentFilter::ShouldRender (const Handle(OpenGl_Workspace)& theWorkspace,
+                                                                           const OpenGl_Element*           theGlElement)
+{
+  if (!myFilter.IsNull()
+   && !myFilter->ShouldRender (theWorkspace, theGlElement))
+  {
+    return Standard_False;
+  }
+
+  const OpenGl_PrimitiveArray* aPArray = dynamic_cast<const OpenGl_PrimitiveArray*> (theGlElement);
+  if (aPArray == NULL
+   || aPArray->DrawMode() < OpenGl_PrimitiveArray::THE_FILLPRIM_FROM
+   || aPArray->DrawMode() > OpenGl_PrimitiveArray::THE_FILLPRIM_TO)
+  {
+    return dynamic_cast<const OpenGl_AspectFace*> (theGlElement) != NULL;
+  }
+
+  Standard_ShortReal aFront = 0.f;
+  Standard_ShortReal aBack  = 0.f;
+
+  return OpenGl_Context::CheckIsTransparent (theWorkspace->AspectFace(),
+                                             theWorkspace->HighlightStyle(),
+                                             aFront, aBack);
 }
index cd45cc3..25d0ca0 100644 (file)
@@ -19,6 +19,8 @@
 #include <OpenGl_Layer.hxx>
 #include <OpenGl_LayerFilter.hxx>
 
+#include <NCollection_Array1.hxx>
+#include <NCollection_Handle.hxx>
 #include <NCollection_Sequence.hxx>
 #include <NCollection_DataMap.hxx>
 
@@ -89,7 +91,9 @@ public:
   //! Render this element
   void Render (const Handle(OpenGl_Workspace)& theWorkspace,
                const Standard_Boolean          theToDrawImmediate,
-               const OpenGl_LayerFilter        theLayersToProcess) const;
+               const OpenGl_LayerFilter        theLayersToProcess,
+               OpenGl_FrameBuffer*             theReadDrawFbo,
+               OpenGl_FrameBuffer*             theOitAccumFbo) const;
 
   //! Returns the set of OpenGL Z-layers.
   const OpenGl_SequenceOfLayers& Layers() const { return myLayers; }
@@ -104,6 +108,132 @@ public:
   //! Returns structure modification state (for ray-tracing).
   Standard_Size ModificationStateOfRaytracable() const { return myModifStateOfRaytraceable; }
 
+protected:
+
+  //! Filter of TKOpenGl elements for processing only shading geometry and
+  //! for collecting number of skipped elements to an external counter.
+  class OpenGl_OpaqueFilter : public OpenGl_RenderFilter
+  {
+  public:
+
+    //! Constructor.
+    //! @param thePrevFilter [in] the previously active filter that should have additive effect.
+    OpenGl_OpaqueFilter() : mySkippedCounter (0) {}
+
+    //! Sets the current active filter in workspace.
+    //! @param thePrevFilter [in] the previously active filter that should have additive effect.
+    void SetPreviousFilter (const Handle(OpenGl_RenderFilter)& thePrevFitler) { myFilter = thePrevFitler; }
+
+    //! Sets the value of the skipped elements counter.
+    void SetSkippedCounter (const Standard_Size theCounter) { mySkippedCounter = theCounter; }
+
+    //! Returns number of skipped elements.
+    Standard_Size NbSkipped() const { return mySkippedCounter; }
+
+    //! Checks whether the element should be rendered or skipped.
+    //! @param theWorkspace [in] the currently used workspace for rendering.
+    //! @param theGlElement [in] the TKOpenGl rendering queue element that should be checked before streaming to GPU.
+    Standard_EXPORT virtual Standard_Boolean ShouldRender (const Handle(OpenGl_Workspace)& theWorkspace,
+                                                           const OpenGl_Element*           theGlElement) Standard_OVERRIDE;
+
+    DEFINE_STANDARD_RTTI_INLINE (OpenGl_OpaqueFilter, OpenGl_RenderFilter)
+
+  private:
+
+    Standard_Size mySkippedCounter;   //!< Counter of skipped elements.
+    Handle(OpenGl_RenderFilter) myFilter; //!< Previous active filter that should be combined.
+  };
+
+  //! Filter of TKOpenGl elements for keeping only shading geometry with transparency.
+  class OpenGl_TransparentFilter : public OpenGl_RenderFilter
+  {
+  public:
+
+    //! Constructor.
+    OpenGl_TransparentFilter() {}
+
+    //! Sets the current active filter in workspace.
+    //! @param thePrevFilter [in] the previously active filter that should have additive effect.
+    void SetPreviousFilter (const Handle(OpenGl_RenderFilter)& thePrevFitler) { myFilter = thePrevFitler; }
+
+    //! Checks whether the element should be rendered or skipped.
+    //! @param theWorkspace [in] the currently used workspace for rendering.
+    //! @param theGlElement [in] the TKOpenGl rendering queue element that should be checked before streaming to GPU.
+    Standard_EXPORT virtual Standard_Boolean ShouldRender (const Handle(OpenGl_Workspace)& theWorkspace,
+                                                           const OpenGl_Element*           theGlElement) Standard_OVERRIDE;
+
+    DEFINE_STANDARD_RTTI_INLINE (OpenGl_TransparentFilter, OpenGl_RenderFilter)
+
+  private:
+
+    Handle(OpenGl_RenderFilter) myFilter; //!< Previous active filter that should be combined.
+  };
+
+  //! Stack of references to existing layers of predefined maximum size.
+  class OpenGl_LayerStack
+  {
+  public:
+    typedef NCollection_Array1<const OpenGl_Layer*>::iterator iterator;
+
+    //! Reallocate internal buffer of the stack.
+    void Allocate (Standard_Integer theSize)
+    {
+      if (theSize > 0)
+      {
+        myStackSpace = new NCollection_Array1<const OpenGl_Layer*> (1, theSize);
+        myStackSpace->Init (NULL);
+        myBackPtr    = myStackSpace->begin();
+      }
+      else
+      {
+        myStackSpace.Nullify();
+        myBackPtr = iterator();
+      }
+    }
+
+    //! Clear stack.
+    void Clear()
+    {
+      if (!myStackSpace.IsNull())
+      {
+        myStackSpace->Init (NULL);
+        myBackPtr = myStackSpace->begin();
+      }
+    }
+
+    //! Push a new layer reference to the stack.
+    void Push (const OpenGl_Layer* theLayer) { (*myBackPtr++) = theLayer; }
+
+    //! Returns iterator to the origin of the stack.
+    iterator Origin() const { return myStackSpace.IsNull() ? iterator() : myStackSpace->begin(); }
+
+    //! Returns iterator to the back of the stack (after last item added).
+    iterator Back() const { return myBackPtr; }
+
+    //! Returns true if nothing has been pushed into the stack.
+    Standard_Boolean IsEmpty() const { return Back() == Origin(); }
+
+  private:
+
+    NCollection_Handle<NCollection_Array1<const OpenGl_Layer*> > myStackSpace;
+    iterator                                                     myBackPtr;
+  };
+
+  //! Render transparent objects using blending operator.
+  //! Additional accumulation framebuffer is used for blended order-independent
+  //! transparency algorithm. It should support floating-point color components
+  //! and share depth with main reading/drawing framebuffer.
+  //! @param theWorkspace [in] the currently used workspace for rendering.
+  //! @param theLayerIter [in/out] the current iterator of transparent layers to process.
+  //! @param theGlobalSettings [in] the set of global settings used for rendering.
+  //! @param theReadDrawFbo [in] the framebuffer for reading depth and writing final color.
+  //! @param theOitAccumFbo [in] the framebuffer for accumulating color and coverage for OIT process.
+  void renderTransparent (const Handle(OpenGl_Workspace)&   theWorkspace,
+                          OpenGl_LayerStack::iterator&      theLayerIter,
+                          const OpenGl_GlobalLayerSettings& theGlobalSettings,
+                          OpenGl_FrameBuffer*               theReadDrawFbo,
+                          OpenGl_FrameBuffer*               theOitAccumFbo) const;
+
 protected:
 
   // number of structures temporary put to default layer
@@ -117,6 +247,12 @@ protected:
 
   mutable Standard_Size   myModifStateOfRaytraceable;
 
+  //! Collection of references to layers with transparency gathered during rendering pass.
+  mutable OpenGl_LayerStack myTransparentToProcess;
+
+  Handle(OpenGl_OpaqueFilter)      myRenderOpaqueFilter; //!< rendering filter for opaque drawing pass (blended OIT).
+  Handle(OpenGl_TransparentFilter) myRenderTranspFilter; //!< rendering filter for transparency drawing pass (blended OIT).
+
 public:
 
   DEFINE_STANDARD_ALLOC
index 167dfe2..fccdcb0 100644 (file)
@@ -40,6 +40,14 @@ public:
     DRAW_MODE_NONE = -1
   };
 
+#if !defined(GL_ES_VERSION_2_0)
+  static const GLint THE_FILLPRIM_FROM = GL_TRIANGLES;
+  static const GLint THE_FILLPRIM_TO   = GL_POLYGON;
+#else
+  static const GLint THE_FILLPRIM_FROM = GL_TRIANGLES;
+  static const GLint THE_FILLPRIM_TO   = GL_TRIANGLE_FAN;
+#endif
+
   //! Empty constructor
   Standard_EXPORT OpenGl_PrimitiveArray (const OpenGl_GraphicDriver* theDriver);
 
index a82a1cc..ac1a156 100755 (executable)
@@ -23,6 +23,7 @@ class OpenGl_RenderFilter;
 DEFINE_STANDARD_HANDLE (OpenGl_RenderFilter, Standard_Transient)
 
 class OpenGl_Element;
+class OpenGl_Workspace;
 
 //! Base class for defining element rendering filters.
 //! This class can be used in pair with advance rendering passes, and for 
@@ -32,13 +33,14 @@ class OpenGl_RenderFilter : public Standard_Transient
 public:
 
   //! Checks whether the element can be rendered or not.
+  //! @param theWorkspace [in] the current workspace.
   //! @param theElement [in] the element to check.
   //! @return True if element can be rendered.
-  virtual Standard_Boolean CanRender (const OpenGl_Element* theElement) = 0;
+  virtual Standard_Boolean ShouldRender (const Handle(OpenGl_Workspace)& theWorkspace, const OpenGl_Element* theElement) = 0;
 
 public:
 
-  DEFINE_STANDARD_RTTIEXT(OpenGl_RenderFilter,Standard_Transient)
+  DEFINE_STANDARD_RTTIEXT(OpenGl_RenderFilter, Standard_Transient)
 };
 
 #endif
index c4977b6..0b5d7dc 100644 (file)
@@ -31,7 +31,8 @@ enum OpenGl_ProgramOptions
   OpenGl_PO_ClipPlanes1 = 0x040, //!< handle 1 clipping plane
   OpenGl_PO_ClipPlanes2 = 0x080, //!< handle 2 clipping planes
   OpenGl_PO_ClipPlanesN = 0x100, //!< handle N clipping planes
-  OpenGl_PO_NB          = 0x200  //!< overall number of combinations
+  OpenGl_PO_WriteOit    = 0x200, //!< write coverage buffer for Blended Order-Independent Transparency
+  OpenGl_PO_NB          = 0x400  //!< overall number of combinations
 };
 
 //! Alias to programs array of predefined length
index 991824c..e3b5eca 100644 (file)
@@ -249,6 +249,12 @@ const char THE_FRAG_CLIP_PLANES_2[] =
   EOL"    discard;"
   EOL"  }";
 
+//! Output color and coverage for accumulation by OIT algorithm.
+const char THE_FRAG_write_oit_buffers[] =
+  EOL"  float aWeight     = occFragColor.a * clamp (1e+2 * pow (1.0 - gl_FragCoord.z * occOitDepthFactor, 3.0), 1e-2, 1e+2);"
+  EOL"  occFragCoverage.r = occFragColor.a * aWeight;"
+  EOL"  occFragColor      = vec4 (occFragColor.rgb * occFragColor.a * aWeight, occFragColor.a);";
+
 #if !defined(GL_ES_VERSION_2_0)
 
   static const GLfloat THE_DEFAULT_AMBIENT[4]    = { 0.0f, 0.0f, 0.0f, 1.0f };
@@ -1069,6 +1075,35 @@ void OpenGl_ShaderManager::PushMaterialState (const Handle(OpenGl_ShaderProgram)
   }
 }
 
+// =======================================================================
+// function : PushOitState
+// purpose  : Pushes state of OIT uniforms to the specified program
+// =======================================================================
+void OpenGl_ShaderManager::PushOitState (const Handle(OpenGl_ShaderProgram)& theProgram) const
+{
+  if (!theProgram->IsValid())
+  {
+    return;
+  }
+
+  if (myOitState.Index() == theProgram->ActiveState (OpenGL_OIT_STATE))
+  {
+    return;
+  }
+
+  const GLint aLocOutput = theProgram->GetStateLocation (OpenGl_OCCT_OIT_OUTPUT);
+  if (aLocOutput != OpenGl_ShaderProgram::INVALID_LOCATION)
+  {
+    theProgram->SetUniform (myContext, aLocOutput, myOitState.ToEnableWrite());
+  }
+
+  const GLint aLocDepthFactor = theProgram->GetStateLocation (OpenGl_OCCT_OIT_DEPTH_FACTOR);
+  if (aLocDepthFactor != OpenGl_ShaderProgram::INVALID_LOCATION)
+  {
+    theProgram->SetUniform (myContext, aLocDepthFactor, myOitState.DepthFactor());
+  }
+}
+
 // =======================================================================
 // function : PushState
 // purpose  : Pushes state of OCCT graphics parameters to the program
@@ -1082,6 +1117,7 @@ void OpenGl_ShaderManager::PushState (const Handle(OpenGl_ShaderProgram)& thePro
   PushProjectionState  (aProgram);
   PushLightSourceState (aProgram);
   PushMaterialState    (aProgram);
+  PushOitState         (aProgram);
 }
 
 // =======================================================================
@@ -1124,6 +1160,11 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramFont()
   {
     aProgramSrc->SetHeader ("#version 150");
   }
+#else
+  if (myContext->IsGlGreaterEqual (3, 0))
+  {
+    aProgramSrc->SetHeader ("#version 300 es");
+  }
 #endif
   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_VERTEX,   aSrcVert));
   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_FRAGMENT, aSrcFrag));
@@ -1208,6 +1249,94 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramFboBlit()
   return Standard_True;
 }
 
+// =======================================================================
+// function : prepareStdProgramOitCompositing
+// purpose  :
+// =======================================================================
+Standard_Boolean OpenGl_ShaderManager::prepareStdProgramOitCompositing (const Standard_Boolean theMsaa)
+{
+  Handle(OpenGl_ShaderProgram)& aProgram = myOitCompositingProgram[theMsaa ? 1 : 0];
+  Handle(Graphic3d_ShaderProgram) aProgramSrc = new Graphic3d_ShaderProgram();
+  TCollection_AsciiString aSrcVert, aSrcFrag;
+
+  aSrcVert =
+    EOL"THE_SHADER_OUT vec2 TexCoord;"
+    EOL"void main()"
+    EOL"{"
+    EOL"  TexCoord    = occVertex.zw;"
+    EOL"  gl_Position = vec4 (occVertex.x, occVertex.y, 0.0, 1.0);"
+    EOL"}";
+
+  if (!theMsaa)
+  {
+    aSrcFrag =
+      EOL"uniform sampler2D uAccumTexture;"
+      EOL"uniform sampler2D uWeightTexture;"
+      EOL
+      EOL"THE_SHADER_IN vec2 TexCoord;"
+      EOL
+      EOL"void main()"
+      EOL"{"
+      EOL"  vec4 aAccum   = occTexture2D (uAccumTexture,  TexCoord);"
+      EOL"  float aWeight = occTexture2D (uWeightTexture, TexCoord).r;"
+      EOL"  occFragColor = vec4 (aAccum.rgb / max (aWeight, 0.00001), aAccum.a);"
+      EOL"}";
+  #if !defined(GL_ES_VERSION_2_0)
+    if (myContext->IsGlGreaterEqual (3, 2))
+    {
+      aProgramSrc->SetHeader ("#version 150");
+    }
+  #else
+    if (myContext->IsGlGreaterEqual (3, 0))
+    {
+      aProgramSrc->SetHeader ("#version 300 es");
+    }
+  #endif
+  }
+  else
+  {
+    aSrcFrag =
+      EOL"uniform sampler2DMS uAccumTexture;"
+      EOL"uniform sampler2DMS uWeightTexture;"
+      EOL
+      EOL"THE_SHADER_IN vec2 TexCoord;"
+      EOL
+      EOL"void main()"
+      EOL"{"
+      EOL"  ivec2 aTexel  = ivec2 (textureSize (uAccumTexture) * TexCoord);"
+      EOL"  vec4 aAccum   = texelFetch (uAccumTexture,  aTexel, gl_SampleID);"
+      EOL"  float aWeight = texelFetch (uWeightTexture, aTexel, gl_SampleID).r;"
+      EOL"  occFragColor = vec4 (aAccum.rgb / max (aWeight, 0.00001), aAccum.a);"
+      EOL"}";
+  #if !defined(GL_ES_VERSION_2_0)
+    if (myContext->IsGlGreaterEqual (4, 0))
+    {
+      aProgramSrc->SetHeader ("#version 400");
+    }
+  #else
+    if (myContext->IsGlGreaterEqual (3, 0))
+    {
+      aProgramSrc->SetHeader ("#version 300 es");
+    }
+  #endif
+  }
+
+  aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_VERTEX,   aSrcVert));
+  aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_FRAGMENT, aSrcFrag));
+  TCollection_AsciiString aKey;
+  if (!Create (aProgramSrc, aKey, aProgram))
+  {
+    aProgram = new OpenGl_ShaderProgram(); // just mark as invalid
+    return Standard_False;
+  }
+
+  myContext->BindProgram (aProgram);
+  aProgram->SetSampler (myContext, "uAccumTexture",  0);
+  aProgram->SetSampler (myContext, "uWeightTexture", 1);
+  myContext->BindProgram (Handle(OpenGl_ShaderProgram)());
+  return Standard_True;
+}
+
 // =======================================================================
 // function : pointSpriteAlphaSrc
 // purpose  :
@@ -1249,7 +1378,8 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramFlat (Handle(OpenGl_Shad
                                                               const Standard_Integer        theBits)
 {
   Handle(Graphic3d_ShaderProgram) aProgramSrc = new Graphic3d_ShaderProgram();
-  TCollection_AsciiString aSrcVert, aSrcVertExtraOut, aSrcVertExtraMain, aSrcVertExtraFunc, aSrcGetAlpha, aSrcFrag, aSrcFragExtraOut, aSrcFragExtraMain;
+  TCollection_AsciiString aSrcVert, aSrcVertExtraOut, aSrcVertExtraMain, aSrcVertExtraFunc, aSrcGetAlpha;
+  TCollection_AsciiString aSrcFrag, aSrcFragExtraOut, aSrcFragExtraMain, aSrcFragWriteOit;
   TCollection_AsciiString aSrcFragGetColor     = EOL"vec4 getColor(void) { return occColor; }";
   TCollection_AsciiString aSrcFragMainGetColor = EOL"  occFragColor = getColor();";
   if ((theBits & OpenGl_PO_Point) != 0)
@@ -1351,6 +1481,10 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramFlat (Handle(OpenGl_Shad
       aSrcFragExtraMain += THE_FRAG_CLIP_PLANES_N;
     }
   }
+  if ((theBits & OpenGl_PO_WriteOit) != 0)
+  {
+    aSrcFragWriteOit += THE_FRAG_write_oit_buffers;
+  }
 
   TCollection_AsciiString aSrcVertEndMain;
   if ((theBits & OpenGl_PO_StippleLine) != 0)
@@ -1359,7 +1493,6 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramFlat (Handle(OpenGl_Shad
   #if defined(GL_ES_VERSION_2_0)
     if (myContext->IsGlGreaterEqual (3, 0))
     {
-      aProgramSrc->SetHeader ("#version 300 es");
       hasGlslBitOps = true;
     }
   #else
@@ -1421,6 +1554,7 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramFlat (Handle(OpenGl_Shad
       EOL"{"
     + aSrcFragExtraMain
     + aSrcFragMainGetColor
+    + aSrcFragWriteOit
     + EOL"}";
 
 #if !defined(GL_ES_VERSION_2_0)
@@ -1428,6 +1562,11 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramFlat (Handle(OpenGl_Shad
   {
     aProgramSrc->SetHeader ("#version 150");
   }
+#else
+  if (myContext->IsGlGreaterEqual (3, 0))
+  {
+    aProgramSrc->SetHeader ("#version 300 es");
+  }
 #endif
   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_VERTEX,   aSrcVert));
   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_FRAGMENT, aSrcFrag));
@@ -1572,7 +1711,8 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramGouraud (Handle(OpenGl_S
                                                                  const Standard_Integer        theBits)
 {
   Handle(Graphic3d_ShaderProgram) aProgramSrc = new Graphic3d_ShaderProgram();
-  TCollection_AsciiString aSrcVert, aSrcVertColor, aSrcVertExtraOut, aSrcVertExtraMain, aSrcFrag, aSrcFragExtraOut, aSrcFragExtraMain;
+  TCollection_AsciiString aSrcVert, aSrcVertColor, aSrcVertExtraOut, aSrcVertExtraMain;
+  TCollection_AsciiString aSrcFrag, aSrcFragExtraOut, aSrcFragExtraMain, aSrcFragWriteOit;
   TCollection_AsciiString aSrcFragGetColor = EOL"vec4 getColor(void) { return gl_FrontFacing ? FrontColor : BackColor; }";
   if ((theBits & OpenGl_PO_Point) != 0)
   {
@@ -1640,6 +1780,10 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramGouraud (Handle(OpenGl_S
       aSrcFragExtraMain += THE_FRAG_CLIP_PLANES_N;
     }
   }
+  if ((theBits & OpenGl_PO_WriteOit) != 0)
+  {
+    aSrcFragWriteOit += THE_FRAG_write_oit_buffers;
+  }
 
   const TCollection_AsciiString aLights = stdComputeLighting ((theBits & OpenGl_PO_VertColor) != 0);
   aSrcVert = TCollection_AsciiString()
@@ -1673,13 +1817,19 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramGouraud (Handle(OpenGl_S
       EOL"{"
     + aSrcFragExtraMain
     + EOL"  occFragColor = getColor();"
-      EOL"}";
+    + aSrcFragWriteOit
+    + EOL"}";
 
 #if !defined(GL_ES_VERSION_2_0)
   if (myContext->core32 != NULL)
   {
     aProgramSrc->SetHeader ("#version 150");
   }
+#else
+  if (myContext->IsGlGreaterEqual (3, 0))
+  {
+    aProgramSrc->SetHeader ("#version 300 es");
+  }
 #endif
   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_VERTEX,   aSrcVert));
   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_FRAGMENT, aSrcFrag));
@@ -1702,7 +1852,8 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramPhong (Handle(OpenGl_Sha
   #define thePhongCompLight "computeLighting (normalize (Normal), normalize (View), Position, gl_FrontFacing)"
 
   Handle(Graphic3d_ShaderProgram) aProgramSrc = new Graphic3d_ShaderProgram();
-  TCollection_AsciiString aSrcVert, aSrcVertExtraOut, aSrcVertExtraMain, aSrcFrag, aSrcFragExtraOut, aSrcFragGetVertColor, aSrcFragExtraMain;
+  TCollection_AsciiString aSrcVert, aSrcVertExtraOut, aSrcVertExtraMain;
+  TCollection_AsciiString aSrcFrag, aSrcFragExtraOut, aSrcFragGetVertColor, aSrcFragExtraMain, aSrcFragWriteOit;
   TCollection_AsciiString aSrcFragGetColor = EOL"vec4 getColor(void) { return " thePhongCompLight "; }";
   if ((theBits & OpenGl_PO_Point) != 0)
   {
@@ -1763,6 +1914,10 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramPhong (Handle(OpenGl_Sha
       aSrcFragExtraMain += THE_FRAG_CLIP_PLANES_N;
     }
   }
+  if ((theBits & OpenGl_PO_WriteOit) != 0)
+  {
+    aSrcFragWriteOit += THE_FRAG_write_oit_buffers;
+  }
 
   aSrcVert = TCollection_AsciiString()
     + THE_FUNC_transformNormal
@@ -1799,13 +1954,19 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramPhong (Handle(OpenGl_Sha
       EOL"{"
     + aSrcFragExtraMain
     + EOL"  occFragColor = getColor();"
-      EOL"}";
+    + aSrcFragWriteOit
+    + EOL"}";
 
 #if !defined(GL_ES_VERSION_2_0)
   if (myContext->core32 != NULL)
   {
     aProgramSrc->SetHeader ("#version 150");
   }
+#else
+  if (myContext->IsGlGreaterEqual (3, 0))
+  {
+    aProgramSrc->SetHeader ("#version 300 es");
+  }
 #endif
   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_VERTEX,   aSrcVert));
   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_FRAGMENT, aSrcFrag));
@@ -2022,6 +2183,11 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramStereo (Handle(OpenGl_Sh
   {
     aProgramSrc->SetHeader ("#version 150");
   }
+#else
+  if (myContext->IsGlGreaterEqual (3, 0))
+  {
+    aProgramSrc->SetHeader ("#version 300 es");
+  }
 #endif
 
   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_VERTEX,   aSrcVert));
index ce503a6..bba6b92 100644 (file)
@@ -168,6 +168,19 @@ public:
          && myContext->BindProgram (myBlitProgram);
   }
 
+  //! Bind program for blended order-independent transparency buffers compositing.
+  Standard_Boolean BindOitCompositingProgram (const Standard_Boolean theIsMSAAEnabled)
+  {
+    const Standard_Integer aProgramIdx = theIsMSAAEnabled ? 1 : 0;
+    if (myOitCompositingProgram[aProgramIdx].IsNull())
+    {
+      prepareStdProgramOitCompositing (theIsMSAAEnabled);
+    }
+
+    const Handle(OpenGl_ShaderProgram)& aProgram = myOitCompositingProgram [aProgramIdx];
+    return !aProgram.IsNull() && myContext->BindProgram (aProgram);
+  }
+
   //! Bind program for rendering stereoscopic image.
   Standard_Boolean BindStereoProgram (const Graphic3d_StereoMode theStereoMode)
   {
@@ -267,6 +280,20 @@ public:
   //! Pushes current state of material to specified program.
   void PushMaterialState (const Handle(OpenGl_ShaderProgram)& theProgram) const;
 
+public:
+
+  //! Set the state of OIT rendering pass.
+  //! @param theToEnableOitWrite [in] flag indicating whether the special output should be written for OIT algorithm.
+  //! @param theDepthFactor [in] the scalar factor of depth influence to the fragment's coverage.
+  void SetOitState (const bool theToEnableOitWrite, const float theDepthFactor)
+  {
+    myOitState.Set (theToEnableOitWrite, theDepthFactor);
+    myOitState.Update();
+  }
+
+  //! Pushes state of OIT uniforms to the specified program.
+  Standard_EXPORT void PushOitState (const Handle(OpenGl_ShaderProgram)& theProgram) const;
+
 public:
 
   //! Pushes current state of OCCT graphics parameters to specified program.
@@ -339,6 +366,11 @@ protected:
     {
       aBits |= OpenGl_PO_VertColor;
     }
+
+    if (myOitState.ToEnableWrite())
+    {
+      aBits |= OpenGl_PO_WriteOit;
+    }
     return aBits;
   }
 
@@ -378,6 +410,9 @@ protected:
   //! Prepare standard GLSL program for FBO blit operation.
   Standard_EXPORT Standard_Boolean prepareStdProgramFboBlit();
 
+  //! Prepare standard GLSL programs for OIT compositing operation.
+  Standard_EXPORT Standard_Boolean prepareStdProgramOitCompositing (const Standard_Boolean theMsaa);
+
   //! Prepare standard GLSL program without lighting.
   Standard_EXPORT Standard_Boolean prepareStdProgramFlat (Handle(OpenGl_ShaderProgram)& theProgram,
                                                           const Standard_Integer        theBits);
@@ -458,6 +493,7 @@ protected:
   OpenGl_SetOfShaderPrograms         myFlatPrograms;       //!< programs matrix without  lighting
   Handle(OpenGl_ShaderProgram)       myFontProgram;        //!< standard program for textured text
   Handle(OpenGl_ShaderProgram)       myBlitProgram;        //!< standard program for FBO blit emulation
+  Handle(OpenGl_ShaderProgram)       myOitCompositingProgram[2]; //!< standard program for OIT compositing (default and MSAA).
   OpenGl_MapOfShaderPrograms         myMapOfLightPrograms; //!< map of lighting programs depending on shading model and lights configuration
 
   Handle(OpenGl_ShaderProgram)       myStereoPrograms[Graphic3d_StereoMode_NB]; //!< standard stereo programs
@@ -472,6 +508,7 @@ protected:
   OpenGl_ClippingState               myClippingState;      //!< State of OCCT clipping planes
   OpenGl_LightSourceState            myLightSourceState;   //!< State of OCCT light sources
   OpenGl_MaterialState               myMaterialState;      //!< State of Front and Back materials
+  OpenGl_OitState                    myOitState;           //!< State of OIT uniforms
 
   gp_XYZ                             myLocalOrigin;        //!< local camera transformation
   Standard_Boolean                   myHasLocalOrigin;     //!< flag indicating that local camera transformation has been set
index d792b16..7e3b8ad 100755 (executable)
@@ -70,9 +70,11 @@ Standard_CString OpenGl_ShaderProgram::PredefinedKeywords[] =
   "occBackMaterial",       // OpenGl_OCCT_BACK_MATERIAL
   "occColor",              // OpenGl_OCCT_COLOR
 
+  "occOitOutput",          // OpenGl_OCCT_OIT_OUTPUT
+  "occOitDepthFactor",     // OpenGl_OCCT_OIT_DEPTH_FACTOR
+
   "occTexTrsf2d",          // OpenGl_OCCT_TEXTURE_TRSF2D
   "occPointSize"           // OpenGl_OCCT_POINT_SIZE
-
 };
 
 // =======================================================================
@@ -204,11 +206,43 @@ Standard_Boolean OpenGl_ShaderProgram::Initialize (const Handle(OpenGl_Context)&
     }
 
     TCollection_AsciiString aSource = aDeclarations + anIter.Value()->Source();
+    TCollection_AsciiString anExtensions = "// This section enables extensions used in OCCT GLSL programs\n";
+    if (theCtx->hasDrawBuffers)
+    {
+      anExtensions += "#define OCC_ENABLE_draw_buffers\n";
+    }
+    if (theCtx->hasDrawBuffers == OpenGl_FeatureInExtensions)
+    {
+      if (theCtx->arbDrawBuffers)
+      {
+        anExtensions += "#extension GL_ARB_draw_buffers : enable\n";
+      }
+      else if (theCtx->extDrawBuffers)
+      {
+        anExtensions += "#extension GL_EXT_draw_buffers : enable\n";
+      }
+    }
+
+    if (theCtx->hasSampleVariables == OpenGl_FeatureInExtensions)
+    {
+#if defined(GL_ES_VERSION_2_0)
+      if (theCtx->oesSampleVariables)
+      {
+        anExtensions += "#extension GL_OES_sample_variables : enable\n";
+      }
+#else
+      if (theCtx->arbSampleShading)
+      {
+        anExtensions += "#extension GL_ARB_sample_shading : enable\n";
+      }
+#endif
+    }
+
     switch (anIter.Value()->Type())
     {
       case Graphic3d_TOS_VERTEX:
       {
-        aSource = aHeader + TCollection_AsciiString ("#define VERTEX_SHADER\n") + aSource;
+        aSource = aHeader + TCollection_AsciiString ("#define VERTEX_SHADER\n") + anExtensions + aSource;
         break;
       }
       case Graphic3d_TOS_FRAGMENT:
@@ -219,9 +253,9 @@ Standard_Boolean OpenGl_ShaderProgram::Initialize (const Handle(OpenGl_Context)&
                                          "precision highp int;\n"
                                        : "precision mediump float;\n"
                                          "precision mediump int;\n");
-        aSource = aHeader + aPrefix + aSource;
+        aSource = aHeader + aPrefix + anExtensions + aSource;
       #else
-        aSource = aHeader + aSource;
+        aSource = aHeader + anExtensions + aSource;
       #endif
         break;
       }
@@ -229,6 +263,7 @@ Standard_Boolean OpenGl_ShaderProgram::Initialize (const Handle(OpenGl_Context)&
 
     if (!aShader->LoadSource (theCtx, aSource))
     {
+      theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, aSource);
       const TCollection_ExtendedString aMsg = "Error! Failed to set shader source";
       theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION,
                            GL_DEBUG_TYPE_ERROR,
@@ -241,6 +276,7 @@ Standard_Boolean OpenGl_ShaderProgram::Initialize (const Handle(OpenGl_Context)&
 
     if (!aShader->Compile (theCtx))
     {
+      theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, aSource);
       TCollection_AsciiString aLog;
       aShader->FetchInfoLog (theCtx, aLog);
       if (aLog.IsEmpty())
index f38506f..155845f 100755 (executable)
@@ -65,6 +65,11 @@ enum OpenGl_StateVariable
   OpenGl_OCCT_BACK_MATERIAL,
   OpenGl_OCCT_COLOR,
 
+  // Weighted, Blended Order-Independent Transparency rendering state
+  OpenGl_OCCT_OIT_OUTPUT,
+  OpenGl_OCCT_OIT_DEPTH_FACTOR,
+
+  // Context-dependent state
   OpenGl_OCCT_TEXTURE_TRSF2D,
   OpenGl_OCCT_POINT_SIZE,
 
@@ -124,6 +129,7 @@ enum OpenGl_UniformStateType
   OpenGl_PROJECTION_STATE,
   OpenGl_MATERIAL_STATE,
   OpenGl_SURF_DETAIL_STATE,
+  OpenGL_OIT_STATE,
   OpenGl_UniformStateType_NB
 };
 
index 567a76c..786b27e 100755 (executable)
@@ -161,4 +161,38 @@ protected:
 
 };
 
+//! Defines generic state of order-independent transparency rendering properties.
+class OpenGl_OitState : public OpenGl_StateInterface
+{
+public:
+
+  //! Creates new uniform state.
+  OpenGl_OitState() : myToEnableWrite (false), myDepthFactor (0.5f) {}
+
+  //! Sets the uniform values.
+  //! @param theToEnableWrite [in] flag indicating whether color and coverage
+  //!  values for OIT processing should be written by shader program.
+  //! @param theDepthFactor [in] scalar factor [0-1] defining influence of depth
+  //!  component of a fragment to its final coverage coefficient.
+  void Set (const bool  theToEnableWrite,
+            const float theDepthFactor)
+  {
+    myToEnableWrite = theToEnableWrite;
+    myDepthFactor   = static_cast<float> (Max (0.f, Min (1.f, theDepthFactor)));
+  }
+
+  //! Returns flag indicating whether writing of output for OIT processing
+  //! should be enabled/disabled.
+  bool ToEnableWrite() const { return myToEnableWrite; }
+
+  //! Returns factor defining influence of depth component of a fragment
+  //! to its final coverage coefficient.
+  float DepthFactor() const { return myDepthFactor; }
+
+private:
+
+  bool  myToEnableWrite; //!< writing color and coverage.
+  float myDepthFactor;   //!< factor of depth influence to coverage.
+};
+
 #endif // _OpenGl_State_HeaderFile
index 35fec70..3b03c64 100644 (file)
@@ -192,7 +192,11 @@ bool OpenGl_Texture::GetDataFormat (const Handle(OpenGl_Context)& theCtx,
       }
       else
       {
+      #if !defined(GL_ES_VERSION_2_0)
         theTextFormat  = GL_LUMINANCE8;
+      #else
+        theTextFormat  = GL_LUMINANCE;
+      #endif
         thePixelFormat = GL_LUMINANCE;
       }
       theDataType = GL_FLOAT;
@@ -207,7 +211,11 @@ bool OpenGl_Texture::GetDataFormat (const Handle(OpenGl_Context)& theCtx,
       }
       else
       {
+      #if !defined(GL_ES_VERSION_2_0)
         theTextFormat  = GL_ALPHA8;
+      #else
+        theTextFormat  = GL_ALPHA;
+      #endif
         thePixelFormat = GL_ALPHA;
       }
       theDataType = GL_FLOAT;
@@ -316,7 +324,11 @@ bool OpenGl_Texture::GetDataFormat (const Handle(OpenGl_Context)& theCtx,
       }
       else
       {
+      #if !defined(GL_ES_VERSION_2_0)
         theTextFormat  = GL_LUMINANCE8;
+      #else
+        theTextFormat  = GL_LUMINANCE;
+      #endif
         thePixelFormat = GL_LUMINANCE;
       }
       theDataType = GL_UNSIGNED_BYTE;
@@ -331,7 +343,11 @@ bool OpenGl_Texture::GetDataFormat (const Handle(OpenGl_Context)& theCtx,
       }
       else
       {
+      #if !defined(GL_ES_VERSION_2_0)
         theTextFormat  = GL_ALPHA8;
+      #else
+        theTextFormat  = GL_ALPHA;
+      #endif
         thePixelFormat = GL_ALPHA;
       }
       theDataType = GL_UNSIGNED_BYTE;
@@ -393,9 +409,8 @@ bool OpenGl_Texture::Init (const Handle(OpenGl_Context)& theCtx,
 #if !defined(GL_ES_VERSION_2_0)
   const GLint anIntFormat  = theTextFormat;
 #else
-  // ES does not support sized formats and format conversions - them detected from data type
-  const GLint anIntFormat  = thePixelFormat;
-  (void) theTextFormat;
+  // ES 2.0 does not support sized formats and format conversions - them detected from data type
+  const GLint anIntFormat  = theCtx->IsGlGreaterEqual (3, 0) ? theTextFormat : thePixelFormat;
 #endif
 
   const GLsizei aMaxSize = theCtx->MaxTextureSize();
index 0dc123b..e669a9c 100644 (file)
@@ -61,11 +61,17 @@ OpenGl_View::OpenGl_View (const Handle(Graphic3d_StructureManager)& theMgr,
   myToShowGradTrihedron  (false),
   myStateCounter         (theCounter),
   myLastLightSourceState (0, 0),
+#if !defined(GL_ES_VERSION_2_0)
   myFboColorFormat       (GL_RGBA8),
+#else
+  myFboColorFormat       (GL_RGBA),
+#endif
   myFboDepthFormat       (GL_DEPTH24_STENCIL8),
   myToFlipOutput         (Standard_False),
   myFrameCounter         (0),
   myHasFboBlit           (Standard_True),
+  myToDisableOIT         (Standard_False),
+  myToDisableOITMSAA     (Standard_False),
   myToDisableMSAA        (Standard_False),
   myTransientDrawToFront (Standard_True),
   myBackBufferRestored   (Standard_False),
@@ -90,17 +96,21 @@ OpenGl_View::OpenGl_View (const Handle(Graphic3d_StructureManager)& theMgr,
   aLight.Color.b()   = 1.;
   myNoShadingLight.Append (aLight);
 
-  myCurrLightSourceState  = myStateCounter->Increment();
-  myMainSceneFbos[0]      = new OpenGl_FrameBuffer();
-  myMainSceneFbos[1]      = new OpenGl_FrameBuffer();
-  myImmediateSceneFbos[0] = new OpenGl_FrameBuffer();
-  myImmediateSceneFbos[1] = new OpenGl_FrameBuffer();
-  myOpenGlFBO             = new OpenGl_FrameBuffer();
-  myOpenGlFBO2            = new OpenGl_FrameBuffer();
-  myRaytraceFBO1[0]       = new OpenGl_FrameBuffer();
-  myRaytraceFBO1[1]       = new OpenGl_FrameBuffer();
-  myRaytraceFBO2[0]       = new OpenGl_FrameBuffer();
-  myRaytraceFBO2[1]       = new OpenGl_FrameBuffer();
+  myCurrLightSourceState     = myStateCounter->Increment();
+  myMainSceneFbos[0]         = new OpenGl_FrameBuffer();
+  myMainSceneFbos[1]         = new OpenGl_FrameBuffer();
+  myMainSceneFbosOit[0]      = new OpenGl_FrameBuffer();
+  myMainSceneFbosOit[1]      = new OpenGl_FrameBuffer();
+  myImmediateSceneFbos[0]    = new OpenGl_FrameBuffer();
+  myImmediateSceneFbos[1]    = new OpenGl_FrameBuffer();
+  myImmediateSceneFbosOit[0] = new OpenGl_FrameBuffer();
+  myImmediateSceneFbosOit[1] = new OpenGl_FrameBuffer();
+  myOpenGlFBO                = new OpenGl_FrameBuffer();
+  myOpenGlFBO2               = new OpenGl_FrameBuffer();
+  myRaytraceFBO1[0]          = new OpenGl_FrameBuffer();
+  myRaytraceFBO1[1]          = new OpenGl_FrameBuffer();
+  myRaytraceFBO2[0]          = new OpenGl_FrameBuffer();
+  myRaytraceFBO2[1]          = new OpenGl_FrameBuffer();
 }
 
 // =======================================================================
@@ -142,14 +152,18 @@ void OpenGl_View::ReleaseGlResources (const Handle(OpenGl_Context)& theCtx)
     myBgTextureArray->Release (theCtx.operator->());
   }
 
-  myMainSceneFbos[0]     ->Release (theCtx.operator->());
-  myMainSceneFbos[1]     ->Release (theCtx.operator->());
-  myImmediateSceneFbos[0]->Release (theCtx.operator->());
-  myImmediateSceneFbos[1]->Release (theCtx.operator->());
-  myOpenGlFBO            ->Release (theCtx.operator->());
-  myOpenGlFBO2           ->Release (theCtx.operator->());
-  myFullScreenQuad        .Release (theCtx.operator->());
-  myFullScreenQuadFlip    .Release (theCtx.operator->());
+  myMainSceneFbos[0]        ->Release (theCtx.operator->());
+  myMainSceneFbos[1]        ->Release (theCtx.operator->());
+  myMainSceneFbosOit[0]     ->Release (theCtx.operator->());
+  myMainSceneFbosOit[1]     ->Release (theCtx.operator->());
+  myImmediateSceneFbos[0]   ->Release (theCtx.operator->());
+  myImmediateSceneFbos[1]   ->Release (theCtx.operator->());
+  myImmediateSceneFbosOit[0]->Release (theCtx.operator->());
+  myImmediateSceneFbosOit[1]->Release (theCtx.operator->());
+  myOpenGlFBO               ->Release (theCtx.operator->());
+  myOpenGlFBO2              ->Release (theCtx.operator->());
+  myFullScreenQuad           .Release (theCtx.operator->());
+  myFullScreenQuadFlip       .Release (theCtx.operator->());
 
   releaseRaytraceResources (theCtx);
 }
index 7eaadd2..1d5adcc 100644 (file)
@@ -351,7 +351,8 @@ protected: //! @name low-level redrawing sub-routines
 
   //! Redraws view for the given monographic camera projection, or left/right eye.
   Standard_EXPORT virtual void redraw (const Graphic3d_Camera::Projection theProjection,
-                                       OpenGl_FrameBuffer*                theReadDrawFbo);
+                                       OpenGl_FrameBuffer*                theReadDrawFbo,
+                                       OpenGl_FrameBuffer*                theOitAccumFbo);
 
   //! Redraws view for the given monographic camera projection, or left/right eye.
   //!
@@ -368,6 +369,7 @@ protected: //! @name low-level redrawing sub-routines
   Standard_EXPORT virtual bool redrawImmediate (const Graphic3d_Camera::Projection theProjection,
                                                 OpenGl_FrameBuffer* theReadFbo,
                                                 OpenGl_FrameBuffer* theDrawFbo,
+                                                OpenGl_FrameBuffer* theOitAccumFbo,
                                                 const Standard_Boolean theIsPartialUpdate = Standard_False);
 
   //! Blit image from/to specified buffers.
@@ -383,17 +385,21 @@ protected: //! @name Rendering of GL graphics (with prepared drawing buffer).
   //! Renders the graphical contents of the view into the preprepared window or framebuffer.
   //! @param theProjection [in] the projection that should be used for rendering.
   //! @param theReadDrawFbo [in] the framebuffer for rendering graphics.
+  //! @param theOitAccumFbo [in] the framebuffer for accumulating color and coverage for OIT process.
   //! @param theToDrawImmediate [in] the flag indicates whether the rendering performs in immediate mode.
   Standard_EXPORT virtual void render (Graphic3d_Camera::Projection theProjection,
                                        OpenGl_FrameBuffer*          theReadDrawFbo,
+                                       OpenGl_FrameBuffer*          theOitAccumFbo,
                                        const Standard_Boolean       theToDrawImmediate);
 
   //! Renders the graphical scene.
   //! @param theProjection [in] the projection that is used for rendering.
   //! @param theReadDrawFbo [in] the framebuffer for rendering graphics.
+  //! @param theOitAccumFbo [in] the framebuffer for accumulating color and coverage for OIT process.
   //! @param theToDrawImmediate [in] the flag indicates whether the rendering performs in immediate mode.
   Standard_EXPORT virtual void renderScene (Graphic3d_Camera::Projection theProjection,
                                             OpenGl_FrameBuffer*    theReadDrawFbo,
+                                            OpenGl_FrameBuffer*    theOitAccumFbo,
                                             const Standard_Boolean theToDrawImmediate);
 
   //! Draw background (gradient / image)
@@ -402,9 +408,11 @@ protected: //! @name Rendering of GL graphics (with prepared drawing buffer).
   //! Render set of structures presented in the view.
   //! @param theProjection [in] the projection that is used for rendering.
   //! @param theReadDrawFbo [in] the framebuffer for rendering graphics.
+  //! @param theOitAccumFbo [in] the framebuffer for accumulating color and coverage for OIT process.
   //! @param theToDrawImmediate [in] the flag indicates whether the rendering performs in immediate mode.
   Standard_EXPORT virtual void renderStructs (Graphic3d_Camera::Projection theProjection,
                                               OpenGl_FrameBuffer*    theReadDrawFbo,
+                                              OpenGl_FrameBuffer*    theOitAccumFbo,
                                               const Standard_Boolean theToDrawImmediate);
 
   //! Renders trihedron.
@@ -444,6 +452,15 @@ private:
   //! Blend together views pair into stereo image.
   void drawStereoPair (OpenGl_FrameBuffer* theDrawFbo);
 
+  //! Check and update OIT compatibility with current OpenGL context's state.
+  bool checkOitCompatibility (const Handle(OpenGl_Context)& theGlContext,
+                              const Standard_Boolean theMSAA);
+
+  //! Chooses compatible internal color format for OIT frame buffer.
+  bool chooseOitColorConfiguration (const Handle(OpenGl_Context)& theGlContext,
+                                    const Standard_Integer theConfigIndex,
+                                    OpenGl_ColorFormats& theFormats);
+
 protected:
 
   OpenGl_GraphicDriver*    myDriver;
@@ -497,13 +514,18 @@ protected: //! @name Rendering properties
   //! of the view (without presentation of immediate layers).
   GLint                      myFboColorFormat;        //!< sized format for color attachments
   GLint                      myFboDepthFormat;        //!< sized format for depth-stencil attachments
+  OpenGl_ColorFormats        myFboOitColorConfig;     //!< selected color format configuration for OIT color attachments
   Handle(OpenGl_FrameBuffer) myMainSceneFbos[2];
-  Handle(OpenGl_FrameBuffer) myImmediateSceneFbos[2]; //!< Additional buffers for immediate layer in stereo mode.
+  Handle(OpenGl_FrameBuffer) myMainSceneFbosOit[2];      //!< Additional buffers for transparent draw of main layer.
+  Handle(OpenGl_FrameBuffer) myImmediateSceneFbos[2];    //!< Additional buffers for immediate layer in stereo mode.
+  Handle(OpenGl_FrameBuffer) myImmediateSceneFbosOit[2]; //!< Additional buffers for transparency draw of immediate layer.
   OpenGl_VertexBuffer        myFullScreenQuad;        //!< Vertices for full-screen quad rendering.
   OpenGl_VertexBuffer        myFullScreenQuadFlip;
   Standard_Boolean           myToFlipOutput;          //!< Flag to draw result image upside-down
   unsigned int               myFrameCounter;          //!< redraw counter, for debugging
   Standard_Boolean           myHasFboBlit;            //!< disable FBOs on failure
+  Standard_Boolean           myToDisableOIT;          //!< disable OIT on failure
+  Standard_Boolean           myToDisableOITMSAA;      //!< disable OIT with MSAA on failure
   Standard_Boolean           myToDisableMSAA;         //!< disable MSAA after failure
   Standard_Boolean           myTransientDrawToFront; //!< optimization flag for immediate mode (to render directly to the front buffer)
   Standard_Boolean           myBackBufferRestored;
@@ -1045,6 +1067,7 @@ public:
 
   friend class OpenGl_GraphicDriver;
   friend class OpenGl_Workspace;
+  friend class OpenGl_LayerList;
 };
 
 #endif // _OpenGl_View_Header
index 30ad660..703d127 100644 (file)
@@ -162,6 +162,12 @@ void OpenGl_View::Redraw()
     aNbSamples = OpenGl_Context::GetPowerOfTwo (aNbSamples, aCtx->MaxMsaaSamples());
   }
 
+  bool toUseOit = myRenderParams.TransparencyMethod == Graphic3d_RTM_BLEND_OIT
+               && checkOitCompatibility (aCtx, aNbSamples > 0);
+
+  const bool toInitImmediateFbo = myTransientDrawToFront
+                               && (!aCtx->caps->useSystemBuffer || (toUseOit && HasImmediateStructures()));
+
   if ( aFrameBuffer == NULL
    && !aCtx->DefaultFrameBuffer().IsNull()
    &&  aCtx->DefaultFrameBuffer()->IsValid())
@@ -173,6 +179,7 @@ void OpenGl_View::Redraw()
    && (myTransientDrawToFront
     || aProjectType == Graphic3d_Camera::Projection_Stereo
     || aNbSamples != 0
+    || toUseOit
     || aSizeX != aRendSizeX))
   {
     if (myMainSceneFbos[0]->GetVPSizeX() != aRendSizeX
@@ -193,12 +200,10 @@ void OpenGl_View::Redraw()
       {
         myMainSceneFbos[0]->Init (aCtx, aRendSizeX, aRendSizeY, myFboColorFormat, myFboDepthFormat, aNbSamples);
       }
-      if (myTransientDrawToFront
-       && !aCtx->caps->useSystemBuffer
-       && myMainSceneFbos[0]->IsValid())
-      {
-        myImmediateSceneFbos[0]->InitLazy (aCtx, *myMainSceneFbos[0]);
-      }
+    }
+    if (myMainSceneFbos[0]->IsValid() && (toInitImmediateFbo || myImmediateSceneFbos[0]->IsValid()))
+    {
+      myImmediateSceneFbos[0]->InitLazy (aCtx, *myMainSceneFbos[0]);
     }
   }
   else
@@ -238,6 +243,94 @@ void OpenGl_View::Redraw()
     }
   }
 
+  // create color and coverage accumulation buffers required for OIT algorithm
+  if (toUseOit)
+  {
+    Standard_Integer anFboIt = 0;
+    for (; anFboIt < 2; ++anFboIt)
+    {
+      Handle(OpenGl_FrameBuffer)& aMainSceneFbo          = myMainSceneFbos        [anFboIt];
+      Handle(OpenGl_FrameBuffer)& aMainSceneFboOit       = myMainSceneFbosOit     [anFboIt];
+      Handle(OpenGl_FrameBuffer)& anImmediateSceneFbo    = myImmediateSceneFbos   [anFboIt];
+      Handle(OpenGl_FrameBuffer)& anImmediateSceneFboOit = myImmediateSceneFbosOit[anFboIt];
+      if (aMainSceneFbo->IsValid()
+       && (aMainSceneFboOit->GetVPSizeX() != aRendSizeX
+        || aMainSceneFboOit->GetVPSizeY() != aRendSizeY
+        || aMainSceneFboOit->NbSamples()  != aNbSamples))
+      {
+        Standard_Integer aColorConfig = 0;
+        for (;;) // seemly responding to driver limitation (GL_FRAMEBUFFER_UNSUPPORTED)
+        {
+          if (myFboOitColorConfig.IsEmpty())
+          {
+            if (!chooseOitColorConfiguration (aCtx, aColorConfig++, myFboOitColorConfig))
+            {
+              break;
+            }
+          }
+          if (aMainSceneFboOit->Init (aCtx, aRendSizeX, aRendSizeY, myFboOitColorConfig, aMainSceneFbo->DepthStencilTexture(), aNbSamples))
+          {
+            break;
+          }
+          myFboOitColorConfig.Clear();
+        }
+        if (!aMainSceneFboOit->IsValid())
+        {
+          break;
+        }
+      }
+      else if (!aMainSceneFbo->IsValid())
+      {
+        aMainSceneFboOit->Release (aCtx.operator->());
+        aMainSceneFboOit->ChangeViewport (0, 0);
+      }
+
+      if (anImmediateSceneFbo->IsValid()
+       && (anImmediateSceneFboOit->GetVPSizeX() != aRendSizeX
+        || anImmediateSceneFboOit->GetVPSizeY() != aRendSizeY
+        || anImmediateSceneFboOit->NbSamples()  != aNbSamples))
+      {
+        if (!anImmediateSceneFboOit->Init (aCtx, aRendSizeX, aRendSizeY, myFboOitColorConfig,
+                                           anImmediateSceneFbo->DepthStencilTexture(), aNbSamples))
+        {
+          break;
+        }
+      }
+      else if (!anImmediateSceneFbo->IsValid())
+      {
+        anImmediateSceneFboOit->Release (aCtx.operator->());
+        anImmediateSceneFboOit->ChangeViewport (0, 0);
+      }
+    }
+    if (anFboIt == 0) // only the first OIT framebuffer is mandatory
+    {
+      aCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
+                         "Initialization of float texture framebuffer for use with\n"
+                         "  blended order-independent transparency rendering algorithm has failed.\n"
+                         "  Blended order-independent transparency will not be available.\n");
+      if (aNbSamples > 0)
+      {
+        myToDisableOITMSAA = Standard_True;
+      }
+      else
+      {
+        myToDisableOIT     = Standard_True;
+      }
+      toUseOit = false;
+    }
+  }
+  if (!toUseOit && myMainSceneFbosOit[0]->IsValid())
+  {
+    myMainSceneFbosOit     [0]->Release (aCtx.operator->());
+    myMainSceneFbosOit     [1]->Release (aCtx.operator->());
+    myImmediateSceneFbosOit[0]->Release (aCtx.operator->());
+    myImmediateSceneFbosOit[1]->Release (aCtx.operator->());
+    myMainSceneFbosOit     [0]->ChangeViewport (0, 0);
+    myMainSceneFbosOit     [1]->ChangeViewport (0, 0);
+    myImmediateSceneFbosOit[0]->ChangeViewport (0, 0);
+    myImmediateSceneFbosOit[1]->ChangeViewport (0, 0);
+  }
+
   if (aProjectType == Graphic3d_Camera::Projection_Stereo)
   {
     OpenGl_FrameBuffer* aMainFbos[2] =
@@ -245,22 +338,39 @@ void OpenGl_View::Redraw()
       myMainSceneFbos[0]->IsValid() ? myMainSceneFbos[0].operator->() : NULL,
       myMainSceneFbos[1]->IsValid() ? myMainSceneFbos[1].operator->() : NULL
     };
+    OpenGl_FrameBuffer* aMainFbosOit[2] =
+    {
+      myMainSceneFbosOit[0]->IsValid() ? myMainSceneFbosOit[0].operator->() : NULL,
+      myMainSceneFbosOit[1]->IsValid() ? myMainSceneFbosOit[1].operator->() :
+        myMainSceneFbosOit[0]->IsValid() ? myMainSceneFbosOit[0].operator->() : NULL
+    };
+
     OpenGl_FrameBuffer* anImmFbos[2] =
     {
       myImmediateSceneFbos[0]->IsValid() ? myImmediateSceneFbos[0].operator->() : NULL,
       myImmediateSceneFbos[1]->IsValid() ? myImmediateSceneFbos[1].operator->() : NULL
     };
+    OpenGl_FrameBuffer* anImmFbosOit[2] =
+    {
+      myImmediateSceneFbosOit[0]->IsValid() ? myImmediateSceneFbosOit[0].operator->() : NULL,
+      myImmediateSceneFbosOit[1]->IsValid() ? myImmediateSceneFbosOit[1].operator->() :
+        myImmediateSceneFbosOit[0]->IsValid() ? myImmediateSceneFbosOit[0].operator->() : NULL
+    };
 
     if (!myTransientDrawToFront)
     {
-      anImmFbos[0] = aMainFbos[0];
-      anImmFbos[1] = aMainFbos[1];
+      anImmFbos   [0] = aMainFbos   [0];
+      anImmFbos   [1] = aMainFbos   [1];
+      anImmFbosOit[0] = aMainFbosOit[0];
+      anImmFbosOit[1] = aMainFbosOit[1];
     }
     else if (aStereoMode == Graphic3d_StereoMode_SoftPageFlip
           || aStereoMode == Graphic3d_StereoMode_QuadBuffer)
     {
-      anImmFbos[0] = NULL;
-      anImmFbos[1] = NULL;
+      anImmFbos   [0] = NULL;
+      anImmFbos   [1] = NULL;
+      anImmFbosOit[0] = NULL;
+      anImmFbosOit[1] = NULL;
     }
 
   #if !defined(GL_ES_VERSION_2_0)
@@ -269,7 +379,7 @@ void OpenGl_View::Redraw()
     aCtx->SetResolution (myRenderParams.Resolution, myRenderParams.ResolutionRatio(),
                          aMainFbos[0] != NULL ? myRenderParams.RenderResolutionScale : 1.0f);
 
-    redraw (Graphic3d_Camera::Projection_MonoLeftEye, aMainFbos[0]);
+    redraw (Graphic3d_Camera::Projection_MonoLeftEye, aMainFbos[0], aMainFbosOit[0]);
     myBackBufferRestored = Standard_True;
     myIsImmediateDrawn   = Standard_False;
   #if !defined(GL_ES_VERSION_2_0)
@@ -277,7 +387,7 @@ void OpenGl_View::Redraw()
   #endif
     aCtx->SetResolution (myRenderParams.Resolution, myRenderParams.ResolutionRatio(),
                          anImmFbos[0] != NULL ? myRenderParams.RenderResolutionScale : 1.0f);
-    if (!redrawImmediate (Graphic3d_Camera::Projection_MonoLeftEye, aMainFbos[0], anImmFbos[0]))
+    if (!redrawImmediate (Graphic3d_Camera::Projection_MonoLeftEye, aMainFbos[0], anImmFbos[0], anImmFbosOit[0]))
     {
       toSwap = false;
     }
@@ -292,12 +402,12 @@ void OpenGl_View::Redraw()
     aCtx->SetResolution (myRenderParams.Resolution, myRenderParams.ResolutionRatio(),
                          aMainFbos[1] != NULL ? myRenderParams.RenderResolutionScale : 1.0f);
 
-    redraw (Graphic3d_Camera::Projection_MonoRightEye, aMainFbos[1]);
+    redraw (Graphic3d_Camera::Projection_MonoRightEye, aMainFbos[1], aMainFbosOit[1]);
     myBackBufferRestored = Standard_True;
     myIsImmediateDrawn   = Standard_False;
     aCtx->SetResolution (myRenderParams.Resolution, myRenderParams.ResolutionRatio(),
                          anImmFbos[1] != NULL ? myRenderParams.RenderResolutionScale : 1.0f);
-    if (!redrawImmediate (Graphic3d_Camera::Projection_MonoRightEye, aMainFbos[1], anImmFbos[1]))
+    if (!redrawImmediate (Graphic3d_Camera::Projection_MonoRightEye, aMainFbos[1], anImmFbos[1], anImmFbosOit[1]))
     {
       toSwap = false;
     }
@@ -310,15 +420,19 @@ void OpenGl_View::Redraw()
   }
   else
   {
-    OpenGl_FrameBuffer* aMainFbo = myMainSceneFbos[0]->IsValid() ? myMainSceneFbos[0].operator->() : aFrameBuffer;
-    OpenGl_FrameBuffer* anImmFbo = aFrameBuffer;
-    if (!aCtx->caps->useSystemBuffer && myImmediateSceneFbos[0]->IsValid())
+    OpenGl_FrameBuffer* aMainFbo    = myMainSceneFbos[0]->IsValid() ? myMainSceneFbos[0].operator->() : aFrameBuffer;
+    OpenGl_FrameBuffer* aMainFboOit = myMainSceneFbosOit[0]->IsValid() ? myMainSceneFbosOit[0].operator->() : NULL;
+    OpenGl_FrameBuffer* anImmFbo    = aFrameBuffer;
+    OpenGl_FrameBuffer* anImmFboOit = NULL;
+    if (!myTransientDrawToFront)
     {
-      anImmFbo = myImmediateSceneFbos[0].operator->();
+      anImmFbo    = aMainFbo;
+      anImmFboOit = aMainFboOit;
     }
-    if (!myTransientDrawToFront)
+    else if (myImmediateSceneFbos[0]->IsValid())
     {
-      anImmFbo = aMainFbo;
+      anImmFbo    = myImmediateSceneFbos[0].operator->();
+      anImmFboOit = myImmediateSceneFbosOit[0]->IsValid() ? myImmediateSceneFbosOit[0].operator->() : NULL;
     }
 
   #if !defined(GL_ES_VERSION_2_0)
@@ -329,12 +443,13 @@ void OpenGl_View::Redraw()
   #endif
     aCtx->SetResolution (myRenderParams.Resolution, myRenderParams.ResolutionRatio(),
                          aMainFbo != aFrameBuffer ? myRenderParams.RenderResolutionScale : 1.0f);
-    redraw (aProjectType, aMainFbo);
+
+    redraw (aProjectType, aMainFbo, aMainFboOit);
     myBackBufferRestored = Standard_True;
     myIsImmediateDrawn   = Standard_False;
     aCtx->SetResolution (myRenderParams.Resolution, myRenderParams.ResolutionRatio(),
                          anImmFbo != aFrameBuffer ? myRenderParams.RenderResolutionScale : 1.0f);
-    if (!redrawImmediate (aProjectType, aMainFbo, anImmFbo))
+    if (!redrawImmediate (aProjectType, aMainFbo, anImmFbo, anImmFboOit))
     {
       toSwap = false;
     }
@@ -437,11 +552,19 @@ void OpenGl_View::RedrawImmediate()
       myImmediateSceneFbos[0]->IsValid() ? myImmediateSceneFbos[0].operator->() : NULL,
       myImmediateSceneFbos[1]->IsValid() ? myImmediateSceneFbos[1].operator->() : NULL
     };
+    OpenGl_FrameBuffer* anImmFbosOit[2] =
+    {
+      myImmediateSceneFbosOit[0]->IsValid() ? myImmediateSceneFbosOit[0].operator->() : NULL,
+      myImmediateSceneFbosOit[1]->IsValid() ? myImmediateSceneFbosOit[1].operator->() :
+        myImmediateSceneFbosOit[0]->IsValid() ? myImmediateSceneFbosOit[0].operator->() : NULL
+    };
     if (aStereoMode == Graphic3d_StereoMode_SoftPageFlip
      || aStereoMode == Graphic3d_StereoMode_QuadBuffer)
     {
-      anImmFbos[0] = NULL;
-      anImmFbos[1] = NULL;
+      anImmFbos[0]    = NULL;
+      anImmFbos[1]    = NULL;
+      anImmFbosOit[0] = NULL;
+      anImmFbosOit[1] = NULL;
     }
 
     if (aCtx->arbFBO != NULL)
@@ -460,6 +583,7 @@ void OpenGl_View::RedrawImmediate()
     toSwap = redrawImmediate (Graphic3d_Camera::Projection_MonoLeftEye,
                               aMainFbos[0],
                               anImmFbos[0],
+                              anImmFbosOit[0],
                               Standard_True) || toSwap;
     if (aStereoMode == Graphic3d_StereoMode_SoftPageFlip
     &&  toSwap
@@ -483,6 +607,7 @@ void OpenGl_View::RedrawImmediate()
     toSwap = redrawImmediate (Graphic3d_Camera::Projection_MonoRightEye,
                               aMainFbos[1],
                               anImmFbos[1],
+                              anImmFbosOit[1],
                               Standard_True) || toSwap;
     if (anImmFbos[0] != NULL)
     {
@@ -493,9 +618,11 @@ void OpenGl_View::RedrawImmediate()
   {
     OpenGl_FrameBuffer* aMainFbo = myMainSceneFbos[0]->IsValid() ? myMainSceneFbos[0].operator->() : NULL;
     OpenGl_FrameBuffer* anImmFbo = aFrameBuffer;
-    if (!aCtx->caps->useSystemBuffer && myImmediateSceneFbos[0]->IsValid())
+    OpenGl_FrameBuffer* anImmFboOit = NULL;
+    if (myImmediateSceneFbos[0]->IsValid())
     {
-      anImmFbo = myImmediateSceneFbos[0].operator->();
+      anImmFbo    = myImmediateSceneFbos[0].operator->();
+      anImmFboOit = myImmediateSceneFbosOit[0]->IsValid() ? myImmediateSceneFbosOit[0].operator->() : NULL;
     }
   #if !defined(GL_ES_VERSION_2_0)
     if (aMainFbo == NULL)
@@ -508,6 +635,7 @@ void OpenGl_View::RedrawImmediate()
     toSwap = redrawImmediate (aProjectType,
                               aMainFbo,
                               anImmFbo,
+                              anImmFboOit,
                               Standard_True) || toSwap;
     if (anImmFbo != NULL
      && anImmFbo != aFrameBuffer)
@@ -539,7 +667,9 @@ void OpenGl_View::RedrawImmediate()
 // function : redraw
 // purpose  :
 // =======================================================================
-void OpenGl_View::redraw (const Graphic3d_Camera::Projection theProjection, OpenGl_FrameBuffer* theReadDrawFbo)
+void OpenGl_View::redraw (const Graphic3d_Camera::Projection theProjection,
+                          OpenGl_FrameBuffer*                theReadDrawFbo,
+                          OpenGl_FrameBuffer*                theOitAccumFbo)
 {
   Handle(OpenGl_Context) aCtx = myWorkspace->GetGlContext();
   if (theReadDrawFbo != NULL)
@@ -574,7 +704,7 @@ void OpenGl_View::redraw (const Graphic3d_Camera::Projection theProjection, Open
 
   glClear (toClear);
 
-  render (theProjection, theReadDrawFbo, Standard_False);
+  render (theProjection, theReadDrawFbo, theOitAccumFbo, Standard_False);
 }
 
 // =======================================================================
@@ -582,9 +712,10 @@ void OpenGl_View::redraw (const Graphic3d_Camera::Projection theProjection, Open
 // purpose  :
 // =======================================================================
 bool OpenGl_View::redrawImmediate (const Graphic3d_Camera::Projection theProjection,
-                                   OpenGl_FrameBuffer*    theReadFbo,
-                                   OpenGl_FrameBuffer*    theDrawFbo,
-                                   const Standard_Boolean theIsPartialUpdate)
+                                   OpenGl_FrameBuffer*                theReadFbo,
+                                   OpenGl_FrameBuffer*                theDrawFbo,
+                                   OpenGl_FrameBuffer*                theOitAccumFbo,
+                                   const Standard_Boolean             theIsPartialUpdate)
 {
   Handle(OpenGl_Context) aCtx = myWorkspace->GetGlContext();
   GLboolean toCopyBackToFront = GL_FALSE;
@@ -639,7 +770,7 @@ bool OpenGl_View::redrawImmediate (const Graphic3d_Camera::Projection theProject
   glClearDepthf (1.0f);
 #endif
 
-  render (theProjection, theDrawFbo, Standard_True);
+  render (theProjection, theDrawFbo, theOitAccumFbo, Standard_True);
 
   return !toCopyBackToFront;
 }
@@ -650,6 +781,7 @@ bool OpenGl_View::redrawImmediate (const Graphic3d_Camera::Projection theProject
 //=======================================================================
 void OpenGl_View::render (Graphic3d_Camera::Projection theProjection,
                           OpenGl_FrameBuffer*          theOutputFBO,
+                          OpenGl_FrameBuffer*          theOitAccumFbo,
                           const Standard_Boolean       theToDrawImmediate)
 {
   // ==================================
@@ -774,7 +906,7 @@ void OpenGl_View::render (Graphic3d_Camera::Projection theProjection,
 
   myWorkspace->SetEnvironmentTexture (myTextureEnv);
 
-  renderScene (theProjection, theOutputFBO, theToDrawImmediate);
+  renderScene (theProjection, theOutputFBO, theOitAccumFbo, theToDrawImmediate);
 
   myWorkspace->SetEnvironmentTexture (Handle(OpenGl_Texture)());
 
@@ -834,6 +966,7 @@ void OpenGl_View::InvalidateBVHData (const Graphic3d_ZLayerId theLayerId)
 //=======================================================================
 void OpenGl_View::renderStructs (Graphic3d_Camera::Projection theProjection,
                                  OpenGl_FrameBuffer*          theReadDrawFbo,
+                                 OpenGl_FrameBuffer*          theOitAccumFbo,
                                  const Standard_Boolean       theToDrawImmediate)
 {
   if ( myZLayers.NbStructures() <= 0 )
@@ -870,7 +1003,7 @@ void OpenGl_View::renderStructs (Graphic3d_Camera::Projection theProjection,
       if (aCtx->arbFBOBlit != NULL)
       {
         // Render bottom OSD layer
-        myZLayers.Render (myWorkspace, theToDrawImmediate, OpenGl_LF_Bottom);
+        myZLayers.Render (myWorkspace, theToDrawImmediate, OpenGl_LF_Bottom, theReadDrawFbo, theOitAccumFbo);
 
         myWorkspace->SetRenderFilter (myRaytraceFilter);
         {
@@ -884,7 +1017,7 @@ void OpenGl_View::renderStructs (Graphic3d_Camera::Projection theProjection,
           }
 
           // Render non-polygonal elements in default layer
-          myZLayers.Render (myWorkspace, theToDrawImmediate, OpenGl_LF_Default);
+          myZLayers.Render (myWorkspace, theToDrawImmediate, OpenGl_LF_Default, theReadDrawFbo, theOitAccumFbo);
         }
         myWorkspace->SetRenderFilter (myRaytraceFilter->PrevRenderFilter());
       }
@@ -906,7 +1039,7 @@ void OpenGl_View::renderStructs (Graphic3d_Camera::Projection theProjection,
       raytrace (aSizeX, aSizeY, theProjection, theReadDrawFbo, aCtx);
 
       // Render upper (top and topmost) OpenGL layers
-      myZLayers.Render (myWorkspace, theToDrawImmediate, OpenGl_LF_Upper);
+      myZLayers.Render (myWorkspace, theToDrawImmediate, OpenGl_LF_Upper, theReadDrawFbo, theOitAccumFbo);
     }
   }
 
@@ -914,7 +1047,7 @@ void OpenGl_View::renderStructs (Graphic3d_Camera::Projection theProjection,
   // mode or in case of ray-tracing failure
   if (toRenderGL)
   {
-    myZLayers.Render (myWorkspace, theToDrawImmediate, OpenGl_LF_All);
+    myZLayers.Render (myWorkspace, theToDrawImmediate, OpenGl_LF_All, theReadDrawFbo, theOitAccumFbo);
 
     // Set flag that scene was redrawn by standard pipeline
     myWasRedrawnGL = Standard_True;
@@ -948,6 +1081,7 @@ void OpenGl_View::Invalidate()
 //=======================================================================
 void OpenGl_View::renderScene (Graphic3d_Camera::Projection theProjection,
                                OpenGl_FrameBuffer*          theReadDrawFbo,
+                               OpenGl_FrameBuffer*          theOitAccumFbo,
                                const Standard_Boolean       theToDrawImmediate)
 {
   const Handle(OpenGl_Context)& aContext = myWorkspace->GetGlContext();
@@ -960,7 +1094,7 @@ void OpenGl_View::renderScene (Graphic3d_Camera::Projection theProjection,
     aContext->ShaderManager()->UpdateClippingState();
   }
 
-  renderStructs (theProjection, theReadDrawFbo, theToDrawImmediate);
+  renderStructs (theProjection, theReadDrawFbo, theOitAccumFbo, theToDrawImmediate);
   myWorkspace->DisableTexture();
 
   // Apply restored view matrix.
@@ -1476,3 +1610,74 @@ void OpenGl_View::copyBackToFront()
 #endif
   myIsImmediateDrawn = Standard_False;
 }
+
+// =======================================================================
+// function : checkOitCompatibility
+// purpose  :
+// =======================================================================
+Standard_Boolean OpenGl_View::checkOitCompatibility (const Handle(OpenGl_Context)& theGlContext,
+                                                     const Standard_Boolean theMSAA)
+{
+  // determine if OIT is supported by current OpenGl context
+  Standard_Boolean& aToDisableOIT = theMSAA ? myToDisableMSAA : myToDisableOIT;
+  if (aToDisableOIT)
+  {
+    return Standard_False;
+  }
+
+  TCollection_ExtendedString aCompatibilityMsg;
+  if (!theGlContext->hasFloatBuffer
+   && !theGlContext->hasHalfFloatBuffer)
+  {
+    aCompatibilityMsg += "OpenGL context does not support floating-point RGBA color buffer format.\n";
+  }
+  if (theMSAA && !theGlContext->hasSampleVariables)
+  {
+    aCompatibilityMsg += "Current version of GLSL does not support built-in sample variables.\n";
+  }
+  if (!theGlContext->hasDrawBuffers)
+  {
+    aCompatibilityMsg += "OpenGL context does not support multiple draw buffers.\n";
+  }
+  if (aCompatibilityMsg.IsEmpty())
+  {
+    return Standard_True;
+  }
+
+  aCompatibilityMsg += "  Blended order-independent transparency will not be available.\n";
+  theGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION,
+                          GL_DEBUG_TYPE_ERROR,
+                          0,
+                          GL_DEBUG_SEVERITY_HIGH,
+                          aCompatibilityMsg);
+
+  aToDisableOIT = Standard_True;
+  return Standard_False;
+}
+
+// =======================================================================
+// function : chooseOitColorConfiguration
+// purpose  :
+// =======================================================================
+bool OpenGl_View::chooseOitColorConfiguration (const Handle(OpenGl_Context)& theGlContext,
+                                               const Standard_Integer theConfigIndex,
+                                               OpenGl_ColorFormats& theFormats)
+{
+  theFormats.Clear();
+  switch (theConfigIndex)
+  {
+    case 0: // choose best applicable color format combination
+    {
+      theFormats.Append (theGlContext->hasHalfFloatBuffer ? GL_RGBA16F : GL_RGBA32F);
+      theFormats.Append (theGlContext->hasHalfFloatBuffer ? GL_R16F    : GL_R32F);
+      return true;
+    }
+    case 1: // choose non-optimal applicable color format combination
+    {
+      theFormats.Append (theGlContext->hasHalfFloatBuffer ? GL_RGBA16F : GL_RGBA32F);
+      theFormats.Append (theGlContext->hasHalfFloatBuffer ? GL_RGBA16F : GL_RGBA32F);
+      return true;
+    }
+  }
+  return false; // color combination does not exist
+}
index 4f17f24..7ec727d 100644 (file)
@@ -712,7 +712,7 @@ const OpenGl_AspectFace* OpenGl_Workspace::ApplyAspectFace()
   }
   else
   {
-    myGlContext->SetShadingMaterial (myAspectFaceSet, myHighlightStyle, myUseDepthWrite);
+    myGlContext->SetShadingMaterial (myAspectFaceSet, myHighlightStyle);
   }
 
   if (myAspectFaceSet->Aspect()->ToMapTexture())
@@ -1104,15 +1104,16 @@ Standard_Boolean OpenGl_Workspace::BufferDump (const Handle(OpenGl_FrameBuffer)&
 }
 
 // =======================================================================
-// function : CanRender
+// function : ShouldRender
 // purpose  :
 // =======================================================================
-Standard_Boolean OpenGl_RaytraceFilter::CanRender (const OpenGl_Element* theElement)
+Standard_Boolean OpenGl_RaytraceFilter::ShouldRender (const Handle(OpenGl_Workspace)& theWorkspace,
+                                                      const OpenGl_Element*           theElement)
 {
   Standard_Boolean aPrevFilterResult = Standard_True;
   if (!myPrevRenderFilter.IsNull())
   {
-    aPrevFilterResult = myPrevRenderFilter->CanRender (theElement);
+    aPrevFilterResult = myPrevRenderFilter->ShouldRender (theWorkspace, theElement);
   }
   return aPrevFilterResult &&
     !OpenGl_Raytrace::IsRaytracedElement (theElement);
index 10cb687..9086b01 100644 (file)
@@ -61,7 +61,8 @@ public:
   //! Checks whether the element can be rendered or not.
   //! @param theElement [in] the element to check.
   //! @return True if element can be rendered.
-  virtual Standard_Boolean CanRender (const OpenGl_Element* theElement) Standard_OVERRIDE;
+  virtual Standard_Boolean ShouldRender (const Handle(OpenGl_Workspace)& theWorkspace,
+                                         const OpenGl_Element*           theElement) Standard_OVERRIDE;
 
 private:
 
index 5a0c1df..716eed8 100644 (file)
   THE_ATTRIBUTE vec4 occVertColor;
 #elif (__VERSION__ >= 130)
   out vec4 occFragColor;
+  #ifdef OCC_ENABLE_draw_buffers
+    out vec4 occFragCoverage;
+  #endif
 #else
-  #define occFragColor gl_FragColor
+  #ifdef OCC_ENABLE_draw_buffers
+    #define occFragColor    gl_FragData[0]
+    #define occFragCoverage gl_FragData[1]
+  #else
+    #define occFragColor gl_FragColor
+  #endif
 #endif
 
 // Matrix state
@@ -110,6 +118,10 @@ uniform               sampler2D occActiveSampler;      //!< Current active sampl
 uniform               vec4      occTexTrsf2d[2];       //!< 2D texture transformation parameters
 uniform               float     occPointSize;          //!< point size
 
+//! Parameters of blended order-independent transparency rendering algorithm
+uniform               int       occOitOutput;      //!< Enable bit for writing output color buffers for OIT (occFragColor, occFragCoverage)
+uniform               float     occOitDepthFactor; //!< Influence of the depth component to the coverage of the accumulated fragment
+
 //! Parameters of clipping planes
 uniform               vec4 occClipPlaneEquations[THE_MAX_CLIP_PLANES];
 uniform THE_PREC_ENUM int  occClipPlaneCount;   //!< Total number of clip planes
index 925e5d2..15311c7 100755 (executable)
@@ -166,10 +166,11 @@ vec4 computeLighting (in vec3 theNormal,
   vec4 aMaterialDiffuse  = gl_FrontFacing ? occFrontMaterial_Diffuse()  : occBackMaterial_Diffuse();
   vec4 aMaterialSpecular = gl_FrontFacing ? occFrontMaterial_Specular() : occBackMaterial_Specular();
   vec4 aMaterialEmission = gl_FrontFacing ? occFrontMaterial_Emission() : occBackMaterial_Emission();
-  return vec4 (Ambient,  1.0) * aMaterialAmbient
-       + vec4 (Diffuse,  1.0) * aMaterialDiffuse
-       + vec4 (Specular, 1.0) * aMaterialSpecular
-                              + aMaterialEmission;
+  vec3 aColor = Ambient  * aMaterialAmbient.rgb
+              + Diffuse  * aMaterialDiffuse.rgb
+              + Specular * aMaterialSpecular.rgb
+                         + aMaterialEmission.rgb;
+  return vec4 (aColor, aMaterialDiffuse.a);
 }
 
 //! Entry point to the Fragment Shader
@@ -185,7 +186,14 @@ void main()
     }
   }
 
-  gl_FragColor = computeLighting (normalize (Normal),
+  occFragColor = computeLighting (normalize (Normal),
                                   normalize (View),
                                   Position);
+
+  if (occOitOutput != 0)
+  {
+    float aWeight     = occFragColor.a * clamp (1e+2 * pow (1.0 - gl_FragCoord.z * occOitDepthFactor, 3.0), 1e-2, 1e+2);
+    occFragCoverage.r = occFragColor.a * aWeight;
+    occFragColor      = vec4 (occFragColor.rgb * occFragColor.a * aWeight, occFragColor.a);
+  }
 }
index da73849..d2d9191 100644 (file)
@@ -50,8 +50,16 @@ static const char Shaders_Declarations_glsl[] =
   "  THE_ATTRIBUTE vec4 occVertColor;\n"
   "#elif (__VERSION__ >= 130)\n"
   "  out vec4 occFragColor;\n"
+  "  #ifdef OCC_ENABLE_draw_buffers\n"
+  "    out vec4 occFragCoverage;\n"
+  "  #endif\n"
   "#else\n"
-  "  #define occFragColor gl_FragColor\n"
+  "  #ifdef OCC_ENABLE_draw_buffers\n"
+  "    #define occFragColor    gl_FragData[0]\n"
+  "    #define occFragCoverage gl_FragData[1]\n"
+  "  #else\n"
+  "    #define occFragColor gl_FragColor\n"
+  "  #endif\n"
   "#endif\n"
   "\n"
   "// Matrix state\n"
@@ -113,6 +121,10 @@ static const char Shaders_Declarations_glsl[] =
   "uniform               vec4      occTexTrsf2d[2];       //!< 2D texture transformation parameters\n"
   "uniform               float     occPointSize;          //!< point size\n"
   "\n"
+  "//! Parameters of blended order-independent transparency rendering algorithm\n"
+  "uniform               int       occOitOutput;      //!< Enable bit for writing output color buffers for OIT (occFragColor, occFragCoverage)\n"
+  "uniform               float     occOitDepthFactor; //!< Influence of the depth component to the coverage of the accumulated fragment\n"
+  "\n"
   "//! Parameters of clipping planes\n"
   "uniform               vec4 occClipPlaneEquations[THE_MAX_CLIP_PLANES];\n"
   "uniform THE_PREC_ENUM int  occClipPlaneCount;   //!< Total number of clip planes\n";
index c8c0b14..e9245b4 100644 (file)
@@ -9123,6 +9123,14 @@ static Standard_Integer VRenderParams (Draw_Interpretor& theDI,
       case Graphic3d_RM_RAYTRACING:    theDI << "raytrace ";      break;
     }
     theDI << "\n";
+    theDI << "transparency:  ";
+    switch (aParams.TransparencyMethod)
+    {
+      case Graphic3d_RTM_BLEND_UNORDERED: theDI << "Basic blended transparency with non-commuting operator "; break;
+      case Graphic3d_RTM_BLEND_OIT:       theDI << "Weighted Blended Order-Independent Transparency, depth weight factor: "
+                                                << TCollection_AsciiString (aParams.OitDepthFactor); break;
+    }
+    theDI << "\n";
     theDI << "msaa:           " <<  aParams.NbMsaaSamples                               << "\n";
     theDI << "rendScale:      " <<  aParams.RenderResolutionScale                       << "\n";
     theDI << "rayDepth:       " <<  aParams.RaytracingDepth                             << "\n";
@@ -9232,6 +9240,50 @@ static Standard_Integer VRenderParams (Draw_Interpretor& theDI,
         aParams.NbMsaaSamples = aNbSamples;
       }
     }
+    else if (aFlag == "-oit")
+    {
+      if (toPrint)
+      {
+        if (aParams.TransparencyMethod == Graphic3d_RTM_BLEND_OIT)
+        {
+          theDI << "on, depth weight factor: " << TCollection_AsciiString (aParams.OitDepthFactor) << " ";
+        }
+        else
+        {
+          theDI << "off" << " ";
+        }
+        continue;
+      }
+      else if (++anArgIter >= theArgNb)
+      {
+        std::cerr << "Error: wrong syntax at argument '" << anArg << "'\n";
+        return 1;
+      }
+
+      TCollection_AsciiString aParam = theArgVec[anArgIter];
+      aParam.LowerCase();
+      if (aParam.IsRealValue())
+      {
+        const Standard_ShortReal aWeight = (Standard_ShortReal) Draw::Atof (theArgVec[anArgIter]);
+        if (aWeight < 0.f || aWeight > 1.f)
+        {
+          std::cerr << "Error: invalid value of Weighted Order-Independent Transparency depth weight factor " << aWeight << ". Should be within range [0.0; 1.0]\n";
+          return 1;
+        }
+
+        aParams.TransparencyMethod = Graphic3d_RTM_BLEND_OIT;
+        aParams.OitDepthFactor     = aWeight;
+      }
+      else if (aParam == "off")
+      {
+        aParams.TransparencyMethod = Graphic3d_RTM_BLEND_UNORDERED;
+      }
+      else
+      {
+        std::cerr << "Error: wrong syntax at argument '" << anArg << "'\n";
+        return 1;
+      }
+    }
     else if (aFlag == "-rendscale"
           || aFlag == "-renderscale"
           || aFlag == "-renderresolutionscale")
@@ -11070,27 +11122,28 @@ void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands)
     __FILE__, VRenderParams, group);
   theCommands.Add("vrenderparams",
     "\n    Manages rendering parameters: "
-    "\n      '-raster'                Disables GPU ray-tracing"
-    "\n      '-msaa         0..4'     Specifies number of samples for MSAA"
-    "\n      '-rendScale    value     Rendering resolution scale factor"
-    "\n      '-rayTrace'              Enables  GPU ray-tracing"
-    "\n      '-rayDepth     0..10'    Defines maximum ray-tracing depth"
-    "\n      '-shadows      on|off'   Enables/disables shadows rendering"
-    "\n      '-reflections  on|off'   Enables/disables specular reflections"
-    "\n      '-fsaa         on|off'   Enables/disables adaptive anti-aliasing"
-    "\n      '-gleam        on|off'   Enables/disables transparency shadow effects"
-    "\n      '-gi           on|off'   Enables/disables global illumination effects"
-    "\n      '-brng         on|off'   Enables/disables blocked RNG (fast coherent PT)"
-    "\n      '-env          on|off'   Enables/disables environment map background"
-    "\n      '-twoside      on|off'   Enables/disables two-sided BSDF models (PT mode)"
-    "\n      '-iss          on|off'   Enables/disables adaptive screen sampling (PT mode)"
-    "\n      '-issd         on|off'   Shows screen sampling distribution in ISS mode"
-    "\n      '-maxrad       > 0.0'    Value used for clamping radiance estimation (PT mode)"
-    "\n      '-nbtiles      64..1024' Specifies number of screen tiles in ISS mode"
-    "\n      '-rebuildGlsl  on|off'   Rebuild Ray-Tracing GLSL programs (for debugging)"
-    "\n      '-shadingModel model'    Controls shading model from enumeration"
-    "\n                               color, flat, gouraud, phong"
-    "\n      '-resolution   value'    Sets a new pixels density (PPI), defines scaling factor for parameters like text size"
+    "\n      '-raster'                   Disables GPU ray-tracing"
+    "\n      '-msaa         0..4'        Specifies number of samples for MSAA"
+    "\n      '-oit          off|0.0-1.0' Enables/disables OIT and sets depth weight factor"
+    "\n      '-rendScale    value        Rendering resolution scale factor"
+    "\n      '-rayTrace'                 Enables  GPU ray-tracing"
+    "\n      '-rayDepth     0..10'       Defines maximum ray-tracing depth"
+    "\n      '-shadows      on|off'      Enables/disables shadows rendering"
+    "\n      '-reflections  on|off'      Enables/disables specular reflections"
+    "\n      '-fsaa         on|off'      Enables/disables adaptive anti-aliasing"
+    "\n      '-gleam        on|off'      Enables/disables transparency shadow effects"
+    "\n      '-gi           on|off'      Enables/disables global illumination effects"
+    "\n      '-brng         on|off'      Enables/disables blocked RNG (fast coherent PT)"
+    "\n      '-env          on|off'      Enables/disables environment map background"
+    "\n      '-twoside      on|off'      Enables/disables two-sided BSDF models (PT mode)"
+    "\n      '-iss          on|off'      Enables/disables adaptive screen sampling (PT mode)"
+    "\n      '-issd         on|off'      Shows screen sampling distribution in ISS mode"
+    "\n      '-maxrad       > 0.0'       Value used for clamping radiance estimation (PT mode)"
+    "\n      '-nbtiles      64..1024'    Specifies number of screen tiles in ISS mode"
+    "\n      '-rebuildGlsl  on|off'      Rebuild Ray-Tracing GLSL programs (for debugging)"
+    "\n      '-shadingModel model'       Controls shading model from enumeration"
+    "\n                                  color, flat, gouraud, phong"
+    "\n      '-resolution   value'       Sets a new pixels density (PPI), defines scaling factor for parameters like text size"
     "\n    Unlike vcaps, these parameters dramatically change visual properties."
     "\n    Command is intended to control presentation quality depending on"
     "\n    hardware capabilities and performance.",
old mode 100644 (file)
new mode 100755 (executable)
index faed1c1..9db6b25
@@ -18,3 +18,4 @@
 019 manipulator
 020 anim
 021 dimensions
+022 transparency
diff --git a/tests/v3d/transparency/begin b/tests/v3d/transparency/begin
new file mode 100644 (file)
index 0000000..a79f0fc
--- /dev/null
@@ -0,0 +1,2 @@
+set subgroup "transparency"
+vinit View1
\ No newline at end of file
diff --git a/tests/v3d/transparency/blend b/tests/v3d/transparency/blend
new file mode 100644 (file)
index 0000000..0c40cd9
--- /dev/null
@@ -0,0 +1,41 @@
+puts "========"
+puts "Transparency - check different blend operators"
+puts "========"
+
+# custom shapes
+set aShape1 [locate_data_file occ/Top.brep]
+set aShape2 [locate_data_file occ/Bottom.brep]
+
+vinit View1
+vsetdispmode 1
+vsetgradientbg 180 180 180 255 255 255 2
+restore $aShape1 s1
+restore $aShape2 s2
+vdisplay s1
+vdisplay s2
+vsettransparency s1 0.5
+vsettransparency s2 0.5
+
+# check blending artifacts
+vviewparams -scale 4.519 -at 93.051 -88.513 17.789 -eye -156.923 -151.929 6.147 -up -0.246 0.969 0.002
+
+vrenderparams -oit off
+vdump $imagedir/${casename}_blend_artifacts_unordered.png
+
+vrenderparams -oit 1.0
+vdump $imagedir/${casename}_blend_artifacts_oit.png
+
+# check depth occlusion
+vsetcolor s1 red
+vsetcolor s2 black
+
+vviewparams -scale 5.807 -at -59.913 -276.799 -4.312 -eye -69.465 -20.350 23.739 -up 0.999 0.038 -0.009
+
+vrenderparams -oit off
+vdump $imagedir/${casename}_occlusion_unordered.png
+
+vrenderparams -oit 0.0
+vdump $imagedir/${casename}_occlusion_oit_nodepth.png
+
+vrenderparams -oit 1.0
+vdump $imagedir/${casename}_occlusion_oit.png
diff --git a/tests/v3d/transparency/highlight b/tests/v3d/transparency/highlight
new file mode 100644 (file)
index 0000000..4b1320d
--- /dev/null
@@ -0,0 +1,16 @@
+puts "========"
+puts "Transparency - shading highlight"
+puts "========"
+
+psphere s 1
+vinit View1
+vdisplay -dispMode 1 s
+vfit
+vsettransparency s 0.5
+vrenderparams -oit 0
+vselprops dynHighlight -dispMode -1
+vmoveto 250 250
+checkcolor 250 250 0 1 1
+if { $stat != 1 } {
+   puts "Error : Highlighting is broken."
+}