mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-11 07:11:54 +00:00
- refactored the entire Stereo3D system to get rid of the class hierarchy and all its ugly implications.
Ultimately all this needs is a small data table describing the geometric properties of each mode and a single Present function that calls the mode specific variants. Code size got reduced from 50kb to less than 20kb with proper separation of the generic parts from the OpenGL parts.
This commit is contained in:
parent
036307927a
commit
c3d5b960ee
29 changed files with 687 additions and 1723 deletions
|
@ -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/.+")
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -127,6 +127,7 @@ public:
|
|||
void SetupLevel();
|
||||
void ResetSWScene();
|
||||
|
||||
void PresentStereo();
|
||||
void RenderScreenQuad();
|
||||
void PostProcessScene(int fixedcm, const std::function<void()> &afterBloomDrawEndScene2D);
|
||||
void AmbientOccludeScene(float m5);
|
||||
|
|
364
src/gl/renderer/gl_stereo3d.cpp
Normal file
364
src/gl/renderer/gl_stereo3d.cpp
Normal file
|
@ -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<float>(Gamma, 0.1f, 4.f);
|
||||
shader.Uniforms->Contrast = clamp<float>(vid_contrast, 0.1f, 3.f);
|
||||
shader.Uniforms->Brightness = clamp<float>(vid_brightness, -0.8f, 0.8f);
|
||||
shader.Uniforms->Saturation = clamp<float>(vid_saturation, -15.0f, 15.0f);
|
||||
shader.Uniforms->GrayFormula = static_cast<int>(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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 */
|
|
@ -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_ */
|
|
@ -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<float>(Gamma, 0.1f, 4.f);
|
||||
shader.Uniforms->Contrast = clamp<float>(vid_contrast, 0.1f, 3.f);
|
||||
shader.Uniforms->Brightness = clamp<float>(vid_brightness, -0.8f, 0.8f);
|
||||
shader.Uniforms->Saturation = clamp<float>(vid_saturation, -15.0f, 15.0f);
|
||||
shader.Uniforms->GrayFormula = static_cast<int>(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 */
|
|
@ -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_ */
|
|
@ -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<QuadStereo*>(this)->checkInitialRenderContextState();
|
||||
}
|
||||
|
||||
/* static */
|
||||
const QuadStereo& QuadStereo::getInstance(float ipd)
|
||||
{
|
||||
static QuadStereo instance(ipd);
|
||||
return instance;
|
||||
}
|
||||
|
||||
} /* namespace s3d */
|
|
@ -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_ */
|
|
@ -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 */
|
|
@ -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_ */
|
|
@ -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 */
|
|
@ -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 <cstring> // 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<const EyePose *> 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_ */
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
|
@ -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_ */
|
|
@ -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_
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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); }
|
||||
};
|
176
src/hwrenderer/utility/hw_vrmodes.cpp
Normal file
176
src/hwrenderer/utility/hw_vrmodes.cpp
Normal file
|
@ -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 };
|
||||
}
|
||||
}
|
||||
|
46
src/hwrenderer/utility/hw_vrmodes.h
Normal file
46
src/hwrenderer/utility/hw_vrmodes.h
Normal file
|
@ -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;
|
||||
};
|
|
@ -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_
|
Loading…
Reference in a new issue