0029300: Visualization, TKOpenGl - provide depth pre-pass option
[occt.git] / src / OpenGl / OpenGl_LayerList.cxx
index ccefa2e..aa361ac 100644 (file)
 
 #include <Graphic3d_GraphicDriver.hxx>
 
+namespace
+{
+  //! Auxiliary class extending sequence iterator with index.
+  class OpenGl_IndexedLayerIterator : public OpenGl_SequenceOfLayers::Iterator
+  {
+  public:
+    //! Main constructor.
+    OpenGl_IndexedLayerIterator (const OpenGl_SequenceOfLayers& theSeq)
+    : OpenGl_SequenceOfLayers::Iterator (theSeq),
+      myIndex (theSeq.Lower()) {}
+
+    //! Return index of current position.
+    Standard_Integer Index() const { return myIndex; }
+
+    //! Move to the next position.
+    void Next()
+    {
+      OpenGl_SequenceOfLayers::Iterator::Next();
+      ++myIndex;
+    }
+
+  private:
+    Standard_Integer myIndex;
+  };
+
+  //! Iterator through layers with filter.
+  class OpenGl_FilteredIndexedLayerIterator
+  {
+  public:
+    //! Main constructor.
+    OpenGl_FilteredIndexedLayerIterator (const OpenGl_SequenceOfLayers& theSeq,
+                                         Standard_Integer theDefaultLayerIndex,
+                                         Standard_Boolean theToDrawImmediate,
+                                         OpenGl_LayerFilter theLayersToProcess)
+    : myIter (theSeq),
+      myDefaultLayerIndex (theDefaultLayerIndex),
+      myLayersToProcess (theLayersToProcess),
+      myToDrawImmediate (theToDrawImmediate)
+    {
+      next();
+    }
+
+    //! Return true if iterator points to the valid value.
+    bool More() const { return myIter.More(); }
+
+    //! Return layer at current position.
+    const OpenGl_Layer& Value() const { return *myIter.Value(); }
+
+    //! Return index of current position.
+    Standard_Integer Index() const { return myIter.Index(); }
+
+    //! Go to the next item.
+    void Next()
+    {
+      myIter.Next();
+      next();
+    }
+
+  private:
+    //! Look for the nearest item passing filters.
+    void next()
+    {
+      for (; myIter.More(); myIter.Next())
+      {
+        if (myIter.Value()->IsImmediate() != myToDrawImmediate)
+        {
+          continue;
+        }
+
+        switch (myLayersToProcess)
+        {
+          case OpenGl_LF_All:
+          {
+            break;
+          }
+          case OpenGl_LF_Upper:
+          {
+            if (myIter.Index() <= myDefaultLayerIndex)
+            {
+              continue;
+            }
+            break;
+          }
+          case OpenGl_LF_Bottom:
+          {
+            if (myIter.Index() >= myDefaultLayerIndex)
+            {
+              continue;
+            }
+            break;
+          }
+          case OpenGl_LF_Default:
+          {
+            if (myIter.Index() != myDefaultLayerIndex)
+            {
+              continue;
+            }
+            break;
+          }
+        }
+        return;
+      }
+    }
+  private:
+    OpenGl_IndexedLayerIterator myIter;
+    Standard_Integer            myDefaultLayerIndex;
+    OpenGl_LayerFilter          myLayersToProcess;
+    Standard_Boolean            myToDrawImmediate;
+  };
+}
+
 //=======================================================================
 //function : OpenGl_LayerList
 //purpose  : Constructor
@@ -223,11 +334,10 @@ void OpenGl_LayerList::RemoveStructure (const OpenGl_Structure* theStructure)
   }
 
   // scan through layers and remove it
-  Standard_Integer aSeqId = 1;
-  for (OpenGl_SequenceOfLayers::Iterator anIts (myLayers); anIts.More(); anIts.Next(), ++aSeqId)
+  for (OpenGl_IndexedLayerIterator anIts (myLayers); anIts.More(); anIts.Next())
   {
     OpenGl_Layer& aLayerEx = *anIts.ChangeValue();
-    if (aSeqPos == aSeqId)
+    if (aSeqPos == anIts.Index())
     {
       continue;
     }
@@ -240,7 +350,7 @@ void OpenGl_LayerList::RemoveStructure (const OpenGl_Structure* theStructure)
         --myImmediateNbStructures;
       }
 
-      if (aSeqId == myDefaultLayerIndex
+      if (anIts.Index() == myDefaultLayerIndex
        && theStructure->IsRaytracable())
       {
         ++myModifStateOfRaytraceable;
@@ -299,10 +409,9 @@ void OpenGl_LayerList::ChangeLayer (const OpenGl_Structure*  theStructure,
   }
 
   // scan through layers and remove it
-  Standard_Integer aSeqId = 1;
-  for (OpenGl_SequenceOfLayers::Iterator anIts (myLayers); anIts.More(); anIts.Next(), ++aSeqId)
+  for (OpenGl_IndexedLayerIterator anIts (myLayers); anIts.More(); anIts.Next())
   {
-    if (aSeqPos == aSeqId)
+    if (aSeqPos == anIts.Index())
     {
       continue;
     }
@@ -311,7 +420,7 @@ void OpenGl_LayerList::ChangeLayer (const OpenGl_Structure*  theStructure,
     OpenGl_Layer& aLayerEx = *anIts.ChangeValue();
     if (aLayerEx.Remove (theStructure, aPriority, Standard_True))
     {
-      if (aSeqId == myDefaultLayerIndex
+      if (anIts.Index() == myDefaultLayerIndex
        && theStructure->IsRaytracable())
       {
         ++myModifStateOfRaytraceable;
@@ -356,10 +465,9 @@ void OpenGl_LayerList::ChangePriority (const OpenGl_Structure*  theStructure,
     return;
   }
 
-  Standard_Integer aSeqId = 1;
-  for (OpenGl_SequenceOfLayers::Iterator anIts (myLayers); anIts.More(); anIts.Next(), ++aSeqId)
+  for (OpenGl_IndexedLayerIterator anIts (myLayers); anIts.More(); anIts.Next())
   {
-    if (aSeqPos == aSeqId)
+    if (aSeqPos == anIts.Index())
     {
       continue;
     }
@@ -412,11 +520,12 @@ void OpenGl_LayerList::Render (const Handle(OpenGl_Workspace)& theWorkspace,
                                OpenGl_FrameBuffer*             theOitAccumFbo) const
 {
   // Remember global settings for glDepth function and write mask.
-  OpenGl_GlobalLayerSettings aDefaultSettings;
+  OpenGl_GlobalLayerSettings aPrevSettings;
 
   const Handle(OpenGl_Context)& aCtx = theWorkspace->GetGlContext();
-  aCtx->core11fwd->glGetIntegerv (GL_DEPTH_FUNC,      &aDefaultSettings.DepthFunc);
-  aCtx->core11fwd->glGetBooleanv (GL_DEPTH_WRITEMASK, &aDefaultSettings.DepthMask);
+  aCtx->core11fwd->glGetIntegerv (GL_DEPTH_FUNC,      &aPrevSettings.DepthFunc);
+  aCtx->core11fwd->glGetBooleanv (GL_DEPTH_WRITEMASK, &aPrevSettings.DepthMask);
+  OpenGl_GlobalLayerSettings aDefaultSettings = aPrevSettings;
 
   // 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
@@ -436,81 +545,114 @@ void OpenGl_LayerList::Render (const Handle(OpenGl_Workspace)& theWorkspace,
   myTransparentToProcess.Clear();
 
   OpenGl_LayerStack::iterator aStackIter (myTransparentToProcess.Origin());
-  Standard_Integer aSeqId = myLayers.Lower();
-  bool toClearDepth = false;
-  for (OpenGl_SequenceOfLayers::Iterator aLayerIter (myLayers); aLayerIter.More(); aLayerIter.Next(), ++aSeqId)
+  Standard_Integer aClearDepthLayerPrev = -1, aClearDepthLayer = -1;
+  const bool toPerformDepthPrepass = theWorkspace->View()->RenderingParams().ToEnableDepthPrepass
+                                  && aPrevSettings.DepthMask == GL_TRUE;
+  for (OpenGl_FilteredIndexedLayerIterator aLayerIterStart (myLayers, myDefaultLayerIndex, theToDrawImmediate, theLayersToProcess); aLayerIterStart.More();)
   {
-    if (theLayersToProcess == OpenGl_LF_Bottom)
-    {
-      if (aSeqId >= myDefaultLayerIndex) continue;
-    }
-    else if (theLayersToProcess == OpenGl_LF_Upper)
+    bool hasSkippedDepthLayers = false;
+    for (int aPassIter = toPerformDepthPrepass ? 0 : 2; aPassIter < 3; ++aPassIter)
     {
-      if (aSeqId <= myDefaultLayerIndex) continue;
-    }
-    else if (theLayersToProcess == OpenGl_LF_Default)
-    {
-      if (aSeqId != myDefaultLayerIndex) continue;
-    }
+      if (aPassIter == 0)
+      {
+        aCtx->SetColorMask (false);
+        aDefaultSettings.DepthFunc = aPrevSettings.DepthFunc;
+        aDefaultSettings.DepthMask = GL_TRUE;
+      }
+      else if (aPassIter == 1)
+      {
+        if (!hasSkippedDepthLayers)
+        {
+          continue;
+        }
+        aCtx->SetColorMask (true);
+        aDefaultSettings = aPrevSettings;
+      }
+      else if (aPassIter == 2)
+      {
+        aCtx->SetColorMask (true);
+        if (toPerformDepthPrepass)
+        {
+          aDefaultSettings.DepthFunc = GL_EQUAL;
+          aDefaultSettings.DepthMask = GL_FALSE;
+        }
+      }
 
-    const OpenGl_Layer& aLayer = *aLayerIter.Value();
-    if (aLayer.IsImmediate() != theToDrawImmediate)
-    {
-      continue;
+      OpenGl_FilteredIndexedLayerIterator aLayerIter (aLayerIterStart);
+      for (; aLayerIter.More(); aLayerIter.Next())
+      {
+        const OpenGl_Layer& aLayer = aLayerIter.Value();
+
+        // make sure to clear depth of previous layers even if layer has no structures
+        if (aLayer.LayerSettings().ToClearDepth())
+        {
+          aClearDepthLayer = aLayerIter.Index();
+        }
+        if (aLayer.NbStructures() < 1)
+        {
+          continue;
+        }
+        else if (aClearDepthLayer > aClearDepthLayerPrev)
+        {
+          // 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 (aPassIter == 2)
+          {
+            aLayerIterStart = aLayerIter;
+          }
+          else
+          {
+            aClearDepthLayer = -1;
+          }
+          break;
+        }
+        else if (aPassIter == 0
+             && !aLayer.LayerSettings().ToRenderInDepthPrepass())
+        {
+          hasSkippedDepthLayers = true;
+          continue;
+        }
+        else if (aPassIter == 1
+              && aLayer.LayerSettings().ToRenderInDepthPrepass())
+        {
+          continue;
+        }
+
+        // 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 (aPassIter != 0
+         && myRenderOpaqueFilter->NbSkipped() > 0)
+        {
+          myTransparentToProcess.Push (&aLayer);
+        }
+      }
+      if (aPassIter == 2
+      && !aLayerIter.More())
+      {
+        aLayerIterStart = aLayerIter;
+      }
     }
-    else if (aLayer.NbStructures() < 1)
+
+    if (!myTransparentToProcess.IsEmpty())
     {
-      // Make sure to clear depth of previous layers even if layer has no structures.
-      toClearDepth = toClearDepth || aLayer.LayerSettings().ToClearDepth();
-      continue;
+      renderTransparent (theWorkspace, aStackIter, aPrevSettings, theReadDrawFbo, theOitAccumFbo);
     }
-
-    // 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 (aClearDepthLayer > aClearDepthLayerPrev)
     {
-      if (!myTransparentToProcess.IsEmpty())
-      {
-        renderTransparent (theWorkspace, aStackIter, aDefaultSettings, theReadDrawFbo, theOitAccumFbo);
-      }
-
-      toClearDepth = false;
+      aClearDepthLayerPrev = aClearDepthLayer;
       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)
-  {
-    glDepthMask (GL_TRUE);
-    glClear (GL_DEPTH_BUFFER_BIT);
   }
 
-  aCtx->core11fwd->glDepthMask (aDefaultSettings.DepthMask);
-  aCtx->core11fwd->glDepthFunc (aDefaultSettings.DepthFunc);
+  aCtx->core11fwd->glDepthMask (aPrevSettings.DepthMask);
+  aCtx->core11fwd->glDepthFunc (aPrevSettings.DepthFunc);
 
   theWorkspace->SetRenderFilter (aPrevFilter);
 }