0027925: Visualization - implement order-independent transparency algorithm within...
[occt.git] / src / OpenGl / OpenGl_View_Redraw.cxx
index 6b76f4f..703d127 100644 (file)
@@ -31,7 +31,6 @@
 #include <OpenGl_Matrix.hxx>
 #include <OpenGl_Workspace.hxx>
 #include <OpenGl_View.hxx>
-#include <OpenGl_Trihedron.hxx>
 #include <OpenGl_GraduatedTrihedron.hxx>
 #include <OpenGl_PrimitiveArray.hxx>
 #include <OpenGl_ShaderManager.hxx>
 #include <OpenGl_Structure.hxx>
 #include <OpenGl_ArbFBO.hxx>
 
-#define EPSI 0.0001
-
-namespace
-{
-  static const GLfloat THE_DEFAULT_AMBIENT[4]    = { 0.0f, 0.0f, 0.0f, 1.0f };
-  static const GLfloat THE_DEFAULT_SPOT_DIR[3]   = { 0.0f, 0.0f, -1.0f };
-  static const GLfloat THE_DEFAULT_SPOT_EXPONENT = 0.0f;
-  static const GLfloat THE_DEFAULT_SPOT_CUTOFF   = 180.0f;
-}
-
-extern void InitLayerProp (const int theListId); //szvgl: defined in OpenGl_GraphicDriver_Layer.cxx
-
-#if !defined(GL_ES_VERSION_2_0)
-
-//=======================================================================
-//function : bindLight
-//purpose  :
-//=======================================================================
-static void bindLight (const OpenGl_Light&             theLight,
-                       GLenum&                         theLightGlId,
-                       Graphic3d_Vec4&                 theAmbientColor,
-                       const Handle(OpenGl_Workspace)& theWorkspace)
-{
-  // Only 8 lights in OpenGL...
-  if (theLightGlId > GL_LIGHT7)
-  {
-    return;
-  }
-
-  if (theLight.Type == Graphic3d_TOLS_AMBIENT)
-  {
-    // add RGBA intensity of the ambient light
-    theAmbientColor += theLight.Color;
-    return;
-  }
-
-  const Handle(OpenGl_Context)& aContext = theWorkspace->GetGlContext();
-
-  // the light is a headlight?
-  if (theLight.IsHeadlight)
-  {
-    aContext->WorldViewState.Push();
-    aContext->WorldViewState.SetIdentity();
-
-    aContext->ApplyWorldViewMatrix();
-  }
-
-  // setup light type
-  switch (theLight.Type)
-  {
-    case Graphic3d_TOLS_AMBIENT    : break; // handled by separate if-clause at beginning of method
-    case Graphic3d_TOLS_DIRECTIONAL:
-    {
-      // if the last parameter of GL_POSITION, is zero, the corresponding light source is a Directional one
-      const OpenGl_Vec4 anInfDir = -theLight.Direction;
-
-      // to create a realistic effect,  set the GL_SPECULAR parameter to the same value as the GL_DIFFUSE.
-      glLightfv (theLightGlId, GL_AMBIENT,               THE_DEFAULT_AMBIENT);
-      glLightfv (theLightGlId, GL_DIFFUSE,               theLight.Color.GetData());
-      glLightfv (theLightGlId, GL_SPECULAR,              theLight.Color.GetData());
-      glLightfv (theLightGlId, GL_POSITION,              anInfDir.GetData());
-      glLightfv (theLightGlId, GL_SPOT_DIRECTION,        THE_DEFAULT_SPOT_DIR);
-      glLightf  (theLightGlId, GL_SPOT_EXPONENT,         THE_DEFAULT_SPOT_EXPONENT);
-      glLightf  (theLightGlId, GL_SPOT_CUTOFF,           THE_DEFAULT_SPOT_CUTOFF);
-      break;
-    }
-    case Graphic3d_TOLS_POSITIONAL:
-    {
-      // to create a realistic effect, set the GL_SPECULAR parameter to the same value as the GL_DIFFUSE
-      glLightfv (theLightGlId, GL_AMBIENT,               THE_DEFAULT_AMBIENT);
-      glLightfv (theLightGlId, GL_DIFFUSE,               theLight.Color.GetData());
-      glLightfv (theLightGlId, GL_SPECULAR,              theLight.Color.GetData());
-      glLightfv (theLightGlId, GL_POSITION,              theLight.Position.GetData());
-      glLightfv (theLightGlId, GL_SPOT_DIRECTION,        THE_DEFAULT_SPOT_DIR);
-      glLightf  (theLightGlId, GL_SPOT_EXPONENT,         THE_DEFAULT_SPOT_EXPONENT);
-      glLightf  (theLightGlId, GL_SPOT_CUTOFF,           THE_DEFAULT_SPOT_CUTOFF);
-      glLightf  (theLightGlId, GL_CONSTANT_ATTENUATION,  theLight.ConstAttenuation());
-      glLightf  (theLightGlId, GL_LINEAR_ATTENUATION,    theLight.LinearAttenuation());
-      glLightf  (theLightGlId, GL_QUADRATIC_ATTENUATION, 0.0);
-      break;
-    }
-    case Graphic3d_TOLS_SPOT:
-    {
-      glLightfv (theLightGlId, GL_AMBIENT,               THE_DEFAULT_AMBIENT);
-      glLightfv (theLightGlId, GL_DIFFUSE,               theLight.Color.GetData());
-      glLightfv (theLightGlId, GL_SPECULAR,              theLight.Color.GetData());
-      glLightfv (theLightGlId, GL_POSITION,              theLight.Position.GetData());
-      glLightfv (theLightGlId, GL_SPOT_DIRECTION,        theLight.Direction.GetData());
-      glLightf  (theLightGlId, GL_SPOT_EXPONENT,         theLight.Concentration() * 128.0f);
-      glLightf  (theLightGlId, GL_SPOT_CUTOFF,          (theLight.Angle() * 180.0f) / GLfloat(M_PI));
-      glLightf  (theLightGlId, GL_CONSTANT_ATTENUATION,  theLight.ConstAttenuation());
-      glLightf  (theLightGlId, GL_LINEAR_ATTENUATION,    theLight.LinearAttenuation());
-      glLightf  (theLightGlId, GL_QUADRATIC_ATTENUATION, 0.0f);
-      break;
-    }
-  }
-
-  // restore matrix in case of headlight
-  if (theLight.IsHeadlight)
-  {
-    aContext->WorldViewState.Pop();
-  }
-
-  glEnable (theLightGlId++);
-}
-#endif
-
 //=======================================================================
 //function : drawBackground
 //purpose  :
@@ -154,9 +46,8 @@ void OpenGl_View::drawBackground (const Handle(OpenGl_Workspace)& theWorkspace)
 {
   const Handle(OpenGl_Context)& aCtx = theWorkspace->GetGlContext();
 
-  if ((theWorkspace->NamedStatus & OPENGL_NS_WHITEBACK) != 0 // no background
-    || (!myBgTextureArray->IsDefined()                       // no texture
-     && !myBgGradientArray->IsDefined()))                    // no gradient
+  if (!myBgTextureArray->IsDefined()   // no texture
+   && !myBgGradientArray->IsDefined()) // no gradient
   {
     return;
   }
@@ -242,9 +133,9 @@ void OpenGl_View::Redraw()
   myWindow->SetSwapInterval();
 
   ++myFrameCounter;
-  const Graphic3d_StereoMode      aStereoMode  = myRenderParams.StereoMode;
-  Graphic3d_Camera::Projection    aProjectType = myCamera->ProjectionType();
-  Handle(OpenGl_Context)          aCtx         = myWorkspace->GetGlContext();
+  const Graphic3d_StereoMode   aStereoMode  = myRenderParams.StereoMode;
+  Graphic3d_Camera::Projection aProjectType = myCamera->ProjectionType();
+  Handle(OpenGl_Context)       aCtx         = myWorkspace->GetGlContext();
 
   // release pending GL resources
   aCtx->ReleaseDelayed();
@@ -252,9 +143,6 @@ void OpenGl_View::Redraw()
   // fetch OpenGl context state
   aCtx->FetchState();
 
-  // set resolution ratio
-  aCtx->SetResolutionRatio (RenderingParams().ResolutionRatio());
-
   OpenGl_FrameBuffer* aFrameBuffer = myFBO.operator->();
   bool toSwap = aCtx->IsRender()
             && !aCtx->caps->buffersNoSwap
@@ -262,9 +150,11 @@ void OpenGl_View::Redraw()
 
   Standard_Integer aSizeX = aFrameBuffer != NULL ? aFrameBuffer->GetVPSizeX() : myWindow->Width();
   Standard_Integer aSizeY = aFrameBuffer != NULL ? aFrameBuffer->GetVPSizeY() : myWindow->Height();
+  Standard_Integer aRendSizeX = Standard_Integer(myRenderParams.RenderResolutionScale * aSizeX + 0.5f);
+  Standard_Integer aRendSizeY = Standard_Integer(myRenderParams.RenderResolutionScale * aSizeY + 0.5f);
 
   // determine multisampling parameters
-  Standard_Integer aNbSamples = !myToDisableMSAA
+  Standard_Integer aNbSamples = !myToDisableMSAA && aSizeX == aRendSizeX
                               ? Max (Min (myRenderParams.NbMsaaSamples, aCtx->MaxMsaaSamples()), 0)
                               : 0;
   if (aNbSamples != 0)
@@ -272,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())
@@ -282,10 +178,12 @@ void OpenGl_View::Redraw()
   if (myHasFboBlit
    && (myTransientDrawToFront
     || aProjectType == Graphic3d_Camera::Projection_Stereo
-    || aNbSamples != 0))
+    || aNbSamples != 0
+    || toUseOit
+    || aSizeX != aRendSizeX))
   {
-    if (myMainSceneFbos[0]->GetVPSizeX() != aSizeX
-     || myMainSceneFbos[0]->GetVPSizeY() != aSizeY
+    if (myMainSceneFbos[0]->GetVPSizeX() != aRendSizeX
+     || myMainSceneFbos[0]->GetVPSizeY() != aRendSizeY
      || myMainSceneFbos[0]->NbSamples()  != aNbSamples)
     {
       if (!myTransientDrawToFront)
@@ -300,15 +198,13 @@ void OpenGl_View::Redraw()
       // for further blitting and rendering immediate presentations on top
       if (aCtx->core20fwd != NULL)
       {
-        myMainSceneFbos[0]->Init (aCtx, aSizeX, aSizeY, myFboColorFormat, myFboDepthFormat, aNbSamples);
-      }
-      if (myTransientDrawToFront
-       && !aCtx->caps->useSystemBuffer
-       && myMainSceneFbos[0]->IsValid())
-      {
-        myImmediateSceneFbos[0]->InitLazy (aCtx, *myMainSceneFbos[0]);
+        myMainSceneFbos[0]->Init (aCtx, aRendSizeX, aRendSizeY, myFboColorFormat, myFboDepthFormat, aNbSamples);
       }
     }
+    if (myMainSceneFbos[0]->IsValid() && (toInitImmediateFbo || myImmediateSceneFbos[0]->IsValid()))
+    {
+      myImmediateSceneFbos[0]->InitLazy (aCtx, *myMainSceneFbos[0]);
+    }
   }
   else
   {
@@ -347,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] =
@@ -354,34 +338,56 @@ 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)
     aCtx->SetReadDrawBuffer (aStereoMode == Graphic3d_StereoMode_QuadBuffer ? GL_BACK_LEFT : GL_BACK);
   #endif
-    redraw (Graphic3d_Camera::Projection_MonoLeftEye, aMainFbos[0]);
+    aCtx->SetResolution (myRenderParams.Resolution, myRenderParams.ResolutionRatio(),
+                         aMainFbos[0] != NULL ? myRenderParams.RenderResolutionScale : 1.0f);
+
+    redraw (Graphic3d_Camera::Projection_MonoLeftEye, aMainFbos[0], aMainFbosOit[0]);
     myBackBufferRestored = Standard_True;
     myIsImmediateDrawn   = Standard_False;
   #if !defined(GL_ES_VERSION_2_0)
     aCtx->SetReadDrawBuffer (aStereoMode == Graphic3d_StereoMode_QuadBuffer ? GL_BACK_LEFT : GL_BACK);
   #endif
-    if (!redrawImmediate (Graphic3d_Camera::Projection_MonoLeftEye, aMainFbos[0], anImmFbos[0]))
+    aCtx->SetResolution (myRenderParams.Resolution, myRenderParams.ResolutionRatio(),
+                         anImmFbos[0] != NULL ? myRenderParams.RenderResolutionScale : 1.0f);
+    if (!redrawImmediate (Graphic3d_Camera::Projection_MonoLeftEye, aMainFbos[0], anImmFbos[0], anImmFbosOit[0]))
     {
       toSwap = false;
     }
@@ -393,30 +399,40 @@ void OpenGl_View::Redraw()
   #if !defined(GL_ES_VERSION_2_0)
     aCtx->SetReadDrawBuffer (aStereoMode == Graphic3d_StereoMode_QuadBuffer ? GL_BACK_RIGHT : GL_BACK);
   #endif
-    redraw (Graphic3d_Camera::Projection_MonoRightEye, aMainFbos[1]);
+    aCtx->SetResolution (myRenderParams.Resolution, myRenderParams.ResolutionRatio(),
+                         aMainFbos[1] != NULL ? myRenderParams.RenderResolutionScale : 1.0f);
+
+    redraw (Graphic3d_Camera::Projection_MonoRightEye, aMainFbos[1], aMainFbosOit[1]);
     myBackBufferRestored = Standard_True;
     myIsImmediateDrawn   = Standard_False;
-    if (!redrawImmediate (Graphic3d_Camera::Projection_MonoRightEye, aMainFbos[1], anImmFbos[1]))
+    aCtx->SetResolution (myRenderParams.Resolution, myRenderParams.ResolutionRatio(),
+                         anImmFbos[1] != NULL ? myRenderParams.RenderResolutionScale : 1.0f);
+    if (!redrawImmediate (Graphic3d_Camera::Projection_MonoRightEye, aMainFbos[1], anImmFbos[1], anImmFbosOit[1]))
     {
       toSwap = false;
     }
 
     if (anImmFbos[0] != NULL)
     {
+      aCtx->SetResolution (myRenderParams.Resolution, myRenderParams.ResolutionRatio(), 1.0f);
       drawStereoPair (aFrameBuffer);
     }
   }
   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)
@@ -425,10 +441,15 @@ void OpenGl_View::Redraw()
       aCtx->SetReadDrawBuffer (GL_BACK);
     }
   #endif
-    redraw (aProjectType, aMainFbo);
+    aCtx->SetResolution (myRenderParams.Resolution, myRenderParams.ResolutionRatio(),
+                         aMainFbo != aFrameBuffer ? myRenderParams.RenderResolutionScale : 1.0f);
+
+    redraw (aProjectType, aMainFbo, aMainFboOit);
     myBackBufferRestored = Standard_True;
     myIsImmediateDrawn   = Standard_False;
-    if (!redrawImmediate (aProjectType, aMainFbo, anImmFbo))
+    aCtx->SetResolution (myRenderParams.Resolution, myRenderParams.ResolutionRatio(),
+                         anImmFbo != aFrameBuffer ? myRenderParams.RenderResolutionScale : 1.0f);
+    if (!redrawImmediate (aProjectType, aMainFbo, anImmFbo, anImmFboOit))
     {
       toSwap = false;
     }
@@ -440,24 +461,6 @@ void OpenGl_View::Redraw()
     }
   }
 
-#if defined(_WIN32) && defined(HAVE_VIDEOCAPTURE)
-  if (OpenGl_AVIWriter_AllowWriting (myWindow->PlatformWindow()->NativeHandle()))
-  {
-    GLint params[4];
-    glGetIntegerv (GL_VIEWPORT, params);
-    int nWidth  = params[2] & ~0x7;
-    int nHeight = params[3] & ~0x7;
-
-    const int nBitsPerPixel = 24;
-    GLubyte* aDumpData = new GLubyte[nWidth * nHeight * nBitsPerPixel / 8];
-
-    glPixelStorei (GL_PACK_ALIGNMENT, 1);
-    glReadPixels (0, 0, nWidth, nHeight, GL_BGR_EXT, GL_UNSIGNED_BYTE, aDumpData);
-    OpenGl_AVIWriter_AVIWriter (aDumpData, nWidth, nHeight, nBitsPerPixel);
-    delete[] aDumpData;
-  }
-#endif
-
   if (myRenderParams.Method == Graphic3d_RM_RAYTRACING
    && myRenderParams.IsGlobalIlluminationEnabled)
   {
@@ -474,6 +477,10 @@ void OpenGl_View::Redraw()
     Redraw();
   }
 
+  // reset state for safety
+  aCtx->BindProgram (Handle(OpenGl_ShaderProgram)());
+  aCtx->ShaderManager()->PushState (Handle(OpenGl_ShaderProgram)());
+
   // Swap the buffers
   if (toSwap)
   {
@@ -545,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)
@@ -562,9 +577,13 @@ void OpenGl_View::RedrawImmediate()
       aCtx->SetReadDrawBuffer (aStereoMode == Graphic3d_StereoMode_QuadBuffer ? GL_BACK_LEFT : GL_BACK);
     }
   #endif
+
+    aCtx->SetResolution (myRenderParams.Resolution, myRenderParams.ResolutionRatio(),
+                         anImmFbos[0] != NULL ? myRenderParams.RenderResolutionScale : 1.0f);
     toSwap = redrawImmediate (Graphic3d_Camera::Projection_MonoLeftEye,
                               aMainFbos[0],
                               anImmFbos[0],
+                              anImmFbosOit[0],
                               Standard_True) || toSwap;
     if (aStereoMode == Graphic3d_StereoMode_SoftPageFlip
     &&  toSwap
@@ -583,9 +602,12 @@ void OpenGl_View::RedrawImmediate()
       aCtx->SetReadDrawBuffer (aStereoMode == Graphic3d_StereoMode_QuadBuffer ? GL_BACK_RIGHT : GL_BACK);
     }
   #endif
+    aCtx->SetResolution (myRenderParams.Resolution, myRenderParams.ResolutionRatio(),
+                         anImmFbos[1] != NULL ? myRenderParams.RenderResolutionScale : 1.0f);
     toSwap = redrawImmediate (Graphic3d_Camera::Projection_MonoRightEye,
                               aMainFbos[1],
                               anImmFbos[1],
+                              anImmFbosOit[1],
                               Standard_True) || toSwap;
     if (anImmFbos[0] != NULL)
     {
@@ -596,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)
@@ -606,9 +630,12 @@ void OpenGl_View::RedrawImmediate()
       aCtx->SetReadDrawBuffer (GL_BACK);
     }
   #endif
+    aCtx->SetResolution (myRenderParams.Resolution, myRenderParams.ResolutionRatio(),
+                         anImmFbo != aFrameBuffer ? myRenderParams.RenderResolutionScale : 1.0f);
     toSwap = redrawImmediate (aProjectType,
                               aMainFbo,
                               anImmFbo,
+                              anImmFboOit,
                               Standard_True) || toSwap;
     if (anImmFbo != NULL
      && anImmFbo != aFrameBuffer)
@@ -620,6 +647,10 @@ void OpenGl_View::RedrawImmediate()
   // bind default FBO
   bindDefaultFbo();
 
+  // reset state for safety
+  aCtx->BindProgram (Handle(OpenGl_ShaderProgram)());
+  aCtx->ShaderManager()->PushState (Handle(OpenGl_ShaderProgram)());
+
   if (toSwap && !aCtx->caps->buffersNoSwap)
   {
     aCtx->SwapBuffers();
@@ -636,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)
@@ -651,7 +684,8 @@ void OpenGl_View::redraw (const Graphic3d_Camera::Projection theProjection, Open
   }
 
   // request reset of material
-  myWorkspace->NamedStatus    |= OPENGL_NS_RESMAT;
+  aCtx->ShaderManager()->UpdateMaterialState();
+
   myWorkspace->UseZBuffer()    = Standard_True;
   myWorkspace->UseDepthWrite() = Standard_True;
   GLbitfield toClear = GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT;
@@ -665,20 +699,12 @@ void OpenGl_View::redraw (const Graphic3d_Camera::Projection theProjection, Open
   glClearDepthf (1.0f);
 #endif
 
-  if (myWorkspace->NamedStatus & OPENGL_NS_WHITEBACK)
-  {
-    // set background to white
-    glClearColor (1.0f, 1.0f, 1.0f, 1.0f);
-  }
-  else
-  {
-    const OpenGl_Vec4& aBgColor = myBgColor;
-    glClearColor (aBgColor.r(), aBgColor.g(), aBgColor.b(), 0.0f);
-  }
+  const OpenGl_Vec4& aBgColor = myBgColor;
+  glClearColor (aBgColor.r(), aBgColor.g(), aBgColor.b(), 0.0f);
 
   glClear (toClear);
 
-  render (theProjection, theReadDrawFbo, Standard_False);
+  render (theProjection, theReadDrawFbo, theOitAccumFbo, Standard_False);
 }
 
 // =======================================================================
@@ -686,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;
@@ -743,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;
 }
@@ -754,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)
 {
   // ==================================
@@ -787,31 +815,22 @@ void OpenGl_View::render (Graphic3d_Camera::Projection theProjection,
 
   // Update matrices if camera has changed.
   Graphic3d_WorldViewProjState aWVPState = myCamera->WorldViewProjState();
-  const Standard_Boolean isCameraChanged = myWorldViewProjState != aWVPState;
-  const Standard_Boolean isSameView      = aManager->IsSameView (this);
-  if (isCameraChanged)
+  if (myWorldViewProjState != aWVPState)
   {
-    aContext->ProjectionState.SetCurrent (myCamera->ProjectionMatrixF());
-    aContext->WorldViewState .SetCurrent (myCamera->OrientationMatrixF());
     myAccumFrames = 0;
+    myWorldViewProjState = aWVPState;
   }
 
-  // Apply new matrix state if camera has changed or this view differs from the one
-  // that was previously used for configuring matrices of shader manager
-  // (ApplyProjectionMatrix and ApplyWorldViewMatrix will affect the manager).
-  if (isCameraChanged || !isSameView)
-  {
-    aContext->ApplyProjectionMatrix();
-    aContext->ApplyWorldViewMatrix();
-  }
-
+  myLocalOrigin.SetCoord (0.0, 0.0, 0.0);
+  aContext->ProjectionState.SetCurrent (myCamera->ProjectionMatrixF());
+  aContext->WorldViewState .SetCurrent (myCamera->OrientationMatrixF());
+  aContext->ApplyProjectionMatrix();
+  aContext->ApplyWorldViewMatrix();
   if (aManager->ModelWorldState().Index() == 0)
   {
     aContext->ShaderManager()->UpdateModelWorldStateTo (OpenGl_Mat4());
   }
 
-  myWorldViewProjState = aWVPState;
-
   // ====================================
   //      Step 2: Redraw background
   // ====================================
@@ -887,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)());
 
@@ -900,12 +919,6 @@ void OpenGl_View::render (Graphic3d_Camera::Projection theProjection,
   // before drawing auxiliary stuff (trihedrons, overlayer)
   myWorkspace->ResetAppliedAspect();
 
-
-  // We need to disable (unbind) all shaders programs to ensure
-  // that all objects without specified aspect will be drawn
-  // correctly (such as background)
-  aContext->BindProgram (NULL);
-
   // Render trihedron
   if (!theToDrawImmediate)
   {
@@ -924,6 +937,10 @@ void OpenGl_View::render (Graphic3d_Camera::Projection theProjection,
     }
   }
 
+  // reset FFP state for safety
+  aContext->BindProgram (Handle(OpenGl_ShaderProgram)());
+  aContext->ShaderManager()->PushState (Handle(OpenGl_ShaderProgram)());
+
   // ==============================================================
   //      Step 6: Keep shader manager informed about last View
   // ==============================================================
@@ -949,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 )
@@ -985,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);
         {
@@ -999,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());
       }
@@ -1021,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);
     }
   }
 
@@ -1029,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;
@@ -1042,18 +1060,6 @@ void OpenGl_View::renderStructs (Graphic3d_Camera::Projection theProjection,
 //=======================================================================
 void OpenGl_View::renderTrihedron (const Handle(OpenGl_Workspace) &theWorkspace)
 {
-  // display global trihedron
-  if (myToShowTrihedron)
-  {
-    // disable environment texture
-    Handle(OpenGl_Texture) anEnvironmentTexture = theWorkspace->EnvironmentTexture();
-    theWorkspace->SetEnvironmentTexture (Handle(OpenGl_Texture)());
-
-    myTrihedron.Render (theWorkspace);
-
-    // restore environment texture
-    theWorkspace->SetEnvironmentTexture (anEnvironmentTexture);
-  }
   if (myToShowGradTrihedron)
   {
     myGraduatedTrihedron.Render (theWorkspace);
@@ -1075,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();
@@ -1087,87 +1094,9 @@ void OpenGl_View::renderScene (Graphic3d_Camera::Projection theProjection,
     aContext->ShaderManager()->UpdateClippingState();
   }
 
-#if !defined(GL_ES_VERSION_2_0)
-  // Apply Lights
-  if (aContext->core11 != NULL)
-  {
-    // setup lights
-    Graphic3d_Vec4 anAmbientColor (THE_DEFAULT_AMBIENT[0],
-                                   THE_DEFAULT_AMBIENT[1],
-                                   THE_DEFAULT_AMBIENT[2],
-                                   THE_DEFAULT_AMBIENT[3]);
-    GLenum aLightGlId = GL_LIGHT0;
-
-    OpenGl_ListOfLight::Iterator aLightIt (myShadingModel == Graphic3d_TOSM_NONE ? myNoShadingLight : myLights);
-    for (; aLightIt.More(); aLightIt.Next())
-    {
-      bindLight (aLightIt.Value(), aLightGlId, anAmbientColor, myWorkspace);
-    }
-
-    // apply accumulated ambient color
-    anAmbientColor.a() = 1.0f;
-    glLightModelfv (GL_LIGHT_MODEL_AMBIENT, anAmbientColor.GetData());
-
-    if (aLightGlId != GL_LIGHT0)
-    {
-      glEnable (GL_LIGHTING);
-    }
-    // switch off unused lights
-    for (; aLightGlId <= GL_LIGHT7; ++aLightGlId)
-    {
-      glDisable (aLightGlId);
-    }
-  }
-#endif
-
-  // Clear status bitfields
-  myWorkspace->NamedStatus &= ~(OPENGL_NS_2NDPASSNEED | OPENGL_NS_2NDPASSDO);
-
-  // First pass
-  renderStructs (theProjection, theReadDrawFbo, theToDrawImmediate);
+  renderStructs (theProjection, theReadDrawFbo, theOitAccumFbo, theToDrawImmediate);
   myWorkspace->DisableTexture();
 
-  // Second pass
-  if (myWorkspace->NamedStatus & OPENGL_NS_2NDPASSNEED)
-  {
-    myWorkspace->NamedStatus |= OPENGL_NS_2NDPASSDO;
-
-    // Remember OpenGl properties
-    GLint aSaveBlendDst = GL_ONE_MINUS_SRC_ALPHA, aSaveBlendSrc = GL_SRC_ALPHA;
-    GLint aSaveZbuffFunc;
-    GLboolean aSaveZbuffWrite;
-    glGetBooleanv (GL_DEPTH_WRITEMASK, &aSaveZbuffWrite);
-    glGetIntegerv (GL_DEPTH_FUNC, &aSaveZbuffFunc);
-  #if !defined(GL_ES_VERSION_2_0)
-    glGetIntegerv (GL_BLEND_DST, &aSaveBlendDst);
-    glGetIntegerv (GL_BLEND_SRC, &aSaveBlendSrc);
-  #endif
-    GLboolean wasZbuffEnabled = glIsEnabled (GL_DEPTH_TEST);
-    GLboolean wasBlendEnabled = glIsEnabled (GL_BLEND);
-
-    // Change the properties for second rendering pass
-    glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-    glEnable (GL_BLEND);
-
-    glDepthFunc (GL_EQUAL);
-    glDepthMask (GL_FALSE);
-    glEnable (GL_DEPTH_TEST);
-
-    // Render the view
-    renderStructs (theProjection, theReadDrawFbo, theToDrawImmediate);
-    myWorkspace->DisableTexture();
-
-    // Restore properties back
-    glBlendFunc (aSaveBlendSrc, aSaveBlendDst);
-    if (!wasBlendEnabled)
-      glDisable (GL_BLEND);
-
-    glDepthFunc (aSaveZbuffFunc);
-    glDepthMask (aSaveZbuffWrite);
-    if (!wasZbuffEnabled)
-      glDisable (GL_DEPTH_FUNC);
-  }
-
   // Apply restored view matrix.
   aContext->ApplyWorldViewMatrix();
 
@@ -1261,6 +1190,10 @@ bool OpenGl_View::blitBuffers (OpenGl_FrameBuffer*    theReadFbo,
                                const Standard_Boolean theToFlip)
 {
   Handle(OpenGl_Context) aCtx = myWorkspace->GetGlContext();
+  const Standard_Integer aReadSizeX = theReadFbo != NULL ? theReadFbo->GetVPSizeX() : myWindow->Width();
+  const Standard_Integer aReadSizeY = theReadFbo != NULL ? theReadFbo->GetVPSizeY() : myWindow->Height();
+  const Standard_Integer aDrawSizeX = theDrawFbo != NULL ? theDrawFbo->GetVPSizeX() : myWindow->Width();
+  const Standard_Integer aDrawSizeY = theDrawFbo != NULL ? theDrawFbo->GetVPSizeY() : myWindow->Height();
   if (theReadFbo == NULL || aCtx->IsFeedback())
   {
     return false;
@@ -1280,6 +1213,9 @@ bool OpenGl_View::blitBuffers (OpenGl_FrameBuffer*    theReadFbo,
   {
     aCtx->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, OpenGl_FrameBuffer::NO_FRAMEBUFFER);
   }
+  const Standard_Integer aViewport[4] = { 0, 0, aDrawSizeX, aDrawSizeY };
+  aCtx->ResizeViewport (aViewport);
+
 #if !defined(GL_ES_VERSION_2_0)
   aCtx->core20fwd->glClearDepth  (1.0);
 #else
@@ -1287,7 +1223,6 @@ bool OpenGl_View::blitBuffers (OpenGl_FrameBuffer*    theReadFbo,
 #endif
   aCtx->core20fwd->glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
 
-#if !defined(GL_ES_VERSION_2_0)
   if (aCtx->arbFBOBlit != NULL
    && theReadFbo->NbSamples() != 0)
   {
@@ -1322,8 +1257,8 @@ bool OpenGl_View::blitBuffers (OpenGl_FrameBuffer*    theReadFbo,
     }
 
     // we don't copy stencil buffer here... does it matter for performance?
-    aCtx->arbFBOBlit->glBlitFramebuffer (0, 0, theReadFbo->GetVPSizeX(), theReadFbo->GetVPSizeY(),
-                                         0, 0, theReadFbo->GetVPSizeX(), theReadFbo->GetVPSizeY(),
+    aCtx->arbFBOBlit->glBlitFramebuffer (0, 0, aReadSizeX, aReadSizeY,
+                                         0, 0, aDrawSizeX, aDrawSizeY,
                                          aCopyMask, GL_NEAREST);
     const int anErr = ::glGetError();
     if (anErr != GL_NO_ERROR)
@@ -1362,7 +1297,6 @@ bool OpenGl_View::blitBuffers (OpenGl_FrameBuffer*    theReadFbo,
     }
   }
   else
-#endif
   {
     aCtx->core20fwd->glDepthFunc (GL_ALWAYS);
     aCtx->core20fwd->glDepthMask (GL_TRUE);
@@ -1377,13 +1311,30 @@ bool OpenGl_View::blitBuffers (OpenGl_FrameBuffer*    theReadFbo,
 
     myWorkspace->DisableTexture();
 
+    const Graphic3d_TypeOfTextureFilter aFilter = (aDrawSizeX == aReadSizeX && aDrawSizeY == aReadSizeY) ? Graphic3d_TOTF_NEAREST : Graphic3d_TOTF_BILINEAR;
+    const GLint aFilterGl = aFilter == Graphic3d_TOTF_NEAREST ? GL_NEAREST : GL_LINEAR;
+
     OpenGl_VertexBuffer* aVerts = initBlitQuad (theToFlip);
     const Handle(OpenGl_ShaderManager)& aManager = aCtx->ShaderManager();
     if (aVerts->IsValid()
      && aManager->BindFboBlitProgram())
     {
-      theReadFbo->ColorTexture()       ->Bind   (aCtx, GL_TEXTURE0 + 0);
-      theReadFbo->DepthStencilTexture()->Bind   (aCtx, GL_TEXTURE0 + 1);
+      theReadFbo->ColorTexture()->Bind (aCtx, GL_TEXTURE0 + 0);
+      if (theReadFbo->ColorTexture()->GetParams()->Filter() != aFilter)
+      {
+        theReadFbo->ColorTexture()->GetParams()->SetFilter (aFilter);
+        aCtx->core20fwd->glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, aFilterGl);
+        aCtx->core20fwd->glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, aFilterGl);
+      }
+
+      theReadFbo->DepthStencilTexture()->Bind (aCtx, GL_TEXTURE0 + 1);
+      if (theReadFbo->DepthStencilTexture()->GetParams()->Filter() != aFilter)
+      {
+        theReadFbo->DepthStencilTexture()->GetParams()->SetFilter (aFilter);
+        aCtx->core20fwd->glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, aFilterGl);
+        aCtx->core20fwd->glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, aFilterGl);
+      }
+
       aVerts->BindVertexAttrib (aCtx, Graphic3d_TOA_POS);
 
       aCtx->core20fwd->glDrawArrays (GL_TRIANGLE_STRIP, 0, 4);
@@ -1603,9 +1554,11 @@ void OpenGl_View::copyBackToFront()
 
   OpenGl_Mat4 aProjectMat;
   Graphic3d_TransformUtils::Ortho2D (aProjectMat,
-    0.f, static_cast<GLfloat> (myWindow->Width()), 0.f, static_cast<GLfloat> (myWindow->Height()));
+                                     0.0f, static_cast<GLfloat> (myWindow->Width()),
+                                     0.0f, static_cast<GLfloat> (myWindow->Height()));
+
+  const Handle(OpenGl_Context)& aCtx = myWorkspace->GetGlContext();
 
-  Handle(OpenGl_Context) aCtx = myWorkspace->GetGlContext();
   aCtx->WorldViewState.Push();
   aCtx->ProjectionState.Push();
 
@@ -1615,6 +1568,9 @@ void OpenGl_View::copyBackToFront()
   aCtx->ApplyProjectionMatrix();
   aCtx->ApplyWorldViewMatrix();
 
+  // synchronize FFP state before copying pixels
+  aCtx->BindProgram (Handle(OpenGl_ShaderProgram)());
+  aCtx->ShaderManager()->PushState (Handle(OpenGl_ShaderProgram)());
   aCtx->DisableFeatures();
 
   switch (aCtx->DrawBuffer())
@@ -1654,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
+}