From: kgv Date: Wed, 15 Apr 2015 13:25:38 +0000 (+0300) Subject: 0026025: Visualization, TKOpenGl - stereoscopic output does not work X-Git-Tag: V6_9_0_beta2~3 X-Git-Url: http://git.dev.opencascade.org/gitweb/?p=occt.git;a=commitdiff_plain;h=38a0206f6028e04f0846bb1187456558fefb550f;hp=b85b0b073199e5fde4949c0df656bd19bfc3c989 0026025: Visualization, TKOpenGl - stereoscopic output does not work OpenGl_View::Render() - pass target FBO as parameter. OpenGl_Context - revise Read/Write buffers management logic, taking into account FBOs. Graphic3d_Camera::UpdateProjection() - setup LProjection and RProjection the same as MProjection in case of Projection_MonoLeftEye/Projection_MonoRightEye for API consistency. --- diff --git a/src/Graphic3d/Graphic3d_Camera.cxx b/src/Graphic3d/Graphic3d_Camera.cxx index edf72cdaf1..198aa0ee46 100644 --- a/src/Graphic3d/Graphic3d_Camera.cxx +++ b/src/Graphic3d/Graphic3d_Camera.cxx @@ -734,6 +734,7 @@ Graphic3d_Camera::TransformMatrices& StereoEyeProj (aLeft, aRight, aBot, aTop, aZNear, aZFar, aIOD, aFocus, Standard_True, *theMatrices.MProjection); + *theMatrices.LProjection = *theMatrices.MProjection; break; } @@ -742,6 +743,7 @@ Graphic3d_Camera::TransformMatrices& StereoEyeProj (aLeft, aRight, aBot, aTop, aZNear, aZFar, aIOD, aFocus, Standard_False, *theMatrices.MProjection); + *theMatrices.RProjection = *theMatrices.MProjection; break; } diff --git a/src/Graphic3d/Graphic3d_Camera.hxx b/src/Graphic3d/Graphic3d_Camera.hxx index 92e90002bb..56620af801 100644 --- a/src/Graphic3d/Graphic3d_Camera.hxx +++ b/src/Graphic3d/Graphic3d_Camera.hxx @@ -90,7 +90,7 @@ public: //! Enumerates supported monographic projections. //! - Projection_Orthographic : orthographic projection. //! - Projection_Perspective : perspective projection. - //! - Projection_Stere : stereographic projection. + //! - Projection_Stereo : stereographic projection. //! - Projection_MonoLeftEye : mono projection for stereo left eye. //! - Projection_MonoRightEye : mono projection for stereo right eye. enum Projection diff --git a/src/OpenGl/OpenGl_Context.cxx b/src/OpenGl/OpenGl_Context.cxx index 10e7a42836..7e53da093f 100644 --- a/src/OpenGl/OpenGl_Context.cxx +++ b/src/OpenGl/OpenGl_Context.cxx @@ -123,6 +123,7 @@ OpenGl_Context::OpenGl_Context (const Handle(OpenGl_Caps)& theCaps) #else myRenderMode (0), #endif + myReadBuffer (0), myDrawBuffer (0), myDefaultVao (0), myIsGlDebugCtx (Standard_False) @@ -288,93 +289,58 @@ Standard_Integer OpenGl_Context::MaxClipPlanes() const return myMaxClipPlanes; } -// ======================================================================= -// function : SetDrawBufferLeft -// purpose : -// ======================================================================= -void OpenGl_Context::SetDrawBufferLeft() -{ #if !defined(GL_ES_VERSION_2_0) - switch (myDrawBuffer) +inline Standard_Integer stereoToMonoBuffer (const Standard_Integer theBuffer) +{ + switch (theBuffer) { - case GL_BACK_RIGHT : - case GL_BACK : - glDrawBuffer (GL_BACK_LEFT); - myDrawBuffer = GL_BACK_LEFT; - break; - - case GL_FRONT_RIGHT : - case GL_FRONT : - glDrawBuffer (GL_FRONT_LEFT); - myDrawBuffer = GL_FRONT_LEFT; - break; - - case GL_FRONT_AND_BACK : - case GL_RIGHT : - glDrawBuffer (GL_LEFT); - myDrawBuffer = GL_LEFT; - break; + case GL_BACK_LEFT: + case GL_BACK_RIGHT: + return GL_BACK; + case GL_FRONT_LEFT: + case GL_FRONT_RIGHT: + return GL_FRONT; + default: + return theBuffer; } -#endif } +#endif // ======================================================================= -// function : SetDrawBufferRight +// function : SetReadBuffer // purpose : // ======================================================================= -void OpenGl_Context::SetDrawBufferRight() +void OpenGl_Context::SetReadBuffer (const Standard_Integer theReadBuffer) { #if !defined(GL_ES_VERSION_2_0) - switch (myDrawBuffer) + myReadBuffer = !myIsStereoBuffers ? stereoToMonoBuffer (theReadBuffer) : theReadBuffer; + if (myReadBuffer < GL_COLOR_ATTACHMENT0 + && arbFBO != NULL) { - case GL_BACK_LEFT : - case GL_BACK : - glDrawBuffer (GL_BACK_RIGHT); - myDrawBuffer = GL_BACK_RIGHT; - break; - - case GL_FRONT_LEFT : - case GL_FRONT : - glDrawBuffer (GL_FRONT_RIGHT); - myDrawBuffer = GL_FRONT_RIGHT; - break; - - case GL_FRONT_AND_BACK : - case GL_LEFT : - glDrawBuffer (GL_RIGHT); - myDrawBuffer = GL_RIGHT; - break; + arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, OpenGl_FrameBuffer::NO_FRAMEBUFFER); } + ::glReadBuffer (myReadBuffer); +#else + (void )theReadBuffer; #endif } // ======================================================================= -// function : SetDrawBufferMono +// function : SetDrawBuffer // purpose : // ======================================================================= -void OpenGl_Context::SetDrawBufferMono() +void OpenGl_Context::SetDrawBuffer (const Standard_Integer theDrawBuffer) { #if !defined(GL_ES_VERSION_2_0) - switch (myDrawBuffer) + myDrawBuffer = !myIsStereoBuffers ? stereoToMonoBuffer (theDrawBuffer) : theDrawBuffer; + if (myDrawBuffer < GL_COLOR_ATTACHMENT0 + && arbFBO != NULL) { - case GL_BACK_LEFT : - case GL_BACK_RIGHT : - glDrawBuffer (GL_BACK); - myDrawBuffer = GL_BACK; - break; - - case GL_FRONT_LEFT : - case GL_FRONT_RIGHT : - glDrawBuffer (GL_FRONT); - myDrawBuffer = GL_FRONT; - break; - - case GL_LEFT : - case GL_RIGHT : - glDrawBuffer (GL_FRONT_AND_BACK); - myDrawBuffer = GL_FRONT_AND_BACK; - break; + arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, OpenGl_FrameBuffer::NO_FRAMEBUFFER); } + ::glDrawBuffer (myDrawBuffer); +#else + (void )theDrawBuffer; #endif } @@ -391,8 +357,9 @@ void OpenGl_Context::FetchState() ::glGetIntegerv (GL_RENDER_MODE, &myRenderMode); } - // cache draw buffer state - glGetIntegerv (GL_DRAW_BUFFER, &myDrawBuffer); + // cache buffers state + ::glGetIntegerv (GL_READ_BUFFER, &myReadBuffer); + ::glGetIntegerv (GL_DRAW_BUFFER, &myDrawBuffer); #endif } diff --git a/src/OpenGl/OpenGl_Context.hxx b/src/OpenGl/OpenGl_Context.hxx index 7a8a58c24c..ce67d6012a 100644 --- a/src/OpenGl/OpenGl_Context.hxx +++ b/src/OpenGl/OpenGl_Context.hxx @@ -487,20 +487,24 @@ public: public: //! @name methods to alter or retrieve current state - //! Switch to left stereographic rendering buffer. - //! This method can be used to keep unchanged choise - //! of front/back/both buffer rendering. - Standard_EXPORT void SetDrawBufferLeft(); + //! Return active read buffer. + Standard_Integer ReadBuffer() { return myReadBuffer; } - //! Switch to right stereographic rendering buffer. - //! This method can be used to keep unchanged choise - //! of front/back/both buffer rendering. - Standard_EXPORT void SetDrawBufferRight(); + //! Switch read buffer, wrapper for ::glReadBuffer(). + Standard_EXPORT void SetReadBuffer (const Standard_Integer theReadBuffer); - //! Switch to non-stereographic rendering buffer. - //! This method can be used to keep unchanged choise - //! of front/back/both buffer rendering. - Standard_EXPORT void SetDrawBufferMono(); + //! Return active draw buffer. + Standard_Integer DrawBuffer() { return myDrawBuffer; } + + //! Switch draw buffer, wrapper for ::glDrawBuffer(). + Standard_EXPORT void SetDrawBuffer (const Standard_Integer theDrawBuffer); + + //! Switch read/draw buffers. + void SetReadDrawBuffer (const Standard_Integer theBuffer) + { + SetReadBuffer (theBuffer); + SetDrawBuffer (theBuffer); + } //! Fetch OpenGl context state. This class tracks value of several OpenGl //! state variables. Consulting the cached values is quicker than @@ -667,6 +671,7 @@ private: //! @name fields tracking current state Handle(OpenGl_Sampler) myTexSampler; //!< currently active sampler object Handle(OpenGl_FrameBuffer) myDefaultFbo; //!< default Frame Buffer Object Standard_Integer myRenderMode; //!< value for active rendering mode + Standard_Integer myReadBuffer; //!< current read buffer Standard_Integer myDrawBuffer; //!< current draw buffer unsigned int myDefaultVao; //!< default Vertex Array Object Standard_Boolean myIsGlDebugCtx; //!< debug context initialization state diff --git a/src/OpenGl/OpenGl_FrameBuffer.cxx b/src/OpenGl/OpenGl_FrameBuffer.cxx index 6667238126..59f99c813b 100644 --- a/src/OpenGl/OpenGl_FrameBuffer.cxx +++ b/src/OpenGl/OpenGl_FrameBuffer.cxx @@ -99,6 +99,23 @@ Standard_Boolean OpenGl_FrameBuffer::Init (const Handle(OpenGl_Context)& theGlCo return Standard_True; } +// ======================================================================= +// function : Init +// purpose : +// ======================================================================= +Standard_Boolean OpenGl_FrameBuffer::InitLazy (const Handle(OpenGl_Context)& theGlContext, + const GLsizei theViewportSizeX, + const GLsizei theViewportSizeY) +{ + if (myVPSizeX == theViewportSizeX + && myVPSizeY == theViewportSizeY) + { + return IsValid(); + } + + return Init (theGlContext, theViewportSizeX, theViewportSizeY); +} + // ======================================================================= // function : InitWithRB // purpose : diff --git a/src/OpenGl/OpenGl_FrameBuffer.hxx b/src/OpenGl/OpenGl_FrameBuffer.hxx index 65bc08b324..799b2920bd 100644 --- a/src/OpenGl/OpenGl_FrameBuffer.hxx +++ b/src/OpenGl/OpenGl_FrameBuffer.hxx @@ -88,6 +88,11 @@ public: const GLsizei theViewportSizeX, const GLsizei theViewportSizeY); + //! (Re-)initialize FBO with specified dimensions. + Standard_EXPORT Standard_Boolean InitLazy (const Handle(OpenGl_Context)& theGlCtx, + const GLsizei theViewportSizeX, + const GLsizei theViewportSizeY); + //! (Re-)initialize FBO with specified dimensions. //! The Render Buffer Objects will be used for Color, Depth and Stencil attachments (as opposite to textures). //! @param theGlCtx currently bound OpenGL context diff --git a/src/OpenGl/OpenGl_ShaderManager.cxx b/src/OpenGl/OpenGl_ShaderManager.cxx index 01ca6725ba..a5d22af259 100644 --- a/src/OpenGl/OpenGl_ShaderManager.cxx +++ b/src/OpenGl/OpenGl_ShaderManager.cxx @@ -235,6 +235,7 @@ void OpenGl_ShaderManager::clear() myMapOfLightPrograms.Clear(); myFontProgram.Nullify(); myBlitProgram.Nullify(); + myAnaglyphProgram.Nullify(); switchLightPrograms(); } @@ -1578,6 +1579,60 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramPhong (Handle(OpenGl_Sha return Standard_True; } +// ======================================================================= +// function : prepareStdProgramAnaglyph +// purpose : +// ======================================================================= +Standard_Boolean OpenGl_ShaderManager::prepareStdProgramAnaglyph() +{ + Handle(Graphic3d_ShaderProgram) aProgramSrc = new Graphic3d_ShaderProgram(); + TCollection_AsciiString aSrcVert = + EOL"THE_SHADER_OUT vec2 TexCoord;" + EOL"void main()" + EOL"{" + EOL" TexCoord = occVertex.zw;" + EOL" gl_Position = vec4(occVertex.x, occVertex.y, 0.0, 1.0);" + EOL"}"; + + TCollection_AsciiString aSrcFrag = + EOL"uniform sampler2D uLeftSampler;" + EOL"uniform sampler2D uRightSampler;" + EOL + EOL"THE_SHADER_IN vec2 TexCoord;" + EOL + EOL"void main()" + EOL"{" + EOL" vec4 aColorL = occTexture2D (uLeftSampler, TexCoord);" + EOL" vec4 aColorR = occTexture2D (uRightSampler, TexCoord);" + EOL" aColorL.b = 0.0;" + EOL" aColorL.g = 0.0;" + EOL" aColorR.r = 0.0;" + EOL" occFragColor = aColorL + aColorR;" + EOL"}"; + +#if !defined(GL_ES_VERSION_2_0) + if (myContext->core32 != NULL) + { + aProgramSrc->SetHeader ("#version 150"); + } +#endif + + aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_VERTEX, aSrcVert)); + aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_FRAGMENT, aSrcFrag)); + TCollection_AsciiString aKey; + if (!Create (aProgramSrc, aKey, myAnaglyphProgram)) + { + myAnaglyphProgram = new OpenGl_ShaderProgram(); // just mark as invalid + return Standard_False; + } + + myContext->BindProgram (myAnaglyphProgram); + myAnaglyphProgram->SetSampler (myContext, "uLeftSampler", 0); + myAnaglyphProgram->SetSampler (myContext, "uRightSampler", 1); + myContext->BindProgram (NULL); + return Standard_True; +} + // ======================================================================= // function : bindProgramWithState // purpose : diff --git a/src/OpenGl/OpenGl_ShaderManager.hxx b/src/OpenGl/OpenGl_ShaderManager.hxx index 780b76fb8e..b08d866ad8 100644 --- a/src/OpenGl/OpenGl_ShaderManager.hxx +++ b/src/OpenGl/OpenGl_ShaderManager.hxx @@ -156,6 +156,17 @@ public: && myContext->BindProgram (myBlitProgram); } + //! Bind program for rendering Anaglyph image. + Standard_Boolean BindAnaglyphProgram() + { + if (myAnaglyphProgram.IsNull()) + { + prepareStdProgramAnaglyph(); + } + return !myAnaglyphProgram.IsNull() + && myContext->BindProgram (myAnaglyphProgram); + } + public: //! Returns current state of OCCT light sources. @@ -354,6 +365,9 @@ protected: //! Set pointer myLightPrograms to active lighting programs set from myMapOfLightPrograms Standard_EXPORT void switchLightPrograms(); + //! Prepare standard GLSL program for Anaglyph image. + Standard_EXPORT Standard_Boolean prepareStdProgramAnaglyph(); + protected: Visual3d_TypeOfModel myShadingModel; //!< lighting shading model @@ -364,6 +378,8 @@ protected: Handle(OpenGl_ShaderProgram) myBlitProgram; //!< standard program for FBO blit emulation OpenGl_MapOfShaderPrograms myMapOfLightPrograms; //!< map of lighting programs depending on shading model and lights configuration + Handle(OpenGl_ShaderProgram) myAnaglyphProgram; //!< standard program for Anaglyph image + OpenGl_Context* myContext; //!< OpenGL context protected: diff --git a/src/OpenGl/OpenGl_View.cxx b/src/OpenGl/OpenGl_View.cxx index d1c77aa01a..44926c33d2 100644 --- a/src/OpenGl/OpenGl_View.cxx +++ b/src/OpenGl/OpenGl_View.cxx @@ -500,13 +500,3 @@ const TEL_TRANSFORM_PERSISTENCE* OpenGl_View::BeginTransformPersistence (const H theCtx->ApplyProjectionMatrix(); return aTransPersPrev; } - -/*----------------------------------------------------------------------*/ - -void OpenGl_View::GetMatrices (OpenGl_Mat4& theOrientation, - OpenGl_Mat4& theViewMapping) const -{ - theViewMapping = myCamera->ProjectionMatrixF(); - theOrientation = myCamera->OrientationMatrixF(); -} -/*----------------------------------------------------------------------*/ diff --git a/src/OpenGl/OpenGl_View.hxx b/src/OpenGl/OpenGl_View.hxx index d3c30a08ca..5f28f800d1 100644 --- a/src/OpenGl/OpenGl_View.hxx +++ b/src/OpenGl/OpenGl_View.hxx @@ -170,6 +170,8 @@ class OpenGl_View : public MMgt_TShared void Render (const Handle(OpenGl_PrinterContext)& thePrintContext, const Handle(OpenGl_Workspace)& theWorkspace, + OpenGl_FrameBuffer* theReadDrawFbo, + Graphic3d_Camera::Projection theProjection, const Graphic3d_CView& theCView, const Aspect_CLayer2d& theCUnderLayer, const Aspect_CLayer2d& theCOverLayer, @@ -198,10 +200,6 @@ class OpenGl_View : public MMgt_TShared //! marks primitive set for rebuild. void InvalidateBVHData (const Standard_Integer theLayerId); - //! Returns view-mapping and orientation matrices. - void GetMatrices (OpenGl_Mat4& theOrientation, - OpenGl_Mat4& theViewMapping) const; - //! Returns list of immediate structures rendered on top of main presentation const OpenGl_SequenceOfStructure& ImmediateStructures() const { @@ -218,6 +216,7 @@ class OpenGl_View : public MMgt_TShared protected: void RenderStructs (const Handle(OpenGl_Workspace)& theWorkspace, + OpenGl_FrameBuffer* theReadDrawFbo, const Graphic3d_CView& theCView, const Standard_Boolean theToDrawImmediate); @@ -234,6 +233,7 @@ protected: //! matrices supplied by 3d view. void RedrawScene (const Handle(OpenGl_PrinterContext)& thePrintContext, const Handle(OpenGl_Workspace)& theWorkspace, + OpenGl_FrameBuffer* theReadDrawFbo, const Graphic3d_CView& theCView, const Standard_Boolean theToDrawImmediate); @@ -587,14 +587,14 @@ protected: //! @name methods related to ray-tracing const OpenGl_Vec3* theOrigins, const OpenGl_Vec3* theDirects, const OpenGl_Mat4& theUnviewMat, - OpenGl_FrameBuffer* theOutputFBO, + OpenGl_FrameBuffer* theReadDrawFbo, const Handle(OpenGl_Context)& theGlContext); //! Redraws the window using OpenGL/GLSL ray-tracing. Standard_Boolean raytrace (const Graphic3d_CView& theCView, const Standard_Integer theSizeX, const Standard_Integer theSizeY, - OpenGl_FrameBuffer* theOutputFBO, + OpenGl_FrameBuffer* theReadDrawFbo, const Handle(OpenGl_Context)& theGlContext); protected: //! @name fields related to ray-tracing diff --git a/src/OpenGl/OpenGl_View_2.cxx b/src/OpenGl/OpenGl_View_2.cxx index 4240be52da..3abea5156f 100644 --- a/src/OpenGl/OpenGl_View_2.cxx +++ b/src/OpenGl/OpenGl_View_2.cxx @@ -245,6 +245,8 @@ void OpenGl_View::DrawBackground (const Handle(OpenGl_Workspace)& theWorkspace) //call_func_redraw_all_structs_proc void OpenGl_View::Render (const Handle(OpenGl_PrinterContext)& thePrintContext, const Handle(OpenGl_Workspace)& theWorkspace, + OpenGl_FrameBuffer* theOutputFBO, + Graphic3d_Camera::Projection theProjection, const Graphic3d_CView& theCView, const Aspect_CLayer2d& theCUnderLayer, const Aspect_CLayer2d& theCOverLayer, @@ -433,42 +435,17 @@ void OpenGl_View::Render (const Handle(OpenGl_PrinterContext)& thePrintContext, } // Redraw 3d scene - if (!myCamera->IsStereo() || !aContext->HasStereoBuffers()) + if (theProjection == Graphic3d_Camera::Projection_MonoLeftEye) { - // single-pass monographic rendering - // redraw scene with normal orientation and projection - RedrawScene (thePrintContext, theWorkspace, theCView, theToDrawImmediate); - } - else - { - // two stereographic passes - - // safely switch to left Eye buffer - aContext->SetDrawBufferLeft(); - aContext->ProjectionState.SetCurrent (myCamera->ProjectionStereoLeftF()); aContext->ApplyProjectionMatrix(); - - // redraw left Eye - RedrawScene (thePrintContext, theWorkspace, theCView, theToDrawImmediate); - - // reset depth buffer of first rendering pass - if (theWorkspace->UseDepthTest()) - { - glClear (GL_DEPTH_BUFFER_BIT); - } - // safely switch to right Eye buffer - aContext->SetDrawBufferRight(); - + } + else if (theProjection == Graphic3d_Camera::Projection_MonoRightEye) + { aContext->ProjectionState.SetCurrent (myCamera->ProjectionStereoRightF()); aContext->ApplyProjectionMatrix(); - - // redraw right Eye - RedrawScene (thePrintContext, theWorkspace, theCView, theToDrawImmediate); - - // switch back to monographic rendering - aContext->SetDrawBufferMono(); } + RedrawScene (thePrintContext, theWorkspace, theOutputFBO, theCView, theToDrawImmediate); // =============================== // Step 5: Trihedron @@ -547,6 +524,7 @@ void OpenGl_View::InvalidateBVHData (const Graphic3d_ZLayerId theLayerId) //ExecuteViewDisplay void OpenGl_View::RenderStructs (const Handle(OpenGl_Workspace)& theWorkspace, + OpenGl_FrameBuffer* theReadDrawFbo, const Graphic3d_CView& theCView, const Standard_Boolean theToDrawImmediate) { @@ -601,21 +579,10 @@ void OpenGl_View::RenderStructs (const Handle(OpenGl_Workspace)& theWorkspace, if (!toRenderGL) { - OpenGl_FrameBuffer* anOutputFBO = NULL; - - if (theWorkspace->ResultFBO()->IsValid()) - { - anOutputFBO = theWorkspace->ResultFBO().operator->(); - } - else if (theCView.ptrFBO != NULL) - { - anOutputFBO = (OpenGl_FrameBuffer* )theCView.ptrFBO; - } - - const Standard_Integer aSizeX = anOutputFBO != NULL ? - anOutputFBO->GetVPSizeX() : theWorkspace->Width(); - const Standard_Integer aSizeY = anOutputFBO != NULL ? - anOutputFBO->GetVPSizeY() : theWorkspace->Height(); + const Standard_Integer aSizeX = theReadDrawFbo != NULL ? + theReadDrawFbo->GetVPSizeX() : theWorkspace->Width(); + const Standard_Integer aSizeY = theReadDrawFbo != NULL ? + theReadDrawFbo->GetVPSizeY() : theWorkspace->Height(); if (myOpenGlFBO.IsNull()) myOpenGlFBO = new OpenGl_FrameBuffer; @@ -631,8 +598,8 @@ void OpenGl_View::RenderStructs (const Handle(OpenGl_Workspace)& theWorkspace, myRaytraceFilter->SetPrevRenderFilter (theWorkspace->GetRenderFilter()); - if (anOutputFBO != NULL) - anOutputFBO->UnbindBuffer (aCtx); + if (theReadDrawFbo != NULL) + theReadDrawFbo->UnbindBuffer (aCtx); // Prepare preliminary OpenGL output if (aCtx->arbFBOBlit != NULL) @@ -642,9 +609,9 @@ void OpenGl_View::RenderStructs (const Handle(OpenGl_Workspace)& theWorkspace, theWorkspace->SetRenderFilter (myRaytraceFilter); { - if (anOutputFBO != NULL) + if (theReadDrawFbo != NULL) { - anOutputFBO->BindReadBuffer (aCtx); + theReadDrawFbo->BindReadBuffer (aCtx); } else { @@ -664,9 +631,9 @@ void OpenGl_View::RenderStructs (const Handle(OpenGl_Workspace)& theWorkspace, theWorkspace->SetRenderFilter (myRaytraceFilter->PrevRenderFilter()); } - if (anOutputFBO != NULL) + if (theReadDrawFbo != NULL) { - anOutputFBO->BindBuffer (aCtx); + theReadDrawFbo->BindBuffer (aCtx); } else { @@ -674,7 +641,7 @@ void OpenGl_View::RenderStructs (const Handle(OpenGl_Workspace)& theWorkspace, } // Ray-tracing polygonal primitive arrays - raytrace (theCView, aSizeX, aSizeY, anOutputFBO, aCtx); + raytrace (theCView, aSizeX, aSizeY, theReadDrawFbo, aCtx); // Render upper (top and topmost) OpenGL layers myZLayers.Render (theWorkspace, theToDrawImmediate, OpenGl_LF_Upper); @@ -1032,6 +999,7 @@ void OpenGl_View::ChangePriority (const OpenGl_Structure *theStructure, void OpenGl_View::RedrawScene (const Handle(OpenGl_PrinterContext)& thePrintContext, const Handle(OpenGl_Workspace)& theWorkspace, + OpenGl_FrameBuffer* theReadDrawFbo, const Graphic3d_CView& theCView, const Standard_Boolean theToDrawImmediate) { @@ -1165,14 +1133,14 @@ void OpenGl_View::RedrawScene (const Handle(OpenGl_PrinterContext)& thePrintCont theWorkspace->NamedStatus |= OPENGL_NS_FORBIDSETTEX; theWorkspace->DisableTexture(); // Render the view - RenderStructs (theWorkspace, theCView, theToDrawImmediate); + RenderStructs (theWorkspace, theReadDrawFbo, theCView, theToDrawImmediate); break; case Visual3d_TOD_ENVIRONMENT: theWorkspace->NamedStatus |= OPENGL_NS_FORBIDSETTEX; theWorkspace->EnableTexture (myTextureEnv); // Render the view - RenderStructs (theWorkspace, theCView, theToDrawImmediate); + RenderStructs (theWorkspace, theReadDrawFbo, theCView, theToDrawImmediate); theWorkspace->DisableTexture(); break; @@ -1180,7 +1148,7 @@ void OpenGl_View::RedrawScene (const Handle(OpenGl_PrinterContext)& thePrintCont // First pass theWorkspace->NamedStatus &= ~OPENGL_NS_FORBIDSETTEX; // Render the view - RenderStructs (theWorkspace, theCView, theToDrawImmediate); + RenderStructs (theWorkspace, theReadDrawFbo, theCView, theToDrawImmediate); theWorkspace->DisableTexture(); // Second pass @@ -1213,7 +1181,7 @@ void OpenGl_View::RedrawScene (const Handle(OpenGl_PrinterContext)& thePrintCont theWorkspace->NamedStatus |= OPENGL_NS_FORBIDSETTEX; // Render the view - RenderStructs (theWorkspace, theCView, theToDrawImmediate); + RenderStructs (theWorkspace, theReadDrawFbo, theCView, theToDrawImmediate); theWorkspace->DisableTexture(); // Restore properties back diff --git a/src/OpenGl/OpenGl_View_Raytrace.cxx b/src/OpenGl/OpenGl_View_Raytrace.cxx index 757f0b297d..4a0196eed1 100644 --- a/src/OpenGl/OpenGl_View_Raytrace.cxx +++ b/src/OpenGl/OpenGl_View_Raytrace.cxx @@ -2208,7 +2208,7 @@ Standard_Boolean OpenGl_View::runRaytraceShaders (const Graphic3d_CView& const OpenGl_Vec3* theOrigins, const OpenGl_Vec3* theDirects, const OpenGl_Mat4& theUnviewMat, - OpenGl_FrameBuffer* theOutputFBO, + OpenGl_FrameBuffer* theReadDrawFbo, const Handle(OpenGl_Context)& theGlContext) { bindRaytraceTextures (theGlContext); @@ -2296,8 +2296,8 @@ Standard_Boolean OpenGl_View::runRaytraceShaders (const Graphic3d_CView& { glEnable (GL_BLEND); - if (theOutputFBO != NULL) - theOutputFBO->BindBuffer (theGlContext); + if (theReadDrawFbo != NULL) + theReadDrawFbo->BindBuffer (theGlContext); } else { @@ -2328,7 +2328,7 @@ Standard_Boolean OpenGl_View::runRaytraceShaders (const Graphic3d_CView& Standard_Boolean OpenGl_View::raytrace (const Graphic3d_CView& theCView, const Standard_Integer theSizeX, const Standard_Integer theSizeY, - OpenGl_FrameBuffer* theOutputFBO, + OpenGl_FrameBuffer* theReadDrawFbo, const Handle(OpenGl_Context)& theGlContext) { if (!initRaytraceResources (theCView, theGlContext)) @@ -2347,15 +2347,11 @@ Standard_Boolean OpenGl_View::raytrace (const Graphic3d_CView& theCView, } // Get model-view and projection matrices - OpenGl_Mat4 aOrientationMatrix; - OpenGl_Mat4 aViewMappingMatrix; - OpenGl_Mat4 aInverOrientMatrix; - - GetMatrices (aOrientationMatrix, - aViewMappingMatrix); + OpenGl_Mat4 aOrientationMatrix = myCamera->OrientationMatrixF(); + OpenGl_Mat4 aViewMappingMatrix = theGlContext->ProjectionState.Current(); + OpenGl_Mat4 aInverOrientMatrix; aOrientationMatrix.Inverted (aInverOrientMatrix); - if (!updateRaytraceLightSources (aInverOrientMatrix, theGlContext)) { return Standard_False; @@ -2375,9 +2371,9 @@ Standard_Boolean OpenGl_View::raytrace (const Graphic3d_CView& theCView, glDisable (GL_DEPTH_TEST); glBlendFunc (GL_ONE, GL_SRC_ALPHA); - if (theOutputFBO != NULL) + if (theReadDrawFbo != NULL) { - theOutputFBO->BindBuffer (theGlContext); + theReadDrawFbo->BindBuffer (theGlContext); } // Generate ray-traced image @@ -2397,7 +2393,7 @@ Standard_Boolean OpenGl_View::raytrace (const Graphic3d_CView& theCView, aOrigins, aDirects, anUnviewMat, - theOutputFBO, + theReadDrawFbo, theGlContext); if (!aResult) diff --git a/src/OpenGl/OpenGl_Window.cxx b/src/OpenGl/OpenGl_Window.cxx index 2b9649bafd..5fedea6e84 100644 --- a/src/OpenGl/OpenGl_Window.cxx +++ b/src/OpenGl/OpenGl_Window.cxx @@ -896,25 +896,3 @@ void OpenGl_Window::DisableFeatures() const } #endif } - -// ======================================================================= -// function : MakeFrontBufCurrent -// purpose : TelMakeFrontBufCurrent -// ======================================================================= -void OpenGl_Window::MakeFrontBufCurrent() const -{ -#if !defined(GL_ES_VERSION_2_0) - glDrawBuffer (GL_FRONT); -#endif -} - -// ======================================================================= -// function : MakeBackBufCurrent -// purpose : TelMakeBackBufCurrent -// ======================================================================= -void OpenGl_Window::MakeBackBufCurrent() const -{ -#if !defined(GL_ES_VERSION_2_0) - glDrawBuffer (GL_BACK); -#endif -} diff --git a/src/OpenGl/OpenGl_Window.hxx b/src/OpenGl/OpenGl_Window.hxx index 7f7dee2a71..6b0d22496f 100644 --- a/src/OpenGl/OpenGl_Window.hxx +++ b/src/OpenGl/OpenGl_Window.hxx @@ -83,12 +83,6 @@ protected: void EnableFeatures() const; void DisableFeatures() const; - //! Draw directly to the FRONT buffer. Can cause artifacts on the screen. - void MakeFrontBufCurrent() const; - - //! Draw to BACK buffer. Normal and default state. - void MakeBackBufCurrent() const; - protected: Handle(OpenGl_Context) myGlContext; diff --git a/src/OpenGl/OpenGl_Workspace.cxx b/src/OpenGl/OpenGl_Workspace.cxx index 606d30846b..237ece8dc4 100644 --- a/src/OpenGl/OpenGl_Workspace.cxx +++ b/src/OpenGl/OpenGl_Workspace.cxx @@ -176,7 +176,10 @@ OpenGl_Workspace::OpenGl_Workspace (const Handle(OpenGl_GraphicDriver)& theDrive PolygonOffset_applied (THE_DEFAULT_POFFSET) { myGlContext->core11fwd->glPixelStorei (GL_UNPACK_ALIGNMENT, 1); - myResultFBO = new OpenGl_FrameBuffer(); + myMainSceneFbos[0] = new OpenGl_FrameBuffer(); + myMainSceneFbos[1] = new OpenGl_FrameBuffer(); + myImmediateSceneFbos[0] = new OpenGl_FrameBuffer(); + myImmediateSceneFbos[1] = new OpenGl_FrameBuffer(); if (!myGlContext->GetResource ("OpenGl_LineAttributes", myLineAttribs)) { @@ -224,6 +227,16 @@ Standard_Boolean OpenGl_Workspace::SetImmediateModeDrawToFront (const Standard_B return aPrevMode; } +inline void nullifyGlResource (Handle(OpenGl_Resource)& theResource, + const Handle(OpenGl_Context)& theCtx) +{ + if (!theResource.IsNull()) + { + theResource->Release (theCtx.operator->()); + theResource.Nullify(); + } +} + // ======================================================================= // function : ~OpenGl_Workspace // purpose : @@ -236,15 +249,12 @@ OpenGl_Workspace::~OpenGl_Workspace() myGlContext->ReleaseResource ("OpenGl_LineAttributes", Standard_True); } - if (!myResultFBO.IsNull()) - { - myResultFBO->Release (myGlContext.operator->()); - myResultFBO.Nullify(); - } - if (myFullScreenQuad.IsValid()) - { - myFullScreenQuad.Release (myGlContext.operator->()); - } + nullifyGlResource (myMainSceneFbos[0], myGlContext); + nullifyGlResource (myMainSceneFbos[1], myGlContext); + nullifyGlResource (myImmediateSceneFbos[0], myGlContext); + nullifyGlResource (myImmediateSceneFbos[1], myGlContext); + + myFullScreenQuad.Release (myGlContext.operator->()); } // ======================================================================= @@ -652,6 +662,211 @@ Handle(OpenGl_Texture) OpenGl_Workspace::EnableTexture (const Handle(OpenGl_Text return aPrevTexture; } +// ======================================================================= +// function : bindDefaultFbo +// purpose : +// ======================================================================= +void OpenGl_Workspace::bindDefaultFbo (OpenGl_FrameBuffer* theCustomFbo) +{ + OpenGl_FrameBuffer* anFbo = (theCustomFbo != NULL && theCustomFbo->IsValid()) + ? theCustomFbo + : (!myGlContext->DefaultFrameBuffer().IsNull() + && myGlContext->DefaultFrameBuffer()->IsValid() + ? myGlContext->DefaultFrameBuffer().operator->() + : NULL); + if (anFbo != NULL) + { + anFbo->BindBuffer (myGlContext); + } + else + { + #if !defined(GL_ES_VERSION_2_0) + myGlContext->SetReadDrawBuffer (GL_BACK); + #else + if (myGlContext->arbFBO != NULL) + { + myGlContext->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, OpenGl_FrameBuffer::NO_FRAMEBUFFER); + } + #endif + } + myGlContext->core11fwd->glViewport (0, 0, myWidth, myHeight); +} + +// ======================================================================= +// function : blitBuffers +// purpose : +// ======================================================================= +bool OpenGl_Workspace::blitBuffers (OpenGl_FrameBuffer* theReadFbo, + OpenGl_FrameBuffer* theDrawFbo) +{ + if (theReadFbo == NULL) + { + return false; + } + + // clear destination before blitting + if (theDrawFbo != NULL + && theDrawFbo->IsValid()) + { + theDrawFbo->BindBuffer (myGlContext); + } + else + { + myGlContext->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, OpenGl_FrameBuffer::NO_FRAMEBUFFER); + } +#if !defined(GL_ES_VERSION_2_0) + myGlContext->core20fwd->glClearDepth (1.0); +#else + myGlContext->core20fwd->glClearDepthf (1.0f); +#endif + myGlContext->core20fwd->glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + +/*#if !defined(GL_ES_VERSION_2_0) + if (myGlContext->arbFBOBlit != NULL) + { + theReadFbo->BindReadBuffer (myGlContext); + if (theDrawFbo != NULL + && theDrawFbo->IsValid()) + { + theDrawFbo->BindDrawBuffer (myGlContext); + } + else + { + myGlContext->arbFBO->glBindFramebuffer (GL_DRAW_FRAMEBUFFER, OpenGl_FrameBuffer::NO_FRAMEBUFFER); + } + // we don't copy stencil buffer here... does it matter for performance? + myGlContext->arbFBOBlit->glBlitFramebuffer (0, 0, theReadFbo->GetVPSizeX(), theReadFbo->GetVPSizeY(), + 0, 0, theReadFbo->GetVPSizeX(), theReadFbo->GetVPSizeY(), + GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, GL_NEAREST); + + if (theDrawFbo != NULL + && theDrawFbo->IsValid()) + { + theDrawFbo->BindBuffer (myGlContext); + } + else + { + myGlContext->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, OpenGl_FrameBuffer::NO_FRAMEBUFFER); + } + } + else +#endif*/ + { + myGlContext->core20fwd->glDepthFunc (GL_ALWAYS); + myGlContext->core20fwd->glDepthMask (GL_TRUE); + myGlContext->core20fwd->glEnable (GL_DEPTH_TEST); + + DisableTexture(); + if (!myFullScreenQuad.IsValid()) + { + OpenGl_Vec4 aQuad[4] = + { + OpenGl_Vec4( 1.0f, -1.0f, 1.0f, 0.0f), + OpenGl_Vec4( 1.0f, 1.0f, 1.0f, 1.0f), + OpenGl_Vec4(-1.0f, -1.0f, 0.0f, 0.0f), + OpenGl_Vec4(-1.0f, 1.0f, 0.0f, 1.0f) + }; + myFullScreenQuad.Init (myGlContext, 4, 4, aQuad[0].GetData()); + } + + const Handle(OpenGl_ShaderManager)& aManager = myGlContext->ShaderManager(); + if (myFullScreenQuad.IsValid() + && aManager->BindFboBlitProgram()) + { + theReadFbo->ColorTexture() ->Bind (myGlContext, GL_TEXTURE0 + 0); + theReadFbo->DepthStencilTexture()->Bind (myGlContext, GL_TEXTURE0 + 1); + myFullScreenQuad.BindVertexAttrib (myGlContext, 0); + + myGlContext->core20fwd->glDrawArrays (GL_TRIANGLE_STRIP, 0, 4); + + myFullScreenQuad.UnbindVertexAttrib (myGlContext, 0); + theReadFbo->DepthStencilTexture()->Unbind (myGlContext, GL_TEXTURE0 + 1); + theReadFbo->ColorTexture() ->Unbind (myGlContext, GL_TEXTURE0 + 0); + } + else + { + TCollection_ExtendedString aMsg = TCollection_ExtendedString() + + "Error! FBO blitting has failed"; + myGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB, + GL_DEBUG_TYPE_ERROR_ARB, + 0, + GL_DEBUG_SEVERITY_HIGH_ARB, + aMsg); + myHasFboBlit = Standard_False; + theReadFbo->Release (myGlContext.operator->()); + return true; + } + } + return true; +} + +// ======================================================================= +// function : drawStereoPair +// purpose : +// ======================================================================= +void OpenGl_Workspace::drawStereoPair() +{ + OpenGl_FrameBuffer* aPair[2] = + { + myImmediateSceneFbos[0]->IsValid() ? myImmediateSceneFbos[0].operator->() : NULL, + myImmediateSceneFbos[1]->IsValid() ? myImmediateSceneFbos[1].operator->() : NULL + }; + if (aPair[0] == NULL + || aPair[1] == NULL) + { + aPair[0] = myMainSceneFbos[0]->IsValid() ? myMainSceneFbos[0].operator->() : NULL; + aPair[1] = myMainSceneFbos[1]->IsValid() ? myMainSceneFbos[1].operator->() : NULL; + } + + if (aPair[0] == NULL + || aPair[1] == NULL) + { + return; + } + + myGlContext->core20fwd->glDepthFunc (GL_ALWAYS); + myGlContext->core20fwd->glDepthMask (GL_TRUE); + myGlContext->core20fwd->glEnable (GL_DEPTH_TEST); + + DisableTexture(); + if (!myFullScreenQuad.IsValid()) + { + OpenGl_Vec4 aQuad[4] = + { + OpenGl_Vec4( 1.0f, -1.0f, 1.0f, 0.0f), + OpenGl_Vec4( 1.0f, 1.0f, 1.0f, 1.0f), + OpenGl_Vec4(-1.0f, -1.0f, 0.0f, 0.0f), + OpenGl_Vec4(-1.0f, 1.0f, 0.0f, 1.0f) + }; + myFullScreenQuad.Init (myGlContext, 4, 4, aQuad[0].GetData()); + } + + const Handle(OpenGl_ShaderManager)& aManager = myGlContext->ShaderManager(); + if (myFullScreenQuad.IsValid() + && aManager->BindAnaglyphProgram()) + { + aPair[0]->ColorTexture()->Bind (myGlContext, GL_TEXTURE0 + 0); + aPair[1]->ColorTexture()->Bind (myGlContext, GL_TEXTURE0 + 1); + myFullScreenQuad.BindVertexAttrib (myGlContext, 0); + + myGlContext->core20fwd->glDrawArrays (GL_TRIANGLE_STRIP, 0, 4); + + myFullScreenQuad.UnbindVertexAttrib (myGlContext, 0); + aPair[1]->ColorTexture()->Unbind (myGlContext, GL_TEXTURE0 + 1); + aPair[0]->ColorTexture()->Unbind (myGlContext, GL_TEXTURE0 + 0); + } + else + { + TCollection_ExtendedString aMsg = TCollection_ExtendedString() + + "Error! Anaglyph has failed"; + myGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB, + GL_DEBUG_TYPE_ERROR_ARB, + 0, + GL_DEBUG_SEVERITY_HIGH_ARB, + aMsg); + } +} + // ======================================================================= // function : Redraw // purpose : @@ -675,14 +890,6 @@ void OpenGl_Workspace::Redraw (const Graphic3d_CView& theCView, myGlContext->FetchState(); OpenGl_FrameBuffer* aFrameBuffer = (OpenGl_FrameBuffer* )theCView.ptrFBO; - if (aFrameBuffer != NULL) - { - aFrameBuffer->SetupViewport (myGlContext); - } - else - { - myGlContext->core11fwd->glViewport (0, 0, myWidth, myHeight); - } bool toSwap = myGlContext->IsRender() && !myGlContext->caps->buffersNoSwap && aFrameBuffer == NULL; @@ -690,60 +897,135 @@ void OpenGl_Workspace::Redraw (const Graphic3d_CView& theCView, Standard_Integer aSizeX = aFrameBuffer != NULL ? aFrameBuffer->GetVPSizeX() : myWidth; Standard_Integer aSizeY = aFrameBuffer != NULL ? aFrameBuffer->GetVPSizeY() : myHeight; - if (!myGlContext->DefaultFrameBuffer().IsNull() - && myGlContext->DefaultFrameBuffer()->IsValid()) + if ( aFrameBuffer == NULL + && !myGlContext->DefaultFrameBuffer().IsNull() + && myGlContext->DefaultFrameBuffer()->IsValid()) { - myGlContext->DefaultFrameBuffer()->BindBuffer (myGlContext); + aFrameBuffer = myGlContext->DefaultFrameBuffer().operator->(); } if (myHasFboBlit && myTransientDrawToFront) { - if (myResultFBO->GetVPSizeX() != aSizeX - || myResultFBO->GetVPSizeY() != aSizeY) + if (myMainSceneFbos[0]->GetVPSizeX() != aSizeX + || myMainSceneFbos[0]->GetVPSizeY() != aSizeY) { // prepare FBOs containing main scene // for further blitting and rendering immediate presentations on top if (myGlContext->core20fwd != NULL) { - myResultFBO->Init (myGlContext, aSizeX, aSizeY); + myMainSceneFbos[0]->Init (myGlContext, aSizeX, aSizeY); } } - - if (myResultFBO->IsValid()) - { - myResultFBO->SetupViewport (myGlContext); - } } else { - myResultFBO->Release (myGlContext.operator->()); - myResultFBO->ChangeViewport (0, 0); + myMainSceneFbos [0]->Release (myGlContext.operator->()); + myMainSceneFbos [1]->Release (myGlContext.operator->()); + myImmediateSceneFbos[0]->Release (myGlContext.operator->()); + myImmediateSceneFbos[1]->Release (myGlContext.operator->()); + myMainSceneFbos [0]->ChangeViewport (0, 0); + myMainSceneFbos [1]->ChangeViewport (0, 0); + myImmediateSceneFbos[0]->ChangeViewport (0, 0); + myImmediateSceneFbos[1]->ChangeViewport (0, 0); } // draw entire frame using normal OpenGL pipeline - if (myResultFBO->IsValid()) - { - myResultFBO->BindBuffer (myGlContext); - } - else if (aFrameBuffer != NULL) + const Handle(Graphic3d_Camera)& aCamera = myView->Camera(); + Graphic3d_Camera::Projection aProjectType = aCamera->ProjectionType(); + if (aProjectType == Graphic3d_Camera::Projection_Stereo) { - aFrameBuffer->BindBuffer (myGlContext); + if (aFrameBuffer != NULL + || !myGlContext->IsRender()) + { + // implicitly switch to mono camera for image dump + aProjectType = Graphic3d_Camera::Projection_Perspective; + } + else if (myMainSceneFbos[0]->IsValid()) + { + myMainSceneFbos[1]->InitLazy (myGlContext, aSizeX, aSizeY); + if (!myMainSceneFbos[1]->IsValid()) + { + // no enough memory? + aProjectType = Graphic3d_Camera::Projection_Perspective; + } + else if (!myGlContext->HasStereoBuffers()) + { + myImmediateSceneFbos[0]->InitLazy (myGlContext, aSizeX, aSizeY); + myImmediateSceneFbos[1]->InitLazy (myGlContext, aSizeX, aSizeY); + if (!myImmediateSceneFbos[0]->IsValid() + || !myImmediateSceneFbos[1]->IsValid()) + { + aProjectType = Graphic3d_Camera::Projection_Perspective; + } + } + } } - redraw1 (theCView, theCUnderLayer, theCOverLayer); - myBackBufferRestored = Standard_True; - myIsImmediateDrawn = Standard_False; - if (!redrawImmediate (theCView, theCOverLayer, theCUnderLayer, aFrameBuffer)) + if (aProjectType == Graphic3d_Camera::Projection_Stereo) { - toSwap = false; - } + OpenGl_FrameBuffer* aMainFbos[2] = + { + myMainSceneFbos[0]->IsValid() ? myMainSceneFbos[0].operator->() : NULL, + myMainSceneFbos[1]->IsValid() ? myMainSceneFbos[1].operator->() : NULL + }; + OpenGl_FrameBuffer* anImmFbos[2] = + { + myImmediateSceneFbos[0]->IsValid() ? myImmediateSceneFbos[0].operator->() : NULL, + myImmediateSceneFbos[1]->IsValid() ? myImmediateSceneFbos[1].operator->() : NULL + }; - if (aFrameBuffer != NULL) + #if !defined(GL_ES_VERSION_2_0) + myGlContext->SetReadDrawBuffer (GL_BACK_LEFT); + #endif + redraw1 (theCView, theCUnderLayer, theCOverLayer, + aMainFbos[0], Graphic3d_Camera::Projection_MonoLeftEye); + myBackBufferRestored = Standard_True; + myIsImmediateDrawn = Standard_False; + #if !defined(GL_ES_VERSION_2_0) + myGlContext->SetReadDrawBuffer (GL_BACK_LEFT); + #endif + if (!redrawImmediate (theCView, theCOverLayer, theCUnderLayer, aMainFbos[0], aProjectType, anImmFbos[0])) + { + toSwap = false; + } + + #if !defined(GL_ES_VERSION_2_0) + myGlContext->SetReadDrawBuffer (GL_BACK_RIGHT); + #endif + redraw1 (theCView, theCUnderLayer, theCOverLayer, + aMainFbos[1], Graphic3d_Camera::Projection_MonoRightEye); + myBackBufferRestored = Standard_True; + myIsImmediateDrawn = Standard_False; + if (!redrawImmediate (theCView, theCOverLayer, theCUnderLayer, aMainFbos[1], aProjectType, anImmFbos[1])) + { + toSwap = false; + } + + if (anImmFbos[0] != NULL) + { + bindDefaultFbo (aFrameBuffer); + drawStereoPair(); + } + } + else { - aFrameBuffer->UnbindBuffer (myGlContext); - // move back original viewport - myGlContext->core11fwd->glViewport (0, 0, myWidth, myHeight); + OpenGl_FrameBuffer* aMainFbo = myMainSceneFbos[0]->IsValid() ? myMainSceneFbos[0].operator->() : NULL; + #if !defined(GL_ES_VERSION_2_0) + if (aMainFbo == NULL + && aFrameBuffer == NULL) + { + myGlContext->SetReadDrawBuffer (GL_BACK); + } + #endif + redraw1 (theCView, theCUnderLayer, theCOverLayer, + aMainFbo != NULL ? aMainFbo : aFrameBuffer, aProjectType); + myBackBufferRestored = Standard_True; + myIsImmediateDrawn = Standard_False; + if (!redrawImmediate (theCView, theCOverLayer, theCUnderLayer, aMainFbo, aProjectType, aFrameBuffer)) + { + toSwap = false; + } } #if defined(_WIN32) && defined(HAVE_VIDEOCAPTURE) @@ -764,11 +1046,14 @@ void OpenGl_Workspace::Redraw (const Graphic3d_CView& theCView, } #endif + // bind default FBO + bindDefaultFbo(); + // Swap the buffers if (toSwap) { GetGlContext()->SwapBuffers(); - if (!myResultFBO->IsValid()) + if (!myMainSceneFbos[0]->IsValid()) { myBackBufferRestored = Standard_False; } @@ -786,15 +1071,27 @@ void OpenGl_Workspace::Redraw (const Graphic3d_CView& theCView, // function : redraw1 // purpose : // ======================================================================= -void OpenGl_Workspace::redraw1 (const Graphic3d_CView& theCView, - const Aspect_CLayer2d& theCUnderLayer, - const Aspect_CLayer2d& theCOverLayer) +void OpenGl_Workspace::redraw1 (const Graphic3d_CView& theCView, + const Aspect_CLayer2d& theCUnderLayer, + const Aspect_CLayer2d& theCOverLayer, + OpenGl_FrameBuffer* theReadDrawFbo, + const Graphic3d_Camera::Projection theProjection) { if (myView.IsNull()) { return; } + if (theReadDrawFbo != NULL) + { + theReadDrawFbo->BindBuffer (myGlContext); + theReadDrawFbo->SetupViewport (myGlContext); + } + else + { + myGlContext->core11fwd->glViewport (0, 0, myWidth, myHeight); + } + // request reset of material NamedStatus |= OPENGL_NS_RESMAT; @@ -838,7 +1135,7 @@ void OpenGl_Workspace::redraw1 (const Graphic3d_CView& theCView, glClear (toClear); Handle(OpenGl_Workspace) aWS (this); - myView->Render (myPrintContext, aWS, theCView, theCUnderLayer, theCOverLayer, Standard_False); + myView->Render (myPrintContext, aWS, theReadDrawFbo, theProjection, theCView, theCUnderLayer, theCOverLayer, Standard_False); } // ======================================================================= @@ -864,8 +1161,27 @@ void OpenGl_Workspace::copyBackToFront() DisableFeatures(); - glDrawBuffer (GL_FRONT); - glReadBuffer (GL_BACK); + switch (myGlContext->DrawBuffer()) + { + case GL_BACK_LEFT: + { + myGlContext->SetReadBuffer (GL_BACK_LEFT); + myGlContext->SetDrawBuffer (GL_FRONT_LEFT); + break; + } + case GL_BACK_RIGHT: + { + myGlContext->SetReadBuffer (GL_BACK_RIGHT); + myGlContext->SetDrawBuffer (GL_FRONT_RIGHT); + break; + } + default: + { + myGlContext->SetReadBuffer (GL_BACK); + myGlContext->SetDrawBuffer (GL_FRONT); + break; + } + } glRasterPos2i (0, 0); glCopyPixels (0, 0, myWidth + 1, myHeight + 1, GL_COLOR); @@ -876,8 +1192,9 @@ void OpenGl_Workspace::copyBackToFront() myGlContext->WorldViewState.Pop(); myGlContext->ProjectionState.Pop(); myGlContext->ApplyProjectionMatrix(); - glDrawBuffer (GL_BACK); + // read/write from front buffer now + myGlContext->SetReadBuffer (myGlContext->DrawBuffer()); #endif myIsImmediateDrawn = Standard_False; } @@ -911,9 +1228,33 @@ void OpenGl_Workspace::RedrawImmediate (const Graphic3d_CView& theCView, const Aspect_CLayer2d& theCUnderLayer, const Aspect_CLayer2d& theCOverLayer) { + const Handle(Graphic3d_Camera)& aCamera = myView->Camera(); + Graphic3d_Camera::Projection aProjectType = aCamera->ProjectionType(); + OpenGl_FrameBuffer* aFrameBuffer = (OpenGl_FrameBuffer* )theCView.ptrFBO; + if ( aFrameBuffer == NULL + && !myGlContext->DefaultFrameBuffer().IsNull() + && myGlContext->DefaultFrameBuffer()->IsValid()) + { + aFrameBuffer = myGlContext->DefaultFrameBuffer().operator->(); + } + + if (aProjectType == Graphic3d_Camera::Projection_Stereo) + { + if (aFrameBuffer != NULL) + { + // implicitly switch to mono camera for image dump + aProjectType = Graphic3d_Camera::Projection_Perspective; + } + else if (myMainSceneFbos[0]->IsValid() + && !myMainSceneFbos[1]->IsValid()) + { + aProjectType = Graphic3d_Camera::Projection_Perspective; + } + } + if (!myTransientDrawToFront || !myBackBufferRestored - || (myGlContext->caps->buffersNoSwap && !myResultFBO->IsValid())) + || (myGlContext->caps->buffersNoSwap && !myMainSceneFbos[0]->IsValid())) { Redraw (theCView, theCUnderLayer, theCOverLayer); return; @@ -923,13 +1264,77 @@ void OpenGl_Workspace::RedrawImmediate (const Graphic3d_CView& theCView, return; } - if (!myGlContext->DefaultFrameBuffer().IsNull() - && myGlContext->DefaultFrameBuffer()->IsValid()) + bool toSwap = false; + if (aProjectType == Graphic3d_Camera::Projection_Stereo) + { + OpenGl_FrameBuffer* aMainFbos[2] = + { + myMainSceneFbos[0]->IsValid() ? myMainSceneFbos[0].operator->() : NULL, + myMainSceneFbos[1]->IsValid() ? myMainSceneFbos[1].operator->() : NULL + }; + OpenGl_FrameBuffer* anImmFbos[2] = + { + myImmediateSceneFbos[0]->IsValid() ? myImmediateSceneFbos[0].operator->() : NULL, + myImmediateSceneFbos[1]->IsValid() ? myImmediateSceneFbos[1].operator->() : NULL + }; + + if (myGlContext->arbFBO != NULL) + { + myGlContext->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, OpenGl_FrameBuffer::NO_FRAMEBUFFER); + } + #if !defined(GL_ES_VERSION_2_0) + if (anImmFbos[0] == NULL) + { + myGlContext->SetReadDrawBuffer (GL_BACK_LEFT); + } + #endif + toSwap = redrawImmediate (theCView, theCUnderLayer, theCOverLayer, + aMainFbos[0], + Graphic3d_Camera::Projection_MonoLeftEye, + anImmFbos[0], + Standard_True) || toSwap; + + if (myGlContext->arbFBO != NULL) + { + myGlContext->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, OpenGl_FrameBuffer::NO_FRAMEBUFFER); + } + #if !defined(GL_ES_VERSION_2_0) + if (anImmFbos[1] == NULL) + { + myGlContext->SetReadDrawBuffer (GL_BACK_RIGHT); + } + #endif + toSwap = redrawImmediate (theCView, theCUnderLayer, theCOverLayer, + aMainFbos[1], + Graphic3d_Camera::Projection_MonoRightEye, + anImmFbos[1], + Standard_True) || toSwap; + if (anImmFbos[0] != NULL) + { + bindDefaultFbo (aFrameBuffer); + drawStereoPair(); + } + } + else { - myGlContext->DefaultFrameBuffer()->BindBuffer (myGlContext); + OpenGl_FrameBuffer* aMainFbo = myMainSceneFbos[0]->IsValid() ? myMainSceneFbos[0].operator->() : NULL; + #if !defined(GL_ES_VERSION_2_0) + if (aMainFbo == NULL) + { + myGlContext->SetReadDrawBuffer (GL_BACK); + } + #endif + toSwap = redrawImmediate (theCView, theCUnderLayer, theCOverLayer, + aMainFbo, + aProjectType, + aFrameBuffer, + Standard_True) || toSwap; } - if (redrawImmediate (theCView, theCUnderLayer, theCOverLayer, NULL, Standard_True) + // bind default FBO + bindDefaultFbo(); + + if (toSwap && !myGlContext->caps->buffersNoSwap) { myGlContext->SwapBuffers(); @@ -937,7 +1342,6 @@ void OpenGl_Workspace::RedrawImmediate (const Graphic3d_CView& theCView, else { myGlContext->core11fwd->glFlush(); - MakeBackBufCurrent(); } } @@ -948,7 +1352,9 @@ void OpenGl_Workspace::RedrawImmediate (const Graphic3d_CView& theCView, bool OpenGl_Workspace::redrawImmediate (const Graphic3d_CView& theCView, const Aspect_CLayer2d& theCUnderLayer, const Aspect_CLayer2d& theCOverLayer, - OpenGl_FrameBuffer* theTargetFBO, + OpenGl_FrameBuffer* theReadFbo, + const Graphic3d_Camera::Projection theProjection, + OpenGl_FrameBuffer* theDrawFbo, const Standard_Boolean theIsPartialUpdate) { GLboolean toCopyBackToFront = GL_FALSE; @@ -956,116 +1362,16 @@ bool OpenGl_Workspace::redrawImmediate (const Graphic3d_CView& theCView, { myBackBufferRestored = Standard_False; } - else if (myResultFBO->IsValid() + else if (theReadFbo != NULL + && theReadFbo->IsValid() && myGlContext->IsRender()) { - // clear destination before blitting - if (theTargetFBO != NULL) - { - theTargetFBO->BindBuffer (myGlContext); - } - else if (!myGlContext->DefaultFrameBuffer().IsNull() - && myGlContext->DefaultFrameBuffer()->IsValid()) - { - myGlContext->DefaultFrameBuffer()->BindBuffer (myGlContext); - } - else - { - myGlContext->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, OpenGl_FrameBuffer::NO_FRAMEBUFFER); - } - #if !defined(GL_ES_VERSION_2_0) - myGlContext->core20fwd->glClearDepth (1.0); - #else - myGlContext->core20fwd->glClearDepthf (1.0f); - #endif - myGlContext->core20fwd->glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); - - /*#if !defined(GL_ES_VERSION_2_0) - if (myGlContext->arbFBOBlit != NULL) - { - myResultFBO->BindReadBuffer (myGlContext); - if (theTargetFBO != NULL) - { - theTargetFBO->BindDrawBuffer (myGlContext); - } - else if (!myGlContext->DefaultFrameBuffer().IsNull() - && myGlContext->DefaultFrameBuffer()->IsValid()) - { - myGlContext->DefaultFrameBuffer()->BindDrawBuffer (myGlContext); - } - else - { - myGlContext->arbFBO->glBindFramebuffer (GL_DRAW_FRAMEBUFFER, OpenGl_FrameBuffer::NO_FRAMEBUFFER); - } - // we don't copy stencil buffer here... does it matter for performance? - myGlContext->arbFBOBlit->glBlitFramebuffer (0, 0, myResultFBO->GetVPSizeX(), myResultFBO->GetVPSizeY(), - 0, 0, myResultFBO->GetVPSizeX(), myResultFBO->GetVPSizeY(), - GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, GL_NEAREST); - - if (theTargetFBO != NULL) - { - theTargetFBO->BindBuffer (myGlContext); - } - else if (!myGlContext->DefaultFrameBuffer().IsNull() - && myGlContext->DefaultFrameBuffer()->IsValid()) - { - myGlContext->DefaultFrameBuffer()->BindBuffer (myGlContext); - } - else - { - myGlContext->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, OpenGl_FrameBuffer::NO_FRAMEBUFFER); - } - } - else - #endif*/ + if (!blitBuffers (theReadFbo, theDrawFbo)) { - myGlContext->core20fwd->glDepthFunc (GL_ALWAYS); - myGlContext->core20fwd->glDepthMask (GL_TRUE); - myGlContext->core20fwd->glEnable (GL_DEPTH_TEST); - - DisableTexture(); - if (!myFullScreenQuad.IsValid()) - { - OpenGl_Vec4 aQuad[4] = - { - OpenGl_Vec4( 1.0f, -1.0f, 1.0f, 0.0f), - OpenGl_Vec4( 1.0f, 1.0f, 1.0f, 1.0f), - OpenGl_Vec4(-1.0f, -1.0f, 0.0f, 0.0f), - OpenGl_Vec4(-1.0f, 1.0f, 0.0f, 1.0f) - }; - myFullScreenQuad.Init (myGlContext, 4, 4, aQuad[0].GetData()); - } - - const Handle(OpenGl_ShaderManager)& aManager = myGlContext->ShaderManager(); - if (myFullScreenQuad.IsValid() - && aManager->BindFboBlitProgram()) - { - myResultFBO->ColorTexture() ->Bind (myGlContext, GL_TEXTURE0 + 0); - myResultFBO->DepthStencilTexture()->Bind (myGlContext, GL_TEXTURE0 + 1); - myFullScreenQuad.BindVertexAttrib (myGlContext, 0); - - myGlContext->core20fwd->glDrawArrays (GL_TRIANGLE_STRIP, 0, 4); - - myFullScreenQuad.UnbindVertexAttrib (myGlContext, 0); - myResultFBO->DepthStencilTexture()->Unbind (myGlContext, GL_TEXTURE0 + 1); - myResultFBO->ColorTexture() ->Unbind (myGlContext, GL_TEXTURE0 + 0); - } - else - { - TCollection_ExtendedString aMsg = TCollection_ExtendedString() - + "Error! FBO blitting has failed"; - myGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB, - GL_DEBUG_TYPE_ERROR_ARB, - 0, - GL_DEBUG_SEVERITY_HIGH_ARB, - aMsg); - myHasFboBlit = Standard_False; - myResultFBO->Release (myGlContext.operator->()); - return true; - } + return true; } } - else if (theTargetFBO == NULL) + else if (theDrawFbo == NULL) { #if !defined(GL_ES_VERSION_2_0) myGlContext->core11fwd->glGetBooleanv (GL_DOUBLEBUFFER, &toCopyBackToFront); @@ -1079,7 +1385,6 @@ bool OpenGl_Workspace::redrawImmediate (const Graphic3d_CView& theCView, return true; } copyBackToFront(); - MakeFrontBufCurrent(); } else { @@ -1118,7 +1423,8 @@ bool OpenGl_Workspace::redrawImmediate (const Graphic3d_CView& theCView, glDisable (GL_DEPTH_TEST); } - myView->Render (myPrintContext, aWS, theCView, theCUnderLayer, theCOverLayer, Standard_True); + myView->Render (myPrintContext, aWS, theDrawFbo, theProjection, + theCView, theCUnderLayer, theCOverLayer, Standard_True); if (!myView->ImmediateStructures().IsEmpty()) { glDisable (GL_DEPTH_TEST); @@ -1135,12 +1441,7 @@ bool OpenGl_Workspace::redrawImmediate (const Graphic3d_CView& theCView, aStructure->Render (aWS); } - if (toCopyBackToFront) - { - MakeBackBufCurrent(); - return false; - } - return true; + return !toCopyBackToFront; } IMPLEMENT_STANDARD_HANDLE (OpenGl_RaytraceFilter, OpenGl_RenderFilter) diff --git a/src/OpenGl/OpenGl_Workspace.hxx b/src/OpenGl/OpenGl_Workspace.hxx index 2b1ba4541d..c135788c78 100644 --- a/src/OpenGl/OpenGl_Workspace.hxx +++ b/src/OpenGl/OpenGl_Workspace.hxx @@ -265,22 +265,31 @@ public: //! @return true if clipping algorithm enabled inline Standard_Boolean IsCullingEnabled() const { return myIsCullingEnabled; } - //! Returns framebuffer storing cached main presentation of the view. - const Handle(OpenGl_FrameBuffer)& ResultFBO() const { return myResultFBO; } - protected: //! Copy content of Back buffer to the Front buffer void copyBackToFront(); + //! Blit image from/to specified buffers. + bool blitBuffers (OpenGl_FrameBuffer* theReadFbo, + OpenGl_FrameBuffer* theDrawFbo); + virtual Standard_Boolean Activate(); - void redraw1 (const Graphic3d_CView& theCView, - const Aspect_CLayer2d& theCUnderLayer, - const Aspect_CLayer2d& theCOverLayer); + void redraw1 (const Graphic3d_CView& theCView, + const Aspect_CLayer2d& theCUnderLayer, + const Aspect_CLayer2d& theCOverLayer, + OpenGl_FrameBuffer* theReadDrawFbo, + const Graphic3d_Camera::Projection theProjection); + + //! Setup default FBO. + void bindDefaultFbo (OpenGl_FrameBuffer* theCustomFbo = NULL); + + //! Blend together views pair into stereo image. + void drawStereoPair(); - //! Blit snapshot containing main scene (myResultFBO or BackBuffer) - //! into presentation buffer (myResultFBO->offscreen FBO or myResultFBO->BackBuffer or BackBuffer->FrontBuffer), + //! Blit snapshot containing main scene (myMainSceneFbos or BackBuffer) + //! into presentation buffer (myMainSceneFbos -> offscreen FBO or myMainSceneFbos -> BackBuffer or BackBuffer -> FrontBuffer), //! and redraw immediate structures on top. //! //! When scene caching is disabled (myTransientDrawToFront, no double buffer in window, etc.), @@ -290,7 +299,9 @@ protected: bool redrawImmediate (const Graphic3d_CView& theCView, const Aspect_CLayer2d& theCUnderLayer, const Aspect_CLayer2d& theCOverLayer, - OpenGl_FrameBuffer* theTargetFBO, + OpenGl_FrameBuffer* theReadFbo, + const Graphic3d_Camera::Projection theProjection, + OpenGl_FrameBuffer* theDrawFbo, const Standard_Boolean theIsPartialUpdate = Standard_False); void updateMaterial (const int theFlag); @@ -300,9 +311,12 @@ protected: protected: //! @name protected fields - //! Framebuffer stores cached main presentation of the view (without presentation of immediate layers). - Handle(OpenGl_FrameBuffer) myResultFBO; - //! Special flag which is invalidated when myResultFBO can not be blitted for some reason (e.g. driver bugs). + //! Two framebuffers (left and right views) store cached main presentation + //! of the view (without presentation of immediate layers). + Handle(OpenGl_FrameBuffer) myMainSceneFbos[2]; + //! Additional buffers for immediate layer in stereo mode. + Handle(OpenGl_FrameBuffer) myImmediateSceneFbos[2]; + //! Special flag which is invalidated when myMainSceneFbos can not be blitted for some reason (e.g. driver bugs). Standard_Boolean myHasFboBlit; //! Vertices for full-screen quad rendering. diff --git a/src/OpenGl/OpenGl_Workspace_2.cxx b/src/OpenGl/OpenGl_Workspace_2.cxx index 2bf1720f41..e4171b126a 100644 --- a/src/OpenGl/OpenGl_Workspace_2.cxx +++ b/src/OpenGl/OpenGl_Workspace_2.cxx @@ -550,9 +550,6 @@ Standard_Boolean OpenGl_Workspace::Print } } - // activate the offscreen buffer - aFrameBuffer->BindBuffer (GetGlContext()); - // calculate offset for centered printing int aDevOffx = (int)(devWidth - width) /2; int aDevOffy = (int)(devHeight - height)/2; @@ -564,18 +561,21 @@ Standard_Boolean OpenGl_Workspace::Print if (!showBackground) NamedStatus |= OPENGL_NS_WHITEBACK; + // switch to mono camera for image dump + const Graphic3d_Camera::Projection aProjectType = myView->Camera()->ProjectionType() != Graphic3d_Camera::Projection_Stereo + ? myView->Camera()->ProjectionType() + : Graphic3d_Camera::Projection_Perspective; if (!IsTiling) { myPrintContext->SetScale ((GLfloat )aFrameWidth /viewWidth, (GLfloat )aFrameHeight/viewHeight); - aFrameBuffer->SetupViewport (GetGlContext()); - redraw1 (ACView, ACUnderLayer, ACOverLayer); + redraw1 (ACView, ACUnderLayer, ACOverLayer, aFrameBuffer, aProjectType); if (!myTransientDrawToFront) { // render to FBO only if allowed to render to back buffer myBackBufferRestored = Standard_True; myIsImmediateDrawn = Standard_False; - redrawImmediate (ACView, ACUnderLayer, ACOverLayer, aFrameBuffer); + redrawImmediate (ACView, ACUnderLayer, ACOverLayer, NULL, aProjectType, aFrameBuffer); myBackBufferRestored = Standard_False; myIsImmediateDrawn = Standard_False; } @@ -683,14 +683,13 @@ Standard_Boolean OpenGl_Workspace::Print aFrameHeight; // draw to the offscreen buffer and capture the result - aFrameBuffer->SetupViewport (GetGlContext()); - redraw1 (ACView, ACUnderLayer, ACOverLayer); + redraw1 (ACView, ACUnderLayer, ACOverLayer, aFrameBuffer, aProjectType); if (!myTransientDrawToFront) { // render to FBO only if forces to render to back buffer myBackBufferRestored = Standard_True; myIsImmediateDrawn = Standard_False; - redrawImmediate (ACView, ACUnderLayer, ACOverLayer, aFrameBuffer); + redrawImmediate (ACView, ACUnderLayer, ACOverLayer, NULL, aProjectType, aFrameBuffer); myBackBufferRestored = Standard_False; myIsImmediateDrawn = Standard_False; }