diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 40a3925c50..d77e733e02 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -697,7 +697,6 @@ file( GLOB HEADER_FILES hwrenderer/dynlights/*.h hwrenderer/postprocessing/*.h hwrenderer/scene/*.h - hwrenderer/stereo3d/*.h hwrenderer/textures/*.h hwrenderer/utility/*.h gl/*.h @@ -706,7 +705,6 @@ file( GLOB HEADER_FILES gl/models/*.h gl/renderer/*.h gl/scene/*.h - gl/stereo3d/*.h gl/shaders/*.h gl/system/*.h gl/textures/*.h @@ -1055,16 +1053,10 @@ set (PCH_SOURCES gl/renderer/gl_lightdata.cpp gl/renderer/gl_postprocess.cpp gl/renderer/gl_postprocessstate.cpp + gl/renderer/gl_stereo3d.cpp gl/shaders/gl_shader.cpp gl/shaders/gl_shaderprogram.cpp gl/shaders/gl_postprocessshader.cpp - gl/stereo3d/gl_stereo3d.cpp - gl/stereo3d/gl_stereo_cvars.cpp - gl/stereo3d/gl_stereo_leftright.cpp - gl/stereo3d/gl_anaglyph.cpp - gl/stereo3d/gl_quadstereo.cpp - gl/stereo3d/gl_sidebyside3d.cpp - gl/stereo3d/gl_interleaved3d.cpp gl_load/gl_interface.cpp gl/system/gl_framebuffer.cpp gl/system/gl_debug.cpp @@ -1074,7 +1066,6 @@ set (PCH_SOURCES hwrenderer/data/flatvertices.cpp hwrenderer/dynlights/hw_aabbtree.cpp hwrenderer/dynlights/hw_shadowmap.cpp - hwrenderer/stereo3d/hw_eyepose.cpp hwrenderer/scene/hw_skydome.cpp hwrenderer/postprocessing/hw_postprocess_cvars.cpp hwrenderer/postprocessing/hw_postprocessshader.cpp @@ -1094,6 +1085,7 @@ set (PCH_SOURCES hwrenderer/utility/hw_cvars.cpp hwrenderer/utility/hw_lighting.cpp hwrenderer/utility/hw_shaderpatcher.cpp + hwrenderer/utility/hw_vrmodes.cpp menu/joystickmenu.cpp menu/loadsavemenu.cpp @@ -1424,7 +1416,6 @@ source_group("Hardware Renderer\\Models" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SO source_group("Hardware Renderer\\Postprocessing" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/hwrenderer/postprocessing/.+") source_group("Hardware Renderer\\Renderer" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/hwrenderer/renderer/.+") source_group("Hardware Renderer\\Scene" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/hwrenderer/scene/.+") -source_group("Hardware Renderer\\Stereo3D" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/hwrenderer/stereo3d/.+") source_group("Hardware Renderer\\Shaders" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/hwrenderer/shaders/.+") source_group("Hardware Renderer\\System" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/hwrenderer/system/.+") source_group("Hardware Renderer\\Textures" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/hwrenderer/textures/.+") @@ -1436,7 +1427,6 @@ source_group("OpenGL Renderer\\Dynamic Lights" REGULAR_EXPRESSION "^${CMAKE_CURR source_group("OpenGL Renderer\\Models" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/gl/models/.+") source_group("OpenGL Renderer\\Renderer" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/gl/renderer/.+") source_group("OpenGL Renderer\\Scene" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/gl/scene/.+") -source_group("OpenGL Renderer\\Stereo3D" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/gl/stereo3d/.+") source_group("OpenGL Renderer\\Shaders" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/gl/shaders/.+") source_group("OpenGL Renderer\\System" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/gl/system/.+") source_group("OpenGL Renderer\\Textures" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/gl/textures/.+") diff --git a/src/gl/renderer/gl_postprocess.cpp b/src/gl/renderer/gl_postprocess.cpp index e371699d71..1789876d7a 100644 --- a/src/gl/renderer/gl_postprocess.cpp +++ b/src/gl/renderer/gl_postprocess.cpp @@ -47,8 +47,8 @@ #include "hwrenderer/postprocessing/hw_lensshader.h" #include "hwrenderer/postprocessing/hw_fxaashader.h" #include "hwrenderer/postprocessing/hw_presentshader.h" +#include "hwrenderer/utility/hw_vrmodes.h" #include "gl/shaders/gl_postprocessshaderinstance.h" -#include "gl/stereo3d/gl_stereo3d.h" #include "gl/textures/gl_hwtexture.h" #include "r_videoscale.h" @@ -654,18 +654,18 @@ void FGLRenderer::ApplyFXAA() void FGLRenderer::Flush() { - const s3d::Stereo3DMode& stereo3dMode = s3d::Stereo3DMode::getCurrentMode(); + auto vrmode = VRMode::GetVRMode(true); const auto &mSceneViewport = screen->mSceneViewport; const auto &mScreenViewport = screen->mScreenViewport; - if (stereo3dMode.IsMono()) + if (vrmode->mEyeCount == 1) { CopyToBackbuffer(nullptr, true); } else { // Render 2D to eye textures - for (int eye_ix = 0; eye_ix < stereo3dMode.eye_count(); ++eye_ix) + for (int eye_ix = 0; eye_ix < vrmode->mEyeCount; ++eye_ix) { FGLDebug::PushGroup("Eye2D"); mBuffers->BindEyeFB(eye_ix); @@ -678,7 +678,9 @@ void FGLRenderer::Flush() FGLPostProcessState savedState; FGLDebug::PushGroup("PresentEyes"); - stereo3dMode.Present(); + // Note: This here is the ONLY place in the entire engine where the OpenGL dependent parts of the Stereo3D code need to be dealt with. + // There's absolutely no need to create a overly complex class hierarchy for just this. + GLRenderer->PresentStereo(); FGLDebug::PopGroup(); } } diff --git a/src/gl/renderer/gl_renderer.cpp b/src/gl/renderer/gl_renderer.cpp index b70c7ed61b..25e4234897 100644 --- a/src/gl/renderer/gl_renderer.cpp +++ b/src/gl/renderer/gl_renderer.cpp @@ -61,7 +61,6 @@ #include "hwrenderer/postprocessing/hw_present3dRowshader.h" #include "hwrenderer/postprocessing/hw_shadowmapshader.h" #include "gl/shaders/gl_postprocessshaderinstance.h" -#include "gl/stereo3d/gl_stereo3d.h" #include "gl/textures/gl_samplers.h" #include "gl/dynlights/gl_lightbuffer.h" #include "r_videoscale.h" diff --git a/src/gl/renderer/gl_renderer.h b/src/gl/renderer/gl_renderer.h index c89d85705d..0d2bd43b1f 100644 --- a/src/gl/renderer/gl_renderer.h +++ b/src/gl/renderer/gl_renderer.h @@ -127,6 +127,7 @@ public: void SetupLevel(); void ResetSWScene(); + void PresentStereo(); void RenderScreenQuad(); void PostProcessScene(int fixedcm, const std::function &afterBloomDrawEndScene2D); void AmbientOccludeScene(float m5); diff --git a/src/gl/renderer/gl_stereo3d.cpp b/src/gl/renderer/gl_stereo3d.cpp new file mode 100644 index 0000000000..6035a67bf1 --- /dev/null +++ b/src/gl/renderer/gl_stereo3d.cpp @@ -0,0 +1,364 @@ +// +//--------------------------------------------------------------------------- +// +// Copyright(C) 2015 Christopher Bruns +// All rights reserved. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see http://www.gnu.org/licenses/ +// +//-------------------------------------------------------------------------- +// +/* +** gl_stereo3d.cpp +** Stereoscopic 3D API +** +*/ + +#include "gl_load/gl_system.h" +#include "gl/renderer/gl_renderer.h" +#include "gl/renderer/gl_renderbuffers.h" +#include "hwrenderer/utility/hw_vrmodes.h" +#include "gl/system/gl_framebuffer.h" +#include "gl/renderer/gl_postprocessstate.h" +#include "hwrenderer/postprocessing/hw_presentshader.h" +#include "hwrenderer/postprocessing/hw_present3dRowshader.h" + +EXTERN_CVAR(Int, vr_mode) +EXTERN_CVAR(Float, vid_saturation) +EXTERN_CVAR(Float, vid_brightness) +EXTERN_CVAR(Float, vid_contrast) +EXTERN_CVAR(Int, gl_satformula) + +//========================================================================== +// +// +// +//========================================================================== + +static void PresentAnaglyph(bool r, bool g, bool b) +{ + GLRenderer->mBuffers->BindOutputFB(); + GLRenderer->ClearBorders(); + + glColorMask(r, g, b, 1); + GLRenderer->mBuffers->BindEyeTexture(0, 0); + GLRenderer->DrawPresentTexture(screen->mOutputLetterbox, true); + + glColorMask(!r, !g, !b, 1); + GLRenderer->mBuffers->BindEyeTexture(1, 0); + GLRenderer->DrawPresentTexture(screen->mOutputLetterbox, true); + + glColorMask(1, 1, 1, 1); +} + +//========================================================================== +// +// +// +//========================================================================== + +static void PresentSideBySide() +{ + GLRenderer->mBuffers->BindOutputFB(); + GLRenderer->ClearBorders(); + + // Compute screen regions to use for left and right eye views + int leftWidth = screen->mOutputLetterbox.width / 2; + int rightWidth = screen->mOutputLetterbox.width - leftWidth; + IntRect leftHalfScreen = screen->mOutputLetterbox; + leftHalfScreen.width = leftWidth; + IntRect rightHalfScreen = screen->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 void PresentTopBottom() +{ + GLRenderer->mBuffers->BindOutputFB(); + GLRenderer->ClearBorders(); + + // Compute screen regions to use for left and right eye views + int topHeight = screen->mOutputLetterbox.height / 2; + int bottomHeight = screen->mOutputLetterbox.height - topHeight; + IntRect topHalfScreen = screen->mOutputLetterbox; + topHalfScreen.height = topHeight; + topHalfScreen.top = topHeight; + IntRect bottomHalfScreen = screen->mOutputLetterbox; + bottomHalfScreen.height = bottomHeight; + bottomHalfScreen.top = 0; + + GLRenderer->mBuffers->BindEyeTexture(0, 0); + GLRenderer->DrawPresentTexture(topHalfScreen, true); + + GLRenderer->mBuffers->BindEyeTexture(1, 0); + GLRenderer->DrawPresentTexture(bottomHalfScreen, true); +} + +//========================================================================== +// +// +// +//========================================================================== + +static void prepareInterleavedPresent(FPresentShaderBase& shader) +{ + GLRenderer->mBuffers->BindOutputFB(); + GLRenderer->ClearBorders(); + + + // Bind each eye texture, for composition in the shader + GLRenderer->mBuffers->BindEyeTexture(0, 0); + GLRenderer->mBuffers->BindEyeTexture(1, 1); + + glActiveTexture(GL_TEXTURE0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + glActiveTexture(GL_TEXTURE1); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + const IntRect& box = screen->mOutputLetterbox; + glViewport(box.left, box.top, box.width, box.height); + + shader.Bind(NOQUEUE); + + if (GLRenderer->framebuffer->IsHWGammaActive()) + { + shader.Uniforms->InvGamma = 1.0f; + shader.Uniforms->Contrast = 1.0f; + shader.Uniforms->Brightness = 0.0f; + shader.Uniforms->Saturation = 1.0f; + } + else + { + shader.Uniforms->InvGamma = 1.0f / clamp(Gamma, 0.1f, 4.f); + shader.Uniforms->Contrast = clamp(vid_contrast, 0.1f, 3.f); + shader.Uniforms->Brightness = clamp(vid_brightness, -0.8f, 0.8f); + shader.Uniforms->Saturation = clamp(vid_saturation, -15.0f, 15.0f); + shader.Uniforms->GrayFormula = static_cast(gl_satformula); + } + shader.Uniforms->Scale = { + screen->mScreenViewport.width / (float)GLRenderer->mBuffers->GetWidth(), + screen->mScreenViewport.height / (float)GLRenderer->mBuffers->GetHeight() + }; + shader.Uniforms.Set(); +} + +//========================================================================== +// +// +// +//========================================================================== + +static void PresentColumnInterleaved() +{ + FGLPostProcessState savedState; + savedState.SaveTextureBindings(2); + prepareInterleavedPresent(*GLRenderer->mPresent3dColumnShader); + + // Compute absolute offset from top of screen to top of current display window + // because we need screen-relative, not window-relative, scan line parity + + // Todo: + //auto clientoffset = screen->GetClientOffset(); + //auto windowHOffset = clientoffset.X % 2; + int windowHOffset = 0; + + GLRenderer->mPresent3dColumnShader->Uniforms->WindowPositionParity = windowHOffset; + GLRenderer->mPresent3dColumnShader->Uniforms.Set(); + + GLRenderer->RenderScreenQuad(); +} + +//========================================================================== +// +// +// +//========================================================================== + +static void PresentRowInterleaved() +{ + FGLPostProcessState savedState; + savedState.SaveTextureBindings(2); + prepareInterleavedPresent(*GLRenderer->mPresent3dRowShader); + + // Todo: + //auto clientoffset = screen->GetClientOffset(); + //auto windowVOffset = clientoffset.Y % 2; + int windowVOffset = 0; + + GLRenderer->mPresent3dRowShader->Uniforms->WindowPositionParity = + (windowVOffset + + screen->mOutputLetterbox.height + 1 // +1 because of origin at bottom + ) % 2; + + GLRenderer->mPresent3dRowShader->Uniforms.Set(); + GLRenderer->RenderScreenQuad(); +} + +//========================================================================== +// +// +// +//========================================================================== + +static void PresentCheckerInterleaved() +{ + FGLPostProcessState savedState; + savedState.SaveTextureBindings(2); + prepareInterleavedPresent(*GLRenderer->mPresent3dCheckerShader); + + // Compute absolute offset from top of screen to top of current display window + // because we need screen-relative, not window-relative, scan line parity + + //auto clientoffset = screen->GetClientOffset(); + //auto windowHOffset = clientoffset.X % 2; + //auto windowVOffset = clientoffset.Y % 2; + int windowHOffset = 0; + int windowVOffset = 0; + + GLRenderer->mPresent3dCheckerShader->Uniforms->WindowPositionParity = + (windowVOffset + + windowHOffset + + screen->mOutputLetterbox.height + 1 // +1 because of origin at bottom + ) % 2; // because we want the top pixel offset, but gl_FragCoord.y is the bottom pixel offset + + GLRenderer->mPresent3dCheckerShader->Uniforms.Set(); + GLRenderer->RenderScreenQuad(); +} + +//========================================================================== +// +// Sometimes the stereo render context is not ready immediately at start up +// +//========================================================================== + +bool QuadStereoCheckInitialRenderContextState() +{ + // Keep trying until we see at least one good OpenGL context to render to + static bool bQuadStereoSupported = false; + static bool bDecentContextWasFound = false; + static int contextCheckCount = 0; + if ((!bDecentContextWasFound) && (contextCheckCount < 200)) + { + contextCheckCount += 1; + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); // This question is about the main screen display context + GLboolean supportsStereo, supportsBuffered; + glGetBooleanv(GL_DOUBLEBUFFER, &supportsBuffered); + if (supportsBuffered) // Finally, a useful OpenGL context + { + // This block will be executed exactly ONCE during a game run + bDecentContextWasFound = true; // now we can stop checking every frame... + // Now check whether this context supports hardware stereo + glGetBooleanv(GL_STEREO, &supportsStereo); + bQuadStereoSupported = supportsStereo && supportsBuffered; + } + } + return bQuadStereoSupported; +} + +//========================================================================== +// +// +// +//========================================================================== + +static void PresentQuadStereo() +{ + if (QuadStereoCheckInitialRenderContextState()) + { + GLRenderer->mBuffers->BindOutputFB(); + + glDrawBuffer(GL_BACK_LEFT); + GLRenderer->ClearBorders(); + GLRenderer->mBuffers->BindEyeTexture(0, 0); + GLRenderer->DrawPresentTexture(screen->mOutputLetterbox, true); + + glDrawBuffer(GL_BACK_RIGHT); + GLRenderer->ClearBorders(); + GLRenderer->mBuffers->BindEyeTexture(1, 0); + GLRenderer->DrawPresentTexture(screen->mOutputLetterbox, true); + + glDrawBuffer(GL_BACK); + } + else + { + GLRenderer->mBuffers->BindOutputFB(); + GLRenderer->ClearBorders(); + GLRenderer->mBuffers->BindEyeTexture(0, 0); + GLRenderer->DrawPresentTexture(screen->mOutputLetterbox, true); + } +} + + +void FGLRenderer::PresentStereo() +{ + switch (vr_mode) + { + default: + return; + + case VR_GREENMAGENTA: + PresentAnaglyph(false, true, true); + break; + + case VR_REDCYAN: + PresentAnaglyph(true, false, false); + break; + + case VR_AMBERBLUE: + PresentAnaglyph(true, true, false); + break; + + case VR_SIDEBYSIDEFULL: + case VR_SIDEBYSIDESQUISHED: + PresentSideBySide(); + break; + + case VR_TOPBOTTOM: + PresentTopBottom(); + break; + + case VR_ROWINTERLEAVED: + PresentRowInterleaved(); + break; + + case VR_COLUMNINTERLEAVED: + PresentColumnInterleaved(); + break; + + case VR_CHECKERINTERLEAVED: + PresentCheckerInterleaved(); + break; + + case VR_QUADSTEREO: + PresentQuadStereo(); + break; + } +} + diff --git a/src/gl/scene/gl_drawinfo.cpp b/src/gl/scene/gl_drawinfo.cpp index f143c67955..fbc5aa60ca 100644 --- a/src/gl/scene/gl_drawinfo.cpp +++ b/src/gl/scene/gl_drawinfo.cpp @@ -40,7 +40,6 @@ #include "hwrenderer/scene/hw_clipper.h" #include "gl/scene/gl_portal.h" #include "gl/renderer/gl_renderstate.h" -#include "gl/stereo3d/scoped_color_mask.h" #include "gl/renderer/gl_quaddrawer.h" #include "gl/dynlights/gl_lightbuffer.h" @@ -253,26 +252,25 @@ void FDrawInfo::SetupFloodStencil(wallseg * ws) // Create stencil glStencilFunc(GL_EQUAL, recursion, ~0); // create stencil glStencilOp(GL_KEEP, GL_KEEP, GL_INCR); // increment stencil of valid pixels - { // Use revertible color mask, to avoid stomping on anaglyph 3D state - ScopedColorMask colorMask(0, 0, 0, 0); // glColorMask(0, 0, 0, 0); // don't write to the graphics buffer - gl_RenderState.EnableTexture(false); - gl_RenderState.ResetColor(); - glEnable(GL_DEPTH_TEST); - glDepthMask(true); + glColorMask(0, 0, 0, 0); // don't write to the graphics buffer + gl_RenderState.EnableTexture(false); + gl_RenderState.ResetColor(); + glEnable(GL_DEPTH_TEST); + glDepthMask(true); - gl_RenderState.Apply(); - FQuadDrawer qd; - qd.Set(0, ws->x1, ws->z1, ws->y1, 0, 0); - qd.Set(1, ws->x1, ws->z2, ws->y1, 0, 0); - qd.Set(2, ws->x2, ws->z2, ws->y2, 0, 0); - qd.Set(3, ws->x2, ws->z1, ws->y2, 0, 0); - qd.Render(GL_TRIANGLE_FAN); + gl_RenderState.Apply(); + FQuadDrawer qd; + qd.Set(0, ws->x1, ws->z1, ws->y1, 0, 0); + qd.Set(1, ws->x1, ws->z2, ws->y1, 0, 0); + qd.Set(2, ws->x2, ws->z2, ws->y2, 0, 0); + qd.Set(3, ws->x2, ws->z1, ws->y2, 0, 0); + qd.Render(GL_TRIANGLE_FAN); - glStencilFunc(GL_EQUAL, recursion + 1, ~0); // draw sky into stencil - glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); // this stage doesn't modify the stencil + glStencilFunc(GL_EQUAL, recursion + 1, ~0); // draw sky into stencil + glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); // this stage doesn't modify the stencil - } // glColorMask(1, 1, 1, 1); // don't write to the graphics buffer + glColorMask(1, 1, 1, 1); // don't write to the graphics buffer gl_RenderState.EnableTexture(true); glDisable(GL_DEPTH_TEST); glDepthMask(false); @@ -282,26 +280,25 @@ void FDrawInfo::ClearFloodStencil(wallseg * ws) { int recursion = GLRenderer->mPortalState.GetRecursion(); - glStencilOp(GL_KEEP,GL_KEEP,GL_DECR); + glStencilOp(GL_KEEP, GL_KEEP, GL_DECR); gl_RenderState.EnableTexture(false); - { - // Use revertible color mask, to avoid stomping on anaglyph 3D state - ScopedColorMask colorMask(0, 0, 0, 0); // glColorMask(0,0,0,0); // don't write to the graphics buffer - gl_RenderState.ResetColor(); + // Use revertible color mask, to avoid stomping on anaglyph 3D state + glColorMask(0, 0, 0, 0); // don't write to the graphics buffer + gl_RenderState.ResetColor(); - gl_RenderState.Apply(); - FQuadDrawer qd; - qd.Set(0, ws->x1, ws->z1, ws->y1, 0, 0); - qd.Set(1, ws->x1, ws->z2, ws->y1, 0, 0); - qd.Set(2, ws->x2, ws->z2, ws->y2, 0, 0); - qd.Set(3, ws->x2, ws->z1, ws->y2, 0, 0); - qd.Render(GL_TRIANGLE_FAN); + gl_RenderState.Apply(); + FQuadDrawer qd; + qd.Set(0, ws->x1, ws->z1, ws->y1, 0, 0); + qd.Set(1, ws->x1, ws->z2, ws->y1, 0, 0); + qd.Set(2, ws->x2, ws->z2, ws->y2, 0, 0); + qd.Set(3, ws->x2, ws->z1, ws->y2, 0, 0); + qd.Render(GL_TRIANGLE_FAN); - // restore old stencil op. - glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); - glStencilFunc(GL_EQUAL, recursion, ~0); - gl_RenderState.EnableTexture(true); - } // glColorMask(1, 1, 1, 1); + // restore old stencil op. + glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); + glStencilFunc(GL_EQUAL, recursion, ~0); + gl_RenderState.EnableTexture(true); + glColorMask(1, 1, 1, 1); glEnable(GL_DEPTH_TEST); glDepthMask(true); } diff --git a/src/gl/scene/gl_portal.cpp b/src/gl/scene/gl_portal.cpp index 2aa853d129..9d1a85ae74 100644 --- a/src/gl/scene/gl_portal.cpp +++ b/src/gl/scene/gl_portal.cpp @@ -42,7 +42,6 @@ #include "gl/data/gl_vertexbuffer.h" #include "hwrenderer/scene/hw_clipper.h" #include "gl/scene/gl_portal.h" -#include "gl/stereo3d/scoped_color_mask.h" //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- @@ -135,7 +134,7 @@ bool GLPortal::Start(bool usestencil, bool doquery, HWDrawInfo *outer_di, HWDraw glStencilFunc(GL_EQUAL, mState->recursion, ~0); // create stencil glStencilOp(GL_KEEP, GL_KEEP, GL_INCR); // increment stencil of valid pixels { - ScopedColorMask colorMask(0, 0, 0, 0); // glColorMask(0,0,0,0); // don't write to the graphics buffer + glColorMask(0,0,0,0); // don't write to the graphics buffer gl_RenderState.SetEffect(EFF_STENCIL); gl_RenderState.EnableTexture(false); gl_RenderState.ResetColor(); @@ -166,7 +165,7 @@ bool GLPortal::Start(bool usestencil, bool doquery, HWDrawInfo *outer_di, HWDraw // set normal drawing mode gl_RenderState.EnableTexture(true); glDepthFunc(GL_LESS); - // glColorMask(1, 1, 1, 1); + glColorMask(1, 1, 1, 1); gl_RenderState.SetEffect(EFF_NONE); glDepthRange(0, 1); @@ -194,7 +193,7 @@ bool GLPortal::Start(bool usestencil, bool doquery, HWDrawInfo *outer_di, HWDraw glStencilFunc(GL_EQUAL, mState->recursion + 1, ~0); // draw sky into stencil glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); // this stage doesn't modify the stencil gl_RenderState.EnableTexture(true); - // glColorMask(1,1,1,1); + glColorMask(1,1,1,1); gl_RenderState.SetEffect(EFF_NONE); glDisable(GL_DEPTH_TEST); glDepthMask(false); // don't write to Z-buffer! @@ -242,46 +241,45 @@ void GLPortal::End(HWDrawInfo *di, bool usestencil) // Restore the old view if (vp.camera != nullptr) vp.camera->renderflags = (vp.camera->renderflags & ~RF_MAYBEINVISIBLE) | savedvisibility; + glColorMask(0, 0, 0, 0); // no graphics + gl_RenderState.SetEffect(EFF_NONE); + gl_RenderState.ResetColor(); + gl_RenderState.EnableTexture(false); + gl_RenderState.Apply(); + + if (needdepth) { - ScopedColorMask colorMask(0, 0, 0, 0); // glColorMask(0, 0, 0, 0); // no graphics - gl_RenderState.SetEffect(EFF_NONE); - gl_RenderState.ResetColor(); - gl_RenderState.EnableTexture(false); - gl_RenderState.Apply(); - - if (needdepth) - { - // first step: reset the depth buffer to max. depth - glDepthRange(1, 1); // always - glDepthFunc(GL_ALWAYS); // write the farthest depth value - DrawPortalStencil(); - } - else - { - glEnable(GL_DEPTH_TEST); - } - - // second step: restore the depth buffer to the previous values and reset the stencil - glDepthFunc(GL_LEQUAL); - glDepthRange(0, 1); - glStencilOp(GL_KEEP, GL_KEEP, GL_DECR); - glStencilFunc(GL_EQUAL, mState->recursion, ~0); // draw sky into stencil + // first step: reset the depth buffer to max. depth + glDepthRange(1, 1); // always + glDepthFunc(GL_ALWAYS); // write the farthest depth value DrawPortalStencil(); - glDepthFunc(GL_LESS); + } + else + { + glEnable(GL_DEPTH_TEST); + } + + // second step: restore the depth buffer to the previous values and reset the stencil + glDepthFunc(GL_LEQUAL); + glDepthRange(0, 1); + glStencilOp(GL_KEEP, GL_KEEP, GL_DECR); + glStencilFunc(GL_EQUAL, mState->recursion, ~0); // draw sky into stencil + DrawPortalStencil(); + glDepthFunc(GL_LESS); - gl_RenderState.EnableTexture(true); - gl_RenderState.SetEffect(EFF_NONE); - } // glColorMask(1, 1, 1, 1); + gl_RenderState.EnableTexture(true); + gl_RenderState.SetEffect(EFF_NONE); + glColorMask(1, 1, 1, 1); mState->recursion--; // restore old stencil op. - glStencilOp(GL_KEEP,GL_KEEP,GL_KEEP); - glStencilFunc(GL_EQUAL, mState->recursion,~0); // draw sky into stencil + glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); + glStencilFunc(GL_EQUAL, mState->recursion, ~0); // draw sky into stencil } else { - if (needdepth) + if (needdepth) { glClear(GL_DEPTH_BUFFER_BIT); } @@ -302,17 +300,17 @@ void GLPortal::End(HWDrawInfo *di, bool usestencil) gl_RenderState.ResetColor(); glDepthFunc(GL_LEQUAL); glDepthRange(0, 1); - { - ScopedColorMask colorMask(0, 0, 0, 1); // mark portal in alpha channel but don't touch color - gl_RenderState.SetEffect(EFF_STENCIL); - gl_RenderState.EnableTexture(false); - gl_RenderState.BlendFunc(GL_ONE, GL_ZERO); - gl_RenderState.BlendEquation(GL_FUNC_ADD); - gl_RenderState.Apply(); - DrawPortalStencil(); - gl_RenderState.SetEffect(EFF_NONE); - gl_RenderState.EnableTexture(true); - } + glColorMask(0, 0, 0, 1); // mark portal in alpha channel but don't touch color + gl_RenderState.SetEffect(EFF_STENCIL); + gl_RenderState.EnableTexture(false); + gl_RenderState.BlendFunc(GL_ONE, GL_ZERO); + gl_RenderState.BlendEquation(GL_FUNC_ADD); + gl_RenderState.Apply(); + DrawPortalStencil(); + gl_RenderState.SetEffect(EFF_NONE); + gl_RenderState.EnableTexture(true); + glColorMask(1, 1, 1, 1); // mark portal in alpha channel but don't touch color + glDepthFunc(GL_LESS); } } diff --git a/src/gl/scene/gl_scene.cpp b/src/gl/scene/gl_scene.cpp index 2e1b004aad..942e646ae2 100644 --- a/src/gl/scene/gl_scene.cpp +++ b/src/gl/scene/gl_scene.cpp @@ -53,8 +53,7 @@ #include "hwrenderer/scene/hw_portal.h" #include "gl/scene/gl_drawinfo.h" #include "gl/scene/gl_portal.h" -#include "gl/stereo3d/gl_stereo3d.h" -#include "hwrenderer/utility/scoped_view_shifter.h" +#include "hwrenderer/utility/hw_vrmodes.h" //========================================================================== // @@ -380,10 +379,10 @@ void FDrawInfo::EndDrawScene(sector_t * viewsector) void FDrawInfo::DrawEndScene2D(sector_t * viewsector) { const bool renderHUDModel = IsHUDModelForPlayerAvailable(players[consoleplayer].camera->player); + auto vrmode = VRMode::GetVRMode(true); - // This should be removed once all 2D stuff is really done through the 2D interface. VPUniforms.mViewMatrix.loadIdentity(); - VPUniforms.mProjectionMatrix.ortho(0, screen->GetWidth(), screen->GetHeight(), 0, -1.0f, 1.0f); + VPUniforms.mProjectionMatrix = vrmode->GetHUDSpriteProjection(); ApplyVPUniforms(); glDisable(GL_DEPTH_TEST); glDisable(GL_MULTISAMPLE); @@ -465,27 +464,24 @@ sector_t * FGLRenderer::RenderViewpoint (FRenderViewpoint &mainvp, AActor * came R_SetupFrame (mainvp, r_viewwindow, camera); // Render (potentially) multiple views for stereo 3d - float viewShift[3]; - const s3d::Stereo3DMode& stereo3dMode = mainview && toscreen? s3d::Stereo3DMode::getCurrentMode() : s3d::Stereo3DMode::getMonoMode(); - stereo3dMode.SetUp(); - for (int eye_ix = 0; eye_ix < stereo3dMode.eye_count(); ++eye_ix) + // Fixme. The view offsetting should be done with a static table and not require setup of the entire render state for the mode. + auto vrmode = VRMode::GetVRMode(mainview && toscreen); + for (int eye_ix = 0; eye_ix < vrmode->mEyeCount; ++eye_ix) { - const auto eye = stereo3dMode.getEyePose(eye_ix); - eye->SetUp(); + const auto &eye = vrmode->mEyes[eye_ix]; screen->SetViewportRects(bounds); Set3DViewport(mainview); FDrawInfo *di = FDrawInfo::StartDrawInfo(mainvp, nullptr); - auto vp = di->Viewpoint; + auto &vp = di->Viewpoint; di->SetViewArea(); auto cm = di->SetFullbrightFlags(mainview ? vp.camera->player : nullptr); di->Viewpoint.FieldOfView = fov; // Set the real FOV for the current scene (it's not necessarily the same as the global setting in r_viewpoint) // Stereo mode specific perspective projection - di->VPUniforms.mProjectionMatrix = eye->GetProjection(fov, ratio, fovratio); - // Stereo mode specific viewpoint adjustment - temporarily shifts global ViewPos - eye->GetViewShift(vp.HWAngles.Yaw.Degrees, viewShift); - ScopedViewShifter viewShifter(vp.Pos, viewShift); + di->VPUniforms.mProjectionMatrix = eye.GetProjection(fov, ratio, fovratio); + // Stereo mode specific viewpoint adjustment + vp.Pos += eye.GetViewShift(vp.HWAngles.Yaw.Degrees); di->SetupView(vp.Pos.X, vp.Pos.Y, vp.Pos.Z, false, false); @@ -497,7 +493,7 @@ sector_t * FGLRenderer::RenderViewpoint (FRenderViewpoint &mainvp, AActor * came PostProcessScene(cm, [&]() { di->DrawEndScene2D(mainvp.sector); }); } di->EndDrawInfo(); - if (!stereo3dMode.IsMono()) + if (vrmode->mEyeCount > 1) mBuffers->BlitToEyeTexture(eye_ix); } diff --git a/src/gl/scene/gl_weapon.cpp b/src/gl/scene/gl_weapon.cpp index fdc10ef19c..fe5119639b 100644 --- a/src/gl/scene/gl_weapon.cpp +++ b/src/gl/scene/gl_weapon.cpp @@ -38,7 +38,6 @@ #include "gl/data/gl_vertexbuffer.h" #include "gl/scene/gl_drawinfo.h" #include "gl/models/gl_models.h" -#include "gl/stereo3d/gl_stereo3d.h" #include "gl/dynlights/gl_lightbuffer.h" //========================================================================== @@ -91,8 +90,6 @@ void FDrawInfo::DrawPSprite (HUDSprite *huds) void FDrawInfo::DrawPlayerSprites(bool hudModelStep) { - s3d::Stereo3DMode::getCurrentMode().AdjustPlayerSprites(this); - int oldlightmode = level.lightmode; if (!hudModelStep && level.lightmode == 8) level.lightmode = 2; // Software lighting cannot handle 2D content so revert to lightmode 2 for that. for(auto &hudsprite : hudsprites) diff --git a/src/gl/stereo3d/gl_anaglyph.cpp b/src/gl/stereo3d/gl_anaglyph.cpp deleted file mode 100644 index 791c499822..0000000000 --- a/src/gl/stereo3d/gl_anaglyph.cpp +++ /dev/null @@ -1,84 +0,0 @@ -// -//--------------------------------------------------------------------------- -// -// Copyright(C) 2015 Christopher Bruns -// All rights reserved. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see http://www.gnu.org/licenses/ -// -//-------------------------------------------------------------------------- -// -/* -** gl_anaglyph.cpp -** Color mask based stereoscopic 3D modes for GZDoom -** -*/ - -#include "gl_anaglyph.h" -#include "gl/renderer/gl_renderbuffers.h" - -namespace s3d { - -MaskAnaglyph::MaskAnaglyph(const ColorMask& leftColorMask, double ipdMeters) - : leftEye(leftColorMask, ipdMeters), rightEye(leftColorMask.inverse(), ipdMeters) -{ - eye_ptrs.Push(&leftEye); - eye_ptrs.Push(&rightEye); -} - -void MaskAnaglyph::Present() const -{ - GLRenderer->mBuffers->BindOutputFB(); - GLRenderer->ClearBorders(); - - gl_RenderState.SetColorMask(leftEye.GetColorMask().r, leftEye.GetColorMask().g, leftEye.GetColorMask().b, true); - gl_RenderState.ApplyColorMask(); - GLRenderer->mBuffers->BindEyeTexture(0, 0); - GLRenderer->DrawPresentTexture(screen->mOutputLetterbox, true); - - gl_RenderState.SetColorMask(rightEye.GetColorMask().r, rightEye.GetColorMask().g, rightEye.GetColorMask().b, true); - gl_RenderState.ApplyColorMask(); - GLRenderer->mBuffers->BindEyeTexture(1, 0); - GLRenderer->DrawPresentTexture(screen->mOutputLetterbox, true); - - gl_RenderState.ResetColorMask(); - gl_RenderState.ApplyColorMask(); -} - - -/* static */ -const GreenMagenta& GreenMagenta::getInstance(float ipd) -{ - static GreenMagenta instance(ipd); - return instance; -} - - -/* static */ -const RedCyan& RedCyan::getInstance(float ipd) -{ - static RedCyan instance(ipd); - return instance; -} - - -/* static */ -const AmberBlue& AmberBlue::getInstance(float ipd) -{ - static AmberBlue instance(ipd); - return instance; -} - - -} /* namespace s3d */ diff --git a/src/gl/stereo3d/gl_anaglyph.h b/src/gl/stereo3d/gl_anaglyph.h deleted file mode 100644 index 110493de91..0000000000 --- a/src/gl/stereo3d/gl_anaglyph.h +++ /dev/null @@ -1,113 +0,0 @@ -// -//--------------------------------------------------------------------------- -// -// Copyright(C) 2015 Christopher Bruns -// All rights reserved. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see http://www.gnu.org/licenses/ -// -//-------------------------------------------------------------------------- -// -/* -** gl_anaglyph.h -** Color mask based stereoscopic 3D modes for GZDoom -** -*/ - -#ifndef GL_ANAGLYPH_H_ -#define GL_ANAGLYPH_H_ - -#include "gl_stereo3d.h" -#include "gl_stereo_leftright.h" -#include "gl_load/gl_system.h" -#include "gl/renderer/gl_renderstate.h" - - -namespace s3d { - - -class ColorMask -{ -public: - ColorMask(bool r, bool g, bool b) : r(r), g(g), b(b) {} - ColorMask inverse() const { return ColorMask(!r, !g, !b); } - - bool r; - bool g; - bool b; -}; - - -class AnaglyphLeftPose : public LeftEyePose -{ -public: - AnaglyphLeftPose(const ColorMask& colorMask, float ipd) : LeftEyePose(ipd), colorMask(colorMask) {} - ColorMask GetColorMask() const { return colorMask; } - -private: - ColorMask colorMask; -}; - -class AnaglyphRightPose : public RightEyePose -{ -public: - AnaglyphRightPose(const ColorMask& colorMask, float ipd) : RightEyePose(ipd), colorMask(colorMask) {} - ColorMask GetColorMask() const { return colorMask; } - -private: - ColorMask colorMask; -}; - -class MaskAnaglyph : public Stereo3DMode -{ -public: - MaskAnaglyph(const ColorMask& leftColorMask, double ipdMeters); - void Present() const override; -private: - AnaglyphLeftPose leftEye; - AnaglyphRightPose rightEye; -}; - - -class RedCyan : public MaskAnaglyph -{ -public: - static const RedCyan& getInstance(float ipd); - - RedCyan(float ipd) : MaskAnaglyph(ColorMask(true, false, false), ipd) {} -}; - -class GreenMagenta : public MaskAnaglyph -{ -public: - static const GreenMagenta& getInstance(float ipd); - - GreenMagenta(float ipd) : MaskAnaglyph(ColorMask(false, true, false), ipd) {} -}; - -class AmberBlue : public MaskAnaglyph -{ -public: - static const AmberBlue& getInstance(float ipd); - - AmberBlue(float ipd) : MaskAnaglyph(ColorMask(true, true, false), ipd) {} -}; - -// TODO matrix anaglyph - - -} /* namespace s3d */ - - -#endif /* GL_ANAGLYPH_H_ */ diff --git a/src/gl/stereo3d/gl_interleaved3d.cpp b/src/gl/stereo3d/gl_interleaved3d.cpp deleted file mode 100644 index 3ab0b309db..0000000000 --- a/src/gl/stereo3d/gl_interleaved3d.cpp +++ /dev/null @@ -1,232 +0,0 @@ -/* -** gl_interleaved3d.cpp -** Interleaved image stereoscopic 3D modes for GZDoom -** -**--------------------------------------------------------------------------- -** Copyright 2016 Christopher Bruns -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in the -** documentation and/or other materials provided with the distribution. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -**--------------------------------------------------------------------------- -** -** -*/ - -#include "gl_interleaved3d.h" -#include "gl/renderer/gl_renderbuffers.h" -#include "gl/renderer/gl_postprocessstate.h" -#include "gl/system/gl_framebuffer.h" -#include "hwrenderer/postprocessing/hw_present3dRowshader.h" - -#ifdef _WIN32 -#include "hardware.h" -#endif // _WIN32 - -EXTERN_CVAR(Float, vid_saturation) -EXTERN_CVAR(Float, vid_brightness) -EXTERN_CVAR(Float, vid_contrast) -EXTERN_CVAR(Int, gl_satformula) -EXTERN_CVAR(Bool, fullscreen) -EXTERN_CVAR(Int, win_x) // screen pixel position of left of display window -EXTERN_CVAR(Int, win_y) // screen pixel position of top of display window - -namespace s3d { - -/* static */ -const CheckerInterleaved3D& CheckerInterleaved3D::getInstance(float ipd) -{ - static CheckerInterleaved3D instance(ipd); - return instance; -} - -/* static */ -const ColumnInterleaved3D& ColumnInterleaved3D::getInstance(float ipd) -{ - static ColumnInterleaved3D instance(ipd); - return instance; -} - -/* static */ -const RowInterleaved3D& RowInterleaved3D::getInstance(float ipd) -{ - static RowInterleaved3D instance(ipd); - return instance; -} - -static void prepareInterleavedPresent(FPresentShaderBase& shader) -{ - GLRenderer->mBuffers->BindOutputFB(); - GLRenderer->ClearBorders(); - - - // Bind each eye texture, for composition in the shader - GLRenderer->mBuffers->BindEyeTexture(0, 0); - GLRenderer->mBuffers->BindEyeTexture(1, 1); - - glActiveTexture(GL_TEXTURE0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - - glActiveTexture(GL_TEXTURE1); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - - const IntRect& box = screen->mOutputLetterbox; - glViewport(box.left, box.top, box.width, box.height); - - shader.Bind(NOQUEUE); - - if ( GLRenderer->framebuffer->IsHWGammaActive() ) - { - shader.Uniforms->InvGamma = 1.0f; - shader.Uniforms->Contrast = 1.0f; - shader.Uniforms->Brightness = 0.0f; - shader.Uniforms->Saturation = 1.0f; - } - else - { - shader.Uniforms->InvGamma = 1.0f / clamp(Gamma, 0.1f, 4.f); - shader.Uniforms->Contrast = clamp(vid_contrast, 0.1f, 3.f); - shader.Uniforms->Brightness = clamp(vid_brightness, -0.8f, 0.8f); - shader.Uniforms->Saturation = clamp(vid_saturation, -15.0f, 15.0f); - shader.Uniforms->GrayFormula = static_cast(gl_satformula); - } - shader.Uniforms->Scale = { - screen->mScreenViewport.width / (float)GLRenderer->mBuffers->GetWidth(), - screen->mScreenViewport.height / (float)GLRenderer->mBuffers->GetHeight() - }; - shader.Uniforms.Set(); -} - -// fixme: I don't know how to get absolute window position on Mac and Linux -// fixme: I don't know how to get window border decoration size anywhere -// So for now I'll hard code the border effect on my test machine. -// Workaround for others is to fuss with vr_swap_eyes CVAR until it looks right. -// Presumably the top/left window border on my test machine has an odd number of pixels -// in the horizontal direction, and an even number in the vertical direction. -#define WINDOW_BORDER_HORIZONTAL_PARITY 1 -#define WINDOW_BORDER_VERTICAL_PARITY 0 - -void CheckerInterleaved3D::Present() const -{ - FGLPostProcessState savedState; - savedState.SaveTextureBindings(2); - prepareInterleavedPresent(*GLRenderer->mPresent3dCheckerShader); - - // Compute absolute offset from top of screen to top of current display window - // because we need screen-relative, not window-relative, scan line parity - int windowVOffset = 0; - int windowHOffset = 0; - -#ifdef _WIN32 - /* this needs to be done differently! - if (!fullscreen) { - I_SaveWindowedPos(); // update win_y CVAR - windowHOffset = (win_x + WINDOW_BORDER_HORIZONTAL_PARITY) % 2; - windowVOffset = (win_y + WINDOW_BORDER_VERTICAL_PARITY) % 2; - } - */ -#endif // _WIN32 - - GLRenderer->mPresent3dCheckerShader->Uniforms->WindowPositionParity = - (windowVOffset - + windowHOffset - + screen->mOutputLetterbox.height + 1 // +1 because of origin at bottom - ) % 2; // because we want the top pixel offset, but gl_FragCoord.y is the bottom pixel offset - - GLRenderer->mPresent3dCheckerShader->Uniforms.Set(); - GLRenderer->RenderScreenQuad(); -} - -void s3d::CheckerInterleaved3D::AdjustViewports() const -{ - // decrease the total pixel count by 2, but keep the same aspect ratio - const float sqrt2 = 1.41421356237f; - // Change size of renderbuffer, and align to screen - screen->mSceneViewport.height /= sqrt2; - screen->mSceneViewport.top /= sqrt2; - screen->mSceneViewport.width /= sqrt2; - screen->mSceneViewport.left /= sqrt2; - - screen->mScreenViewport.height /= sqrt2; - screen->mScreenViewport.top /= sqrt2; - screen->mScreenViewport.width /= sqrt2; - screen->mScreenViewport.left /= sqrt2; -} - -void ColumnInterleaved3D::Present() const -{ - FGLPostProcessState savedState; - savedState.SaveTextureBindings(2); - prepareInterleavedPresent(*GLRenderer->mPresent3dColumnShader); - - // Compute absolute offset from top of screen to top of current display window - // because we need screen-relative, not window-relative, scan line parity - int windowHOffset = 0; - -#ifdef _WIN32 - /* this needs to be done differently! - if (!fullscreen) { - I_SaveWindowedPos(); // update win_y CVAR - windowHOffset = (win_x + WINDOW_BORDER_HORIZONTAL_PARITY) % 2; - } - */ -#endif // _WIN32 - - GLRenderer->mPresent3dColumnShader->Uniforms->WindowPositionParity = windowHOffset; - GLRenderer->mPresent3dColumnShader->Uniforms.Set(); - - GLRenderer->RenderScreenQuad(); -} - -void RowInterleaved3D::Present() const -{ - FGLPostProcessState savedState; - savedState.SaveTextureBindings(2); - prepareInterleavedPresent(*GLRenderer->mPresent3dRowShader); - - // Compute absolute offset from top of screen to top of current display window - // because we need screen-relative, not window-relative, scan line parity - int windowVOffset = 0; - -#ifdef _WIN32 - /* this needs to be done differently! - if (! fullscreen) { - I_SaveWindowedPos(); // update win_y CVAR - windowVOffset = (win_y + WINDOW_BORDER_VERTICAL_PARITY) % 2; - } - */ -#endif // _WIN32 - - GLRenderer->mPresent3dRowShader->Uniforms->WindowPositionParity = - (windowVOffset - + screen->mOutputLetterbox.height + 1 // +1 because of origin at bottom - ) % 2; - - GLRenderer->mPresent3dRowShader->Uniforms.Set(); - GLRenderer->RenderScreenQuad(); -} - - -} /* namespace s3d */ diff --git a/src/gl/stereo3d/gl_interleaved3d.h b/src/gl/stereo3d/gl_interleaved3d.h deleted file mode 100644 index 68125cccda..0000000000 --- a/src/gl/stereo3d/gl_interleaved3d.h +++ /dev/null @@ -1,75 +0,0 @@ -/* -** gl_interleaved3d.h -** Interleaved stereoscopic 3D modes for GZDoom -** -**--------------------------------------------------------------------------- -** Copyright 2016 Christopher Bruns -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in the -** documentation and/or other materials provided with the distribution. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -**--------------------------------------------------------------------------- -** -** -*/ - -#ifndef GL_INTERLEAVED3D_H_ -#define GL_INTERLEAVED3D_H_ - -#include "gl_stereo3d.h" -#include "gl_stereo_leftright.h" -#include "gl_sidebyside3d.h" -#include "gl_load/gl_system.h" -#include "gl/renderer/gl_renderstate.h" - -namespace s3d { - -class CheckerInterleaved3D : public SideBySideSquished -{ -public: - static const CheckerInterleaved3D& getInstance(float ipd); - CheckerInterleaved3D(double ipdMeters) : SideBySideSquished(ipdMeters) {} - void Present() const override; - void AdjustViewports() const override; -}; - -class ColumnInterleaved3D : public SideBySideSquished -{ -public: - static const ColumnInterleaved3D& getInstance(float ipd); - ColumnInterleaved3D(double ipdMeters) : SideBySideSquished(ipdMeters) {} - void Present() const override; -}; - -class RowInterleaved3D : public TopBottom3D -{ -public: - static const RowInterleaved3D& getInstance(float ipd); - RowInterleaved3D(double ipdMeters) : TopBottom3D(ipdMeters) {} - void Present() const override; -}; - -} /* namespace s3d */ - - -#endif /* GL_INTERLEAVED3D_H_ */ diff --git a/src/gl/stereo3d/gl_quadstereo.cpp b/src/gl/stereo3d/gl_quadstereo.cpp deleted file mode 100644 index dce114caf1..0000000000 --- a/src/gl/stereo3d/gl_quadstereo.cpp +++ /dev/null @@ -1,115 +0,0 @@ -// -//--------------------------------------------------------------------------- -// -// Copyright(C) 2015 Christopher Bruns -// All rights reserved. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see http://www.gnu.org/licenses/ -// -//-------------------------------------------------------------------------- -// -/* -** gl_quadstereo.cpp -** Quad-buffered OpenGL stereoscopic 3D mode for GZDoom -** -*/ - -#include "gl_quadstereo.h" -#include "gl/renderer/gl_renderbuffers.h" - -namespace s3d { - -QuadStereo::QuadStereo(double ipdMeters) - : leftEye(ipdMeters), rightEye(ipdMeters) -{ - // Check whether quad-buffered stereo is supported in the current context - // We are assuming the OpenGL context is already current at this point, - // i.e. this constructor is called "just in time". - - // First initialize to mono-ish initial state - bQuadStereoSupported = leftEye.bQuadStereoSupported = rightEye.bQuadStereoSupported = false; - eye_ptrs.Push(&leftEye); // We ALWAYS want to show at least this one view... - // We will possibly advance to true stereo mode in the Setup() method... -} - -// Sometimes the stereo render context is not ready immediately at start up -/* private */ -void QuadStereo::checkInitialRenderContextState() -{ - // Keep trying until we see at least one good OpenGL context to render to - static bool bDecentContextWasFound = false; - static int contextCheckCount = 0; - if ( (! bDecentContextWasFound) && (contextCheckCount < 200) ) - { - contextCheckCount += 1; - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); // This question is about the main screen display context - GLboolean supportsStereo, supportsBuffered; - glGetBooleanv(GL_DOUBLEBUFFER, &supportsBuffered); - if (supportsBuffered) // Finally, a useful OpenGL context - { - // This block will be executed exactly ONCE during a game run - bDecentContextWasFound = true; // now we can stop checking every frame... - // Now check whether this context supports hardware stereo - glGetBooleanv(GL_STEREO, &supportsStereo); - bQuadStereoSupported = supportsStereo && supportsBuffered; - leftEye.bQuadStereoSupported = bQuadStereoSupported; - rightEye.bQuadStereoSupported = bQuadStereoSupported; - if (bQuadStereoSupported) - eye_ptrs.Push(&rightEye); // Use the other eye too, if we can do stereo - } - } -} - -void QuadStereo::Present() const -{ - if (bQuadStereoSupported) - { - GLRenderer->mBuffers->BindOutputFB(); - - glDrawBuffer(GL_BACK_LEFT); - GLRenderer->ClearBorders(); - GLRenderer->mBuffers->BindEyeTexture(0, 0); - GLRenderer->DrawPresentTexture(screen->mOutputLetterbox, true); - - glDrawBuffer(GL_BACK_RIGHT); - GLRenderer->ClearBorders(); - GLRenderer->mBuffers->BindEyeTexture(1, 0); - GLRenderer->DrawPresentTexture(screen->mOutputLetterbox, true); - - glDrawBuffer(GL_BACK); - } - else - { - GLRenderer->mBuffers->BindOutputFB(); - GLRenderer->ClearBorders(); - GLRenderer->mBuffers->BindEyeTexture(0, 0); - GLRenderer->DrawPresentTexture(screen->mOutputLetterbox, true); - } -} - -void QuadStereo::SetUp() const -{ - Stereo3DMode::SetUp(); - // Maybe advance to true stereo mode (ONCE), after the stereo context is finally ready - const_cast(this)->checkInitialRenderContextState(); -} - -/* static */ -const QuadStereo& QuadStereo::getInstance(float ipd) -{ - static QuadStereo instance(ipd); - return instance; -} - -} /* namespace s3d */ diff --git a/src/gl/stereo3d/gl_quadstereo.h b/src/gl/stereo3d/gl_quadstereo.h deleted file mode 100644 index 014a91991b..0000000000 --- a/src/gl/stereo3d/gl_quadstereo.h +++ /dev/null @@ -1,77 +0,0 @@ -// -//--------------------------------------------------------------------------- -// -// Copyright(C) 2015 Christopher Bruns -// All rights reserved. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see http://www.gnu.org/licenses/ -// -//-------------------------------------------------------------------------- -// -/* -** gl_quadstereo.h -** Quad-buffered OpenGL stereoscopic 3D mode for GZDoom -** -*/ - -#ifndef GL_QUADSTEREO_H_ -#define GL_QUADSTEREO_H_ - -#include "gl_stereo3d.h" -#include "gl_stereo_leftright.h" -#include "gl_load/gl_system.h" - -namespace s3d { - - -class QuadStereoLeftPose : public LeftEyePose -{ -public: - QuadStereoLeftPose(float ipd) : LeftEyePose(ipd), bQuadStereoSupported(false) {} - bool bQuadStereoSupported; -}; - -class QuadStereoRightPose : public RightEyePose -{ -public: - QuadStereoRightPose(float ipd) : RightEyePose(ipd), bQuadStereoSupported(false){} - bool bQuadStereoSupported; -}; - -// To use Quad-buffered stereo mode with nvidia 3d vision glasses, -// you must either: -// A) be using a Quadro series video card, OR -// -// B) be using nvidia driver version 314.07 or later -// AND have your monitor set to 120 Hz refresh rate -// AND have gzdoom in true full screen mode -class QuadStereo : public Stereo3DMode -{ -public: - QuadStereo(double ipdMeters); - void Present() const override; - void SetUp() const override; - static const QuadStereo& getInstance(float ipd); -private: - QuadStereoLeftPose leftEye; - QuadStereoRightPose rightEye; - bool bQuadStereoSupported; - void checkInitialRenderContextState(); -}; - - -} /* namespace s3d */ - - -#endif /* GL_QUADSTEREO_H_ */ diff --git a/src/gl/stereo3d/gl_sidebyside3d.cpp b/src/gl/stereo3d/gl_sidebyside3d.cpp deleted file mode 100644 index 12d7cf41fe..0000000000 --- a/src/gl/stereo3d/gl_sidebyside3d.cpp +++ /dev/null @@ -1,150 +0,0 @@ -/* -** gl_sidebyside3d.cpp -** Mosaic image stereoscopic 3D modes for GZDoom -** -**--------------------------------------------------------------------------- -** Copyright 2016 Christopher Bruns -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in the -** documentation and/or other materials provided with the distribution. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -**--------------------------------------------------------------------------- -** -** -*/ - -#include "gl/scene/gl_drawinfo.h" -#include "gl_sidebyside3d.h" -#include "gl/renderer/gl_renderbuffers.h" - -namespace s3d { - -void SideBySideBase::Present() const -{ - GLRenderer->mBuffers->BindOutputFB(); - GLRenderer->ClearBorders(); - - // Compute screen regions to use for left and right eye views - int leftWidth = screen->mOutputLetterbox.width / 2; - int rightWidth = screen->mOutputLetterbox.width - leftWidth; - IntRect leftHalfScreen = screen->mOutputLetterbox; - leftHalfScreen.width = leftWidth; - IntRect rightHalfScreen = screen->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 - screen->mSceneViewport.width /= 2; - screen->mSceneViewport.left /= 2; - screen->mScreenViewport.width /= 2; - screen->mScreenViewport.left /= 2; -} - -/* static */ -const SideBySideSquished& SideBySideSquished::getInstance(float ipd) -{ - static SideBySideSquished instance(ipd); - return instance; -} - -SideBySideSquished::SideBySideSquished(double ipdMeters) - : leftEye(ipdMeters), rightEye(ipdMeters) -{ - eye_ptrs.Push(&leftEye); - eye_ptrs.Push(&rightEye); -} - -/* static */ -const SideBySideFull& SideBySideFull::getInstance(float ipd) -{ - static SideBySideFull instance(ipd); - return instance; -} - -SideBySideFull::SideBySideFull(double ipdMeters) - : leftEye(ipdMeters, 0.5f), rightEye(ipdMeters, 0.5f) -{ - eye_ptrs.Push(&leftEye); - eye_ptrs.Push(&rightEye); -} - -/* virtual */ -void SideBySideFull::AdjustPlayerSprites(FDrawInfo *di) const /* override */ -{ - // Show weapon at double width, so it would appear normal width after rescaling - int w = screen->mScreenViewport.width; - int h = screen->mScreenViewport.height; - di->VPUniforms.mProjectionMatrix.ortho(w/2, w + w/2, h, 0, -1.0f, 1.0f); - di->ApplyVPUniforms(); -} - -/* static */ -const TopBottom3D& TopBottom3D::getInstance(float ipd) -{ - static TopBottom3D instance(ipd); - return instance; -} - -void TopBottom3D::Present() const -{ - GLRenderer->mBuffers->BindOutputFB(); - GLRenderer->ClearBorders(); - - // Compute screen regions to use for left and right eye views - int topHeight = screen->mOutputLetterbox.height / 2; - int bottomHeight = screen->mOutputLetterbox.height - topHeight; - IntRect topHalfScreen = screen->mOutputLetterbox; - topHalfScreen.height = topHeight; - topHalfScreen.top = topHeight; - IntRect bottomHalfScreen = screen->mOutputLetterbox; - bottomHalfScreen.height = bottomHeight; - bottomHalfScreen.top = 0; - - GLRenderer->mBuffers->BindEyeTexture(0, 0); - GLRenderer->DrawPresentTexture(topHalfScreen, true); - - GLRenderer->mBuffers->BindEyeTexture(1, 0); - GLRenderer->DrawPresentTexture(bottomHalfScreen, true); -} - -// AdjustViewports() is called from within FLGRenderer::SetOutputViewport(...) -void TopBottom3D::AdjustViewports() const -{ - // Change size of renderbuffer, and align to screen - screen->mSceneViewport.height /= 2; - screen->mSceneViewport.top /= 2; - screen->mScreenViewport.height /= 2; - screen->mScreenViewport.top /= 2; -} - -} /* namespace s3d */ diff --git a/src/gl/stereo3d/gl_sidebyside3d.h b/src/gl/stereo3d/gl_sidebyside3d.h deleted file mode 100644 index ca0a22aa42..0000000000 --- a/src/gl/stereo3d/gl_sidebyside3d.h +++ /dev/null @@ -1,87 +0,0 @@ -/* -** gl_sidebyside3d.h -** Mosaic image stereoscopic 3D modes for GZDoom -** -**--------------------------------------------------------------------------- -** Copyright 2016 Christopher Bruns -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in the -** documentation and/or other materials provided with the distribution. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -**--------------------------------------------------------------------------- -** -** -*/ - -#ifndef GL_SIDEBYSIDE3D_H_ -#define GL_SIDEBYSIDE3D_H_ - -#include "gl_stereo3d.h" -#include "gl_stereo_leftright.h" -#include "gl_load/gl_system.h" -#include "gl/renderer/gl_renderstate.h" - - -namespace s3d { - -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); -private: - LeftEyePose leftEye; - RightEyePose rightEye; -}; - -class SideBySideFull : public SideBySideBase -{ -public: - static const SideBySideFull& getInstance(float ipd); - SideBySideFull(double ipdMeters); - virtual void AdjustPlayerSprites(FDrawInfo *di) const override; -private: - LeftEyePose leftEye; - RightEyePose rightEye; -}; - -class TopBottom3D : public SideBySideSquished -{ -public: - static const TopBottom3D& getInstance(float ipd); - TopBottom3D(double ipdMeters) : SideBySideSquished(ipdMeters) {} - void Present() const override; - virtual void AdjustViewports() const override; -}; - -} /* namespace s3d */ - - -#endif /* GL_SIDEBYSIDE3D_H_ */ diff --git a/src/gl/stereo3d/gl_stereo3d.cpp b/src/gl/stereo3d/gl_stereo3d.cpp deleted file mode 100644 index 609e037dbe..0000000000 --- a/src/gl/stereo3d/gl_stereo3d.cpp +++ /dev/null @@ -1,53 +0,0 @@ -// -//--------------------------------------------------------------------------- -// -// Copyright(C) 2015 Christopher Bruns -// All rights reserved. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see http://www.gnu.org/licenses/ -// -//-------------------------------------------------------------------------- -// -/* -** gl_stereo3d.cpp -** Stereoscopic 3D API -** -*/ - -#include "gl_load/gl_system.h" -#include "gl/stereo3d/gl_stereo3d.h" - -namespace s3d { - - -Stereo3DMode::Stereo3DMode() -{ -} - -Stereo3DMode::~Stereo3DMode() -{ -} - -// Avoid static initialization order fiasco by declaring first Mode type (Mono) here in the -// same source file as Stereo3DMode::getCurrentMode() -// https://isocpp.org/wiki/faq/ctors#static-init-order - -/* static */ -const MonoView& MonoView::getInstance() -{ - static MonoView instance; - return instance; -} - -} /* namespace s3d */ diff --git a/src/gl/stereo3d/gl_stereo3d.h b/src/gl/stereo3d/gl_stereo3d.h deleted file mode 100644 index 8468d5ad97..0000000000 --- a/src/gl/stereo3d/gl_stereo3d.h +++ /dev/null @@ -1,90 +0,0 @@ -// -//--------------------------------------------------------------------------- -// -// Copyright(C) 2015 Christopher Bruns -// All rights reserved. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see http://www.gnu.org/licenses/ -// -//-------------------------------------------------------------------------- -// -/* -** gl_stereo3d.h -** Stereoscopic 3D API -** -*/ - -#ifndef GL_STEREO3D_H_ -#define GL_STEREO3D_H_ - -#include // needed for memcpy on linux, which is needed by VSMatrix copy ctor -#include "tarray.h" -#include "r_data/matrix.h" -#include "gl/renderer/gl_renderer.h" -#include "hwrenderer/stereo3d/hw_eyepose.h" - -/* stereoscopic 3D API */ -namespace s3d { - -/* Base class for stereoscopic 3D rendering modes */ -class Stereo3DMode -{ -public: - /* static methods for managing the selected stereoscopic view state */ - static const Stereo3DMode& getCurrentMode(); - static const Stereo3DMode& getMonoMode(); - - Stereo3DMode(); - virtual ~Stereo3DMode(); - virtual int eye_count() const { return eye_ptrs.Size(); } - virtual const EyePose * getEyePose(int ix) const { return eye_ptrs(ix); } - - /* hooks for setup and cleanup operations for each stereo mode */ - virtual void SetUp() const {}; - - virtual bool IsMono() const { return false; } - virtual void AdjustViewports() const {}; - virtual void AdjustPlayerSprites(FDrawInfo *di) const {}; - virtual void Present() const = 0; - -protected: - TArray eye_ptrs; - -private: - static Stereo3DMode const * currentStereo3DMode; - static void setCurrentMode(const Stereo3DMode& mode); -}; - - -/** -* Ordinary non-3D rendering -*/ -class MonoView : public Stereo3DMode -{ -public: - static const MonoView& getInstance(); - - bool IsMono() const override { return true; } - void Present() const override { } - -protected: - MonoView() { eye_ptrs.Push(¢ralEye); } - EyePose centralEye; -}; - - -} /* namespace st3d */ - - -#endif /* GL_STEREO3D_H_ */ diff --git a/src/gl/stereo3d/gl_stereo_cvars.cpp b/src/gl/stereo3d/gl_stereo_cvars.cpp deleted file mode 100644 index 3fbad45a1b..0000000000 --- a/src/gl/stereo3d/gl_stereo_cvars.cpp +++ /dev/null @@ -1,127 +0,0 @@ -// -//--------------------------------------------------------------------------- -// -// Copyright(C) 2015 Christopher Bruns -// All rights reserved. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see http://www.gnu.org/licenses/ -// -//-------------------------------------------------------------------------- -// -/* -** gl_stereo_cvars.cpp -** Console variables related to stereoscopic 3D in GZDoom -** -*/ - -#include "gl/stereo3d/gl_stereo3d.h" -#include "gl/stereo3d/gl_stereo_leftright.h" -#include "gl/stereo3d/gl_anaglyph.h" -#include "gl/stereo3d/gl_quadstereo.h" -#include "gl/stereo3d/gl_sidebyside3d.h" -#include "gl/stereo3d/gl_interleaved3d.h" -#include "version.h" - -// Set up 3D-specific console variables: -CVAR(Int, vr_mode, 0, CVAR_GLOBALCONFIG) - -// switch left and right eye views -CVAR(Bool, vr_swap_eyes, false, CVAR_GLOBALCONFIG) - -// intraocular distance in meters -CVAR(Float, vr_ipd, 0.062f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) // METERS - -// distance between viewer and the display screen -CVAR(Float, vr_screendist, 0.80f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) // METERS - -// default conversion between (vertical) DOOM units and meters -CVAR(Float, vr_hunits_per_meter, 41.0f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) // METERS - -// Manage changing of 3D modes: -namespace s3d { - -// Initialize static member -Stereo3DMode const * Stereo3DMode::currentStereo3DMode = 0; // "nullptr" not resolved on linux (presumably not C++11) - -/* static */ -void Stereo3DMode::setCurrentMode(const Stereo3DMode& mode) { - Stereo3DMode::currentStereo3DMode = &mode; -} - -/* static */ -const Stereo3DMode& Stereo3DMode::getCurrentMode() -{ - // NOTE: Ensure that these vr_mode values correspond to the ones in wadsrc/static/menudef.z - switch (vr_mode) - { - case 1: - setCurrentMode(GreenMagenta::getInstance(vr_ipd)); - break; - case 2: - setCurrentMode(RedCyan::getInstance(vr_ipd)); - break; - case 3: - setCurrentMode(SideBySideFull::getInstance(vr_ipd)); - break; - case 4: - setCurrentMode(SideBySideSquished::getInstance(vr_ipd)); - break; - case 5: - setCurrentMode(LeftEyeView::getInstance(vr_ipd)); - break; - case 6: - setCurrentMode(RightEyeView::getInstance(vr_ipd)); - break; - case 7: - if (screen->enable_quadbuffered) { - setCurrentMode(QuadStereo::getInstance(vr_ipd)); - } - else { - setCurrentMode(MonoView::getInstance()); - } - break; - // TODO: 8: Oculus Rift - case 9: - setCurrentMode(AmberBlue::getInstance(vr_ipd)); - break; - // TODO: 10: HTC Vive/OpenVR - case 11: - setCurrentMode(TopBottom3D::getInstance(vr_ipd)); - break; - case 12: - setCurrentMode(RowInterleaved3D::getInstance(vr_ipd)); - break; - case 13: - setCurrentMode(ColumnInterleaved3D::getInstance(vr_ipd)); - break; - case 14: - setCurrentMode(CheckerInterleaved3D::getInstance(vr_ipd)); - break; - case 0: - default: - setCurrentMode(MonoView::getInstance()); - break; - } - return *currentStereo3DMode; -} - -const Stereo3DMode& Stereo3DMode::getMonoMode() -{ - setCurrentMode(MonoView::getInstance()); - return *currentStereo3DMode; -} - - -} /* namespace s3d */ - diff --git a/src/gl/stereo3d/gl_stereo_leftright.cpp b/src/gl/stereo3d/gl_stereo_leftright.cpp deleted file mode 100644 index be1d0a3d9b..0000000000 --- a/src/gl/stereo3d/gl_stereo_leftright.cpp +++ /dev/null @@ -1,73 +0,0 @@ -// -//--------------------------------------------------------------------------- -// -// Copyright(C) 2015 Christopher Bruns -// All rights reserved. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see http://www.gnu.org/licenses/ -// -//-------------------------------------------------------------------------- -// -/* -** gl_stereo_leftright.cpp -** Offsets for left and right eye views -** -*/ - -#include "gl_stereo_leftright.h" -#include "vectors.h" // RAD2DEG -#include "doomtype.h" // M_PI -#include "hwrenderer/utility/hw_cvars.h" -#include "gl_load/gl_system.h" -#include "gl/renderer/gl_renderstate.h" -#include "gl/renderer/gl_renderer.h" -#include "gl/renderer/gl_renderbuffers.h" - -namespace s3d { - - -/* static */ -const LeftEyeView& LeftEyeView::getInstance(float ipd) -{ - static LeftEyeView instance(ipd); - instance.setIpd(ipd); - return instance; -} - -void LeftEyeView::Present() const -{ - GLRenderer->mBuffers->BindOutputFB(); - GLRenderer->ClearBorders(); - GLRenderer->mBuffers->BindEyeTexture(0, 0); - GLRenderer->DrawPresentTexture(screen->mOutputLetterbox, true); -} - -/* static */ -const RightEyeView& RightEyeView::getInstance(float ipd) -{ - static RightEyeView instance(ipd); - instance.setIpd(ipd); - return instance; -} - -void RightEyeView::Present() const -{ - GLRenderer->mBuffers->BindOutputFB(); - GLRenderer->ClearBorders(); - GLRenderer->mBuffers->BindEyeTexture(0, 0); - GLRenderer->DrawPresentTexture(screen->mOutputLetterbox, true); -} - - -} /* namespace s3d */ diff --git a/src/gl/stereo3d/gl_stereo_leftright.h b/src/gl/stereo3d/gl_stereo_leftright.h deleted file mode 100644 index ad4ccb769c..0000000000 --- a/src/gl/stereo3d/gl_stereo_leftright.h +++ /dev/null @@ -1,67 +0,0 @@ -// -//--------------------------------------------------------------------------- -// -// Copyright(C) 2015 Christopher Bruns -// All rights reserved. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see http://www.gnu.org/licenses/ -// -//-------------------------------------------------------------------------- -// -/* -** gl_stereo_leftright.h -** Offsets for left and right eye views -** -*/ - -#ifndef GL_STEREO_LEFTRIGHT_H_ -#define GL_STEREO_LEFTRIGHT_H_ - -#include "gl_stereo3d.h" - -namespace s3d { - - -/** - * As if viewed through the left eye only - */ -class LeftEyeView : public Stereo3DMode -{ -public: - static const LeftEyeView& getInstance(float ipd); - - LeftEyeView(float ipd) : eye(ipd) { eye_ptrs.Push(&eye); } - void setIpd(float ipd) { eye.setIpd(ipd); } - void Present() const override; -protected: - LeftEyePose eye; -}; - - -class RightEyeView : public Stereo3DMode -{ -public: - static const RightEyeView& getInstance(float ipd); - - RightEyeView(float ipd) : eye(ipd) { eye_ptrs.Push(&eye); } - void setIpd(float ipd) { eye.setIpd(ipd); } - void Present() const override; -protected: - RightEyePose eye; -}; - - -} /* namespace s3d */ - -#endif /* GL_STEREO_LEFTRIGHT_H_ */ diff --git a/src/gl/stereo3d/scoped_color_mask.h b/src/gl/stereo3d/scoped_color_mask.h deleted file mode 100644 index 4e2103a28f..0000000000 --- a/src/gl/stereo3d/scoped_color_mask.h +++ /dev/null @@ -1,56 +0,0 @@ -// -//--------------------------------------------------------------------------- -// -// Copyright(C) 2015 Christopher Bruns -// All rights reserved. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see http://www.gnu.org/licenses/ -// -//-------------------------------------------------------------------------- -// -/* -** scoped_color_mask.h -** Stack-scoped class for temporarily changing the OpenGL color mask setting. -** -*/ - -#ifndef GL_STEREO3D_SCOPED_COLOR_MASK_H_ -#define GL_STEREO3D_SCOPED_COLOR_MASK_H_ - -#include "gl_load/gl_system.h" - -/** -* Temporarily change color mask -*/ -class ScopedColorMask -{ -public: - ScopedColorMask(bool r, bool g, bool b, bool a) - { - gl_RenderState.GetColorMask(saved[0], saved[1], saved[2], saved[3]); - gl_RenderState.SetColorMask(r, g, b, a); - gl_RenderState.ApplyColorMask(); - gl_RenderState.EnableDrawBuffers(1); - } - ~ScopedColorMask() { - gl_RenderState.EnableDrawBuffers(gl_RenderState.GetPassDrawBufferCount()); - gl_RenderState.SetColorMask(saved[0], saved[1], saved[2], saved[3]); - gl_RenderState.ApplyColorMask(); - } -private: - bool saved[4]; -}; - - -#endif // GL_STEREO3D_SCOPED_COLOR_MASK_H_ diff --git a/src/gl/system/gl_framebuffer.cpp b/src/gl/system/gl_framebuffer.cpp index 37e5f9f454..451a9f7cb0 100644 --- a/src/gl/system/gl_framebuffer.cpp +++ b/src/gl/system/gl_framebuffer.cpp @@ -37,10 +37,10 @@ #include "gl/renderer/gl_renderbuffers.h" #include "gl/textures/gl_samplers.h" #include "hwrenderer/utility/hw_clock.h" +#include "hwrenderer/utility/hw_vrmodes.h" #include "gl/data/gl_vertexbuffer.h" #include "gl/data/gl_uniformbuffer.h" #include "gl/models/gl_models.h" -#include "gl/stereo3d/gl_stereo3d.h" #include "gl/shaders/gl_shaderprogram.h" #include "gl_debug.h" #include "r_videoscale.h" @@ -375,7 +375,10 @@ void OpenGLFrameBuffer::SetViewportRects(IntRect *bounds) { Super::SetViewportRects(bounds); if (!bounds) - s3d::Stereo3DMode::getCurrentMode().AdjustViewports(); + { + auto vrmode = VRMode::GetVRMode(true); + vrmode->AdjustViewport(); + } } diff --git a/src/hwrenderer/stereo3d/hw_eyepose.cpp b/src/hwrenderer/stereo3d/hw_eyepose.cpp deleted file mode 100644 index 43e6d9bd45..0000000000 --- a/src/hwrenderer/stereo3d/hw_eyepose.cpp +++ /dev/null @@ -1,97 +0,0 @@ -// -//--------------------------------------------------------------------------- -// -// Copyright(C) 2015 Christopher Bruns -// All rights reserved. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see http://www.gnu.org/licenses/ -// -//-------------------------------------------------------------------------- -// -/* -** gl_stereo_leftright.cpp -** Offsets for left and right eye views -** -*/ - -#include "vectors.h" // RAD2DEG -#include "doomtype.h" // M_PI -#include "hwrenderer/utility/hw_cvars.h" -#include "hw_eyepose.h" -#include "v_video.h" - -EXTERN_CVAR(Float, vr_screendist) -EXTERN_CVAR(Float, vr_hunits_per_meter) -EXTERN_CVAR(Bool, vr_swap_eyes) - - -/* virtual */ -VSMatrix EyePose::GetProjection(float fov, float aspectRatio, float fovRatio) const -{ - VSMatrix result; - - float fovy = (float)(2 * RAD2DEG(atan(tan(DEG2RAD(fov) / 2) / fovRatio))); - result.perspective(fovy, aspectRatio, screen->GetZNear(), screen->GetZFar()); - - return result; -} - -/* virtual */ -void EyePose::GetViewShift(float yaw, float outViewShift[3]) const -{ - // pass-through for Mono view - outViewShift[0] = 0; - outViewShift[1] = 0; - outViewShift[2] = 0; -} - -/* virtual */ -VSMatrix ShiftedEyePose::GetProjection(float fov, float aspectRatio, float fovRatio) const -{ - double zNear = screen->GetZNear(); - double zFar = screen->GetZFar(); - - // For stereo 3D, use asymmetric frustum shift in projection matrix - // Q: shouldn't shift vary with roll angle, at least for desktop display? - // A: No. (lab) roll is not measured on desktop display (yet) - double frustumShift = zNear * getShift() / vr_screendist; // meters cancel, leaving doom units - // double frustumShift = 0; // Turning off shift for debugging - double fH = zNear * tan(DEG2RAD(fov) / 2) / fovRatio; - double fW = fH * aspectRatio * squish; - double left = -fW - frustumShift; - double right = fW - frustumShift; - double bottom = -fH; - double top = fH; - - VSMatrix result(1); - result.frustum((float)left, (float)right, (float)bottom, (float)top, (float)zNear, (float)zFar); - return result; -} - - -/* virtual */ -void ShiftedEyePose::GetViewShift(float yaw, float outViewShift[3]) const -{ - float dx = -cos(DEG2RAD(yaw)) * vr_hunits_per_meter * getShift(); - float dy = sin(DEG2RAD(yaw)) * vr_hunits_per_meter * getShift(); - outViewShift[0] = dx; - outViewShift[1] = dy; - outViewShift[2] = 0; -} - -float ShiftedEyePose::getShift() const -{ - return vr_swap_eyes ? -shift : shift; -} - diff --git a/src/hwrenderer/stereo3d/hw_eyepose.h b/src/hwrenderer/stereo3d/hw_eyepose.h deleted file mode 100644 index 7531f29ba0..0000000000 --- a/src/hwrenderer/stereo3d/hw_eyepose.h +++ /dev/null @@ -1,47 +0,0 @@ -#pragma once - -#include "r_data/matrix.h" - - -/* Viewpoint of one eye */ -class EyePose -{ -public: - EyePose() {} - virtual ~EyePose() {} - virtual VSMatrix GetProjection(float fov, float aspectRatio, float fovRatio) const; - virtual void GetViewShift(float yaw, float outViewShift[3]) const; - virtual void SetUp() const {} -}; - -class ShiftedEyePose : public EyePose -{ -public: - ShiftedEyePose(float shift, float squish) : shift(shift), squish(squish) {}; - float getShift() const; - virtual VSMatrix GetProjection(float fov, float aspectRatio, float fovRatio) const; - virtual void GetViewShift(float yaw, float outViewShift[3]) const; - -protected: - void setShift(float shift) { this->shift = shift; } - -private: - float shift; - float squish; -}; - - -class LeftEyePose : public ShiftedEyePose -{ -public: - LeftEyePose(float ipd, float squish = 1.f) : ShiftedEyePose( -0.5f * ipd, squish) {} - void setIpd(float ipd) { setShift(-0.5f * ipd); } -}; - - -class RightEyePose : public ShiftedEyePose -{ -public: - RightEyePose(float ipd, float squish = 1.f) : ShiftedEyePose(0.5f * ipd, squish) {} - void setIpd(float ipd) { setShift(0.5f * ipd); } -}; diff --git a/src/hwrenderer/utility/hw_vrmodes.cpp b/src/hwrenderer/utility/hw_vrmodes.cpp new file mode 100644 index 0000000000..d43ad1f76a --- /dev/null +++ b/src/hwrenderer/utility/hw_vrmodes.cpp @@ -0,0 +1,176 @@ +// +//--------------------------------------------------------------------------- +// +// Copyright(C) 2015 Christopher Bruns +// All rights reserved. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see http://www.gnu.org/licenses/ +// +//-------------------------------------------------------------------------- +// +/* +** gl_stereo_leftright.cpp +** Offsets for left and right eye views +** +*/ + +#include "vectors.h" // RAD2DEG +#include "doomtype.h" // M_PI +#include "hwrenderer/utility/hw_cvars.h" +#include "hw_vrmodes.h" +#include "v_video.h" + +// Set up 3D-specific console variables: +CVAR(Int, vr_mode, 0, CVAR_GLOBALCONFIG) + +// switch left and right eye views +CVAR(Bool, vr_swap_eyes, false, CVAR_GLOBALCONFIG) + +// intraocular distance in meters +CVAR(Float, vr_ipd, 0.062f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) // METERS + +// distance between viewer and the display screen +CVAR(Float, vr_screendist, 0.80f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) // METERS + +// default conversion between (vertical) DOOM units and meters +CVAR(Float, vr_hunits_per_meter, 41.0f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) // METERS + + +#define isqrt2 0.7071067812f +static VRMode vrmi_mono = { 1, 1.f, 1.f, 1.f,{ { 0.f, 1.f },{ 0.f, 0.f } } }; +static VRMode vrmi_stereo = { 2, 1.f, 1.f, 1.f,{ { -.5f, 1.f },{ .5f, 1.f } } }; +static VRMode vrmi_sbsfull = { 2, .5f, 1.f, 2.f,{ { -.5f, .5f },{ .5f, .5f } } }; +static VRMode vrmi_sbssquished = { 2, .5f, 1.f, 1.f,{ { -.5f, 1.f },{ .5f, 1.f } } }; +static VRMode vrmi_lefteye = { 1, 1.f, 1.f, 1.f, { { -.5f, 1.f },{ 0.f, 0.f } } }; +static VRMode vrmi_righteye = { 1, 1.f, 1.f, 1.f,{ { .5f, 1.f },{ 0.f, 0.f } } }; +static VRMode vrmi_topbottom = { 2, 1.f, .5f, 1.f,{ { -.5f, 1.f },{ .5f, 1.f } } }; +static VRMode vrmi_checker = { 2, isqrt2, isqrt2, 1.f,{ { -.5f, 1.f },{ .5f, 1.f } } }; + +const VRMode *VRMode::GetVRMode(bool toscreen) +{ + switch (toscreen && vid_rendermode == 4 ? vr_mode : 0) + { + default: + case VR_MONO: + return &vrmi_mono; + + case VR_GREENMAGENTA: + case VR_REDCYAN: + case VR_QUADSTEREO: + case VR_AMBERBLUE: + return &vrmi_stereo; + + case VR_SIDEBYSIDESQUISHED: + case VR_COLUMNINTERLEAVED: + return &vrmi_sbssquished; + + case VR_SIDEBYSIDEFULL: + return &vrmi_sbsfull; + + case VR_TOPBOTTOM: + case VR_ROWINTERLEAVED: + return &vrmi_topbottom; + + case VR_LEFTEYEVIEW: + return &vrmi_lefteye; + + case VR_RIGHTEYEVIEW: + return &vrmi_righteye; + + case VR_CHECKERINTERLEAVED: + return &vrmi_checker; + } +} + +void VRMode::AdjustViewport() const +{ + screen->mSceneViewport.height = (int)(screen->mSceneViewport.height * mVerticalViewportScale); + screen->mSceneViewport.top = (int)(screen->mSceneViewport.top * mVerticalViewportScale); + screen->mSceneViewport.width = (int)(screen->mSceneViewport.width * mHorizontalViewportScale); + screen->mSceneViewport.left = (int)(screen->mSceneViewport.left * mHorizontalViewportScale); + + screen->mScreenViewport.height = (int)(screen->mScreenViewport.height * mVerticalViewportScale); + screen->mScreenViewport.top = (int)(screen->mScreenViewport.top * mVerticalViewportScale); + screen->mScreenViewport.width = (int)(screen->mScreenViewport.width * mHorizontalViewportScale); + screen->mScreenViewport.left = (int)(screen->mScreenViewport.left * mHorizontalViewportScale); +} + +VSMatrix VRMode::GetHUDSpriteProjection() const +{ + VSMatrix mat; + int w = screen->mScreenViewport.width; + int h = screen->mScreenViewport.height; + float scaled_w = w * mWeaponProjectionScale; + float left_ofs = (scaled_w - w) / 2.f; + mat.ortho(left_ofs, left_ofs + w, (float)h, 0, -1.0f, 1.0f); + return mat; +} + +float VREyeInfo::getShift() const +{ + auto res = mShiftFactor * vr_ipd; + return vr_swap_eyes ? -res : res; +} + +VSMatrix VREyeInfo::GetProjection(float fov, float aspectRatio, float fovRatio) const +{ + VSMatrix result; + + if (mShiftFactor == 0) + { + float fovy = (float)(2 * RAD2DEG(atan(tan(DEG2RAD(fov) / 2) / fovRatio))); + result.perspective(fovy, aspectRatio, screen->GetZNear(), screen->GetZFar()); + return result; + } + else + { + double zNear = screen->GetZNear(); + double zFar = screen->GetZFar(); + + // For stereo 3D, use asymmetric frustum shift in projection matrix + // Q: shouldn't shift vary with roll angle, at least for desktop display? + // A: No. (lab) roll is not measured on desktop display (yet) + double frustumShift = zNear * getShift() / vr_screendist; // meters cancel, leaving doom units + // double frustumShift = 0; // Turning off shift for debugging + double fH = zNear * tan(DEG2RAD(fov) / 2) / fovRatio; + double fW = fH * aspectRatio * mScaleFactor; + double left = -fW - frustumShift; + double right = fW - frustumShift; + double bottom = -fH; + double top = fH; + + VSMatrix result(1); + result.frustum((float)left, (float)right, (float)bottom, (float)top, (float)zNear, (float)zFar); + return result; + } +} + + + +/* virtual */ +DVector3 VREyeInfo::GetViewShift(float yaw) const +{ + if (mShiftFactor == 0) + { + // pass-through for Mono view + return { 0,0,0 }; + } + else + { + double dx = -cos(DEG2RAD(yaw)) * vr_hunits_per_meter * getShift(); + double dy = sin(DEG2RAD(yaw)) * vr_hunits_per_meter * getShift(); + return { dx, dy, 0 }; + } +} + diff --git a/src/hwrenderer/utility/hw_vrmodes.h b/src/hwrenderer/utility/hw_vrmodes.h new file mode 100644 index 0000000000..db4fe39850 --- /dev/null +++ b/src/hwrenderer/utility/hw_vrmodes.h @@ -0,0 +1,46 @@ +#pragma once + +#include "r_data/matrix.h" + + +enum +{ + VR_MONO = 0, + VR_GREENMAGENTA = 1, + VR_REDCYAN = 2, + VR_SIDEBYSIDEFULL = 3, + VR_SIDEBYSIDESQUISHED = 4, + VR_LEFTEYEVIEW = 5, + VR_RIGHTEYEVIEW = 6, + VR_QUADSTEREO = 7, + VR_AMBERBLUE = 9, + VR_TOPBOTTOM = 11, + VR_ROWINTERLEAVED = 12, + VR_COLUMNINTERLEAVED = 13, + VR_CHECKERINTERLEAVED = 14 +}; + +struct VREyeInfo +{ + float mShiftFactor; + float mScaleFactor; + + VSMatrix GetProjection(float fov, float aspectRatio, float fovRatio) const; + DVector3 GetViewShift(float yaw) const; +private: + float getShift() const; + +}; + +struct VRMode +{ + int mEyeCount; + float mHorizontalViewportScale; + float mVerticalViewportScale; + float mWeaponProjectionScale; + VREyeInfo mEyes[2]; + + static const VRMode *GetVRMode(bool toscreen = true); + void AdjustViewport() const; + VSMatrix GetHUDSpriteProjection() const; +}; diff --git a/src/hwrenderer/utility/scoped_view_shifter.h b/src/hwrenderer/utility/scoped_view_shifter.h deleted file mode 100644 index 9e80a28adf..0000000000 --- a/src/hwrenderer/utility/scoped_view_shifter.h +++ /dev/null @@ -1,62 +0,0 @@ -// -//--------------------------------------------------------------------------- -// -// Copyright(C) 2015 Christopher Bruns -// All rights reserved. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see http://www.gnu.org/licenses/ -// -//-------------------------------------------------------------------------- -// -/* -** scoped_view_shifter.h -** Stack-scoped class for temporarily changing camera viewpoint -** Used for stereoscopic 3D. -** -*/ - -#ifndef GL_STEREO3D_SCOPED_VIEW_SHIFTER_H_ -#define GL_STEREO3D_SCOPED_VIEW_SHIFTER_H_ - -#include "basictypes.h" -#include "vectors.h" - -/** - * Temporarily shift - */ -class ScopedViewShifter -{ -public: - ScopedViewShifter(DVector3 &var, float dxyz[3]) // in meters - { - // save original values - mVar = &var; - cachedView = var; - // modify values - var += DVector3(dxyz[0], dxyz[1], dxyz[2]); - } - - ~ScopedViewShifter() - { - // restore original values - *mVar = cachedView; - } - -private: - DVector3 *mVar; - DVector3 cachedView; -}; - - -#endif // GL_STEREO3D_SCOPED_VIEW_SHIFTER_H_