Copy stereo3d source files from my GLOOME fork.

This commit is contained in:
Christopher Bruns 2015-10-26 09:08:18 -04:00
parent 4e1723eeb7
commit 694dff67e4
10 changed files with 548 additions and 0 deletions

View File

@ -0,0 +1,29 @@
#include "gl_anaglyph.h"
namespace s3d {
MaskAnaglyph::MaskAnaglyph(const ColorMask& leftColorMask, double ipdMeters)
: leftEye(leftColorMask, ipdMeters), rightEye(leftColorMask.inverse(), ipdMeters)
{
eye_ptrs.push_back(&leftEye);
eye_ptrs.push_back(&rightEye);
}
/* 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;
}
} /* namespace s3d */

View File

@ -0,0 +1,75 @@
#ifndef GL_ANAGLYPH_H_
#define GL_ANAGLYPH_H_
#include "gl_stereo3d.h"
#include "gl_stereo_leftright.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); }
GLboolean r;
GLboolean g;
GLboolean b;
};
class AnaglyphLeftPose : public LeftEyePose
{
public:
AnaglyphLeftPose(const ColorMask& colorMask, float ipd) : LeftEyePose(ipd), colorMask(colorMask) {}
virtual void SetUp() const { glColorMask(colorMask.r, colorMask.g, colorMask.b, true); }
virtual void TearDown() const { glColorMask(1,1,1,1); }
private:
ColorMask colorMask;
};
class AnaglyphRightPose : public RightEyePose
{
public:
AnaglyphRightPose(const ColorMask& colorMask, float ipd) : RightEyePose(ipd), colorMask(colorMask) {}
virtual void SetUp() const { glColorMask(colorMask.r, colorMask.g, colorMask.b, true); }
virtual void TearDown() const { glColorMask(1,1,1,1); }
private:
ColorMask colorMask;
};
class MaskAnaglyph : public Stereo3DMode
{
public:
MaskAnaglyph(const ColorMask& leftColorMask, double ipdMeters);
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) {}
};
// TODO matrix anaglyph
} /* namespace st3d */
#endif /* GL_ANAGLYPH_H_ */

View File

@ -0,0 +1,71 @@
#include "gl/stereo3d/gl_stereo3d.h"
#include "vectors.h" // RAD2DEG
#include "doomtype.h" // M_PI
namespace s3d {
/* virtual */
void EyePose::GetProjection(float fov, float aspectRatio, float fovRatio, GLdouble m[4][4]) const
{
// Lifted from gl_scene.cpp FGLRenderer::SetProjection()
float fovy = 2 * RAD2DEG(atan(tan(DEG2RAD(fov) / 2) / fovRatio));
const double zNear = 5.0;
const double zFar = 65536.0;
double sine, cotangent, deltaZ;
double radians = fovy / 2 * M_PI / 180;
deltaZ = zFar - zNear;
sine = sin(radians);
if ((deltaZ == 0) || (sine == 0) || (aspectRatio == 0)) {
return;
}
cotangent = cos(radians) / sine;
memset(m, 0, 16*sizeof(GLdouble));
m[0][0] = cotangent / aspectRatio;
m[1][1] = cotangent;
m[2][2] = -(zFar + zNear) / deltaZ;
m[2][3] = -1;
m[3][2] = -2 * zNear * zFar / deltaZ;
m[3][3] = 0;
}
/* virtual */
Viewport EyePose::GetViewport(const Viewport& fullViewport) const
{
return fullViewport;
}
/* virtual */
void EyePose::GetViewShift(float yaw, float outViewShift[3]) const
{
// pass-through for Mono view
outViewShift[0] = 0;
outViewShift[1] = 0;
outViewShift[2] = 0;
}
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 */

View File

@ -0,0 +1,80 @@
#ifndef GL_STEREO3D_H_
#define GL_STEREO3D_H_
#include <vector>
#include "gl/system/gl_system.h"
/* stereoscopic 3D API */
namespace s3d {
/* Subregion of current display window */
class Viewport
{
public:
int x, y;
int width, height;
};
/* Viewpoint of one eye */
class EyePose
{
public:
EyePose() {}
virtual ~EyePose() {}
virtual void GetProjection(float fov, float aspectRatio, float fovRatio, GLdouble outMatrix[4][4]) const;
virtual Viewport GetViewport(const Viewport& fullViewport) const;
virtual void GetViewShift(float yaw, float outViewShift[3]) const;
virtual void SetUp() const {};
virtual void TearDown() const {};
};
/* Base class for stereoscopic 3D rendering modes */
class Stereo3DMode
{
public:
/* const_iterator cycles through the various eye viewpoints */
typedef std::vector<const EyePose *>::const_iterator const_iterator;
/* static methods for managing the selected stereoscopic view state */
static const Stereo3DMode& getCurrentMode();
Stereo3DMode();
virtual ~Stereo3DMode();
/* const_iterator cycles through the various eye viewpoints */
virtual const_iterator begin() const { return eye_ptrs.begin(); }
virtual const_iterator end() const { return eye_ptrs.end(); }
/* hooks for setup and cleanup operations for each stereo mode */
virtual void SetUp() const {};
virtual void TearDown() const {};
protected:
std::vector<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();
protected:
MonoView() { eye_ptrs.push_back(&centralEye); }
EyePose centralEye;
};
} /* namespace st3d */
#endif /* GL_STEREO3D_H_ */

View File

@ -0,0 +1,51 @@
#include "gl/stereo3d/gl_stereo3d.h"
#include "gl/stereo3d/gl_stereo_leftright.h"
#include "gl/stereo3d/gl_anaglyph.h"
#include "gl/system/gl_cvars.h"
// Set up 3D-specific console variables:
CVAR(Int, vr_mode, 0, CVAR_GLOBALCONFIG)
// intraocular distance in meters
CVAR(Float, vr_ipd, 0.062f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) // METERS
CVAR(Float, vr_screendist, 0.80f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) // 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 = nullptr;
/* 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(LeftEyeView::getInstance(vr_ipd));
break;
case 4:
setCurrentMode(RightEyeView::getInstance(vr_ipd));
break;
case 0:
default:
setCurrentMode(MonoView::getInstance());
break;
}
return *currentStereo3DMode;
}
} /* namespace s3d */

View File

@ -0,0 +1,79 @@
#include "gl_stereo_leftright.h"
#include "vectors.h" // RAD2DEG
#include "doomtype.h" // M_PI
#include "gl/system/gl_cvars.h"
#include <cmath>
EXTERN_CVAR(Float, vr_screendist)
EXTERN_CVAR(Float, vr_hunits_per_meter)
namespace s3d {
/* virtual */
void ShiftedEyePose::GetProjection(float fov, float aspectRatio, float fovRatio, GLdouble m[4][4]) const
{
// Lifted from gl_scene.cpp FGLRenderer::SetProjection()
float fovy = 2 * RAD2DEG(atan(tan(DEG2RAD(fov) / 2) / fovRatio));
double zNear = 5.0;
double zFar = 65536.0;
// For stereo 3D, use asymmetric frustum shift in projection matrix
// Q: shouldn't shift vary with roll angle, at least for desktop display?
// A: (lab) roll is not measured on desktop display (yet)
double frustumShift = zNear * shift / vr_screendist; // meters cancel
// double frustumShift = 0; // Turning off shift for debugging
double fH = tan(fovy / 360 * M_PI) * zNear;
double fW = fH * aspectRatio;
// Emulate glFrustum command:
// glFrustum(-fW - frustumShift, fW - frustumShift, -fH, fH, zNear, zFar);
double left = -fW - frustumShift;
double right = fW - frustumShift;
double bottom = -fH;
double top = fH;
double deltaZ = zFar - zNear;
memset(m, 0, 16 * sizeof(GLdouble)); // set all elements to zero, cleverly
// https://www.opengl.org/sdk/docs/man2/xhtml/glFrustum.xml
m[0][0] = 2 * zNear / (right - left);
m[1][1] = 2 * zNear / (top - bottom);
m[2][2] = -(zFar + zNear) / deltaZ;
m[2][3] = -1;
m[3][2] = -2 * zNear * zFar / deltaZ;
// m[3][3] = 0; // redundant
// m[2][1] = (top + bottom) / (top - bottom); // zero for the cases I know of...
m[2][0] = (right + left) / (right - left); // asymmetric shift is in this term
}
/* virtual */
void ShiftedEyePose::GetViewShift(float yaw, float outViewShift[3]) const
{
float dx = cos(DEG2RAD(yaw)) * vr_hunits_per_meter * shift;
float dy = sin(DEG2RAD(yaw)) * vr_hunits_per_meter * shift;
outViewShift[0] = dx;
outViewShift[1] = dy;
outViewShift[2] = 0;
}
/* static */
const LeftEyeView& LeftEyeView::getInstance(float ipd)
{
static LeftEyeView instance(ipd);
instance.setIpd(ipd);
return instance;
}
/* static */
const RightEyeView& RightEyeView::getInstance(float ipd)
{
static RightEyeView instance(ipd);
instance.setIpd(ipd);
return instance;
}
} /* namespace s3d */

View File

@ -0,0 +1,71 @@
#ifndef GL_STEREO_LEFTRIGHT_H_
#define GL_STEREO_LEFTRIGHT_H_
#include "gl_stereo3d.h"
namespace s3d {
class ShiftedEyePose : public EyePose
{
public:
ShiftedEyePose(float shift) : shift(shift) {};
float getShift() const { return shift; }
void setShift(float shift) { this->shift = shift; }
virtual void GetProjection(float fov, float aspectRatio, float fovRatio, GLdouble outMatrix[4][4]) const;
virtual void GetViewShift(float yaw, float outViewShift[3]) const;
protected:
float shift;
};
class LeftEyePose : public ShiftedEyePose
{
public:
LeftEyePose(float ipd) : ShiftedEyePose(-0.5*ipd) {}
float getIpd() const { return -2.0*getShift(); }
void setIpd(float ipd) { setShift(-0.5*ipd); }
};
class RightEyePose : public ShiftedEyePose
{
public:
RightEyePose(float ipd) : ShiftedEyePose(+0.5*ipd) {}
float getIpd() const { return +2.0*shift; }
void setIpd(float ipd) { setShift(+0.5*ipd); }
};
/**
* 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_back(&eye); }
float getIpd() const { return eye.getIpd(); }
void setIpd(float ipd) { eye.setIpd(ipd); }
protected:
LeftEyePose eye;
};
class RightEyeView : public Stereo3DMode
{
public:
static const RightEyeView& getInstance(float ipd);
RightEyeView(float ipd) : eye(ipd) { eye_ptrs.push_back(&eye); }
float getIpd() const { return eye.getIpd(); }
void setIpd(float ipd) { eye.setIpd(ipd); }
protected:
RightEyePose eye;
};
} /* namespace s3d */
#endif /* GL_STEREO_LEFTRIGHT_H_ */

View File

@ -0,0 +1,38 @@
#ifndef GL_STEREO3D_SCOPED_COLOR_MASK_H_
#define GL_STEREO3D_SCOPED_COLOR_MASK_H_
#include "gl/glew.h"
/**
* Temporarily change color mask
*/
class ScopedColorMask
{
public:
ScopedColorMask(GLboolean r, GLboolean g, GLboolean b, GLboolean a)
: isPushed(false)
{
setColorMask(r, g, b, a);
}
~ScopedColorMask() {
revert();
}
void setColorMask(GLboolean r, GLboolean g, GLboolean b, GLboolean a) {
if (!isPushed) {
glPushAttrib(GL_COLOR_BUFFER_BIT);
isPushed = true;
}
glColorMask(r, g, b, a);
}
void revert() {
if (isPushed) {
glPopAttrib();
isPushed = false;
}
}
private:
bool isPushed;
};
#endif // GL_STEREO3D_SCOPED_COLOR_MASK_H_

View File

@ -0,0 +1,29 @@
#include "scoped_view_shifter.h"
#include "r_utility.h"
namespace s3d {
ScopedViewShifter::ScopedViewShifter(float dxyz[3]) // in meters
{
// save original values
cachedViewx = viewx;
cachedViewy = viewy;
cachedViewz = viewz;
// modify values
float fViewx = FIXED2FLOAT(viewx) - dxyz[0];
float fViewy = FIXED2FLOAT(viewy) + dxyz[1];
float fViewz = FIXED2FLOAT(viewz) + dxyz[2];
viewx = FLOAT2FIXED(fViewx);
viewy = FLOAT2FIXED(fViewy);
viewz = FLOAT2FIXED(fViewz);
}
ScopedViewShifter::~ScopedViewShifter()
{
// restore original values
viewx = cachedViewx;
viewy = cachedViewy;
viewz = cachedViewz;
}
}

View File

@ -0,0 +1,25 @@
#ifndef GL_STEREO3D_SCOPED_VIEW_SHIFTER_H_
#define GL_STEREO3D_SCOPED_VIEW_SHIFTER_H_
#include "basictypes.h"
namespace s3d {
/**
* Temporarily shift viewx, viewy, viewz
*/
class ScopedViewShifter
{
public:
ScopedViewShifter(float dxyz[3]); // in meters
~ScopedViewShifter();
private:
fixed_t cachedViewx;
fixed_t cachedViewy;
fixed_t cachedViewz;
};
} /* namespace s3d */
#endif // GL_STEREO3D_SCOPED_VIEW_SHIFTER_H_