mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-23 04:22:34 +00:00
Merge commit 'refs/pull/336/head' of https://github.com/coelckers/gzdoom
This commit is contained in:
commit
a05c38fefd
14 changed files with 802 additions and 10 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -50,3 +50,4 @@
|
||||||
/llvm
|
/llvm
|
||||||
/src/r_drawersasm.obj
|
/src/r_drawersasm.obj
|
||||||
/src/r_drawersasm.o
|
/src/r_drawersasm.o
|
||||||
|
/build_cmake
|
||||||
|
|
|
@ -300,6 +300,8 @@ endif()
|
||||||
|
|
||||||
set( LZMA_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/lzma/C" )
|
set( LZMA_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/lzma/C" )
|
||||||
|
|
||||||
|
option( GZDOOM_USE_OPENVR "Support OpenVR API for virtual reality head mounted displays" OFF )
|
||||||
|
|
||||||
if( NOT CMAKE_CROSSCOMPILING )
|
if( NOT CMAKE_CROSSCOMPILING )
|
||||||
if( NOT CROSS_EXPORTS )
|
if( NOT CROSS_EXPORTS )
|
||||||
set( CROSS_EXPORTS "" )
|
set( CROSS_EXPORTS "" )
|
||||||
|
|
|
@ -473,6 +473,29 @@ if( NOT DYN_FLUIDSYNTH )
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if (GZDOOM_USE_OPENVR)
|
||||||
|
find_path(OPENVR_SDK_PATH
|
||||||
|
NAMES
|
||||||
|
headers/openvr.h
|
||||||
|
PATHS
|
||||||
|
C:/Users/cmbruns/git/openvr
|
||||||
|
)
|
||||||
|
find_path(OPENVR_INCLUDE_DIRECTORY
|
||||||
|
NAMES
|
||||||
|
openvr.h
|
||||||
|
PATHS
|
||||||
|
${OPENVR_SDK_PATH}/headers
|
||||||
|
)
|
||||||
|
include_directories("${OPENVR_INCLUDE_DIRECTORY}")
|
||||||
|
find_library(OPENVR_LIBRARY
|
||||||
|
NAMES openvr_api
|
||||||
|
# TODO: Generalize for Mac and Linux and 64-bit Windows
|
||||||
|
PATHS "${OPENVR_SDK_PATH}/lib/win32/"
|
||||||
|
)
|
||||||
|
list(APPEND ZDOOM_LIBS ${OPENVR_LIBRARY})
|
||||||
|
add_definitions("-DUSE_OPENVR")
|
||||||
|
endif()
|
||||||
|
|
||||||
# Start defining source files for ZDoom
|
# Start defining source files for ZDoom
|
||||||
set( PLAT_WIN32_SOURCES
|
set( PLAT_WIN32_SOURCES
|
||||||
sound/mididevices/music_win_mididevice.cpp
|
sound/mididevices/music_win_mididevice.cpp
|
||||||
|
@ -805,6 +828,7 @@ set( FASTMATH_SOURCES
|
||||||
gl/scene/gl_vertex.cpp
|
gl/scene/gl_vertex.cpp
|
||||||
gl/scene/gl_spritelight.cpp
|
gl/scene/gl_spritelight.cpp
|
||||||
gl/dynlights/gl_dynlight1.cpp
|
gl/dynlights/gl_dynlight1.cpp
|
||||||
|
gl/dynlights/gl_dynlight1.cpp
|
||||||
gl/system/gl_load.c
|
gl/system/gl_load.c
|
||||||
gl/models/gl_models.cpp
|
gl/models/gl_models.cpp
|
||||||
)
|
)
|
||||||
|
@ -1006,6 +1030,7 @@ set (PCH_SOURCES
|
||||||
gl/stereo3d/gl_stereo_leftright.cpp
|
gl/stereo3d/gl_stereo_leftright.cpp
|
||||||
gl/stereo3d/scoped_view_shifter.cpp
|
gl/stereo3d/scoped_view_shifter.cpp
|
||||||
gl/stereo3d/gl_anaglyph.cpp
|
gl/stereo3d/gl_anaglyph.cpp
|
||||||
|
gl/stereo3d/gl_openvr.cpp
|
||||||
gl/stereo3d/gl_quadstereo.cpp
|
gl/stereo3d/gl_quadstereo.cpp
|
||||||
gl/stereo3d/gl_sidebyside3d.cpp
|
gl/stereo3d/gl_sidebyside3d.cpp
|
||||||
gl/stereo3d/gl_interleaved3d.cpp
|
gl/stereo3d/gl_interleaved3d.cpp
|
||||||
|
|
|
@ -62,7 +62,7 @@ class VSMatrix {
|
||||||
void perspective(FLOATTYPE fov, FLOATTYPE ratio, FLOATTYPE nearp, FLOATTYPE farp);
|
void perspective(FLOATTYPE fov, FLOATTYPE ratio, FLOATTYPE nearp, FLOATTYPE farp);
|
||||||
void ortho(FLOATTYPE left, FLOATTYPE right, FLOATTYPE bottom, FLOATTYPE top, FLOATTYPE nearp=-1.0f, FLOATTYPE farp=1.0f);
|
void ortho(FLOATTYPE left, FLOATTYPE right, FLOATTYPE bottom, FLOATTYPE top, FLOATTYPE nearp=-1.0f, FLOATTYPE farp=1.0f);
|
||||||
void frustum(FLOATTYPE left, FLOATTYPE right, FLOATTYPE bottom, FLOATTYPE top, FLOATTYPE nearp, FLOATTYPE farp);
|
void frustum(FLOATTYPE left, FLOATTYPE right, FLOATTYPE bottom, FLOATTYPE top, FLOATTYPE nearp, FLOATTYPE farp);
|
||||||
void copy(FLOATTYPE * pDest)
|
void copy(FLOATTYPE * pDest) const
|
||||||
{
|
{
|
||||||
memcpy(pDest, mMatrix, 16 * sizeof(FLOATTYPE));
|
memcpy(pDest, mMatrix, 16 * sizeof(FLOATTYPE));
|
||||||
}
|
}
|
||||||
|
|
|
@ -458,7 +458,8 @@ void FGLRenderBuffers::CreateEyeBuffers(int eye)
|
||||||
|
|
||||||
while (mEyeFBs.Size() <= unsigned(eye))
|
while (mEyeFBs.Size() <= unsigned(eye))
|
||||||
{
|
{
|
||||||
GLuint texture = Create2DTexture("EyeTexture", GL_RGBA16F, mWidth, mHeight);
|
// GL_RGBA16F, GL_RGBA16, GL_RGBA32F all do not work with OpenVR and HTC Vive
|
||||||
|
GLuint texture = Create2DTexture("EyeTexture", GL_RGBA12, mWidth, mHeight);
|
||||||
mEyeTextures.Push(texture);
|
mEyeTextures.Push(texture);
|
||||||
mEyeFBs.Push(CreateFrameBuffer("EyeFB", texture));
|
mEyeFBs.Push(CreateFrameBuffer("EyeFB", texture));
|
||||||
}
|
}
|
||||||
|
@ -485,6 +486,7 @@ GLuint FGLRenderBuffers::Create2DTexture(const FString &name, GLuint format, int
|
||||||
switch (format)
|
switch (format)
|
||||||
{
|
{
|
||||||
case GL_RGBA8: dataformat = GL_RGBA; datatype = GL_UNSIGNED_BYTE; break;
|
case GL_RGBA8: dataformat = GL_RGBA; datatype = GL_UNSIGNED_BYTE; break;
|
||||||
|
case GL_RGBA12: dataformat = GL_RGBA; datatype = GL_UNSIGNED_SHORT; break;
|
||||||
case GL_RGBA16: dataformat = GL_RGBA; datatype = GL_UNSIGNED_SHORT; break;
|
case GL_RGBA16: dataformat = GL_RGBA; datatype = GL_UNSIGNED_SHORT; break;
|
||||||
case GL_RGBA16F: dataformat = GL_RGBA; datatype = GL_FLOAT; break;
|
case GL_RGBA16F: dataformat = GL_RGBA; datatype = GL_FLOAT; break;
|
||||||
case GL_RGBA32F: dataformat = GL_RGBA; datatype = GL_FLOAT; break;
|
case GL_RGBA32F: dataformat = GL_RGBA; datatype = GL_FLOAT; break;
|
||||||
|
@ -740,6 +742,10 @@ void FGLRenderBuffers::BindEyeFB(int eye, bool readBuffer)
|
||||||
glBindFramebuffer(readBuffer ? GL_READ_FRAMEBUFFER : GL_FRAMEBUFFER, mEyeFBs[eye]);
|
glBindFramebuffer(readBuffer ? GL_READ_FRAMEBUFFER : GL_FRAMEBUFFER, mEyeFBs[eye]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GLuint FGLRenderBuffers::GetEyeTextureGLHandle(int eye) const { // Needed for OpenVR API
|
||||||
|
return mEyeTextures[eye];
|
||||||
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
// Shadow map texture and frame buffers
|
// Shadow map texture and frame buffers
|
||||||
|
|
|
@ -50,6 +50,7 @@ public:
|
||||||
void BlitToEyeTexture(int eye);
|
void BlitToEyeTexture(int eye);
|
||||||
void BindEyeTexture(int eye, int texunit);
|
void BindEyeTexture(int eye, int texunit);
|
||||||
void BindEyeFB(int eye, bool readBuffer = false);
|
void BindEyeFB(int eye, bool readBuffer = false);
|
||||||
|
GLuint GetEyeTextureGLHandle(int eye) const; // Needed for OpenVR API
|
||||||
|
|
||||||
void BindShadowMapFB();
|
void BindShadowMapFB();
|
||||||
void BindShadowMapTexture(int index);
|
void BindShadowMapTexture(int index);
|
||||||
|
|
162
src/gl/stereo3d/LSMatrix.h
Normal file
162
src/gl/stereo3d/LSMatrix.h
Normal file
|
@ -0,0 +1,162 @@
|
||||||
|
/*
|
||||||
|
** LSMatrix.h
|
||||||
|
** less-simple matrix class
|
||||||
|
**
|
||||||
|
**---------------------------------------------------------------------------
|
||||||
|
** 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 VR_LS_MATRIX_H_
|
||||||
|
#define VR_LS_MATRIX_H_
|
||||||
|
|
||||||
|
#include "gl/data/gl_matrix.h"
|
||||||
|
#include "openvr.h"
|
||||||
|
|
||||||
|
namespace vr {
|
||||||
|
HmdMatrix34_t;
|
||||||
|
}
|
||||||
|
|
||||||
|
class LSVec3
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
LSVec3(FLOATTYPE x, FLOATTYPE y, FLOATTYPE z, FLOATTYPE w=1.0f)
|
||||||
|
: x(mVec[0]), y(mVec[1]), z(mVec[2]), w(mVec[3])
|
||||||
|
{
|
||||||
|
mVec[0] = x;
|
||||||
|
mVec[1] = y;
|
||||||
|
mVec[2] = z;
|
||||||
|
mVec[3] = w;
|
||||||
|
}
|
||||||
|
|
||||||
|
LSVec3(const LSVec3& rhs)
|
||||||
|
: x(mVec[0]), y(mVec[1]), z(mVec[2]), w(mVec[3])
|
||||||
|
{
|
||||||
|
*this = rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
LSVec3& operator=(const LSVec3& rhs) {
|
||||||
|
LSVec3& lhs = *this;
|
||||||
|
for (int i = 0; i < 4; ++i)
|
||||||
|
lhs[i] = rhs[i];
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
const FLOATTYPE& operator[](int i) const {return mVec[i];}
|
||||||
|
FLOATTYPE& operator[](int i) { return mVec[i]; }
|
||||||
|
|
||||||
|
LSVec3 operator-(const LSVec3& rhs) const {
|
||||||
|
const LSVec3& lhs = *this;
|
||||||
|
LSVec3 result = *this;
|
||||||
|
for (int i = 0; i < 4; ++i)
|
||||||
|
result[i] -= rhs[i];
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
FLOATTYPE mVec[4];
|
||||||
|
FLOATTYPE& x;
|
||||||
|
FLOATTYPE& y;
|
||||||
|
FLOATTYPE& z;
|
||||||
|
FLOATTYPE& w;
|
||||||
|
};
|
||||||
|
|
||||||
|
LSVec3 operator*(FLOATTYPE s, const LSVec3& rhs) {
|
||||||
|
LSVec3 result = rhs;
|
||||||
|
for (int i = 0; i < 4; ++i)
|
||||||
|
result[i] *= s;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
class LSMatrix44 : public VSMatrix
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
LSMatrix44()
|
||||||
|
{
|
||||||
|
loadIdentity();
|
||||||
|
}
|
||||||
|
|
||||||
|
LSMatrix44(const vr::HmdMatrix34_t& m) {
|
||||||
|
loadIdentity();
|
||||||
|
for (int i = 0; i < 3; ++i) {
|
||||||
|
for (int j = 0; j < 4; ++j) {
|
||||||
|
(*this)[i][j] = m.m[i][j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LSMatrix44(const VSMatrix& m) {
|
||||||
|
m.copy(mMatrix);
|
||||||
|
}
|
||||||
|
|
||||||
|
// overload bracket operator to return one row of the matrix, so you can invoke, say, m[2][3]
|
||||||
|
FLOATTYPE* operator[](int i) {return &mMatrix[i*4];}
|
||||||
|
const FLOATTYPE* operator[](int i) const { return &mMatrix[i * 4]; }
|
||||||
|
|
||||||
|
LSMatrix44 operator*(const VSMatrix& rhs) const {
|
||||||
|
LSMatrix44 result(*this);
|
||||||
|
result.multMatrix(rhs);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
LSVec3 operator*(const LSVec3& rhs) const {
|
||||||
|
const LSMatrix44& lhs = *this;
|
||||||
|
LSVec3 result(0, 0, 0, 0);
|
||||||
|
for (int i = 0; i < 4; ++i) {
|
||||||
|
for (int j = 0; j < 4; ++j) {
|
||||||
|
result[i] += lhs[i][j] * rhs[j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
LSMatrix44 getWithoutTranslation() const {
|
||||||
|
LSMatrix44 m = *this;
|
||||||
|
// Remove translation component
|
||||||
|
m[3][3] = 1.0f;
|
||||||
|
m[3][2] = m[3][1] = m[3][0] = 0.0f;
|
||||||
|
m[2][3] = m[1][3] = m[0][3] = 0.0f;
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
LSMatrix44 transpose() const {
|
||||||
|
LSMatrix44 result;
|
||||||
|
for (int i = 0; i < 3; ++i) {
|
||||||
|
for (int j = 0; j < 4; ++j) {
|
||||||
|
result[i][j] = (*this)[j][i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // VR_LS_MATRIX_H_
|
||||||
|
|
||||||
|
|
477
src/gl/stereo3d/gl_openvr.cpp
Normal file
477
src/gl/stereo3d/gl_openvr.cpp
Normal file
|
@ -0,0 +1,477 @@
|
||||||
|
/*
|
||||||
|
** gl_openvr.cpp
|
||||||
|
** Stereoscopic virtual reality mode for the HTC Vive headset
|
||||||
|
**
|
||||||
|
**---------------------------------------------------------------------------
|
||||||
|
** 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.
|
||||||
|
**---------------------------------------------------------------------------
|
||||||
|
**
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef USE_OPENVR
|
||||||
|
|
||||||
|
#include "gl_openvr.h"
|
||||||
|
#include "openvr.h"
|
||||||
|
#include <string>
|
||||||
|
#include "gl/system/gl_system.h"
|
||||||
|
#include "doomtype.h" // Printf
|
||||||
|
#include "d_player.h"
|
||||||
|
#include "g_game.h" // G_Add...
|
||||||
|
#include "p_local.h" // P_TryMove
|
||||||
|
#include "r_utility.h" // viewpitch
|
||||||
|
#include "gl/renderer/gl_renderer.h"
|
||||||
|
#include "gl/renderer/gl_renderbuffers.h"
|
||||||
|
#include "g_levellocals.h" // pixelstretch
|
||||||
|
#include "math/cmath.h"
|
||||||
|
#include "c_cvars.h"
|
||||||
|
#include "LSMatrix.h"
|
||||||
|
|
||||||
|
// For conversion between real-world and doom units
|
||||||
|
#define VERTICAL_DOOM_UNITS_PER_METER 27.0f
|
||||||
|
|
||||||
|
EXTERN_CVAR(Int, screenblocks);
|
||||||
|
|
||||||
|
using namespace vr;
|
||||||
|
|
||||||
|
// feature toggles, for testing and debugging
|
||||||
|
static const bool doTrackHmdYaw = true;
|
||||||
|
static const bool doTrackHmdPitch = true;
|
||||||
|
static const bool doTrackHmdRoll = true;
|
||||||
|
static const bool doLateScheduledRotationTracking = true;
|
||||||
|
static const bool doStereoscopicViewpointOffset = true;
|
||||||
|
static const bool doRenderToDesktop = true; // mirroring to the desktop is very helpful for debugging
|
||||||
|
static const bool doRenderToHmd = true;
|
||||||
|
static const bool doTrackHmdVerticalPosition = false; // todo:
|
||||||
|
static const bool doTrackHmdHorizontalPostion = false; // todo:
|
||||||
|
static const bool doTrackVrControllerPosition = false; // todo:
|
||||||
|
|
||||||
|
namespace s3d
|
||||||
|
{
|
||||||
|
|
||||||
|
/* static */
|
||||||
|
const Stereo3DMode& OpenVRMode::getInstance()
|
||||||
|
{
|
||||||
|
static OpenVRMode instance;
|
||||||
|
if (! instance.hmdWasFound)
|
||||||
|
return MonoView::getInstance();
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
static HmdVector3d_t eulerAnglesFromQuat(HmdQuaternion_t quat) {
|
||||||
|
double q0 = quat.w;
|
||||||
|
// permute axes to make "Y" up/yaw
|
||||||
|
double q2 = quat.x;
|
||||||
|
double q3 = quat.y;
|
||||||
|
double q1 = quat.z;
|
||||||
|
|
||||||
|
// http://stackoverflow.com/questions/18433801/converting-a-3x3-matrix-to-euler-tait-bryan-angles-pitch-yaw-roll
|
||||||
|
double roll = atan2(2 * (q0*q1 + q2*q3), 1 - 2 * (q1*q1 + q2*q2));
|
||||||
|
double pitch = asin(2 * (q0*q2 - q3*q1));
|
||||||
|
double yaw = atan2(2 * (q0*q3 + q1*q2), 1 - 2 * (q2*q2 + q3*q3));
|
||||||
|
|
||||||
|
return HmdVector3d_t{ yaw, pitch, roll };
|
||||||
|
}
|
||||||
|
|
||||||
|
static HmdQuaternion_t quatFromMatrix(HmdMatrix34_t matrix) {
|
||||||
|
HmdQuaternion_t q;
|
||||||
|
typedef float f34[3][4];
|
||||||
|
f34& a = matrix.m;
|
||||||
|
// http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/
|
||||||
|
float trace = a[0][0] + a[1][1] + a[2][2]; // I removed + 1.0f; see discussion with Ethan
|
||||||
|
if (trace > 0) {// I changed M_EPSILON to 0
|
||||||
|
float s = 0.5f / sqrtf(trace + 1.0f);
|
||||||
|
q.w = 0.25f / s;
|
||||||
|
q.x = (a[2][1] - a[1][2]) * s;
|
||||||
|
q.y = (a[0][2] - a[2][0]) * s;
|
||||||
|
q.z = (a[1][0] - a[0][1]) * s;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (a[0][0] > a[1][1] && a[0][0] > a[2][2]) {
|
||||||
|
float s = 2.0f * sqrtf(1.0f + a[0][0] - a[1][1] - a[2][2]);
|
||||||
|
q.w = (a[2][1] - a[1][2]) / s;
|
||||||
|
q.x = 0.25f * s;
|
||||||
|
q.y = (a[0][1] + a[1][0]) / s;
|
||||||
|
q.z = (a[0][2] + a[2][0]) / s;
|
||||||
|
}
|
||||||
|
else if (a[1][1] > a[2][2]) {
|
||||||
|
float s = 2.0f * sqrtf(1.0f + a[1][1] - a[0][0] - a[2][2]);
|
||||||
|
q.w = (a[0][2] - a[2][0]) / s;
|
||||||
|
q.x = (a[0][1] + a[1][0]) / s;
|
||||||
|
q.y = 0.25f * s;
|
||||||
|
q.z = (a[1][2] + a[2][1]) / s;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
float s = 2.0f * sqrtf(1.0f + a[2][2] - a[0][0] - a[1][1]);
|
||||||
|
q.w = (a[1][0] - a[0][1]) / s;
|
||||||
|
q.x = (a[0][2] + a[2][0]) / s;
|
||||||
|
q.y = (a[1][2] + a[2][1]) / s;
|
||||||
|
q.z = 0.25f * s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return q;
|
||||||
|
}
|
||||||
|
|
||||||
|
static HmdVector3d_t eulerAnglesFromMatrix(HmdMatrix34_t mat) {
|
||||||
|
return eulerAnglesFromQuat(quatFromMatrix(mat));
|
||||||
|
}
|
||||||
|
|
||||||
|
OpenVREyePose::OpenVREyePose(int eye)
|
||||||
|
: ShiftedEyePose( 0.0f )
|
||||||
|
, eye(eye)
|
||||||
|
, eyeTexture(nullptr)
|
||||||
|
, verticalDoomUnitsPerMeter(VERTICAL_DOOM_UNITS_PER_METER)
|
||||||
|
, currentPose(nullptr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* virtual */
|
||||||
|
OpenVREyePose::~OpenVREyePose()
|
||||||
|
{
|
||||||
|
dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void vSMatrixFromHmdMatrix34(VSMatrix& m1, const vr::HmdMatrix34_t& m2)
|
||||||
|
{
|
||||||
|
float tmp[16];
|
||||||
|
for (int i = 0; i < 3; ++i) {
|
||||||
|
for (int j = 0; j < 4; ++j) {
|
||||||
|
tmp[4 * i + j] = m2.m[i][j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int i = 3;
|
||||||
|
for (int j = 0; j < 4; ++j) {
|
||||||
|
tmp[4 * i + j] = 0;
|
||||||
|
}
|
||||||
|
tmp[15] = 1;
|
||||||
|
m1.loadMatrix(&tmp[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* virtual */
|
||||||
|
void OpenVREyePose::GetViewShift(FLOATTYPE yaw, FLOATTYPE outViewShift[3]) const
|
||||||
|
{
|
||||||
|
outViewShift[0] = outViewShift[1] = outViewShift[2] = 0;
|
||||||
|
|
||||||
|
if (currentPose == nullptr)
|
||||||
|
return;
|
||||||
|
const vr::TrackedDevicePose_t& hmd = *currentPose;
|
||||||
|
if (! hmd.bDeviceIsConnected)
|
||||||
|
return;
|
||||||
|
if (! hmd.bPoseIsValid)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (! doStereoscopicViewpointOffset)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const vr::HmdMatrix34_t& hmdPose = hmd.mDeviceToAbsoluteTracking;
|
||||||
|
|
||||||
|
// Pitch and Roll are identical between OpenVR and Doom worlds.
|
||||||
|
// But yaw can differ, depending on starting state, and controller movement.
|
||||||
|
float doomYawDegrees = yaw;
|
||||||
|
float openVrYawDegrees = RAD2DEG(-eulerAnglesFromMatrix(hmdPose).v[0]);
|
||||||
|
float deltaYawDegrees = doomYawDegrees - openVrYawDegrees;
|
||||||
|
while (deltaYawDegrees > 180)
|
||||||
|
deltaYawDegrees -= 360;
|
||||||
|
while (deltaYawDegrees < -180)
|
||||||
|
deltaYawDegrees += 360;
|
||||||
|
|
||||||
|
// extract rotation component from hmd transform
|
||||||
|
LSMatrix44 openvr_X_hmd(hmdPose);
|
||||||
|
LSMatrix44 hmdRot = openvr_X_hmd.getWithoutTranslation(); // .transpose();
|
||||||
|
|
||||||
|
/// In these eye methods, just get local inter-eye stereoscopic shift, not full position shift ///
|
||||||
|
|
||||||
|
// compute local eye shift
|
||||||
|
LSMatrix44 eyeShift2;
|
||||||
|
eyeShift2.loadIdentity();
|
||||||
|
eyeShift2 = eyeShift2 * eyeToHeadTransform; // eye to head
|
||||||
|
eyeShift2 = eyeShift2 * hmdRot; // head to openvr
|
||||||
|
|
||||||
|
LSVec3 eye_EyePos = LSVec3(0, 0, 0); // eye position in eye frame
|
||||||
|
LSVec3 hmd_EyePos = LSMatrix44(eyeToHeadTransform) * eye_EyePos;
|
||||||
|
LSVec3 hmd_HmdPos = LSVec3(0, 0, 0); // hmd position in hmd frame
|
||||||
|
LSVec3 openvr_EyePos = openvr_X_hmd * hmd_EyePos;
|
||||||
|
LSVec3 openvr_HmdPos = openvr_X_hmd * hmd_HmdPos;
|
||||||
|
LSVec3 hmd_OtherEyePos = LSMatrix44(otherEyeToHeadTransform) * eye_EyePos;
|
||||||
|
LSVec3 openvr_OtherEyePos = openvr_X_hmd * hmd_OtherEyePos;
|
||||||
|
LSVec3 openvr_EyeOffset = openvr_EyePos - openvr_HmdPos;
|
||||||
|
|
||||||
|
VSMatrix doomInOpenVR = VSMatrix();
|
||||||
|
doomInOpenVR.loadIdentity();
|
||||||
|
// permute axes
|
||||||
|
float permute[] = { // Convert from OpenVR to Doom axis convention, including mirror inversion
|
||||||
|
-1, 0, 0, 0, // X-right in OpenVR -> X-left in Doom
|
||||||
|
0, 0, 1, 0, // Z-backward in OpenVR -> Y-backward in Doom
|
||||||
|
0, 1, 0, 0, // Y-up in OpenVR -> Z-up in Doom
|
||||||
|
0, 0, 0, 1};
|
||||||
|
doomInOpenVR.multMatrix(permute);
|
||||||
|
doomInOpenVR.scale(verticalDoomUnitsPerMeter, verticalDoomUnitsPerMeter, verticalDoomUnitsPerMeter); // Doom units are not meters
|
||||||
|
doomInOpenVR.scale(level.info->pixelstretch, level.info->pixelstretch, 1.0); // Doom universe is scaled by 1990s pixel aspect ratio
|
||||||
|
doomInOpenVR.rotate(deltaYawDegrees, 0, 0, 1);
|
||||||
|
|
||||||
|
LSVec3 doom_EyeOffset = LSMatrix44(doomInOpenVR) * openvr_EyeOffset;
|
||||||
|
outViewShift[0] = doom_EyeOffset[0];
|
||||||
|
outViewShift[1] = doom_EyeOffset[1];
|
||||||
|
outViewShift[2] = doom_EyeOffset[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* virtual */
|
||||||
|
VSMatrix OpenVREyePose::GetProjection(FLOATTYPE fov, FLOATTYPE aspectRatio, FLOATTYPE fovRatio) const
|
||||||
|
{
|
||||||
|
// Ignore those arguments and get the projection from the SDK
|
||||||
|
VSMatrix vs1 = ShiftedEyePose::GetProjection(fov, aspectRatio, fovRatio);
|
||||||
|
return projectionMatrix;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenVREyePose::initialize(vr::IVRSystem& vrsystem)
|
||||||
|
{
|
||||||
|
float zNear = 5.0;
|
||||||
|
float zFar = 65536.0;
|
||||||
|
vr::HmdMatrix44_t projection = vrsystem.GetProjectionMatrix(
|
||||||
|
vr::EVREye(eye), zNear, zFar);
|
||||||
|
vr::HmdMatrix44_t proj_transpose;
|
||||||
|
for (int i = 0; i < 4; ++i) {
|
||||||
|
for (int j = 0; j < 4; ++j) {
|
||||||
|
proj_transpose.m[i][j] = projection.m[j][i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
projectionMatrix.loadIdentity();
|
||||||
|
projectionMatrix.multMatrix(&proj_transpose.m[0][0]);
|
||||||
|
|
||||||
|
vr::HmdMatrix34_t eyeToHead = vrsystem.GetEyeToHeadTransform(vr::EVREye(eye));
|
||||||
|
vSMatrixFromHmdMatrix34(eyeToHeadTransform, eyeToHead);
|
||||||
|
vr::HmdMatrix34_t otherEyeToHead = vrsystem.GetEyeToHeadTransform(eye == Eye_Left ? Eye_Right : Eye_Left);
|
||||||
|
vSMatrixFromHmdMatrix34(otherEyeToHeadTransform, otherEyeToHead);
|
||||||
|
|
||||||
|
if (eyeTexture == nullptr)
|
||||||
|
eyeTexture = new vr::Texture_t();
|
||||||
|
eyeTexture->handle = nullptr; // TODO: populate this at resolve time
|
||||||
|
eyeTexture->eType = vr::TextureType_OpenGL;
|
||||||
|
eyeTexture->eColorSpace = vr::ColorSpace_Linear;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenVREyePose::dispose()
|
||||||
|
{
|
||||||
|
if (eyeTexture) {
|
||||||
|
delete eyeTexture;
|
||||||
|
eyeTexture = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OpenVREyePose::submitFrame() const
|
||||||
|
{
|
||||||
|
if (eyeTexture == nullptr)
|
||||||
|
return false;
|
||||||
|
if (vr::VRCompositor() == nullptr)
|
||||||
|
return false;
|
||||||
|
eyeTexture->handle = (void *)GLRenderer->mBuffers->GetEyeTextureGLHandle((int)eye);
|
||||||
|
vr::VRCompositor()->Submit(vr::EVREye(eye), eyeTexture);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
OpenVRMode::OpenVRMode()
|
||||||
|
: vrSystem(nullptr)
|
||||||
|
, leftEyeView(vr::Eye_Left)
|
||||||
|
, rightEyeView(vr::Eye_Right)
|
||||||
|
, hmdWasFound(false)
|
||||||
|
, sceneWidth(0), sceneHeight(0)
|
||||||
|
{
|
||||||
|
eye_ptrs.Push(&leftEyeView); // default behavior to Mono non-stereo rendering
|
||||||
|
|
||||||
|
EVRInitError eError;
|
||||||
|
if (VR_IsHmdPresent())
|
||||||
|
{
|
||||||
|
vrSystem = VR_Init(&eError, VRApplication_Scene);
|
||||||
|
if (eError != vr::VRInitError_None) {
|
||||||
|
std::string errMsg = VR_GetVRInitErrorAsEnglishDescription(eError);
|
||||||
|
vrSystem = nullptr;
|
||||||
|
return;
|
||||||
|
// TODO: report error
|
||||||
|
}
|
||||||
|
vrSystem->GetRecommendedRenderTargetSize(&sceneWidth, &sceneHeight);
|
||||||
|
|
||||||
|
// OK
|
||||||
|
leftEyeView.initialize(*vrSystem);
|
||||||
|
rightEyeView.initialize(*vrSystem);
|
||||||
|
|
||||||
|
if (!vr::VRCompositor())
|
||||||
|
return;
|
||||||
|
|
||||||
|
eye_ptrs.Push(&rightEyeView); // NOW we render to two eyes
|
||||||
|
hmdWasFound = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* virtual */
|
||||||
|
// AdjustViewports() is called from within FLGRenderer::SetOutputViewport(...)
|
||||||
|
void OpenVRMode::AdjustViewports() const
|
||||||
|
{
|
||||||
|
// Draw the 3D scene into the entire framebuffer
|
||||||
|
GLRenderer->mSceneViewport.width = sceneWidth;
|
||||||
|
GLRenderer->mSceneViewport.height = sceneHeight;
|
||||||
|
GLRenderer->mSceneViewport.left = 0;
|
||||||
|
GLRenderer->mSceneViewport.top = 0;
|
||||||
|
|
||||||
|
GLRenderer->mScreenViewport.width = sceneWidth;
|
||||||
|
GLRenderer->mScreenViewport.height = sceneHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* virtual */
|
||||||
|
void OpenVRMode::Present() const {
|
||||||
|
// TODO: For performance, don't render to the desktop screen here
|
||||||
|
if (doRenderToDesktop) {
|
||||||
|
GLRenderer->mBuffers->BindOutputFB();
|
||||||
|
GLRenderer->ClearBorders();
|
||||||
|
|
||||||
|
// Compute screen regions to use for left and right eye views
|
||||||
|
int leftWidth = GLRenderer->mOutputLetterbox.width / 2;
|
||||||
|
int rightWidth = GLRenderer->mOutputLetterbox.width - leftWidth;
|
||||||
|
GL_IRECT leftHalfScreen = GLRenderer->mOutputLetterbox;
|
||||||
|
leftHalfScreen.width = leftWidth;
|
||||||
|
GL_IRECT rightHalfScreen = GLRenderer->mOutputLetterbox;
|
||||||
|
rightHalfScreen.width = rightWidth;
|
||||||
|
rightHalfScreen.left += leftWidth;
|
||||||
|
|
||||||
|
GLRenderer->mBuffers->BindEyeTexture(0, 0);
|
||||||
|
GLRenderer->DrawPresentTexture(leftHalfScreen, true);
|
||||||
|
GLRenderer->mBuffers->BindEyeTexture(1, 0);
|
||||||
|
GLRenderer->DrawPresentTexture(rightHalfScreen, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (doRenderToHmd)
|
||||||
|
{
|
||||||
|
leftEyeView.submitFrame();
|
||||||
|
rightEyeView.submitFrame();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mAngleFromRadians(double radians)
|
||||||
|
{
|
||||||
|
double m = std::round(65535.0 * radians / (2.0 * M_PI));
|
||||||
|
return int(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenVRMode::updateHmdPose(
|
||||||
|
double hmdYawRadians,
|
||||||
|
double hmdPitchRadians,
|
||||||
|
double hmdRollRadians) const
|
||||||
|
{
|
||||||
|
double hmdyaw = hmdYawRadians;
|
||||||
|
double hmdpitch = hmdPitchRadians;
|
||||||
|
double hmdroll = hmdRollRadians;
|
||||||
|
|
||||||
|
double dYaw = 0;
|
||||||
|
if (doTrackHmdYaw) {
|
||||||
|
// Set HMD angle game state parameters for NEXT frame
|
||||||
|
static double previousYaw = 0;
|
||||||
|
static bool havePreviousYaw = false;
|
||||||
|
if (!havePreviousYaw) {
|
||||||
|
previousYaw = hmdyaw;
|
||||||
|
havePreviousYaw = true;
|
||||||
|
}
|
||||||
|
dYaw = hmdyaw - previousYaw;
|
||||||
|
G_AddViewAngle(mAngleFromRadians(-dYaw));
|
||||||
|
previousYaw = hmdyaw;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* */
|
||||||
|
// Pitch
|
||||||
|
if (doTrackHmdPitch) {
|
||||||
|
double hmdPitchInDoom = -atan(tan(hmdpitch) / level.info->pixelstretch);
|
||||||
|
double viewPitchInDoom = GLRenderer->mAngles.Pitch.Radians();
|
||||||
|
double dPitch = hmdPitchInDoom - viewPitchInDoom;
|
||||||
|
G_AddViewPitch(mAngleFromRadians(-dPitch));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Roll can be local, because it doesn't affect gameplay.
|
||||||
|
if (doTrackHmdRoll)
|
||||||
|
GLRenderer->mAngles.Roll = RAD2DEG(-hmdroll);
|
||||||
|
|
||||||
|
// Late-schedule update to renderer angles directly, too
|
||||||
|
if (doLateScheduledRotationTracking) {
|
||||||
|
if (doTrackHmdPitch)
|
||||||
|
GLRenderer->mAngles.Pitch = RAD2DEG(-hmdpitch);
|
||||||
|
if (doTrackHmdYaw)
|
||||||
|
GLRenderer->mAngles.Yaw += RAD2DEG(dYaw); // "plus" is the correct direction
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* virtual */
|
||||||
|
void OpenVRMode::SetUp() const
|
||||||
|
{
|
||||||
|
super::SetUp();
|
||||||
|
|
||||||
|
cachedScreenBlocks = screenblocks;
|
||||||
|
screenblocks = 12; // always be full-screen during 3D scene render
|
||||||
|
|
||||||
|
if (vr::VRCompositor() == nullptr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
static vr::TrackedDevicePose_t poses[vr::k_unMaxTrackedDeviceCount];
|
||||||
|
vr::VRCompositor()->WaitGetPoses(
|
||||||
|
poses, vr::k_unMaxTrackedDeviceCount, // current pose
|
||||||
|
nullptr, 0 // future pose?
|
||||||
|
);
|
||||||
|
|
||||||
|
TrackedDevicePose_t& hmdPose0 = poses[vr::k_unTrackedDeviceIndex_Hmd];
|
||||||
|
|
||||||
|
if (hmdPose0.bPoseIsValid) {
|
||||||
|
const vr::HmdMatrix34_t& hmdPose = hmdPose0.mDeviceToAbsoluteTracking;
|
||||||
|
HmdVector3d_t eulerAngles = eulerAnglesFromMatrix(hmdPose);
|
||||||
|
// Printf("%.1f %.1f %.1f\n", eulerAngles.v[0], eulerAngles.v[1], eulerAngles.v[2]);
|
||||||
|
updateHmdPose(eulerAngles.v[0], eulerAngles.v[1], eulerAngles.v[2]);
|
||||||
|
leftEyeView.setCurrentHmdPose(&hmdPose0);
|
||||||
|
rightEyeView.setCurrentHmdPose(&hmdPose0);
|
||||||
|
// TODO: position tracking
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* virtual */
|
||||||
|
void OpenVRMode::TearDown() const
|
||||||
|
{
|
||||||
|
screenblocks = cachedScreenBlocks;
|
||||||
|
super::TearDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* virtual */
|
||||||
|
OpenVRMode::~OpenVRMode()
|
||||||
|
{
|
||||||
|
if (vrSystem != nullptr) {
|
||||||
|
VR_Shutdown();
|
||||||
|
vrSystem = nullptr;
|
||||||
|
leftEyeView.dispose();
|
||||||
|
rightEyeView.dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} /* namespace s3d */
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
110
src/gl/stereo3d/gl_openvr.h
Normal file
110
src/gl/stereo3d/gl_openvr.h
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
/*
|
||||||
|
** gl_openvr.h
|
||||||
|
** Stereoscopic virtual reality mode for the HTC Vive headset
|
||||||
|
**
|
||||||
|
**---------------------------------------------------------------------------
|
||||||
|
** 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_OPENVR_H_
|
||||||
|
#define GL_OPENVR_H_
|
||||||
|
|
||||||
|
#include "gl_stereo3d.h"
|
||||||
|
#include "gl_stereo_leftright.h"
|
||||||
|
|
||||||
|
// forward declaration from openvr.h
|
||||||
|
namespace vr {
|
||||||
|
class IVRSystem;
|
||||||
|
struct HmdMatrix44_t;
|
||||||
|
struct Texture_t;
|
||||||
|
struct TrackedDevicePose_t;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* stereoscopic 3D API */
|
||||||
|
namespace s3d {
|
||||||
|
|
||||||
|
class OpenVREyePose : public ShiftedEyePose
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
OpenVREyePose(int eye);
|
||||||
|
virtual ~OpenVREyePose() override;
|
||||||
|
virtual VSMatrix GetProjection(FLOATTYPE fov, FLOATTYPE aspectRatio, FLOATTYPE fovRatio) const override;
|
||||||
|
virtual void GetViewShift(float yaw, float outViewShift[3]) const override;
|
||||||
|
|
||||||
|
void initialize(vr::IVRSystem& vrsystem);
|
||||||
|
void dispose();
|
||||||
|
void setCurrentHmdPose(const vr::TrackedDevicePose_t * pose) const {currentPose = pose;}
|
||||||
|
bool submitFrame() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
VSMatrix projectionMatrix;
|
||||||
|
VSMatrix eyeToHeadTransform;
|
||||||
|
VSMatrix otherEyeToHeadTransform;
|
||||||
|
vr::Texture_t* eyeTexture;
|
||||||
|
int eye;
|
||||||
|
|
||||||
|
// TODO: adjust doomUnitsPerMeter according to player height
|
||||||
|
float verticalDoomUnitsPerMeter;
|
||||||
|
|
||||||
|
mutable const vr::TrackedDevicePose_t * currentPose;
|
||||||
|
};
|
||||||
|
|
||||||
|
class OpenVRMode : public Stereo3DMode
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static const Stereo3DMode& getInstance(); // Might return Mono mode, if no HMD available
|
||||||
|
|
||||||
|
virtual ~OpenVRMode() override;
|
||||||
|
virtual void SetUp() const override; // called immediately before rendering a scene frame
|
||||||
|
virtual void TearDown() const override; // called immediately after rendering a scene frame
|
||||||
|
virtual void Present() const override;
|
||||||
|
virtual void AdjustViewports() const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
OpenVRMode();
|
||||||
|
// void updateDoomViewDirection() const;
|
||||||
|
void updateHmdPose(double hmdYawRadians, double hmdPitchRadians, double hmdRollRadians) const;
|
||||||
|
|
||||||
|
OpenVREyePose leftEyeView;
|
||||||
|
OpenVREyePose rightEyeView;
|
||||||
|
|
||||||
|
vr::IVRSystem* vrSystem;
|
||||||
|
mutable int cachedScreenBlocks;
|
||||||
|
|
||||||
|
private:
|
||||||
|
typedef Stereo3DMode super;
|
||||||
|
bool hmdWasFound;
|
||||||
|
uint32_t sceneWidth, sceneHeight;
|
||||||
|
};
|
||||||
|
|
||||||
|
} /* namespace st3d */
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* GL_OPENVR_H_ */
|
|
@ -25,10 +25,12 @@
|
||||||
**
|
**
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "gl/stereo3d/gl_stereo3d.h"
|
#include "gl_stereo3d.h"
|
||||||
#include "gl/stereo3d/gl_stereo_leftright.h"
|
#include "gl_stereo_leftright.h"
|
||||||
#include "gl/stereo3d/gl_anaglyph.h"
|
#include "gl_anaglyph.h"
|
||||||
#include "gl/stereo3d/gl_quadstereo.h"
|
#include "gl_openvr.h"
|
||||||
|
#include "gl_quadstereo.h"
|
||||||
|
#include "gl_sidebyside3d.h"
|
||||||
#include "gl/stereo3d/gl_sidebyside3d.h"
|
#include "gl/stereo3d/gl_sidebyside3d.h"
|
||||||
#include "gl/stereo3d/gl_interleaved3d.h"
|
#include "gl/stereo3d/gl_interleaved3d.h"
|
||||||
#include "gl/system/gl_cvars.h"
|
#include "gl/system/gl_cvars.h"
|
||||||
|
@ -102,7 +104,11 @@ const Stereo3DMode& Stereo3DMode::getCurrentMode()
|
||||||
case 9:
|
case 9:
|
||||||
setCurrentMode(AmberBlue::getInstance(vr_ipd));
|
setCurrentMode(AmberBlue::getInstance(vr_ipd));
|
||||||
break;
|
break;
|
||||||
// TODO: 10: HTC Vive/OpenVR
|
#ifdef USE_OPENVR
|
||||||
|
case 10:
|
||||||
|
setCurrentMode(OpenVRMode::getInstance());
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
case 11:
|
case 11:
|
||||||
setCurrentMode(TopBottom3D::getInstance(vr_ipd));
|
setCurrentMode(TopBottom3D::getInstance(vr_ipd));
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
|
|
||||||
namespace s3d {
|
namespace s3d {
|
||||||
|
|
||||||
ScopedViewShifter::ScopedViewShifter(float dxyz[3]) // in meters
|
ScopedViewShifter::ScopedViewShifter(float dxyz[3]) // in doom units
|
||||||
{
|
{
|
||||||
// save original values
|
// save original values
|
||||||
cachedView = r_viewpoint.Pos;
|
cachedView = r_viewpoint.Pos;
|
||||||
|
|
|
@ -40,7 +40,7 @@ namespace s3d {
|
||||||
class ScopedViewShifter
|
class ScopedViewShifter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ScopedViewShifter(float dxyz[3]); // in meters
|
ScopedViewShifter(float dxyz[3]); // in doom units
|
||||||
~ScopedViewShifter();
|
~ScopedViewShifter();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -2787,6 +2787,7 @@ OPTVAL_ROWINTERLEAVED = "Row Interleaved";
|
||||||
OPTVAL_COLUMNINTERLEAVED = "Column Interleaved";
|
OPTVAL_COLUMNINTERLEAVED = "Column Interleaved";
|
||||||
OPTVAL_CHECKERBOARD = "Checkerboard";
|
OPTVAL_CHECKERBOARD = "Checkerboard";
|
||||||
OPTVAL_QUADBUFFERED = "Quad-buffered";
|
OPTVAL_QUADBUFFERED = "Quad-buffered";
|
||||||
|
OPTVAL_OPENVR = "OpenVR-Vive";
|
||||||
OPTVAL_UNCHARTED2 = "Uncharted 2";
|
OPTVAL_UNCHARTED2 = "Uncharted 2";
|
||||||
OPTVAL_HEJLDAWSON = "Hejl Dawson";
|
OPTVAL_HEJLDAWSON = "Hejl Dawson";
|
||||||
OPTVAL_REINHARD = "Reinhard";
|
OPTVAL_REINHARD = "Reinhard";
|
||||||
|
|
|
@ -2097,6 +2097,7 @@ OptionValue VRMode
|
||||||
5, "$OPTVAL_LEFTEYE"
|
5, "$OPTVAL_LEFTEYE"
|
||||||
6, "$OPTVAL_RIGHTEYE"
|
6, "$OPTVAL_RIGHTEYE"
|
||||||
7, "$OPTVAL_QUADBUFFERED"
|
7, "$OPTVAL_QUADBUFFERED"
|
||||||
|
10, "$OPTVAL_OPENVR"
|
||||||
}
|
}
|
||||||
|
|
||||||
OptionMenu "GLTextureGLOptions"
|
OptionMenu "GLTextureGLOptions"
|
||||||
|
|
Loading…
Reference in a new issue