diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..5ce158013 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +*.cpp text diff --git a/.gitignore b/.gitignore index 849ed7b2a..b3d0eb257 100644 --- a/.gitignore +++ b/.gitignore @@ -40,3 +40,4 @@ /zlib/x64/ /build_vc2013_64bit /build_vc2015 +/build_cmake diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 799bf6dd4..3ef99327b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -762,6 +762,7 @@ 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 @@ -1120,6 +1121,11 @@ add_executable( zdoom WIN32 MACOSX_BUNDLE gl/scene/gl_walls_draw.cpp gl/scene/gl_vertex.cpp gl/scene/gl_spritelight.cpp + gl/stereo3d/gl_stereo3d.cpp + gl/stereo3d/gl_stereo_cvars.cpp + gl/stereo3d/gl_stereo_leftright.cpp + gl/stereo3d/scoped_view_shifter.cpp + gl/stereo3d/gl_anaglyph.cpp gl/dynlights/gl_dynlight.cpp gl/dynlights/gl_glow.cpp gl/dynlights/gl_dynlight1.cpp @@ -1371,6 +1377,7 @@ source_group("OpenGL Renderer\\HQ Resize Assembly version" REGULAR_EXPRESSION "^ 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_renderer.h b/src/gl/renderer/gl_renderer.h index 534745869..3374c904a 100644 --- a/src/gl/renderer/gl_renderer.h +++ b/src/gl/renderer/gl_renderer.h @@ -5,6 +5,7 @@ #include "v_video.h" #include "vectors.h" #include "r_renderer.h" +#include "gl/data/gl_matrix.h" struct particle_t; class FCanvasTexture; @@ -120,6 +121,7 @@ public: void Flush() {} void SetProjection(float fov, float ratio, float fovratio); + void SetProjection(FLOATTYPE matrix[4][4]); // raw matrix input from stereo 3d modes void SetViewMatrix(fixed_t viewx, fixed_t viewy, fixed_t viewz, bool mirror, bool planemirror); void ProcessScene(bool toscreen = false); diff --git a/src/gl/scene/gl_drawinfo.cpp b/src/gl/scene/gl_drawinfo.cpp index 08eb3b26d..4dba1a2a0 100644 --- a/src/gl/scene/gl_drawinfo.cpp +++ b/src/gl/scene/gl_drawinfo.cpp @@ -56,6 +56,7 @@ #include "gl/utility/gl_clock.h" #include "gl/utility/gl_templates.h" #include "gl/shaders/gl_shader.h" +#include "gl/stereo3d/scoped_color_mask.h" FDrawInfo * gl_drawinfo; @@ -1009,31 +1010,33 @@ void FDrawInfo::SetupFloodStencil(wallseg * ws) int recursion = GLPortal::GetRecursion(); // Create stencil - glStencilFunc(GL_EQUAL,recursion,~0); // create stencil - glStencilOp(GL_KEEP,GL_KEEP,GL_INCR); // increment stencil of valid pixels - 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); + 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); - gl_RenderState.Apply(); - FFlatVertex *ptr = GLRenderer->mVBO->GetBuffer(); - ptr->Set(ws->x1, ws->z1, ws->y1, 0, 0); - ptr++; - ptr->Set(ws->x1, ws->z2, ws->y1, 0, 0); - ptr++; - ptr->Set(ws->x2, ws->z2, ws->y2, 0, 0); - ptr++; - ptr->Set(ws->x2, ws->z1, ws->y2, 0, 0); - ptr++; - GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_FAN); + gl_RenderState.Apply(); + FFlatVertex *ptr = GLRenderer->mVBO->GetBuffer(); + ptr->Set(ws->x1, ws->z1, ws->y1, 0, 0); + ptr++; + ptr->Set(ws->x1, ws->z2, ws->y1, 0, 0); + ptr++; + ptr->Set(ws->x2, ws->z2, ws->y2, 0, 0); + ptr++; + ptr->Set(ws->x2, ws->z1, ws->y2, 0, 0); + ptr++; + GLRenderer->mVBO->RenderCurrent(ptr, 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); @@ -1045,26 +1048,28 @@ void FDrawInfo::ClearFloodStencil(wallseg * ws) glStencilOp(GL_KEEP,GL_KEEP,GL_DECR); gl_RenderState.EnableTexture(false); - 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 + ScopedColorMask colorMask(0, 0, 0, 0); // glColorMask(0,0,0,0); // don't write to the graphics buffer + gl_RenderState.ResetColor(); - gl_RenderState.Apply(); - FFlatVertex *ptr = GLRenderer->mVBO->GetBuffer(); - ptr->Set(ws->x1, ws->z1, ws->y1, 0, 0); - ptr++; - ptr->Set(ws->x1, ws->z2, ws->y1, 0, 0); - ptr++; - ptr->Set(ws->x2, ws->z2, ws->y2, 0, 0); - ptr++; - ptr->Set(ws->x2, ws->z1, ws->y2, 0, 0); - ptr++; - GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_FAN); + gl_RenderState.Apply(); + FFlatVertex *ptr = GLRenderer->mVBO->GetBuffer(); + ptr->Set(ws->x1, ws->z1, ws->y1, 0, 0); + ptr++; + ptr->Set(ws->x1, ws->z2, ws->y1, 0, 0); + ptr++; + ptr->Set(ws->x2, ws->z2, ws->y2, 0, 0); + ptr++; + ptr->Set(ws->x2, ws->z1, ws->y2, 0, 0); + ptr++; + GLRenderer->mVBO->RenderCurrent(ptr, 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 54bc9b540..7ff82db4c 100644 --- a/src/gl/scene/gl_portal.cpp +++ b/src/gl/scene/gl_portal.cpp @@ -59,6 +59,7 @@ #include "gl/scene/gl_drawinfo.h" #include "gl/scene/gl_portal.h" #include "gl/shaders/gl_shader.h" +#include "gl/stereo3d/scoped_color_mask.h" #include "gl/textures/gl_material.h" #include "gl/utility/gl_clock.h" #include "gl/utility/gl_templates.h" @@ -197,7 +198,7 @@ bool GLPortal::Start(bool usestencil, bool doquery) // Create stencil glStencilFunc(GL_EQUAL,recursion,~0); // create stencil glStencilOp(GL_KEEP,GL_KEEP,GL_INCR); // increment stencil of valid pixels - 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(); @@ -206,34 +207,36 @@ bool GLPortal::Start(bool usestencil, bool doquery) if (NeedDepthBuffer()) { - glDepthMask(false); // don't write to Z-buffer! - if (!NeedDepthBuffer()) doquery = false; // too much overhead and nothing to gain. - else if (gl_noquery) doquery = false; - - // If occlusion query is supported let's use it to avoid rendering portals that aren't visible - if (!QueryObject) glGenQueries(1, &QueryObject); - if (QueryObject) { - glBeginQuery(GL_SAMPLES_PASSED, QueryObject); - } - else doquery = false; // some kind of error happened + ScopedColorMask colorMask(0, 0, 0, 0); + glDepthMask(false); // don't write to Z-buffer! + if (!NeedDepthBuffer()) doquery = false; // too much overhead and nothing to gain. + else if (gl_noquery) doquery = false; - DrawPortalStencil(); + // If occlusion query is supported let's use it to avoid rendering portals that aren't visible + if (!QueryObject) glGenQueries(1, &QueryObject); + if (QueryObject) + { + glBeginQuery(GL_SAMPLES_PASSED, QueryObject); + } + else doquery = false; // some kind of error happened - glEndQuery(GL_SAMPLES_PASSED); + DrawPortalStencil(); - // Clear Z-buffer - glStencilFunc(GL_EQUAL,recursion+1,~0); // draw sky into stencil - glStencilOp(GL_KEEP,GL_KEEP,GL_KEEP); // this stage doesn't modify the stencil - glDepthMask(true); // enable z-buffer again - glDepthRange(1,1); - glDepthFunc(GL_ALWAYS); - DrawPortalStencil(); + glEndQuery(GL_SAMPLES_PASSED); - // set normal drawing mode - gl_RenderState.EnableTexture(true); - glDepthFunc(GL_LESS); - glColorMask(1,1,1,1); + // Clear Z-buffer + glStencilFunc(GL_EQUAL, recursion + 1, ~0); // draw sky into stencil + glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); // this stage doesn't modify the stencil + glDepthMask(true); // enable z-buffer again + glDepthRange(1, 1); + glDepthFunc(GL_ALWAYS); + DrawPortalStencil(); + + // set normal drawing mode + gl_RenderState.EnableTexture(true); + glDepthFunc(GL_LESS); + } // glColorMask(1, 1, 1, 1); gl_RenderState.SetEffect(EFF_NONE); glDepthRange(0, 1); @@ -258,12 +261,13 @@ bool GLPortal::Start(bool usestencil, bool doquery) // than the benefit. // Note: We must draw the stencil with z-write enabled here because there is no second pass! + ScopedColorMask colorMask(0, 0, 0, 0); glDepthMask(true); DrawPortalStencil(); glStencilFunc(GL_EQUAL,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! @@ -369,38 +373,39 @@ void GLPortal::End(bool usestencil) viewangle=savedviewangle; GLRenderer->mViewActor=savedviewactor; in_area=savedviewarea; - GLRenderer->SetupView(viewx, viewy, viewz, viewangle, !!(MirrorFlag&1), !!(PlaneMirrorFlag&1)); + GLRenderer->SetupView(viewx, viewy, viewz, viewangle, !!(MirrorFlag & 1), !!(PlaneMirrorFlag & 1)); - 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 + 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, recursion, ~0); // draw sky into stencil 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,recursion,~0); // draw sky into stencil - DrawPortalStencil(); - glDepthFunc(GL_LESS); + 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); recursion--; // restore old stencil op. @@ -433,14 +438,15 @@ void GLPortal::End(bool usestencil) gl_RenderState.ResetColor(); glDepthFunc(GL_LEQUAL); - glDepthRange(0,1); - glColorMask(0,0,0,0); // no graphics - gl_RenderState.SetEffect(EFF_STENCIL); - gl_RenderState.EnableTexture(false); - DrawPortalStencil(); - gl_RenderState.SetEffect(EFF_NONE); - gl_RenderState.EnableTexture(true); - glColorMask(1,1,1,1); + glDepthRange(0, 1); + { + ScopedColorMask colorMask(0, 0, 0, 0); // glColorMask(0,0,0,0); // no graphics + gl_RenderState.SetEffect(EFF_STENCIL); + gl_RenderState.EnableTexture(false); + DrawPortalStencil(); + gl_RenderState.SetEffect(EFF_NONE); + gl_RenderState.EnableTexture(true); + } // glColorMask(1, 1, 1, 1); glDepthFunc(GL_LESS); } PortalAll.Unclock(); diff --git a/src/gl/scene/gl_scene.cpp b/src/gl/scene/gl_scene.cpp index 3d716e215..618c285c0 100644 --- a/src/gl/scene/gl_scene.cpp +++ b/src/gl/scene/gl_scene.cpp @@ -71,6 +71,8 @@ #include "gl/scene/gl_drawinfo.h" #include "gl/scene/gl_portal.h" #include "gl/shaders/gl_shader.h" +#include "gl/stereo3d/gl_stereo3d.h" +#include "gl/stereo3d/scoped_view_shifter.h" #include "gl/textures/gl_material.h" #include "gl/utility/gl_clock.h" #include "gl/utility/gl_convert.h" @@ -254,6 +256,13 @@ void FGLRenderer::SetProjection(float fov, float ratio, float fovratio) gl_RenderState.Set2DMode(false); } +// raw matrix input from stereo 3d modes +void FGLRenderer::SetProjection(FLOATTYPE matrix[4][4]) +{ + gl_RenderState.mProjectionMatrix.loadMatrix(&matrix[0][0]); + gl_RenderState.Set2DMode(false); +} + //----------------------------------------------------------------------------- // // Setup the modelview matrix @@ -802,18 +811,36 @@ sector_t * FGLRenderer::RenderViewpoint (AActor * camera, GL_IRECT * bounds, flo retval = viewsector; - SetViewport(bounds); - mCurrentFoV = fov; - SetProjection(fov, ratio, fovratio); // switch to perspective mode and set up clipper - SetViewAngle(viewangle); - SetViewMatrix(viewx, viewy, viewz, false, false); - gl_RenderState.ApplyMatrices(); + // Render (potentially) multiple views for stereo 3d + FLOATTYPE projectionMatrix[4][4]; + float viewShift[3]; + const s3d::Stereo3DMode& stereo3dMode = s3d::Stereo3DMode::getCurrentMode(); + stereo3dMode.SetUp(); + s3d::Stereo3DMode::const_iterator eye; + for (eye = stereo3dMode.begin(); eye != stereo3dMode.end(); ++eye) + { + (*eye)->SetUp(); + // TODO: stereo specific viewport - needed when implementing side-by-side modes etc. + SetViewport(bounds); + mCurrentFoV = fov; + // Stereo mode specific perspective projection + (*eye)->GetProjection(fov, ratio, fovratio, projectionMatrix); + SetProjection(projectionMatrix); + SetProjection(fov, ratio, fovratio); // switch to perspective mode and set up clipper + SetViewAngle(viewangle); + // Stereo mode specific viewpoint adjustment - temporarily shifts global viewx, viewy, viewz + (*eye)->GetViewShift(GLRenderer->mAngles.Yaw, viewShift); + s3d::ScopedViewShifter viewShifter(viewShift); + SetViewMatrix(viewx, viewy, viewz, false, false); + gl_RenderState.ApplyMatrices(); - clipper.Clear(); - angle_t a1 = FrustumAngle(); - clipper.SafeAddClipRangeRealAngles(viewangle+a1, viewangle-a1); + clipper.Clear(); + angle_t a1 = FrustumAngle(); + clipper.SafeAddClipRangeRealAngles(viewangle + a1, viewangle - a1); - ProcessScene(toscreen); + ProcessScene(toscreen); + } + stereo3dMode.TearDown(); gl_frameCount++; // This counter must be increased right before the interpolations are restored. interpolator.RestoreInterpolations (); diff --git a/src/gl/stereo3d/gl_anaglyph.cpp b/src/gl/stereo3d/gl_anaglyph.cpp index ff3926cfc..e8be92882 100644 --- a/src/gl/stereo3d/gl_anaglyph.cpp +++ b/src/gl/stereo3d/gl_anaglyph.cpp @@ -11,7 +11,7 @@ MaskAnaglyph::MaskAnaglyph(const ColorMask& leftColorMask, double ipdMeters) /* static */ -const GreenMagenta& GreenMagenta::getInstance(float ipd) +const GreenMagenta& GreenMagenta::getInstance(FLOATTYPE ipd) { static GreenMagenta instance(ipd); return instance; @@ -19,7 +19,7 @@ const GreenMagenta& GreenMagenta::getInstance(float ipd) /* static */ -const RedCyan& RedCyan::getInstance(float ipd) +const RedCyan& RedCyan::getInstance(FLOATTYPE ipd) { static RedCyan instance(ipd); return instance; diff --git a/src/gl/stereo3d/gl_anaglyph.h b/src/gl/stereo3d/gl_anaglyph.h index c95d04205..4be6da99e 100644 --- a/src/gl/stereo3d/gl_anaglyph.h +++ b/src/gl/stereo3d/gl_anaglyph.h @@ -3,6 +3,7 @@ #include "gl_stereo3d.h" #include "gl_stereo_leftright.h" +#include "gl/system/gl_system.h" namespace s3d { diff --git a/src/gl/stereo3d/gl_stereo3d.cpp b/src/gl/stereo3d/gl_stereo3d.cpp index 74b36a0fb..e053266b7 100644 --- a/src/gl/stereo3d/gl_stereo3d.cpp +++ b/src/gl/stereo3d/gl_stereo3d.cpp @@ -6,24 +6,23 @@ namespace s3d { /* virtual */ -void EyePose::GetProjection(float fov, float aspectRatio, float fovRatio, GLdouble m[4][4]) const +void EyePose::GetProjection(FLOATTYPE fov, FLOATTYPE aspectRatio, FLOATTYPE fovRatio, FLOATTYPE m[4][4]) const { // Lifted from gl_scene.cpp FGLRenderer::SetProjection() - float fovy = 2 * RAD2DEG(atan(tan(DEG2RAD(fov) / 2) / fovRatio)); - const double zNear = 5.0; - const double zFar = 65536.0; + double fovy = 2 * RAD2DEG(atan(tan(DEG2RAD(fov) / 2) / fovRatio)); + const FLOATTYPE zNear = 5.0; + const FLOATTYPE zFar = 65536.0; - double sine, cotangent, deltaZ; double radians = fovy / 2 * M_PI / 180; - deltaZ = zFar - zNear; - sine = sin(radians); + FLOATTYPE deltaZ = zFar - zNear; + double sine = sin(radians); if ((deltaZ == 0) || (sine == 0) || (aspectRatio == 0)) { return; } - cotangent = cos(radians) / sine; + FLOATTYPE cotangent = FLOATTYPE(cos(radians) / sine); - memset(m, 0, 16*sizeof(GLdouble)); + memset(m, 0, 16*sizeof(FLOATTYPE)); m[0][0] = cotangent / aspectRatio; m[1][1] = cotangent; m[2][2] = -(zFar + zNear) / deltaZ; @@ -40,7 +39,7 @@ Viewport EyePose::GetViewport(const Viewport& fullViewport) const /* virtual */ -void EyePose::GetViewShift(float yaw, float outViewShift[3]) const +void EyePose::GetViewShift(FLOATTYPE yaw, FLOATTYPE outViewShift[3]) const { // pass-through for Mono view outViewShift[0] = 0; diff --git a/src/gl/stereo3d/gl_stereo3d.h b/src/gl/stereo3d/gl_stereo3d.h index ddbaafaf2..6421b2a9e 100644 --- a/src/gl/stereo3d/gl_stereo3d.h +++ b/src/gl/stereo3d/gl_stereo3d.h @@ -2,7 +2,7 @@ #define GL_STEREO3D_H_ #include -#include "gl/system/gl_system.h" +#include "gl/data/gl_matrix.h" /* stereoscopic 3D API */ @@ -24,9 +24,9 @@ class EyePose public: EyePose() {} virtual ~EyePose() {} - virtual void GetProjection(float fov, float aspectRatio, float fovRatio, GLdouble outMatrix[4][4]) const; + virtual void GetProjection(FLOATTYPE fov, FLOATTYPE aspectRatio, FLOATTYPE fovRatio, FLOATTYPE outMatrix[4][4]) const; virtual Viewport GetViewport(const Viewport& fullViewport) const; - virtual void GetViewShift(float yaw, float outViewShift[3]) const; + virtual void GetViewShift(FLOATTYPE yaw, FLOATTYPE outViewShift[3]) const; virtual void SetUp() const {}; virtual void TearDown() const {}; }; diff --git a/src/gl/stereo3d/gl_stereo_cvars.cpp b/src/gl/stereo3d/gl_stereo_cvars.cpp index e9d115080..b91a47daa 100644 --- a/src/gl/stereo3d/gl_stereo_cvars.cpp +++ b/src/gl/stereo3d/gl_stereo_cvars.cpp @@ -33,10 +33,11 @@ const Stereo3DMode& Stereo3DMode::getCurrentMode() case 2: setCurrentMode(RedCyan::getInstance(vr_ipd)); break; - case 3: + // TODO: missing indices 3, 4 for not-yet-implemented side-by-side modes, to match values from GZ3Doom + case 5: setCurrentMode(LeftEyeView::getInstance(vr_ipd)); break; - case 4: + case 6: setCurrentMode(RightEyeView::getInstance(vr_ipd)); break; case 0: diff --git a/src/gl/stereo3d/gl_stereo_leftright.cpp b/src/gl/stereo3d/gl_stereo_leftright.cpp index fd1f97729..58cbb086e 100644 --- a/src/gl/stereo3d/gl_stereo_leftright.cpp +++ b/src/gl/stereo3d/gl_stereo_leftright.cpp @@ -11,10 +11,10 @@ namespace s3d { /* virtual */ -void ShiftedEyePose::GetProjection(float fov, float aspectRatio, float fovRatio, GLdouble m[4][4]) const +void ShiftedEyePose::GetProjection(FLOATTYPE fov, FLOATTYPE aspectRatio, FLOATTYPE fovRatio, FLOATTYPE m[4][4]) const { // Lifted from gl_scene.cpp FGLRenderer::SetProjection() - float fovy = 2 * RAD2DEG(atan(tan(DEG2RAD(fov) / 2) / fovRatio)); + FLOATTYPE fovy = 2 * RAD2DEG(atan(tan(DEG2RAD(fov) / 2) / fovRatio)); double zNear = 5.0; double zFar = 65536.0; @@ -33,7 +33,7 @@ void ShiftedEyePose::GetProjection(float fov, float aspectRatio, float fovRatio, double top = fH; double deltaZ = zFar - zNear; - memset(m, 0, 16 * sizeof(GLdouble)); // set all elements to zero, cleverly + memset(m, 0, 16 * sizeof(FLOATTYPE)); // set all elements to zero, cleverly // https://www.opengl.org/sdk/docs/man2/xhtml/glFrustum.xml m[0][0] = 2 * zNear / (right - left); @@ -48,10 +48,10 @@ void ShiftedEyePose::GetProjection(float fov, float aspectRatio, float fovRatio, /* virtual */ -void ShiftedEyePose::GetViewShift(float yaw, float outViewShift[3]) const +void ShiftedEyePose::GetViewShift(FLOATTYPE yaw, FLOATTYPE outViewShift[3]) const { - float dx = cos(DEG2RAD(yaw)) * vr_hunits_per_meter * shift; - float dy = sin(DEG2RAD(yaw)) * vr_hunits_per_meter * shift; + FLOATTYPE dx = cos(DEG2RAD(yaw)) * vr_hunits_per_meter * shift; + FLOATTYPE dy = sin(DEG2RAD(yaw)) * vr_hunits_per_meter * shift; outViewShift[0] = dx; outViewShift[1] = dy; outViewShift[2] = 0; @@ -59,7 +59,7 @@ void ShiftedEyePose::GetViewShift(float yaw, float outViewShift[3]) const /* static */ -const LeftEyeView& LeftEyeView::getInstance(float ipd) +const LeftEyeView& LeftEyeView::getInstance(FLOATTYPE ipd) { static LeftEyeView instance(ipd); instance.setIpd(ipd); @@ -68,7 +68,7 @@ const LeftEyeView& LeftEyeView::getInstance(float ipd) /* static */ -const RightEyeView& RightEyeView::getInstance(float ipd) +const RightEyeView& RightEyeView::getInstance(FLOATTYPE ipd) { static RightEyeView instance(ipd); instance.setIpd(ipd); diff --git a/src/gl/stereo3d/gl_stereo_leftright.h b/src/gl/stereo3d/gl_stereo_leftright.h index 78f66e7fe..228b6459f 100644 --- a/src/gl/stereo3d/gl_stereo_leftright.h +++ b/src/gl/stereo3d/gl_stereo_leftright.h @@ -9,31 +9,31 @@ namespace s3d { class ShiftedEyePose : public EyePose { public: - ShiftedEyePose(float shift) : shift(shift) {}; - float getShift() const { return shift; } - void setShift(float shift) { this->shift = shift; } - virtual void GetProjection(float fov, float aspectRatio, float fovRatio, GLdouble outMatrix[4][4]) const; - virtual void GetViewShift(float yaw, float outViewShift[3]) const; + ShiftedEyePose(FLOATTYPE shift) : shift(shift) {}; + FLOATTYPE getShift() const { return shift; } + void setShift(FLOATTYPE shift) { this->shift = shift; } + virtual void GetProjection(FLOATTYPE fov, FLOATTYPE aspectRatio, FLOATTYPE fovRatio, FLOATTYPE outMatrix[4][4]) const; + virtual void GetViewShift(FLOATTYPE yaw, FLOATTYPE outViewShift[3]) const; protected: - float shift; + FLOATTYPE shift; }; class LeftEyePose : public ShiftedEyePose { public: - LeftEyePose(float ipd) : ShiftedEyePose(-0.5*ipd) {} - float getIpd() const { return -2.0*getShift(); } - void setIpd(float ipd) { setShift(-0.5*ipd); } + LeftEyePose(FLOATTYPE ipd) : ShiftedEyePose( FLOATTYPE(-0.5) * ipd) {} + FLOATTYPE getIpd() const { return FLOATTYPE(-2.0)*getShift(); } + void setIpd(FLOATTYPE ipd) { setShift(FLOATTYPE(-0.5)*ipd); } }; class RightEyePose : public ShiftedEyePose { public: - RightEyePose(float ipd) : ShiftedEyePose(+0.5*ipd) {} - float getIpd() const { return +2.0*shift; } - void setIpd(float ipd) { setShift(+0.5*ipd); } + RightEyePose(FLOATTYPE ipd) : ShiftedEyePose(FLOATTYPE(+0.5)*ipd) {} + FLOATTYPE getIpd() const { return FLOATTYPE(+2.0)*shift; } + void setIpd(FLOATTYPE ipd) { setShift(FLOATTYPE(+0.5)*ipd); } }; @@ -43,11 +43,11 @@ public: class LeftEyeView : public Stereo3DMode { public: - static const LeftEyeView& getInstance(float ipd); + static const LeftEyeView& getInstance(FLOATTYPE ipd); - LeftEyeView(float ipd) : eye(ipd) { eye_ptrs.push_back(&eye); } - float getIpd() const { return eye.getIpd(); } - void setIpd(float ipd) { eye.setIpd(ipd); } + LeftEyeView(FLOATTYPE ipd) : eye(ipd) { eye_ptrs.push_back(&eye); } + FLOATTYPE getIpd() const { return eye.getIpd(); } + void setIpd(FLOATTYPE ipd) { eye.setIpd(ipd); } protected: LeftEyePose eye; }; @@ -56,11 +56,11 @@ protected: class RightEyeView : public Stereo3DMode { public: - static const RightEyeView& getInstance(float ipd); + static const RightEyeView& getInstance(FLOATTYPE ipd); - RightEyeView(float ipd) : eye(ipd) { eye_ptrs.push_back(&eye); } - float getIpd() const { return eye.getIpd(); } - void setIpd(float ipd) { eye.setIpd(ipd); } + RightEyeView(FLOATTYPE ipd) : eye(ipd) { eye_ptrs.push_back(&eye); } + FLOATTYPE getIpd() const { return eye.getIpd(); } + void setIpd(FLOATTYPE ipd) { eye.setIpd(ipd); } protected: RightEyePose eye; }; diff --git a/src/gl/stereo3d/scoped_color_mask.h b/src/gl/stereo3d/scoped_color_mask.h index cc3a1df1d..f746ba9e4 100644 --- a/src/gl/stereo3d/scoped_color_mask.h +++ b/src/gl/stereo3d/scoped_color_mask.h @@ -1,7 +1,7 @@ #ifndef GL_STEREO3D_SCOPED_COLOR_MASK_H_ #define GL_STEREO3D_SCOPED_COLOR_MASK_H_ -#include "gl/glew.h" +#include "gl/system/gl_system.h" /** * Temporarily change color mask @@ -10,28 +10,15 @@ class ScopedColorMask { public: ScopedColorMask(GLboolean r, GLboolean g, GLboolean b, GLboolean a) - : isPushed(false) { - setColorMask(r, g, b, a); - } - ~ScopedColorMask() { - revert(); - } - void setColorMask(GLboolean r, GLboolean g, GLboolean b, GLboolean a) { - if (!isPushed) { - glPushAttrib(GL_COLOR_BUFFER_BIT); - isPushed = true; - } + glGetBooleanv(GL_COLOR_WRITEMASK, saved); glColorMask(r, g, b, a); } - void revert() { - if (isPushed) { - glPopAttrib(); - isPushed = false; - } + ~ScopedColorMask() { + glColorMask(saved[0], saved[1], saved[2], saved[3]); } private: - bool isPushed; + GLboolean saved[4]; }; diff --git a/wadsrc/static/menudef.z b/wadsrc/static/menudef.z index 75ea1bf5f..3874b0328 100644 --- a/wadsrc/static/menudef.z +++ b/wadsrc/static/menudef.z @@ -124,6 +124,15 @@ OptionValue "FuzzStyle" //5, "Jagged fuzz" I can't see any difference between this and 4 so it's disabled for now. } +OptionValue VRMode +{ + 0, "Normal" + 1, "Green/Magenta" + 2, "Red/Cyan" + 5, "Left Eye" + 6, "Right Eye" +} + OptionMenu "GLTextureGLOptions" { Title "TEXTURE OPTIONS" @@ -173,5 +182,6 @@ OptionMenu "GLPrefOptions" Option "Particle style", gl_particles_style, "Particles" Slider "Ambient light level", gl_light_ambient, 1.0, 255.0, 5.0 Option "Rendering quality", gl_render_precise, "Precision" + Option "Stereo 3D VR", vr_mode, "VRMode" }