From 1f79e23d5be7d29d55f0b45977f582dfc3919593 Mon Sep 17 00:00:00 2001 From: Christopher Bruns Date: Sun, 11 Sep 2016 13:42:41 -0400 Subject: [PATCH] Implement wide side-by-side mode, using adjusted aspect ratio in projection matrix. Use optimal framebuffer size for side-by-side modes. --- src/gl/renderer/gl_renderer.cpp | 3 ++ src/gl/scene/gl_scene.cpp | 1 - src/gl/stereo3d/gl_sidebyside3d.cpp | 58 ++++++++++++++++++++--------- src/gl/stereo3d/gl_sidebyside3d.h | 37 ++++++++++++++++-- src/gl/stereo3d/gl_stereo3d.h | 2 + src/gl/stereo3d/gl_stereo_cvars.cpp | 8 +++- wadsrc/static/language.enu | 1 + wadsrc/static/menudef.z | 1 + 8 files changed, 87 insertions(+), 24 deletions(-) diff --git a/src/gl/renderer/gl_renderer.cpp b/src/gl/renderer/gl_renderer.cpp index ab0e658e7..42b4a8e1b 100644 --- a/src/gl/renderer/gl_renderer.cpp +++ b/src/gl/renderer/gl_renderer.cpp @@ -57,6 +57,7 @@ #include "gl/shaders/gl_colormapshader.h" #include "gl/shaders/gl_lensshader.h" #include "gl/shaders/gl_presentshader.h" +#include "gl/stereo3d/gl_stereo3d.h" #include "gl/textures/gl_texture.h" #include "gl/textures/gl_translate.h" #include "gl/textures/gl_material.h" @@ -273,6 +274,8 @@ void FGLRenderer::SetOutputViewport(GL_IRECT *bounds) mSceneViewport.top += mOutputLetterbox.top; } } + + s3d::Stereo3DMode::getCurrentMode().AdjustViewports(); } //=========================================================================== diff --git a/src/gl/scene/gl_scene.cpp b/src/gl/scene/gl_scene.cpp index 7c04ce77a..6ddd12a1f 100644 --- a/src/gl/scene/gl_scene.cpp +++ b/src/gl/scene/gl_scene.cpp @@ -801,7 +801,6 @@ sector_t * FGLRenderer::RenderViewpoint (AActor * camera, GL_IRECT * bounds, flo { const s3d::EyePose * eye = stereo3dMode.getEyePose(eye_ix); eye->SetUp(); - // TODO: stereo specific viewport - needed when implementing side-by-side modes etc. SetOutputViewport(bounds); Set3DViewport(mainview); mDrawingScene2D = true; diff --git a/src/gl/stereo3d/gl_sidebyside3d.cpp b/src/gl/stereo3d/gl_sidebyside3d.cpp index f526dce8b..8a66fc91c 100644 --- a/src/gl/stereo3d/gl_sidebyside3d.cpp +++ b/src/gl/stereo3d/gl_sidebyside3d.cpp @@ -39,6 +39,36 @@ namespace s3d { +void SideBySideBase::Present() const +{ + GLRenderer->mBuffers->BindOutputFB(); + GLRenderer->ClearBorders(); + + // Compute screen regions to use for left and right eye views + int leftWidth = GLRenderer->mOutputLetterbox.width / 2; + int rightWidth = GLRenderer->mOutputLetterbox.width - leftWidth; + GL_IRECT leftHalfScreen = GLRenderer->mOutputLetterbox; + leftHalfScreen.width = leftWidth; + GL_IRECT rightHalfScreen = GLRenderer->mOutputLetterbox; + rightHalfScreen.width = rightWidth; + rightHalfScreen.left += leftWidth; + + GLRenderer->mBuffers->BindEyeTexture(0, 0); + GLRenderer->DrawPresentTexture(leftHalfScreen, true); + + GLRenderer->mBuffers->BindEyeTexture(1, 0); + GLRenderer->DrawPresentTexture(rightHalfScreen, true); +} + +// AdjustViewports() is called from within FLGRenderer::SetOutputViewport(...) +void SideBySideBase::AdjustViewports() const +{ + // Change size of renderbuffer, and align to screen + GLRenderer->mSceneViewport.width /= 2; + GLRenderer->mSceneViewport.left /= 2; + GLRenderer->mScreenViewport.width /= 2; + GLRenderer->mScreenViewport.left /= 2; +} /* static */ const SideBySideSquished& SideBySideSquished::getInstance(float ipd) @@ -54,26 +84,18 @@ SideBySideSquished::SideBySideSquished(double ipdMeters) eye_ptrs.Push(&rightEye); } -void SideBySideSquished::Present() const +/* static */ +const SideBySideFull& SideBySideFull::getInstance(float ipd) { - GLRenderer->mBuffers->BindOutputFB(); - GLRenderer->ClearBorders(); - - // Compute screen regions to use for left and right eye views - int leftWidth = GLRenderer->mOutputLetterbox.width/2; - int rightWidth = GLRenderer->mOutputLetterbox.width - leftWidth; - GL_IRECT leftHalfScreen = GLRenderer->mOutputLetterbox; - leftHalfScreen.width = leftWidth; - GL_IRECT rightHalfScreen = GLRenderer->mOutputLetterbox; - rightHalfScreen.width = rightWidth; - rightHalfScreen.left += leftWidth; - - GLRenderer->mBuffers->BindEyeTexture(0, 0); - GLRenderer->DrawPresentTexture(leftHalfScreen, true); - - GLRenderer->mBuffers->BindEyeTexture(1, 0); - GLRenderer->DrawPresentTexture(rightHalfScreen, true); + static SideBySideFull instance(ipd); + return instance; } +SideBySideFull::SideBySideFull(double ipdMeters) + : leftEye(ipdMeters), rightEye(ipdMeters) +{ + eye_ptrs.Push(&leftEye); + eye_ptrs.Push(&rightEye); +} } /* namespace s3d */ diff --git a/src/gl/stereo3d/gl_sidebyside3d.h b/src/gl/stereo3d/gl_sidebyside3d.h index 2f2946424..c79c0c4b4 100644 --- a/src/gl/stereo3d/gl_sidebyside3d.h +++ b/src/gl/stereo3d/gl_sidebyside3d.h @@ -44,18 +44,49 @@ namespace s3d { -class SideBySideSquished : public Stereo3DMode +class SideBySideBase : public Stereo3DMode +{ +public: + void Present() const override; + virtual void AdjustViewports() const override; +}; + +class SideBySideSquished : public SideBySideBase { public: static const SideBySideSquished& getInstance(float ipd); - SideBySideSquished(double ipdMeters); - void Present() const override; private: LeftEyePose leftEye; RightEyePose rightEye; }; +class SBSFLeftEyePose : public LeftEyePose { +public: + SBSFLeftEyePose(double ipdMeters) : LeftEyePose(ipdMeters) {} + virtual VSMatrix GetProjection(float fov, float aspectRatio, float fovRatio) const override { + return LeftEyePose::GetProjection(fov, 0.5f * aspectRatio, fovRatio); + } +}; + +class SBSFRightEyePose : public RightEyePose { +public: + SBSFRightEyePose(double ipdMeters) : RightEyePose(ipdMeters) {} + virtual VSMatrix GetProjection(float fov, float aspectRatio, float fovRatio) const override { + return RightEyePose::GetProjection(fov, 0.5f * aspectRatio, fovRatio); + } +}; + +class SideBySideFull : public SideBySideBase +{ +public: + static const SideBySideFull& getInstance(float ipd); + SideBySideFull(double ipdMeters); +private: + SBSFLeftEyePose leftEye; + SBSFRightEyePose rightEye; +}; + } /* namespace s3d */ diff --git a/src/gl/stereo3d/gl_stereo3d.h b/src/gl/stereo3d/gl_stereo3d.h index e2a8a1ea6..747bcd0c0 100644 --- a/src/gl/stereo3d/gl_stereo3d.h +++ b/src/gl/stereo3d/gl_stereo3d.h @@ -31,6 +31,7 @@ #include // needed for memcpy on linux, which is needed by VSMatrix copy ctor #include "tarray.h" #include "gl/data/gl_matrix.h" +#include "gl/renderer/gl_renderer.h" /* stereoscopic 3D API */ @@ -78,6 +79,7 @@ public: virtual void TearDown() const {}; virtual bool IsMono() const { return false; } + virtual void AdjustViewports() const {}; virtual void Present() const = 0; protected: diff --git a/src/gl/stereo3d/gl_stereo_cvars.cpp b/src/gl/stereo3d/gl_stereo_cvars.cpp index cd6336026..0927829fc 100644 --- a/src/gl/stereo3d/gl_stereo_cvars.cpp +++ b/src/gl/stereo3d/gl_stereo_cvars.cpp @@ -72,7 +72,9 @@ const Stereo3DMode& Stereo3DMode::getCurrentMode() case 2: setCurrentMode(RedCyan::getInstance(vr_ipd)); break; - // TODO: missing index 3 for not-yet-implemented side-by-side mode, to match values from GZ3Doom + case 3: + setCurrentMode(SideBySideFull::getInstance(vr_ipd)); + break; case 4: setCurrentMode(SideBySideSquished::getInstance(vr_ipd)); break; @@ -93,7 +95,9 @@ const Stereo3DMode& Stereo3DMode::getCurrentMode() // TODO: 8: Oculus Rift case 9: setCurrentMode(AmberBlue::getInstance(vr_ipd)); - break; case 0: + break; + // TODO: 10: HTC Vive/OpenVR + case 0: default: setCurrentMode(MonoView::getInstance()); break; diff --git a/wadsrc/static/language.enu b/wadsrc/static/language.enu index 4b4013cc7..50526a75b 100644 --- a/wadsrc/static/language.enu +++ b/wadsrc/static/language.enu @@ -2701,6 +2701,7 @@ OPTVAL_REDCYAN = "Red/Cyan"; OPTVAL_AMBERBLUE = "Amber/Blue"; OPTVAL_LEFTEYE = "Left Eye"; OPTVAL_RIGHTEYE = "Right Eye"; +OPTVAL_SBSFULL = "Side-by-side Full"; OPTVAL_SBSNARROW = "Side-by-side Narrow"; OPTVAL_QUADBUFFERED = "Quad-buffered"; OPTVAL_UNCHARTED2 = "Uncharted 2"; diff --git a/wadsrc/static/menudef.z b/wadsrc/static/menudef.z index 28c343c2a..1ab4f1a6d 100644 --- a/wadsrc/static/menudef.z +++ b/wadsrc/static/menudef.z @@ -167,6 +167,7 @@ OptionValue VRMode 1, "$OPTVAL_GREENMAGENTA" 2, "$OPTVAL_REDCYAN" 9, "$OPTVAL_AMBERBLUE" + 3, "$OPTVAL_SBSFULL" 4, "$OPTVAL_SBSNARROW" 5, "$OPTVAL_LEFTEYE" 6, "$OPTVAL_RIGHTEYE"