From f30e86bc4b73215b207952ceca85607118f66849 Mon Sep 17 00:00:00 2001 From: jriegel Date: Wed, 16 Jul 2014 23:08:32 +0200 Subject: [PATCH] Integrating Rift Libs in build --- CMakeLists.txt | 2 + cMake/FindRift.cmake | 100 ++++++ src/Gui/CMakeLists.txt | 20 +- src/Gui/View3DInventorRiftViewer.cpp | 470 +++++++++++++++++++++++++++ 4 files changed, 590 insertions(+), 2 deletions(-) create mode 100644 cMake/FindRift.cmake create mode 100644 src/Gui/View3DInventorRiftViewer.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index ca6a5c1a8..807709e18 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -628,6 +628,8 @@ else(FREECAD_LIBPACK_USE) endif(FREECAD_LIBPACK_USE) +find_package(Rift) + # copy build convenient files for M$ if(WIN32) if (EXISTS BuildAll.bat) diff --git a/cMake/FindRift.cmake b/cMake/FindRift.cmake new file mode 100644 index 000000000..4a77de575 --- /dev/null +++ b/cMake/FindRift.cmake @@ -0,0 +1,100 @@ +# Find OCULUS +# +# This module defines +# OCULUS_FOUND +# OCULUS_INCLUDE_DIRS +# OCULUS_LIBRARIES +# +# Copyright (c) 2012 I-maginer +# +# 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 2 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, write to the Free Software Foundation, Inc., 59 Temple +# Place - Suite 330, Boston, MA 02111-1307, USA, or go to +# http://www.gnu.org/copyleft/lesser.txt +# + +# On a new cmake run, we do not need to be verbose +IF(OCULUS_INCLUDE_DIR AND OCULUS_LIBRARY) + SET(OCULUS_FIND_QUIETLY FALSE) +ENDIF() + +# If OCULUS_ROOT was defined in the environment, use it. +if (NOT OCULUS_ROOT) + if(NOT "$ENV{OCULUS_ROOT}" STREQUAL "") + set(OCULUS_ROOT $ENV{OCULUS_ROOT}) + else() + set(OCULUS_ROOT $ENV{SCOL_DEPENDENCIES_PATH}/oculus/LibOVR) + endif() +endif() + +# concat all the search paths +IF(OCULUS_ROOT) + SET(OCULUS_INCLUDE_SEARCH_DIRS + ${OCULUS_INCLUDE_SEARCH_DIRS} + ${OCULUS_ROOT}/include + ) + SET(OCULUS_LIBRARY_SEARCH_RELEASE_DIRS + ${OCULUS_LIBRARY_SEARCH_DIRS} + ${OCULUS_ROOT}/lib/Win32 + ) + SET(OCULUS_LIBRARY_SEARCH_DEBUG_DIRS + ${OCULUS_LIBRARY_SEARCH_DIRS} + ${OCULUS_ROOT}/lib/Win32 + ) +ENDIF() + +# log message +IF (NOT OCULUS_FIND_QUIETLY) + MESSAGE(STATUS "Checking for OCULUS library") +ENDIF() + +# Search for header files +FIND_PATH(OCULUS_INCLUDE_DIR OVR.h + PATHS ${OCULUS_INCLUDE_SEARCH_DIRS}) + +# Search for libraries files (release mode) +FIND_LIBRARY(OCULUS_LIBRARY_RELEASE libovr + PATHS ${OCULUS_LIBRARY_SEARCH_RELEASE_DIRS}) + +# Search for libraries files (debug mode) +FIND_LIBRARY(OCULUS_LIBRARY_DEBUG libovrd + PATHS ${OCULUS_LIBRARY_SEARCH_DEBUG_DIRS}) + +# Configure libraries for debug/release +SET(OCULUS_INCLUDE_DIRS ${OCULUS_INCLUDE_DIR} CACHE PATH "Directory containing OCULUS header files") +SET(OCULUS_LIBRARY debug ${OCULUS_LIBRARY_DEBUG} optimized ${OCULUS_LIBRARY_RELEASE}) +SET(OCULUS_LIBRARIES ${OCULUS_LIBRARY} CACHE STRING "OCULUS libraries files") + +#IF(OCULUS_INCLUDE_DIR AND OCULUS_LIBRARY) + SET(OCULUS_FOUND TRUE) +#ENDIF() + +# Hide those variables in GUI +SET(OCULUS_INCLUDE_DIR ${OCULUS_INCLUDE_DIR} CACHE INTERNAL "") +SET(OCULUS_LIBRARY_RELEASE ${OCULUS_LIBRARY_RELEASE} CACHE INTERNAL "") +SET(OCULUS_LIBRARY_DEBUG ${OCULUS_LIBRARY_DEBUG} CACHE INTERNAL "") +SET(OCULUS_LIBRARY ${OCULUS_LIBRARY} CACHE INTERNAL "") + +# log find result +IF(OCULUS_FOUND) + IF(NOT OCULUS_FIND_QUIETLY) + MESSAGE(STATUS " libraries: ${OCULUS_LIBRARIES}") + MESSAGE(STATUS " includes: ${OCULUS_INCLUDE_DIRS}") + ENDIF() +ELSE(OCULUS_FOUND) + IF(NOT OCULUS_LIBRARIES) + MESSAGE(STATUS, "OCULUS library or one of it dependencies could not be found.") + ENDIF() + IF(NOT OCULUS_INCLUDE_DIRS) + MESSAGE(STATUS "OCULUS include files could not be found.") + ENDIF() +ENDIF(OCULUS_FOUND) \ No newline at end of file diff --git a/src/Gui/CMakeLists.txt b/src/Gui/CMakeLists.txt index 3a984804c..961298351 100644 --- a/src/Gui/CMakeLists.txt +++ b/src/Gui/CMakeLists.txt @@ -1,13 +1,17 @@ #add_subdirectory(Icons) if(WIN32) -add_definitions(-DFCGui -DQIIS_MAKEDLL) + add_definitions(-DFCGui -DQIIS_MAKEDLL -DOVR_OS_WIN32) endif(WIN32) if (FREECAD_USE_3DCONNEXION) -add_definitions(-D_USE_3DCONNEXION_SDK) + add_definitions(-D_USE_3DCONNEXION_SDK) endif(FREECAD_USE_3DCONNEXION) +if (OCULUS_FOUND) + add_definitions(-D_USE_OCULUS_RIFT_SDK ) +endif(OCULUS_FOUND) + include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} @@ -60,6 +64,17 @@ IF(SPNAV_FOUND) ) ENDIF(SPNAV_FOUND) +IF(OCULUS_FOUND) + add_definitions(-DOCULUS_FOUND) + include_directories( + ${OCULUS_INCLUDE_DIRS} + ) + set(FreeCADGui_LIBS + ${FreeCADGui_LIBS} + ${OCULUS_LIBRARIES} + ) +ENDIF(OCULUS_FOUND) + if(SHIBOKEN_INCLUDE_DIR) add_definitions(-DHAVE_SHIBOKEN) include_directories( @@ -643,6 +658,7 @@ SET(View3D_CPP_SRCS View3DInventor.cpp View3DInventorExamples.cpp View3DInventorViewer.cpp + View3DInventorRiftViewer.cpp View3DPy.cpp ) SET(View3D_SRCS diff --git a/src/Gui/View3DInventorRiftViewer.cpp b/src/Gui/View3DInventorRiftViewer.cpp new file mode 100644 index 000000000..71d0f3ed9 --- /dev/null +++ b/src/Gui/View3DInventorRiftViewer.cpp @@ -0,0 +1,470 @@ +/**************************************************************************\ +* Copyright (c) Bastiaan Veelo (Bastiaan a_t Veelo d_o_t net) +* All rights reserved. Contact me if the below is too restrictive for you. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are +* met: +* +* Redistributions of source code must retain the above copyright notice, +* this list of conditions and the following disclaimer. +* +* 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. +* +* Neither the name of the copyright holder nor the names of its +* contributors may be used to endorse or promote products derived from +* this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "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 COPYRIGHT +* HOLDER OR CONTRIBUTORS 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 "PreCompiled.h" + + +//#define USE_SO_OFFSCREEN_RENDERER +#define USE_FRAMEBUFFER + +#ifdef USE_SO_OFFSCREEN_RENDERER +# ifdef USE_FRAMEBUFFER +# error "Mutually exclusive options defined." +# endif +#endif + +#include +#include +#include +#include +#include +#include +#ifdef USE_SO_OFFSCREEN_RENDERER +# include +#endif +#ifdef USE_FRAMEBUFFER +# include +#endif +#include +#include +#include +//#include +#include <../Src/OVR_CAPI_GL.h> +#include <../Src/CAPI/GL/CAPI_GL_Util.h> // For framebuffer functions. + + +class CoinRiftWidget : public QGLWidget +{ + ovrHmd hmd; + ovrHmdDesc hmdDesc; + ovrEyeType eyes[2]; + ovrEyeRenderDesc eyeRenderDesc[2]; + ovrTexture eyeTexture[2]; + +#ifdef USE_FRAMEBUFFER + GLuint frameBufferID[2], depthBufferID[2]; + // A SoSceneManager has a SoRenderManager to do the rendering -- should we not use SoRenderManager instead? + // We are probably not that interested in events. SoSceneManager::setSceneGraph() searches for the camera + // and sets it in SoRenderManager, but its is actually only used for built-in stereo rendering. We sould + // probably eliminate that search... + SoSceneManager *m_sceneManager; +#endif +#ifdef USE_SO_OFFSCREEN_RENDERER + SoOffscreenRenderer *renderer; +#endif + SoSeparator *rootScene[2]; + SoFrustumCamera *camera[2]; + SoNode *scene; +public: + explicit CoinRiftWidget(); + ~CoinRiftWidget(); + void setSceneGraph(SoNode *sceneGraph); +protected: + void initializeGL(); + void paintGL(); + void resizeGL(int width, int height) { + int side = qMin(width, height); + glViewport((width - side) / 2, (height - side) / 2, side, side); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(-1.0, 1.0, -1.0, 1.0, 0.0, 1000.0); + glMatrixMode(GL_MODELVIEW); + } +}; + + +CoinRiftWidget::CoinRiftWidget() : QGLWidget() +{ + for (int eye = 0; eye < 2; eye++) { + reinterpret_cast(&eyeTexture[eye])->TexId = 0; +#ifdef USE_FRAMEBUFFER + frameBufferID[eye] = 0; + depthBufferID[eye] = 0; +#endif + } + + // OVR will do the swapping. + setAutoBufferSwap(false); + + hmd = ovrHmd_Create(0); + if (!hmd) { + qDebug() << "Could not find Rift device."; + exit(2); + } + ovrHmd_GetDesc(hmd, &hmdDesc); + if (!ovrHmd_StartSensor(hmd, ovrHmdCap_OrientationTracked | // Capabilities we support. + ovrHmdCap_YawCorrectionTracked | + ovrHmdCap_PositionTracked | + ovrHmdCap_LowPersistenceTracked, + ovrHmdCap_OrientationTracked)) { // Capabilities we require. + qDebug() << "Could not start Rift motion sensor."; + exit(3); + } + + resize(hmdDesc.Resolution.w, hmdDesc.Resolution.h); + + // Configure stereo settings. + ovrSizei recommenedTex0Size = ovrHmd_GetFovTextureSize(hmd, ovrEye_Left, + hmdDesc.DefaultEyeFov[0], 1.0f); + ovrSizei recommenedTex1Size = ovrHmd_GetFovTextureSize(hmd, ovrEye_Right, + hmdDesc.DefaultEyeFov[1], 1.0f); + +#ifdef USE_SO_OFFSCREEN_RENDERER + renderer = new SoOffscreenRenderer(SbViewportRegion(std::max(recommenedTex0Size.w, recommenedTex0Size.w), + std::max(recommenedTex1Size.h, recommenedTex1Size.h))); + renderer->setComponents(SoOffscreenRenderer::RGB_TRANSPARENCY); + renderer->setBackgroundColor(SbColor(.0f, .0f, .8f)); +#endif +#ifdef USE_FRAMEBUFFER + m_sceneManager = new SoSceneManager(); + m_sceneManager->setViewportRegion(SbViewportRegion(std::max(recommenedTex0Size.w, recommenedTex0Size.w), + std::max(recommenedTex1Size.h, recommenedTex1Size.h))); + m_sceneManager->setBackgroundColor(SbColor(.0f, .0f, .8f)); +#endif + + scene = new SoSeparator(0); // Placeholder. + for (int eye = 0; eye < 2; eye++) { + rootScene[eye] = new SoSeparator(3); + rootScene[eye]->ref(); + camera[eye] = new SoFrustumCamera(); + camera[eye]->position.setValue(0.0f, 0.0f, 5.0f); + camera[eye]->focalDistance.setValue(5.0f); + camera[eye]->viewportMapping.setValue(SoCamera::LEAVE_ALONE); + rootScene[eye]->addChild(camera[eye]); + rootScene[eye]->addChild(new SoDirectionalLight()); // TODO Connect direction to camera. + rootScene[eye]->addChild(scene); + } + + // Populate ovrEyeDesc[2]. + eyes[0].Eye = ovrEye_Left; + eyes[1].Eye = ovrEye_Right; + eyes[0].Fov = hmdDesc.DefaultEyeFov[0]; + eyes[1].Fov = hmdDesc.DefaultEyeFov[1]; +#ifdef USE_SO_OFFSCREEN_RENDERER + eyes[0].TextureSize.w = renderer->getViewportRegion().getViewportSizePixels().getValue()[0]; + eyes[0].TextureSize.h = renderer->getViewportRegion().getViewportSizePixels().getValue()[1]; + eyes[1].TextureSize = eyes[0].TextureSize; +#endif +#ifdef USE_FRAMEBUFFER + eyes[0].TextureSize = recommenedTex0Size; + eyes[1].TextureSize = recommenedTex1Size; +#endif + eyes[0].RenderViewport.Pos.x = 0; + eyes[0].RenderViewport.Pos.y = 0; + eyes[0].RenderViewport.Size = eyes[0].TextureSize; + eyes[1].RenderViewport.Pos = eyes[0].RenderViewport.Pos; + eyes[1].RenderViewport.Size = eyes[1].TextureSize; + + const int backBufferMultisample = 0; // TODO This is a guess? + ovrGLConfig cfg; + cfg.OGL.Header.API = ovrRenderAPI_OpenGL; + cfg.OGL.Header.RTSize = hmdDesc.Resolution; + cfg.OGL.Header.Multisample = backBufferMultisample; + cfg.OGL.Window = reinterpret_cast(winId()); + makeCurrent(); + cfg.OGL.WglContext = wglGetCurrentContext(); // http://stackoverflow.com/questions/17532033/qglwidget-get-gl-contextes-for-windows + cfg.OGL.GdiDc = wglGetCurrentDC(); + qDebug() << "Window:" << cfg.OGL.Window; + qDebug() << "Context:" << cfg.OGL.WglContext; + qDebug() << "DC:" << cfg.OGL.GdiDc; + + hmdDesc.DistortionCaps = 0; + hmdDesc.DistortionCaps |= ovrDistortion_Chromatic; +// hmdDesc.DistortionCaps |= ovrDistortion_TimeWarp; // Produces black screen... + hmdDesc.DistortionCaps |= ovrDistortion_Vignette; + + bool VSyncEnabled(false); // TODO This is a guess. + if (!ovrHmd_ConfigureRendering(hmd, &cfg.Config, (VSyncEnabled ? 0 : ovrHmdCap_NoVSync), + hmdDesc.DistortionCaps, eyes, eyeRenderDesc)) { + qDebug() << "Could not configure OVR rendering."; + exit(3); + } + + for (int eye = 0; eye < 2; eye++) { + camera[eye]->aspectRatio.setValue((eyeRenderDesc[eye].Desc.Fov.LeftTan + eyeRenderDesc[eye].Desc.Fov.RightTan) / + (eyeRenderDesc[eye].Desc.Fov.UpTan + eyeRenderDesc[eye].Desc.Fov.DownTan)); + camera[eye]->nearDistance.setValue(1.0f); + camera[eye]->farDistance.setValue(100.0f); + camera[eye]->left.setValue(-eyeRenderDesc[eye].Desc.Fov.LeftTan); + camera[eye]->right.setValue(eyeRenderDesc[eye].Desc.Fov.RightTan); + camera[eye]->top.setValue(eyeRenderDesc[eye].Desc.Fov.UpTan); + camera[eye]->bottom.setValue(-eyeRenderDesc[eye].Desc.Fov.DownTan); + } +} + + +CoinRiftWidget::~CoinRiftWidget() +{ +#ifdef USE_SO_OFFSCREEN_RENDERER + delete renderer; +#endif + for (int eye = 0; eye < 2; eye++) { + rootScene[eye]->unref(); + ovrGLTextureData *texData = reinterpret_cast(&eyeTexture[eye]); + if (texData->TexId) { + glDeleteTextures(1, &texData->TexId); + texData->TexId = 0; + } +#ifdef USE_FRAMEBUFFER + if (frameBufferID[eye] != 0) { +// OVR::CAPI::GL::glDeleteFramebuffersExt(1, &frameBufferID[eye]); // TODO + frameBufferID[eye] = 0; + } + if (depthBufferID[eye] != 0) { +// OVR::CAPI::GL::glDeleteRenderbuffersExt(1, &depthBufferID[eye]); // TODO + depthBufferID[eye] = 0; + } +#endif + } + scene = 0; + ovrHmd_StopSensor(hmd); + ovrHmd_Destroy(hmd); +} + + +void CoinRiftWidget::setSceneGraph(SoNode *sceneGraph) +{ + rootScene[0]->replaceChild(scene, sceneGraph); + rootScene[1]->replaceChild(scene, sceneGraph); + scene = sceneGraph; +} + + +void CoinRiftWidget::initializeGL() +{ + makeCurrent(); + // Infer hardware capabilites. +#ifdef USE_FRAMEBUFFER + OVR::CAPI::GL::InitGLExtensions(); + if (OVR::CAPI::GL::glBindFramebufferEXT == NULL) { + qDebug() << "No GL extensions found."; + exit(4); + } + + // Store old framebuffer. + GLint oldfb; + glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &oldfb); +#endif + + // Create rendering target textures. + glEnable(GL_TEXTURE_2D); + for (int eye = 0; eye < 2; eye++) { +#ifdef USE_FRAMEBUFFER + OVR::CAPI::GL::glGenFramebuffersEXT(1, &frameBufferID[eye]); + OVR::CAPI::GL::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, frameBufferID[eye]); + // Create the render buffer. + OVR::CAPI::GL::glGenRenderbuffersEXT(1, &depthBufferID[eye]); + OVR::CAPI::GL::glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depthBufferID[eye]); + OVR::CAPI::GL::glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, + GL_DEPTH_COMPONENT16, + eyes[eye].TextureSize.w, + eyes[eye].TextureSize.h); + // Attach renderbuffer to framebuffer. + OVR::CAPI::GL::glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, + GL_DEPTH_ATTACHMENT_EXT, + GL_RENDERBUFFER_EXT, + depthBufferID[eye]); +#endif + ovrGLTextureData *texData = reinterpret_cast(&eyeTexture[eye]); + texData->Header.API = ovrRenderAPI_OpenGL; + texData->Header.TextureSize = eyes[eye].TextureSize; + texData->Header.RenderViewport = eyes[eye].RenderViewport; + glGenTextures(1, &texData->TexId); + glBindTexture(GL_TEXTURE_2D, texData->TexId); + Q_ASSERT(!glGetError()); + // Allocate storage for the texture. + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, eyes[eye].TextureSize.w, eyes[eye].TextureSize.h, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL); +// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); +// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); +// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + 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_MAX_LEVEL, 0); + Q_ASSERT(!glGetError()); +#ifdef USE_FRAMEBUFFER + // Attach texture to framebuffer color object. + OVR::CAPI::GL::glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, + GL_COLOR_ATTACHMENT0_EXT, + GL_TEXTURE_2D, texData->TexId, 0); + if (OVR::CAPI::GL::glCheckFramebufferStatusEXT(GL_FRAMEBUFFER) != + GL_FRAMEBUFFER_COMPLETE) + qDebug() << "ERROR: FrameBuffer is not operational!"; +#endif + } + glBindTexture(GL_TEXTURE_2D, 0); + glDisable(GL_TEXTURE_2D); + +#ifdef USE_FRAMEBUFFER + // Continue rendering to the orgiginal frame buffer (likely 0, the onscreen buffer). + OVR::CAPI::GL::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, oldfb); +#endif + doneCurrent(); +} + + +void CoinRiftWidget::paintGL() +{ + const int ms(1000 / 60 /*fps*/); + QTimer::singleShot(ms, this, SLOT(updateGL())); + makeCurrent(); + + glEnable(GL_TEXTURE_2D); + + /*ovrFrameTiming hmdFrameTiming =*/ ovrHmd_BeginFrame(hmd, 0); + for (int eyeIndex = 0; eyeIndex < ovrEye_Count; eyeIndex++) { + ovrEyeType eye = hmdDesc.EyeRenderOrder[eyeIndex]; + ovrPosef eyePose = ovrHmd_BeginEyeRender(hmd, eye); + + camera[eye]->orientation.setValue(eyePose.Orientation.x, + eyePose.Orientation.y, + eyePose.Orientation.z, + eyePose.Orientation.w); + + SbVec3f originalPosition(camera[eye]->position.getValue()); + camera[eye]->position.setValue(originalPosition - SbVec3f(eyeRenderDesc[eye].ViewAdjust.x, + eyeRenderDesc[eye].ViewAdjust.y, + eyeRenderDesc[eye].ViewAdjust.z)); + +#ifdef USE_SO_OFFSCREEN_RENDERER + ovrGLTextureData *texData = reinterpret_cast(&eyeTexture[eye]); + glBindTexture(GL_TEXTURE_2D, texData->TexId); + renderer->render(rootScene[eye]); + Q_ASSERT(!glGetError()); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, + eyes[eye].TextureSize.w, + eyes[eye].TextureSize.h, + 0, GL_RGBA /*GL_BGRA*/, GL_UNSIGNED_BYTE, renderer->getBuffer()); + Q_ASSERT(!glGetError()); + glBindTexture(GL_TEXTURE_2D, 0); +#endif +#ifdef USE_FRAMEBUFFER + // Clear state pollution from OVR SDK. + glBindTexture(GL_TEXTURE_2D, 0); // You need this, at least if (hmdDesc.DistortionCaps & ovrDistortion_Chromatic). + OVR::CAPI::GL::glUseProgram(0); // You need this even more. + + GLint oldfb; + glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &oldfb); + // Set up framebuffer for rendering. + OVR::CAPI::GL::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, frameBufferID[eye]); + + m_sceneManager->setSceneGraph(rootScene[eye]); +// m_sceneManager->setCamera(camera[eye]); // SoSceneManager does this implicitly. + m_sceneManager->render(); + + // Continue rendering to the orgiginal frame buffer (likely 0, the onscreen buffer). + OVR::CAPI::GL::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, oldfb); + Q_ASSERT(!glGetError()); +#endif + + camera[eye]->position.setValue(originalPosition); + + // Submit the texture for distortion. + ovrHmd_EndEyeRender(hmd, eye, eyePose, &eyeTexture[eye]); + } + + // Swap buffers. + glDisable(GL_CULL_FACE); + glDisable(GL_DEPTH_TEST); + ovrHmd_EndFrame(hmd); + glEnable(GL_CULL_FACE); + glEnable(GL_DEPTH_TEST); + glClearDepth(1.0); + + doneCurrent(); +} + + +static void cleanup() +{ + //SoDB::finish(); + ovr_Shutdown(); +} + + +int oculusTest(void) +{ + //SoDB::init(); + + //QApplication app(argc, argv); + qAddPostRoutine(cleanup); + + // Moved here because of https://developer.oculusvr.com/forums/viewtopic.php?f=17&t=7915&p=108503#p108503 + // Init libovr. + if (!ovr_Initialize()) { + qDebug() << "Could not initialize Oculus SDK."; + exit(1); + } + + CoinRiftWidget window; + window.show(); + + // An example scene. + static const char * inlineSceneGraph[] = { + "#Inventor V2.1 ascii\n", + "\n", + "Separator {\n", + " Rotation { rotation 1 0 0 0.3 }\n", + " Cone { }\n", + " BaseColor { rgb 1 0 0 }\n", + " Scale { scaleFactor .7 .7 .7 }\n", + " Cube { }\n", + "\n", + " DrawStyle { style LINES }\n", + " ShapeHints { vertexOrdering COUNTERCLOCKWISE }\n", + " Coordinate3 {\n", + " point [\n", + " -2 -2 1.1, -2 -1 1.1, -2 1 1.1, -2 2 1.1,\n", + " -1 -2 1.1, -1 -1 1.1, -1 1 1.1, -1 2 1.1\n", + " 1 -2 1.1, 1 -1 1.1, 1 1 1.1, 1 2 1.1\n", + " 2 -2 1.1, 2 -1 1.1, 2 1 1.1, 2 2 1.1\n", + " ]\n", + " }\n", + "\n", + " Complexity { value 0.7 }\n", + " NurbsSurface {\n", + " numUControlPoints 4\n", + " numVControlPoints 4\n", + " uKnotVector [ 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0 ]\n", + " vKnotVector [ 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0 ]\n", + " }\n", + "}\n", + NULL + }; + + SoInput in; + in.setStringArray(inlineSceneGraph); + + window.setSceneGraph(SoDB::readAll(&in)); + + //return app.exec(); +} \ No newline at end of file