diff --git a/cmake/externals/LibOVR/CMakeLists.txt b/cmake/externals/LibOVR/CMakeLists.txt index 2198ed378a..d491434b5f 100644 --- a/cmake/externals/LibOVR/CMakeLists.txt +++ b/cmake/externals/LibOVR/CMakeLists.txt @@ -9,8 +9,8 @@ if (WIN32) ExternalProject_Add( ${EXTERNAL_NAME} - URL http://static.oculus.com/sdk-downloads/ovr_sdk_win_0.5.0.1.zip - URL_MD5 d3fc4c02db9be5ff08af4ef4c97b32f9 + URL http://static.oculus.com/sdk-downloads/0.6.0.0/1431634088/ovr_sdk_win_0.6.0.0.zip + URL_MD5 a3dfdab037a854fdcf7e6033fa8d7028 CONFIGURE_COMMAND "" BUILD_COMMAND "" INSTALL_COMMAND "" diff --git a/interface/src/plugins/display/DisplayPlugin.h b/interface/src/plugins/display/DisplayPlugin.h index e620b5e04a..711b53e9f4 100644 --- a/interface/src/plugins/display/DisplayPlugin.h +++ b/interface/src/plugins/display/DisplayPlugin.h @@ -21,7 +21,7 @@ #include #include -enum class Eye { +enum Eye { Left, Right, Mono diff --git a/interface/src/plugins/display/OculusBaseDisplayPlugin.cpp b/interface/src/plugins/display/OculusBaseDisplayPlugin.cpp new file mode 100644 index 0000000000..50e1583548 --- /dev/null +++ b/interface/src/plugins/display/OculusBaseDisplayPlugin.cpp @@ -0,0 +1,41 @@ +// +// OculusBaseDisplayPlugin.cpp +// +// Created by Bradley Austin Davis on 2014/04/13. +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#include "OculusBaseDisplayPlugin.h" + +#include + +#include "OculusHelpers.h" + + +void OculusBaseDisplayPlugin::activate() { + ovr_for_each_eye([&](ovrEyeType eye) { + ovrEyeRenderDesc erd = ovrHmd_GetRenderDesc(_hmd, eye, _hmd->MaxEyeFov[eye]); + ovrMatrix4f ovrPerspectiveProjection = + ovrMatrix4f_Projection(erd.Fov, DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP, ovrProjection_RightHanded); + _eyeProjections[eye] = toGlm(ovrPerspectiveProjection); + _eyeOffsets[eye] = erd.HmdToEyeViewOffset; + }); +} + +void OculusBaseDisplayPlugin::deactivate() { +} + +void OculusBaseDisplayPlugin::preRender() { + ovrHmd_GetEyePoses(_hmd, _frameIndex, _eyeOffsets, _eyePoses, nullptr); +} + +glm::mat4 OculusBaseDisplayPlugin::getProjection(Eye eye, const glm::mat4& baseProjection) const { + return _eyeProjections[eye]; +} + +glm::mat4 OculusBaseDisplayPlugin::getModelview(Eye eye, const glm::mat4& baseModelview) const { + return toGlm(_eyePoses[eye]); +} + diff --git a/interface/src/plugins/display/OculusBaseDisplayPlugin.h b/interface/src/plugins/display/OculusBaseDisplayPlugin.h new file mode 100644 index 0000000000..94f73522b5 --- /dev/null +++ b/interface/src/plugins/display/OculusBaseDisplayPlugin.h @@ -0,0 +1,32 @@ +// +// OculusBaseDisplayPlugin.h +// +// Created by Bradley Austin Davis on 2014/04/13. +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#pragma once + +#include "HmdDisplayPlugin.h" + +#include + +class OculusBaseDisplayPlugin : public HmdDisplayPlugin { +public: + // Stereo specific methods + virtual glm::mat4 getProjection(Eye eye, const glm::mat4& baseProjection) const; + virtual glm::mat4 getModelview(Eye eye, const glm::mat4& baseModelview) const; + virtual void activate(); + virtual void deactivate(); + virtual void preRender(); + virtual void configureRendering() = 0; +protected: + ovrHmd _hmd; + unsigned int _frameIndex{ 0 }; + + ovrPosef _eyePoses[2]; + ovrVector3f _eyeOffsets[2]; + glm::mat4 _eyeProjections[2]; +}; diff --git a/interface/src/plugins/display/OculusDisplayPlugin.cpp b/interface/src/plugins/display/OculusDisplayPlugin.cpp deleted file mode 100644 index d32af59ebf..0000000000 --- a/interface/src/plugins/display/OculusDisplayPlugin.cpp +++ /dev/null @@ -1,96 +0,0 @@ -// -// OculusDisplayPlugin.cpp -// -// Created by Bradley Austin Davis on 2014/04/13. -// Copyright 2015 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// -#include "OculusDisplayPlugin.h" - -#include - -bool OculusDisplayPlugin::isSupported() { - ovr_Initialize(); - bool result = false; - if (ovrHmd_Detect() != 0) { - result = true; - } - ovr_Shutdown(); - return result; -} - -void OculusDisplayPlugin::activate() { -} - -void OculusDisplayPlugin::deactivate() { -} - -void OculusDisplayPlugin::init() { -} - -void OculusDisplayPlugin::deinit() { -} - - -void OculusDisplayPlugin::overrideOffAxisFrustum( - float& left, float& right, float& bottom, float& top, - float& nearVal, float& farVal, - glm::vec4& nearClipPlane, glm::vec4& farClipPlane) const { - -} - - - -#if 0 -// Set the desired FBO texture size. If it hasn't changed, this does nothing. -// Otherwise, it must rebuild the FBOs -if (OculusManager::isConnected()) { - DependencyManager::get()->setFrameBufferSize(OculusManager::getRenderTargetSize()); -} else { -#endif - -#if 0 - // Update camera position - if (!OculusManager::isConnected()) { - _myCamera.update(1.0f / _fps); - } -#endif - -#if 0 - if (OculusManager::isConnected()) { - //When in mirror mode, use camera rotation. Otherwise, use body rotation - if (_myCamera.getMode() == CAMERA_MODE_MIRROR) { - OculusManager::display(_myCamera.getRotation(), _myCamera.getPosition(), _myCamera); - } else { - OculusManager::display(_myAvatar->getWorldAlignedOrientation(), _myAvatar->getDefaultEyePosition(), _myCamera); - } - _myCamera.update(1.0f / _fps); - -#endif - -#if 0 - OculusManager::abandonCalibration(); -#endif - -#if 0 - if (OculusManager::isConnected()) { - return getMouseX() >= 0 && getMouseX() <= _glWidget->getDeviceWidth() && - getMouseY() >= 0 && getMouseY() <= _glWidget->getDeviceHeight(); - } -#endif - -#if 0 - if (OculusManager::isConnected()) { - glm::vec2 pos = _applicationOverlay.screenToOverlay(glm::vec2(getTrueMouseX(), getTrueMouseY())); - return pos.x; - } -#endif -#if 0 - if (OculusManager::isConnected()) { - glm::vec2 pos = _applicationOverlay.screenToOverlay(glm::vec2(getTrueMouseX(), getTrueMouseY())); - return pos.y; - } -#endif - diff --git a/interface/src/plugins/display/OculusDisplayPlugin.h b/interface/src/plugins/display/OculusDisplayPlugin.h deleted file mode 100644 index 7b846ae569..0000000000 --- a/interface/src/plugins/display/OculusDisplayPlugin.h +++ /dev/null @@ -1,30 +0,0 @@ -// -// OculusBaseDisplayPlugin.h -// -// Created by Bradley Austin Davis on 2014/04/13. -// Copyright 2015 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// -#pragma once - -#include "HmdDisplayPlugin.h" -#include - -class OculusDisplayPlugin : public HmdDisplayPlugin { -public: - virtual bool isSupported(); - - virtual void init(); - virtual void deinit(); - - virtual void activate(); - virtual void deactivate(); - - virtual void overrideOffAxisFrustum( - float& left, float& right, float& bottom, float& top, - float& nearVal, float& farVal, - glm::vec4& nearClipPlane, glm::vec4& farClipPlane) const; - -}; diff --git a/interface/src/plugins/display/OculusHelpers.h b/interface/src/plugins/display/OculusHelpers.h new file mode 100644 index 0000000000..553a1671e5 --- /dev/null +++ b/interface/src/plugins/display/OculusHelpers.h @@ -0,0 +1,75 @@ +// +// Created by Bradley Austin Davis on 2015/05/26. +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#pragma once + +#include +#include +#include + +// Convenience method for looping over each eye with a lambda +template +inline void ovr_for_each_eye(Function function) { + for (ovrEyeType eye = ovrEyeType::ovrEye_Left; + eye < ovrEyeType::ovrEye_Count; + eye = static_cast(eye + 1)) { + function(eye); + } +} + +inline glm::mat4 toGlm(const ovrMatrix4f & om) { + return glm::transpose(glm::make_mat4(&om.M[0][0])); +} + +inline glm::mat4 toGlm(const ovrFovPort & fovport, float nearPlane = 0.01f, float farPlane = 10000.0f) { + return toGlm(ovrMatrix4f_Projection(fovport, nearPlane, farPlane, true)); +} + +inline glm::vec3 toGlm(const ovrVector3f & ov) { + return glm::make_vec3(&ov.x); +} + +inline glm::vec2 toGlm(const ovrVector2f & ov) { + return glm::make_vec2(&ov.x); +} + +inline glm::uvec2 toGlm(const ovrSizei & ov) { + return glm::uvec2(ov.w, ov.h); +} + +inline glm::quat toGlm(const ovrQuatf & oq) { + return glm::make_quat(&oq.x); +} + +inline glm::mat4 toGlm(const ovrPosef & op) { + glm::mat4 orientation = glm::mat4_cast(toGlm(op.Orientation)); + glm::mat4 translation = glm::translate(glm::mat4(), toGlm(op.Position)); + return translation * orientation; +} + +inline ovrMatrix4f ovrFromGlm(const glm::mat4 & m) { + ovrMatrix4f result; + glm::mat4 transposed(glm::transpose(m)); + memcpy(result.M, &(transposed[0][0]), sizeof(float) * 16); + return result; +} + +inline ovrVector3f ovrFromGlm(const glm::vec3 & v) { + return{ v.x, v.y, v.z }; +} + +inline ovrVector2f ovrFromGlm(const glm::vec2 & v) { + return{ v.x, v.y }; +} + +inline ovrSizei ovrFromGlm(const glm::uvec2 & v) { + return{ (int)v.x, (int)v.y }; +} + +inline ovrQuatf ovrFromGlm(const glm::quat & q) { + return{ q.x, q.y, q.z, q.w }; +} diff --git a/interface/src/plugins/display/OculusWin32DisplayPlugin.cpp b/interface/src/plugins/display/OculusWin32DisplayPlugin.cpp new file mode 100644 index 0000000000..f7414cc551 --- /dev/null +++ b/interface/src/plugins/display/OculusWin32DisplayPlugin.cpp @@ -0,0 +1,200 @@ +// +// Created by Bradley Austin Davis on 2014/04/13. +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#include "OculusWin32DisplayPlugin.h" + + +#include + +bool OculusWin32DisplayPlugin::isSupported() { + ovr_Initialize(); + bool result = false; + if (ovrHmd_Detect() != 0) { + result = true; + } + ovr_Shutdown(); + return result; +} + +// A basic wrapper for constructing a framebuffer with a renderbuffer +// for the depth attachment and an undefined type for the color attachement +// This allows us to reuse the basic framebuffer code for both the Mirror +// FBO as well as the Oculus swap textures we will use to render the scene +// Though we don't really need depth at all for the mirror FBO, or even an +// FBO, but using one means I can just use a glBlitFramebuffer to get it onto +// the screen. +template +struct FramebufferWrapper { + glm::uvec2 size; + oglplus::Framebuffer fbo; + C color{ 0 }; + GLuint depth{ 0 }; + + virtual ~FramebufferWrapper() { + } + + FramebufferWrapper() {} + + virtual void Init(const uvec2 & size) { + this->size = size; + if (!fbo) { + glGenFramebuffers(1, &fbo); + } + initColor(); + initDepth(); + initDone(); + } + + template + void Bound(F f) { + Bound(GL_FRAMEBUFFER, f); + } + + template + void Bound(GLenum target, F f) { + glBindFramebuffer(target, fbo); + onBind(target); + f(); + onUnbind(target); + glBindFramebuffer(target, 0); + } + + void Viewport() { + glViewport(0, 0, size.x, size.y); + } + +private: + virtual void onBind(GLenum target) {} + virtual void onUnbind(GLenum target) {} + + + virtual void initDepth() { + glGenRenderbuffers(1, &depth); + assert(depth); + glBindRenderbuffer(GL_RENDERBUFFER, depth); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, size.x, size.y); + glBindRenderbuffer(GL_RENDERBUFFER, 0); + } + + virtual void initColor() = 0; + virtual void initDone() = 0; +}; + + + +// A base class for FBO wrappers that need to use the Oculus C +// API to manage textures via ovrHmd_CreateSwapTextureSetGL, +// ovrHmd_CreateMirrorTextureGL, etc +template +struct RiftFramebufferWrapper : public FramebufferWrapper { + ovrHmd hmd; + RiftFramebufferWrapper(const ovrHmd & hmd) : hmd(hmd) {}; +}; + +// A wrapper for constructing and using a swap texture set, +// where each frame you draw to a texture via the FBO, +// then submit it and increment to the next texture. +// The Oculus SDK manages the creation and destruction of +// the textures +struct SwapTextureFramebufferWrapper : public RiftFramebufferWrapper{ + SwapTextureFramebufferWrapper(const ovrHmd & hmd) + : RiftFramebufferWrapper(hmd) {} + ~SwapTextureFramebufferWrapper() { + if (color) { + ovrHmd_DestroySwapTextureSet(hmd, color); + color = nullptr; + } + } + + void Increment() { + ++color->CurrentIndex; + color->CurrentIndex %= color->TextureCount; + } + +protected: + virtual void initColor() { + if (color) { + ovrHmd_DestroySwapTextureSet(hmd, color); + color = nullptr; + } + + if (!OVR_SUCCESS(ovrHmd_CreateSwapTextureSetGL(hmd, GL_RGBA, size.x, size.y, &color))) { + FAIL("Unable to create swap textures"); + } + + for (int i = 0; i < color->TextureCount; ++i) { + ovrGLTexture& ovrTex = (ovrGLTexture&)color->Textures[i]; + glBindTexture(GL_TEXTURE_2D, ovrTex.OGL.TexId); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + } + glBindTexture(GL_TEXTURE_2D, 0); + } + + virtual void initDone() { + glBindFramebuffer(GL_FRAMEBUFFER, fbo); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + } + + virtual void onBind(GLenum target) { + ovrGLTexture& tex = (ovrGLTexture&)(color->Textures[color->CurrentIndex]); + glFramebufferTexture2D(target, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex.OGL.TexId, 0); + } + + virtual void onUnbind(GLenum target) { + glFramebufferTexture2D(target, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); + } +}; + +using SwapTexFboPtr = std::shared_ptr; + +// We use a FBO to wrap the mirror texture because it makes it easier to +// render to the screen via glBlitFramebuffer +struct MirrorFramebufferWrapper : public RiftFramebufferWrapper{ + float targetAspect; + MirrorFramebufferWrapper(const ovrHmd & hmd) + : RiftFramebufferWrapper(hmd) {} + ~MirrorFramebufferWrapper() { + if (color) { + ovrHmd_DestroyMirrorTexture(hmd, (ovrTexture*)color); + color = nullptr; + } + } + + void Resize(const uvec2 & size) { + glBindFramebuffer(GL_FRAMEBUFFER, fbo); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + this->size = size; + initColor(); + initDone(); + } +private: + virtual void initDepth() { + } + + void initColor() { + if (color) { + ovrHmd_DestroyMirrorTexture(hmd, (ovrTexture*)color); + color = nullptr; + } + ovrResult result = ovrHmd_CreateMirrorTextureGL(hmd, GL_RGBA, size.x, size.y, (ovrTexture**)&color); + assert(OVR_SUCCESS(result)); + } + + void initDone() { + glBindFramebuffer(GL_FRAMEBUFFER, fbo); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color->OGL.TexId, 0); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + } + +}; + +using MirrorFboPtr = std::shared_ptr; diff --git a/interface/src/plugins/display/OculusWin32DisplayPlugin.h b/interface/src/plugins/display/OculusWin32DisplayPlugin.h new file mode 100644 index 0000000000..436efb5742 --- /dev/null +++ b/interface/src/plugins/display/OculusWin32DisplayPlugin.h @@ -0,0 +1,15 @@ +// +// Created by Bradley Austin Davis on 2015/05/26. +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#pragma once + +#include "OculusBaseDisplayPlugin.h" + +class OculusWin32DisplayPlugin : public OculusBaseDisplayPlugin { +public: + virtual bool isSupported(); +}; diff --git a/interface/src/plugins/display/OglplusHelpers.h b/interface/src/plugins/display/OglplusHelpers.h new file mode 100644 index 0000000000..b74362a617 --- /dev/null +++ b/interface/src/plugins/display/OglplusHelpers.h @@ -0,0 +1,26 @@ +// +// Created by Bradley Austin Davis on 2015/05/26. +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#pragma once + +#define OGLPLUS_USE_GLEW 1 +#define OGLPLUS_USE_GLCOREARB_H 0 +#define OGLPLUS_USE_BOOST_CONFIG 1 +#define OGLPLUS_NO_SITE_CONFIG 1 +#define OGLPLUS_LOW_PROFILE 1 +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +typedef std::shared_ptr FramebufferPtr;