0030748: Visualization - Marker displayed in immediate layer ruins QT Quick view...
[occt.git] / src / OpenGl / OpenGl_LayerList.cxx
index c1efed5..4aee97b 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 <BVH_LinearBuilder.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 <InterfaceGraphic_Graphic3d.hxx>
-#include <InterfaceGraphic.hxx>
+#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;
+  };
+}
+
+struct OpenGl_GlobalLayerSettings
+{
+  GLint DepthFunc;
+  GLboolean DepthMask;
+};
 
 //=======================================================================
 //function : OpenGl_LayerList
 //=======================================================================
 
 OpenGl_LayerList::OpenGl_LayerList (const Standard_Integer theNbPriorities)
- : myNbPriorities (theNbPriorities),
-   myNbStructures (0)
+: myBVHBuilder (new BVH_LinearBuilder<Standard_Real, 3> (BVH_Constants_LeafNodeSizeSingle, BVH_Constants_MaxTreeDepth)),
+  myDefaultLayerIndex (0),
+  myNbPriorities (theNbPriorities),
+  myNbStructures (0),
+  myImmediateNbStructures (0),
+  myModifStateOfRaytraceable (0)
 {
-  // insert default priority layer
-  myLayers.Append (OpenGl_Layer (myNbPriorities));
-  myLayerIds.Bind (0, myLayers.Length());
-}
+  // insert default priority layers
+  myLayers.Append (new OpenGl_Layer (myNbPriorities, myBVHBuilder));
+  myLayerIds.Bind (Graphic3d_ZLayerId_BotOSD,  myLayers.Upper());
 
-//=======================================================================
-//function : ~OpenGl_LayerList
-//purpose  : Destructor
-//=======================================================================
+  myLayers.Append (new OpenGl_Layer (myNbPriorities, myBVHBuilder));
+  myLayerIds.Bind (Graphic3d_ZLayerId_Default, myLayers.Upper());
 
-OpenGl_LayerList::~OpenGl_LayerList ()
-{
-}
+  myLayers.Append (new OpenGl_Layer (myNbPriorities, myBVHBuilder));
+  myLayerIds.Bind (Graphic3d_ZLayerId_Top,     myLayers.Upper());
 
-//=======================================================================
-//function : defaultLayer
-//purpose  :
-//=======================================================================
+  myLayers.Append (new OpenGl_Layer (myNbPriorities, myBVHBuilder));
+  myLayerIds.Bind (Graphic3d_ZLayerId_Topmost, myLayers.Upper());
 
-OpenGl_Layer& OpenGl_LayerList::defaultLayer()
-{
-  return myLayers.ChangeValue (1);
+  myLayers.Append (new OpenGl_Layer (myNbPriorities, myBVHBuilder));
+  myLayerIds.Bind (Graphic3d_ZLayerId_TopOSD,  myLayers.Upper());
+
+  myDefaultLayerIndex = myLayerIds.Find (Graphic3d_ZLayerId_Default);
+
+  myTransparentToProcess.Allocate (myLayers.Length());
 }
 
 //=======================================================================
-//function : NbPriorities
-//purpose  : Method returns the number of available priorities
+//function : ~OpenGl_LayerList
+//purpose  : Destructor
 //=======================================================================
 
-Standard_Integer OpenGl_LayerList::NbPriorities () const
+OpenGl_LayerList::~OpenGl_LayerList()
 {
-  return myNbPriorities;
 }
 
 //=======================================================================
-//function : NbStructures
-//purpose  : Method returns the number of available structures
+//function : SetFrustumCullingBVHBuilder
+//purpose  :
 //=======================================================================
-
-Standard_Integer OpenGl_LayerList::NbStructures () const
+void OpenGl_LayerList::SetFrustumCullingBVHBuilder (const Handle(Select3D_BVHBuilder3d)& theBuilder)
 {
-  return myNbStructures;
+  myBVHBuilder = theBuilder;
+  for (OpenGl_SequenceOfLayers::Iterator anIts (myLayers); anIts.More(); anIts.Next())
+  {
+    anIts.ChangeValue()->SetFrustumCullingBVHBuilder (theBuilder);
+  }
 }
 
 //=======================================================================
@@ -79,43 +204,36 @@ Standard_Integer OpenGl_LayerList::NbStructures () const
 //purpose  : 
 //=======================================================================
 
-void OpenGl_LayerList::AddLayer (const Standard_Integer theLayerId)
+void OpenGl_LayerList::AddLayer (const Graphic3d_ZLayerId theLayerId)
 {
-  if (HasLayer (theLayerId))
+  if (myLayerIds.IsBound (theLayerId))
+  {
     return;
+  }
 
   // add the new layer
-  myLayers.Append (OpenGl_Layer (myNbPriorities));
+  myLayers.Append (new OpenGl_Layer (myNbPriorities, myBVHBuilder));
   myLayerIds.Bind (theLayerId, myLayers.Length());
-}
 
-//=======================================================================
-//function : HasLayer
-//purpose  : 
-//=======================================================================
-
-Standard_Boolean OpenGl_LayerList::HasLayer 
-  (const Standard_Integer theLayerId) const
-{
-  return myLayerIds.IsBound (theLayerId);
+  myTransparentToProcess.Allocate (myLayers.Length());
 }
 
 //=======================================================================
 //function : Layer
 //purpose  : 
 //=======================================================================
-OpenGl_Layer& OpenGl_LayerList::Layer (const Standard_Integer theLayerId)
+OpenGl_Layer& OpenGl_LayerList::Layer (const Graphic3d_ZLayerId theLayerId)
 {
-  return myLayers.ChangeValue (myLayerIds.Find (theLayerId));
+  return *myLayers.ChangeValue (myLayerIds.Find (theLayerId));
 }
 
 //=======================================================================
 //function : Layer
 //purpose  : 
 //=======================================================================
-const OpenGl_Layer& OpenGl_LayerList::Layer (const Standard_Integer theLayerId) const
+const OpenGl_Layer& OpenGl_LayerList::Layer (const Graphic3d_ZLayerId theLayerId) const
 {
-  return myLayers.Value (myLayerIds.Find (theLayerId));
+  return *myLayers.Value (myLayerIds.Find (theLayerId));
 }
 
 //=======================================================================
@@ -123,29 +241,37 @@ const OpenGl_Layer& OpenGl_LayerList::Layer (const Standard_Integer theLayerId)
 //purpose  :
 //=======================================================================
 
-void OpenGl_LayerList::RemoveLayer (const Standard_Integer theLayerId)
+void OpenGl_LayerList::RemoveLayer (const Graphic3d_ZLayerId theLayerId)
 {
-  if (!HasLayer (theLayerId) || theLayerId == 0)
+  if (!myLayerIds.IsBound (theLayerId)
+    || theLayerId <= 0)
+  {
     return;
+  }
 
-  Standard_Integer aRemovePos = myLayerIds.Find (theLayerId);
+  const Standard_Integer aRemovePos = myLayerIds.Find (theLayerId);
   
   // move all displayed structures to first layer
-  const OpenGl_PriorityList& aList = myLayers.Value (aRemovePos).PriorityList();
-  defaultLayer ().PriorityList().Append (aList);
+  {
+    const OpenGl_Layer& aLayerToMove = *myLayers.Value (aRemovePos);
+    myLayers.ChangeFirst()->Append (aLayerToMove);
+  }
 
   // remove layer
   myLayers.Remove (aRemovePos);
   myLayerIds.UnBind (theLayerId);
 
   // updated sequence indexes in map
-  OpenGl_LayerSeqIds::Iterator aMapIt (myLayerIds);
-  for ( ; aMapIt.More (); aMapIt.Next ())
+  for (OpenGl_LayerSeqIds::Iterator aMapIt (myLayerIds); aMapIt.More(); aMapIt.Next())
   {
-    Standard_Integer& aSeqIdx = aMapIt.ChangeValue ();
+    Standard_Integer& aSeqIdx = aMapIt.ChangeValue();
     if (aSeqIdx > aRemovePos)
       aSeqIdx--;
   }
+
+  myDefaultLayerIndex = myLayerIds.Find (Graphic3d_ZLayerId_Default);
+
+  myTransparentToProcess.Allocate (myLayers.Length());
 }
 
 //=======================================================================
@@ -153,17 +279,23 @@ void OpenGl_LayerList::RemoveLayer (const Standard_Integer theLayerId)
 //purpose  :
 //=======================================================================
 
-void OpenGl_LayerList::AddStructure (const OpenGl_Structure *theStructure,
-                                     const Standard_Integer  theLayerId,
-                                     const Standard_Integer  thePriority)
+void OpenGl_LayerList::AddStructure (const OpenGl_Structure*  theStruct,
+                                     const Graphic3d_ZLayerId theLayerId,
+                                     const Standard_Integer   thePriority,
+                                     Standard_Boolean         isForChangePriority)
 {
   // add structure to associated layer,
   // if layer doesn't exists, display structure in default layer
-  OpenGl_PriorityList& aList = !HasLayer (theLayerId) ? defaultLayer ().PriorityList() :
-    myLayers.ChangeValue (myLayerIds.Find (theLayerId)).PriorityList();
+  Standard_Integer aSeqPos = myLayers.Lower();
+  myLayerIds.Find (theLayerId, aSeqPos);
 
-  aList.Add (theStructure, thePriority);
-  myNbStructures++;
+  OpenGl_Layer& aLayer = *myLayers.ChangeValue (aSeqPos);
+  aLayer.Add (theStruct, thePriority, isForChangePriority);
+  ++myNbStructures;
+  if (aLayer.IsImmediate())
+  {
+    ++myImmediateNbStructures;
+  }
 
   // Note: In ray-tracing mode we don't modify modification
   // state here. It is redundant, because the possible changes
@@ -172,116 +304,661 @@ void OpenGl_LayerList::AddStructure (const OpenGl_Structure *theStructure,
 
 //=======================================================================
 //function : RemoveStructure
-//purpose  : 
+//purpose  :
 //=======================================================================
 
-void OpenGl_LayerList::RemoveStructure (const OpenGl_Structure *theStructure,
-                                        const Standard_Integer  theLayerId)
+void OpenGl_LayerList::RemoveStructure (const OpenGl_Structure* theStructure)
 {
-  Standard_Integer aSeqPos = !HasLayer (theLayerId) ?
-    1 : myLayerIds.Find (theLayerId);
-  
-  OpenGl_PriorityList& aList = myLayers.ChangeValue (aSeqPos).PriorityList();
+  const Graphic3d_ZLayerId aLayerId = theStructure->ZLayer();
+
+  Standard_Integer aSeqPos = myLayers.Lower();
+  myLayerIds.Find (aLayerId, aSeqPos);
+
+  OpenGl_Layer&    aLayer    = *myLayers.ChangeValue (aSeqPos);
+  Standard_Integer aPriority = -1;
 
   // remove structure from associated list
   // if the structure is not found there,
   // scan through layers and remove it
-  if (aList.Remove (theStructure) >= 0)
+  if (aLayer.Remove (theStructure, aPriority))
   {
-    myNbStructures--;
+    --myNbStructures;
+    if (aLayer.IsImmediate())
+    {
+      --myImmediateNbStructures;
+    }
 
-    if (theStructure->IsRaytracable())
+    if (aLayerId == Graphic3d_ZLayerId_Default
+     && theStructure->IsRaytracable())
     {
-      myModificationState++;
+      ++myModifStateOfRaytraceable;
     }
 
     return;
   }
-  
+
   // scan through layers and remove it
-  Standard_Integer aSeqId = 1;
-  OpenGl_SequenceOfLayers::Iterator anIts;
-  for (anIts.Init (myLayers); anIts.More (); anIts.Next (), aSeqId++)
+  for (OpenGl_IndexedLayerIterator anIts (myLayers); anIts.More(); anIts.Next())
   {
-    OpenGl_PriorityList& aScanList = anIts.ChangeValue ().PriorityList();
-    if (aSeqPos == aSeqId)
-      continue;
-  
-    if (aScanList.Remove (theStructure) >= 0)
+    OpenGl_Layer& aLayerEx = *anIts.ChangeValue();
+    if (aSeqPos == anIts.Index())
     {
-      myNbStructures--;
+      continue;
+    }
 
-      if (theStructure->IsRaytracable())
+    if (aLayerEx.Remove (theStructure, aPriority))
+    {
+      --myNbStructures;
+      if (aLayerEx.IsImmediate())
       {
-        myModificationState++;
+        --myImmediateNbStructures;
       }
 
+      if (anIts.Index() == myDefaultLayerIndex
+       && theStructure->IsRaytracable())
+      {
+        ++myModifStateOfRaytraceable;
+      }
       return;
     }
   }
 }
 
+//=======================================================================
+//function : InvalidateBVHData
+//purpose  :
+//=======================================================================
+void OpenGl_LayerList::InvalidateBVHData (const Graphic3d_ZLayerId theLayerId)
+{
+  Standard_Integer aSeqPos = myLayers.Lower();
+  myLayerIds.Find (theLayerId, aSeqPos);
+  OpenGl_Layer& aLayer = *myLayers.ChangeValue (aSeqPos);
+  aLayer.InvalidateBVHData();
+}
+
 //=======================================================================
 //function : ChangeLayer
 //purpose  :
 //=======================================================================
 
-void OpenGl_LayerList::ChangeLayer (const OpenGl_Structure *theStructure,
-                                    const Standard_Integer  theOldLayerId,
-                                    const Standard_Integer  theNewLayerId)
+void OpenGl_LayerList::ChangeLayer (const OpenGl_Structure*  theStructure,
+                                    const Graphic3d_ZLayerId theOldLayerId,
+                                    const Graphic3d_ZLayerId theNewLayerId)
 {
-  Standard_Integer aSeqPos = !HasLayer (theOldLayerId) ?
-    1 : myLayerIds.Find (theOldLayerId);
-  
-  OpenGl_PriorityList& aList = myLayers.ChangeValue (aSeqPos).PriorityList();
-  Standard_Integer aPriority;
+  Standard_Integer aSeqPos = myLayers.Lower();
+  myLayerIds.Find (theOldLayerId, aSeqPos);
+  OpenGl_Layer&    aLayer    = *myLayers.ChangeValue (aSeqPos);
+  Standard_Integer aPriority = -1;
 
   // take priority and remove structure from list found by <theOldLayerId>
   // if the structure is not found there, scan through all other layers
-  if ((aPriority = aList.Remove (theStructure)) >= 0)
+  if (aLayer.Remove (theStructure, aPriority, Standard_False))
   {
-    myNbStructures--;
+    if (theOldLayerId == Graphic3d_ZLayerId_Default
+     && theStructure->IsRaytracable())
+    {
+      ++myModifStateOfRaytraceable;
+    }
+
+    --myNbStructures;
+    if (aLayer.IsImmediate())
+    {
+      --myImmediateNbStructures;
+    }
+
+    // isForChangePriority should be Standard_False below, because we want
+    // the BVH tree in the target layer to be updated with theStructure
     AddStructure (theStructure, theNewLayerId, aPriority);
+    return;
   }
-  else
+
+  // scan through layers and remove it
+  for (OpenGl_IndexedLayerIterator anIts (myLayers); anIts.More(); anIts.Next())
   {
-    // scan through layers and remove it
-    Standard_Integer aSeqId = 1;
-    OpenGl_SequenceOfLayers::Iterator anIts;
-    for (anIts.Init (myLayers); anIts.More (); anIts.Next (), aSeqId++)
+    if (aSeqPos == anIts.Index())
     {
-      if (aSeqPos == aSeqId)
-        continue;
+      continue;
+    }
   
-      // try to remove structure and get priority value from this layer
-      if ((aPriority = aList.Remove (theStructure)) >= 0)
+    // try to remove structure and get priority value from this layer
+    OpenGl_Layer& aLayerEx = *anIts.ChangeValue();
+    if (aLayerEx.Remove (theStructure, aPriority, Standard_True))
+    {
+      if (anIts.Index() == myDefaultLayerIndex
+       && theStructure->IsRaytracable())
+      {
+        ++myModifStateOfRaytraceable;
+      }
+
+      --myNbStructures;
+      if (aLayerEx.IsImmediate())
+      {
+        --myImmediateNbStructures;
+      }
+
+      // isForChangePriority should be Standard_False below, because we want
+      // the BVH tree in the target layer to be updated with theStructure
+      AddStructure (theStructure, theNewLayerId, aPriority);
+      return;
+    }
+  }
+}
+
+//=======================================================================
+//function : ChangePriority
+//purpose  :
+//=======================================================================
+void OpenGl_LayerList::ChangePriority (const OpenGl_Structure*  theStructure,
+                                       const Graphic3d_ZLayerId theLayerId,
+                                       const Standard_Integer   theNewPriority)
+{
+  Standard_Integer aSeqPos = myLayers.Lower();
+  myLayerIds.Find (theLayerId, aSeqPos);
+  OpenGl_Layer&    aLayer        = *myLayers.ChangeValue (aSeqPos);
+  Standard_Integer anOldPriority = -1;
+
+  if (aLayer.Remove (theStructure, anOldPriority, Standard_True))
+  {
+    --myNbStructures;
+    if (aLayer.IsImmediate())
+    {
+      --myImmediateNbStructures;
+    }
+
+    AddStructure (theStructure, theLayerId, theNewPriority, Standard_True);
+    return;
+  }
+
+  for (OpenGl_IndexedLayerIterator anIts (myLayers); anIts.More(); anIts.Next())
+  {
+    if (aSeqPos == anIts.Index())
+    {
+      continue;
+    }
+
+    OpenGl_Layer& aLayerEx = *anIts.ChangeValue();
+    if (aLayerEx.Remove (theStructure, anOldPriority, Standard_True))
+    {
+      --myNbStructures;
+      if (aLayerEx.IsImmediate())
+      {
+        --myImmediateNbStructures;
+      }
+
+      AddStructure (theStructure, theLayerId, theNewPriority, Standard_True);
+      return;
+    }
+  }
+}
+
+//=======================================================================
+//function : SetLayerSettings
+//purpose  :
+//=======================================================================
+void OpenGl_LayerList::SetLayerSettings (const Graphic3d_ZLayerId        theLayerId,
+                                         const Graphic3d_ZLayerSettings& theSettings)
+{
+  OpenGl_Layer& aLayer = Layer (theLayerId);
+  if (aLayer.LayerSettings().IsImmediate() != theSettings.IsImmediate())
+  {
+    if (theSettings.IsImmediate())
+    {
+      myImmediateNbStructures += aLayer.NbStructures();
+    }
+    else
+    {
+      myImmediateNbStructures -= aLayer.NbStructures();
+    }
+  }
+  aLayer.SetLayerSettings (theSettings);
+}
+
+//=======================================================================
+//function : UpdateCulling
+//purpose  :
+//=======================================================================
+void OpenGl_LayerList::UpdateCulling (const Handle(OpenGl_Workspace)& theWorkspace,
+                                      const Standard_Boolean theToDrawImmediate)
+{
+  const Handle(OpenGl_FrameStats)& aStats = theWorkspace->GetGlContext()->FrameStats();
+  OSD_Timer& aTimer = aStats->ActiveDataFrame().ChangeTimer (Graphic3d_FrameStatsTimer_CpuCulling);
+  aTimer.Start();
+
+  const Standard_Integer aViewId = theWorkspace->View()->Identification();
+  const Graphic3d_CullingTool& aSelector = theWorkspace->View()->BVHTreeSelector();
+  for (OpenGl_IndexedLayerIterator anIts (myLayers); anIts.More(); anIts.Next())
+  {
+    OpenGl_Layer& aLayer = *anIts.ChangeValue();
+    if (aLayer.IsImmediate() != theToDrawImmediate)
+    {
+      continue;
+    }
+
+    aLayer.UpdateCulling (aViewId, aSelector, theWorkspace->View()->RenderingParams().FrustumCullingState);
+  }
+
+  aTimer.Stop();
+  aStats->ActiveDataFrame()[Graphic3d_FrameStatsTimer_CpuCulling] = aTimer.UserTimeCPU();
+}
+
+//=======================================================================
+//function : renderLayer
+//purpose  :
+//=======================================================================
+void OpenGl_LayerList::renderLayer (const Handle(OpenGl_Workspace)& theWorkspace,
+                                    const OpenGl_GlobalLayerSettings& theDefaultSettings,
+                                    const Graphic3d_Layer& theLayer) const
+{
+  const Handle(OpenGl_Context)& aCtx = theWorkspace->GetGlContext();
+
+  const Graphic3d_ZLayerSettings& aLayerSettings = theLayer.LayerSettings();
+  // aLayerSettings.ToClearDepth() is handled outside
+
+  // handle depth test
+  if (aLayerSettings.ToEnableDepthTest())
+  {
+    // assuming depth test is enabled by default
+    glDepthFunc (theDefaultSettings.DepthFunc);
+  }
+  else
+  {
+    glDepthFunc (GL_ALWAYS);
+  }
+
+  // save environment texture
+  Handle(OpenGl_TextureSet) anEnvironmentTexture = theWorkspace->EnvironmentTexture();
+  if (!aLayerSettings.UseEnvironmentTexture())
+  {
+    theWorkspace->SetEnvironmentTexture (Handle(OpenGl_TextureSet)());
+  }
+
+  // handle depth offset
+  const Graphic3d_PolygonOffset anAppliedOffsetParams = theWorkspace->SetDefaultPolygonOffset (aLayerSettings.PolygonOffset());
+
+  // handle depth write
+  theWorkspace->UseDepthWrite() = aLayerSettings.ToEnableDepthWrite() && theDefaultSettings.DepthMask == GL_TRUE;
+  glDepthMask (theWorkspace->UseDepthWrite() ? GL_TRUE : GL_FALSE);
+
+  const Standard_Boolean hasLocalCS = !aLayerSettings.OriginTransformation().IsNull();
+  const Handle(OpenGl_ShaderManager)& aManager = aCtx->ShaderManager();
+  Handle(Graphic3d_LightSet) aLightsBack = aManager->LightSourceState().LightSources();
+  const bool hasOwnLights = aCtx->ColorMask() && !aLayerSettings.Lights().IsNull() && aLayerSettings.Lights() != aLightsBack;
+  if (hasOwnLights)
+  {
+    aLayerSettings.Lights()->UpdateRevision();
+    aManager->UpdateLightSourceStateTo (aLayerSettings.Lights());
+  }
+
+  const Handle(Graphic3d_Camera)& aWorldCamera = theWorkspace->View()->Camera();
+  if (hasLocalCS)
+  {
+    // Apply local camera transformation.
+    // The vertex position is computed by the following formula in GLSL program:
+    //   gl_Position = occProjectionMatrix * occWorldViewMatrix * occModelWorldMatrix * occVertex;
+    // where:
+    //   occProjectionMatrix - matrix defining orthographic/perspective/stereographic projection
+    //   occWorldViewMatrix  - world-view  matrix defining Camera position and orientation
+    //   occModelWorldMatrix - model-world matrix defining Object transformation from local coordinate system to the world coordinate system
+    //   occVertex           - input vertex position
+    //
+    // Since double precision is quite expensive on modern GPUs, and not available on old hardware,
+    // all these values are passed with single float precision to the shader.
+    // As result, single precision become insufficient for handling objects far from the world origin.
+    //
+    // Several approaches can be used to solve precision issues:
+    //  - [Broute force] migrate to double precision for all matrices and vertex position.
+    //    This is too expensive for most hardware.
+    //  - Store only translation part with double precision and pass it to GLSL program.
+    //    This requires modified GLSL programs for computing transformation
+    //    and extra packing mechanism for hardware not supporting double precision natively.
+    //    This solution is less expensive then previous one.
+    //  - Move translation part of occModelWorldMatrix into occWorldViewMatrix.
+    //    The main idea here is that while moving Camera towards the object,
+    //    Camera translation part and Object translation part will compensate each other
+    //    to fit into single float precision.
+    //    But this operation should be performed with double precision - this is why we are moving
+    //    translation part of occModelWorldMatrix to occWorldViewMatrix.
+    //
+    // All approaches might be useful in different scenarios, but for the moment we consider the last one as main scenario.
+    // Here we do the trick:
+    //  - OpenGl_Layer defines the Local Origin, which is expected to be the center of objects stored within it.
+    //    This Local Origin is included into occWorldViewMatrix during rendering.
+    //  - OpenGl_Structure defines Object local transformation occModelWorldMatrix with subtracted Local Origin of the Layer.
+    //    This means that Object itself should be defined within either Local Transformation equal or near to Local Origin of the Layer.
+    theWorkspace->View()->SetLocalOrigin (aLayerSettings.Origin());
+
+    NCollection_Mat4<Standard_Real> aWorldView = aWorldCamera->OrientationMatrix();
+    Graphic3d_TransformUtils::Translate (aWorldView, aLayerSettings.Origin().X(), aLayerSettings.Origin().Y(), aLayerSettings.Origin().Z());
+
+    NCollection_Mat4<Standard_ShortReal> aWorldViewF;
+    aWorldViewF.ConvertFrom (aWorldView);
+    aCtx->WorldViewState.SetCurrent (aWorldViewF);
+    aCtx->ShaderManager()->UpdateClippingState();
+    aCtx->ShaderManager()->UpdateLightSourceState();
+  }
+
+  // render priority list
+  const Standard_Integer aViewId = theWorkspace->View()->Identification();
+  for (Graphic3d_ArrayOfIndexedMapOfStructure::Iterator aMapIter (theLayer.ArrayOfStructures()); aMapIter.More(); aMapIter.Next())
+  {
+    const Graphic3d_IndexedMapOfStructure& aStructures = aMapIter.Value();
+    for (OpenGl_Structure::StructIterator aStructIter (aStructures); aStructIter.More(); aStructIter.Next())
+    {
+      const OpenGl_Structure* aStruct = aStructIter.Value();
+      if (aStruct->IsCulled()
+      || !aStruct->IsVisible (aViewId))
       {
-        myNbStructures--;
-        AddStructure (theStructure, theNewLayerId, aPriority);
-        break;
+        continue;
       }
+
+      aStruct->Render (theWorkspace);
     }
   }
+
+  if (hasOwnLights)
+  {
+    aManager->UpdateLightSourceStateTo (aLightsBack);
+  }
+  if (hasLocalCS)
+  {
+    aCtx->ShaderManager()->RevertClippingState();
+    aCtx->ShaderManager()->UpdateLightSourceState();
+
+    aCtx->WorldViewState.SetCurrent (aWorldCamera->OrientationMatrixF());
+    theWorkspace->View() ->SetLocalOrigin (gp_XYZ (0.0, 0.0, 0.0));
+  }
+
+  // always restore polygon offset between layers rendering
+  theWorkspace->SetDefaultPolygonOffset (anAppliedOffsetParams);
+
+  // restore environment texture
+  if (!aLayerSettings.UseEnvironmentTexture())
+  {
+    theWorkspace->SetEnvironmentTexture (anEnvironmentTexture);
+  }
 }
 
 //=======================================================================
 //function : Render
-//purpose  : Render this element
+//purpose  :
 //=======================================================================
+void OpenGl_LayerList::Render (const Handle(OpenGl_Workspace)& theWorkspace,
+                               const Standard_Boolean          theToDrawImmediate,
+                               const OpenGl_LayerFilter        theLayersToProcess,
+                               OpenGl_FrameBuffer*             theReadDrawFbo,
+                               OpenGl_FrameBuffer*             theOitAccumFbo) const
+{
+  // Remember global settings for glDepth function and write mask.
+  OpenGl_GlobalLayerSettings aPrevSettings;
+
+  const Handle(OpenGl_Context)& aCtx = theWorkspace->GetGlContext();
+  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
+  // 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 Standard_Integer aPrevFilter = theWorkspace->RenderFilter() & ~(Standard_Integer )(OpenGl_RenderFilter_OpaqueOnly | OpenGl_RenderFilter_TransparentOnly);
+  theWorkspace->SetRenderFilter (aPrevFilter | OpenGl_RenderFilter_OpaqueOnly);
+
+  myTransparentToProcess.Clear();
+
+  OpenGl_LayerStack::iterator aStackIter (myTransparentToProcess.Origin());
+  Standard_Integer aClearDepthLayerPrev = -1, aClearDepthLayer = -1;
+  const bool toPerformDepthPrepass = theWorkspace->View()->RenderingParams().ToEnableDepthPrepass
+                                  && aPrevSettings.DepthMask == GL_TRUE;
+  const Handle(Graphic3d_LightSet) aLightsBack = aCtx->ShaderManager()->LightSourceState().LightSources();
+  for (OpenGl_FilteredIndexedLayerIterator aLayerIterStart (myLayers, myDefaultLayerIndex, theToDrawImmediate, theLayersToProcess); aLayerIterStart.More();)
+  {
+    bool hasSkippedDepthLayers = false;
+    for (int aPassIter = toPerformDepthPrepass ? 0 : 2; aPassIter < 3; ++aPassIter)
+    {
+      if (aPassIter == 0)
+      {
+        aCtx->SetColorMask (false);
+        aCtx->ShaderManager()->UpdateLightSourceStateTo (Handle(Graphic3d_LightSet)());
+        aDefaultSettings.DepthFunc = aPrevSettings.DepthFunc;
+        aDefaultSettings.DepthMask = GL_TRUE;
+      }
+      else if (aPassIter == 1)
+      {
+        if (!hasSkippedDepthLayers)
+        {
+          continue;
+        }
+        aCtx->SetColorMask (true);
+        aCtx->ShaderManager()->UpdateLightSourceStateTo (aLightsBack);
+        aDefaultSettings = aPrevSettings;
+      }
+      else if (aPassIter == 2)
+      {
+        aCtx->SetColorMask (true);
+        aCtx->ShaderManager()->UpdateLightSourceStateTo (aLightsBack);
+        if (toPerformDepthPrepass)
+        {
+          aDefaultSettings.DepthFunc = GL_EQUAL;
+          aDefaultSettings.DepthMask = GL_FALSE;
+        }
+      }
+
+      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.IsCulled())
+        {
+          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.
+        theWorkspace->ResetSkippedCounter();
+
+        renderLayer (theWorkspace, aDefaultSettings, aLayer);
+
+        if (aPassIter != 0
+         && theWorkspace->NbSkippedTransparentElements() > 0)
+        {
+          myTransparentToProcess.Push (&aLayer);
+        }
+      }
+      if (aPassIter == 2
+      && !aLayerIter.More())
+      {
+        aLayerIterStart = aLayerIter;
+      }
+    }
 
-void OpenGl_LayerList::Render (const Handle(OpenGl_Workspace) &theWorkspace) const
+    if (!myTransparentToProcess.IsEmpty())
+    {
+      renderTransparent (theWorkspace, aStackIter, aPrevSettings, theReadDrawFbo, theOitAccumFbo);
+    }
+    if (aClearDepthLayer > aClearDepthLayerPrev)
+    {
+      aClearDepthLayerPrev = aClearDepthLayer;
+      glDepthMask (GL_TRUE);
+      glClear (GL_DEPTH_BUFFER_BIT);
+    }
+  }
+
+  aCtx->core11fwd->glDepthMask (aPrevSettings.DepthMask);
+  aCtx->core11fwd->glDepthFunc (aPrevSettings.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
 {
-  int aDefaultDepthFunc;
-  glGetIntegerv (GL_DEPTH_FUNC, &aDefaultDepthFunc);
+  // 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;
+
+  const Standard_Integer aPrevFilter = theWorkspace->RenderFilter() & ~(Standard_Integer )(OpenGl_RenderFilter_OpaqueOnly | OpenGl_RenderFilter_TransparentOnly);
+  theWorkspace->SetRenderFilter (aPrevFilter | OpenGl_RenderFilter_TransparentOnly);
 
-  OpenGl_SequenceOfLayers::Iterator anIts;
-  for(anIts.Init (myLayers); anIts.More (); anIts.Next ())
+  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)
+  {
+    renderLayer (theWorkspace, aGlobalSettings, *(*theLayerIter));
+  }
+
+  // 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 (aPrevFilter | OpenGl_RenderFilter_OpaqueOnly);
+  if (isEnabledOit)
   {
-    const OpenGl_Layer& aLayer = anIts.Value ();
-    if (aLayer.PriorityList().NbStructures () > 0)
+    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_TextureSet) aTextureBack = aCtx->BindTextures (Handle(OpenGl_TextureSet)());
+
+      theOitAccumFbo->ColorTexture (0)->Bind (aCtx, Graphic3d_TextureUnit_0);
+      theOitAccumFbo->ColorTexture (1)->Bind (aCtx, Graphic3d_TextureUnit_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 (1)->Unbind (aCtx, Graphic3d_TextureUnit_1);
+      theOitAccumFbo->ColorTexture (0)->Unbind (aCtx, Graphic3d_TextureUnit_0);
+      aCtx->BindProgram (NULL);
+
+      if (!aTextureBack.IsNull())
+      {
+        aCtx->BindTextures (aTextureBack);
+      }
+    }
+    else
     {
-      // render layer
-      aLayer.Render (theWorkspace, aDefaultDepthFunc);
+      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);
 }