diff --git a/src/Gui/CMakeLists.txt b/src/Gui/CMakeLists.txt index 4a4f6e235..722e875dd 100644 --- a/src/Gui/CMakeLists.txt +++ b/src/Gui/CMakeLists.txt @@ -661,6 +661,7 @@ SET(View3D_CPP_SRCS View3DInventorExamples.cpp View3DInventorViewer.cpp View3DInventorRiftViewer.cpp + CoinRiftWidget.cpp View3DPy.cpp ) SET(View3D_SRCS @@ -675,6 +676,9 @@ SET(View3D_SRCS View3DInventorExamples.h View3DInventorViewer.h View3DPy.h + View3DInventorRiftViewer.h + CoinRiftWidget.h + ) SOURCE_GROUP("View3D" FILES ${View3D_SRCS}) diff --git a/src/Gui/CoinRiftWidget.cpp b/src/Gui/CoinRiftWidget.cpp new file mode 100644 index 000000000..fa4602406 --- /dev/null +++ b/src/Gui/CoinRiftWidget.cpp @@ -0,0 +1,469 @@ +/**************************************************************************\ +* 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" +#include "CoinRiftWidget.h" + +#if BUILD_VR + + + +#undef max + + + + +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."; + throw; + } + + if (!ovrHmd_ConfigureTracking (hmd, ovrTrackingCap_Orientation | + ovrTrackingCap_MagYawCorrection | + ovrTrackingCap_Position, + ovrTrackingCap_Orientation | + ovrTrackingCap_MagYawCorrection | + ovrTrackingCap_Position + )) { // Capabilities we require. + qDebug() << "Could not start Rift motion sensor."; + throw; + } + + resize(hmd->Resolution.w, hmd->Resolution.h); + + // Configure stereo settings. + ovrSizei recommenedTex0Size = ovrHmd_GetFovTextureSize(hmd, ovrEye_Left, + hmd->DefaultEyeFov[0], 1.0f); + ovrSizei recommenedTex1Size = ovrHmd_GetFovTextureSize(hmd, ovrEye_Right, + hmd->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 + basePosition = SbVec3f(0.0f, 0.0f, 5.0f); + + 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(basePosition); + 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]. + eyeRenderDesc[0].Eye = ovrEye_Left; + eyeRenderDesc[1].Eye = ovrEye_Right; + eyeRenderDesc[0].Fov = hmd->DefaultEyeFov[0]; + eyeRenderDesc[1].Fov = hmd->DefaultEyeFov[1]; +#ifdef USE_SO_OFFSCREEN_RENDERER + eyeTexture[0].Header.TextureSize.w = renderer->getViewportRegion().getViewportSizePixels().getValue()[0]; + eyeTexture[0].Header.TextureSize.h = renderer->getViewportRegion().getViewportSizePixels().getValue()[1]; + eyeTexture[1].Header.TextureSize = eyeTexture[0].Header.TextureSize; +#endif +#ifdef USE_FRAMEBUFFER + eyeTexture[0].Header.TextureSize = recommenedTex0Size; + eyeTexture[1].Header.TextureSize = recommenedTex1Size; +#endif + eyeTexture[0].Header.RenderViewport.Pos.x = 0; + eyeTexture[0].Header.RenderViewport.Pos.y = 0; + eyeTexture[0].Header.RenderViewport.Size = eyeTexture[0].Header.TextureSize; + eyeTexture[1].Header.RenderViewport.Pos = eyeTexture[0].Header.RenderViewport.Pos; + eyeTexture[1].Header.RenderViewport.Size = eyeTexture[1].Header.TextureSize; + + const int backBufferMultisample = 0; // TODO This is a guess? + ovrGLConfig cfg; + cfg.OGL.Header.API = ovrRenderAPI_OpenGL; + cfg.OGL.Header.RTSize = hmd->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.DC = wglGetCurrentDC(); + qDebug() << "Window:" << cfg.OGL.Window; + //qDebug() << "Context:" << cfg.OGL.WglContext; + qDebug() << "DC:" << cfg.OGL.DC; + + int DistortionCaps = 0; + DistortionCaps |= ovrDistortionCap_Chromatic; +// DistortionCaps |= ovrDistortionCap_TimeWarp; // Produces black screen... + DistortionCaps |= ovrDistortionCap_Vignette; + DistortionCaps |= ovrDistortionCap_HqDistortion; + + bool VSyncEnabled(false); // TODO This is a guess. + if (!ovrHmd_ConfigureRendering( hmd, + &cfg.Config, + /*(VSyncEnabled ? 0 : ovrHmdCap_NoVSync),*/ + DistortionCaps, + hmd->DefaultEyeFov,//eyes, + eyeRenderDesc)) { + qDebug() << "Could not configure OVR rendering."; + exit(3); + } + + for (int eye = 0; eye < 2; eye++) { + camera[eye]->aspectRatio.setValue((eyeRenderDesc[eye].Fov.LeftTan + eyeRenderDesc[eye].Fov.RightTan) / + (eyeRenderDesc[eye].Fov.UpTan + eyeRenderDesc[eye].Fov.DownTan)); + camera[eye]->nearDistance.setValue(1.0f); + camera[eye]->farDistance.setValue(100.0f); + camera[eye]->left.setValue(-eyeRenderDesc[eye].Fov.LeftTan); + camera[eye]->right.setValue(eyeRenderDesc[eye].Fov.RightTan); + camera[eye]->top.setValue(eyeRenderDesc[eye].Fov.UpTan); + camera[eye]->bottom.setValue(-eyeRenderDesc[eye].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::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); +} + +void CoinRiftWidget::initializeGL() +{ + makeCurrent(); + // Infer hardware capabilites. +#ifdef USE_FRAMEBUFFER + OVR::CAPI::GL::InitGLExtensions(); + if (OVR::CAPI::GL::glBindFramebuffer == 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::glGenFramebuffers(1, &frameBufferID[eye]); + OVR::CAPI::GL::glBindFramebuffer(GL_FRAMEBUFFER_EXT, frameBufferID[eye]); + // Create the render buffer. + // TODO: need to check for OpenGl 3 or higher and load the functions JR 2014 + /*OVR::CAPI::GL::*/glGenRenderbuffers(1, &depthBufferID[eye]); + /*OVR::CAPI::GL::*/glBindRenderbuffer(GL_RENDERBUFFER_EXT, depthBufferID[eye]); + /*OVR::CAPI::GL::*/glRenderbufferStorage(GL_RENDERBUFFER_EXT, + GL_DEPTH_COMPONENT16, + eyeTexture[eye].Header.TextureSize.w, + eyeTexture[eye].Header.TextureSize.h); + // Attach renderbuffer to framebuffer. + OVR::CAPI::GL::glFramebufferRenderbuffer(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 = eyeTexture[eye].Header.TextureSize; + texData->Header.RenderViewport = eyeTexture[eye].Header.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, eyeTexture[eye].Header.TextureSize.w, eyeTexture[eye].Header.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::glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, + GL_COLOR_ATTACHMENT0_EXT, + GL_TEXTURE_2D, texData->TexId, 0); + if (OVR::CAPI::GL::glCheckFramebufferStatus(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::glBindFramebuffer(GL_FRAMEBUFFER_EXT, oldfb); +#endif + doneCurrent(); +} + + +void CoinRiftWidget::paintGL() +{ + const int ms(1000 / 75 /*fps*/); + QTimer::singleShot(ms, this, SLOT(updateGL())); + + // handling the sfety warning + handlingSafetyWarning(); + + makeCurrent(); + + ovrPosef eyePose[2]; + + glEnable(GL_TEXTURE_2D); + + ovrFrameTiming hmdFrameTiming = ovrHmd_BeginFrame(hmd, 0); + for (int eyeIndex = 0; eyeIndex < ovrEye_Count; eyeIndex++) { + ovrEyeType eye = hmd->EyeRenderOrder[eyeIndex]; + eyePose[eye] = ovrHmd_GetEyePose(hmd, eye); + + camera[eye]->orientation.setValue(eyePose[eye].Orientation.x, + eyePose[eye].Orientation.y, + eyePose[eye].Orientation.z, + eyePose[eye].Orientation.w); + + SbVec3f riftPosition = SbVec3f(eyePose[eye].Position.x, + eyePose[eye].Position.y, + eyePose[eye].Position.z); + + //SbVec3f originalPosition(camera[eye]->position.getValue()); + + camera[eye]->position.setValue(basePosition - SbVec3f(eyeRenderDesc[eye].ViewAdjust.x, + eyeRenderDesc[eye].ViewAdjust.y, + eyeRenderDesc[eye].ViewAdjust.z) + riftPosition); + +#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, + eyeTexture[eye].Header.TextureSize.w, + eyeTexture[eye].Header.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::glBindFramebuffer(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::glBindFramebuffer(GL_FRAMEBUFFER_EXT, oldfb); + Q_ASSERT(!glGetError()); +#endif + + //camera[eye]->position.setValue(originalPosition); + + } + + // Submit the texture for distortion. + ovrHmd_EndFrame(hmd, eyePose, eyeTexture); + + // 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(); +} + +void CoinRiftWidget::handlingSafetyWarning(void) +{ + // Health and Safety Warning display state. + ovrHSWDisplayState hswDisplayState; + ovrHmd_GetHSWDisplayState(hmd, &hswDisplayState); + if (hswDisplayState.Displayed) + { + // Dismiss the warning if the user pressed the appropriate key or if the user + // is tapping the side of the HMD. + // If the user has requested to dismiss the warning via keyboard or controller input... + //if (Util_GetAndResetHSWDismissedState()) + ovrHmd_DismissHSWDisplay(hmd); + //else + //{ + // // Detect a moderate tap on the side of the HMD. + // ovrTrackingState ts = ovrHmd_GetTrackingState(hmd, ovr_GetTimeInSeconds()); + // if (ts.StatusFlags & ovrStatus_OrientationTracked) + // { + // const OVR::Vector3f v(ts.RawSensorData.Accelerometer.x, + // ts.RawSensorData.Accelerometer.y, + // ts.RawSensorData.Accelerometer.z); + // // Arbitrary value and representing moderate tap on the side of the DK2 Rift. + // if (v.LengthSq() > 250.f) + // ovrHmd_DismissHSWDisplay(hmd); + // } + //} + } + +} + + +#ifdef BUILD_RIFT_TEST_MAIN + +int main(int argc, char *argv[]) +{ + 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(); +} + +#endif //BUILD_RIFT_TEST_MAIN + +#endif //BUILD_VR \ No newline at end of file diff --git a/src/Gui/CoinRiftWidget.h b/src/Gui/CoinRiftWidget.h new file mode 100644 index 000000000..ace577be9 --- /dev/null +++ b/src/Gui/CoinRiftWidget.h @@ -0,0 +1,111 @@ +/**************************************************************************\ +* Copyright (c) Bastiaan Veelo (Bastiaan a_t Veelo d_o_t net) & Juergen Riegel (FreeCAD@juergen-riegel.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. +\**************************************************************************/ +#ifndef GUI_CoinRiftWidget +#define GUI_CoinRiftWidget + +#if BUILD_VR + +// defines which methode to use to render +#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 +#include +#ifdef USE_SO_OFFSCREEN_RENDERER +# include +#endif +#ifdef USE_FRAMEBUFFER +# include +#endif +#include +#include +#include + +#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 handlingSafetyWarning(void); + void initializeGL(); + void paintGL(); + void resizeGL(int width, int height); + + SbVec3f basePosition; +}; + + +#endif //BUILD_VR + +#endif GUI_CoinRiftWidget \ No newline at end of file diff --git a/src/Gui/View3DInventorRiftViewer.cpp b/src/Gui/View3DInventorRiftViewer.cpp index ef59bacf8..18971b9e7 100644 --- a/src/Gui/View3DInventorRiftViewer.cpp +++ b/src/Gui/View3DInventorRiftViewer.cpp @@ -1,477 +1,38 @@ -/**************************************************************************\ -* 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. -\**************************************************************************/ +/*************************************************************************** + * Copyright (c) 2014 Juergen Riegel * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library 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 Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + #include "PreCompiled.h" #if BUILD_VR -#ifndef OCULUS_FOUND -# error "Build VR without the Oculus SDK makes no sense at all" -#endif +#include "View3DInventorRiftViewer.h" -#define USE_SO_OFFSCREEN_RENDERER -//#define USE_FRAMEBUFFER +#define new DEBUG_CLIENTBLOCK -#ifdef USE_SO_OFFSCREEN_RENDERER -# ifdef USE_FRAMEBUFFER -# error "Mutually exclusive options defined." -# endif -#endif +using namespace Gui; -#include -#include -#include -#include -#include -#include -#include -#ifdef USE_SO_OFFSCREEN_RENDERER -# include -#endif -#ifdef USE_FRAMEBUFFER -# include -#endif -#include -#include -#include - -#include -#include -#include -//#include -#include <../Src/OVR_CAPI_GL.h> -#include <../Src/CAPI/GL/CAPI_GL_Util.h> // For framebuffer functions. - -#undef max - - -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 handlingSafetyWarning(void); - 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); - } - - SbVec3f basePosition; -}; - - -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."; - throw; - } - - if (!ovrHmd_ConfigureTracking (hmd, ovrTrackingCap_Orientation | - ovrTrackingCap_MagYawCorrection | - ovrTrackingCap_Position, - ovrTrackingCap_Orientation | - ovrTrackingCap_MagYawCorrection | - ovrTrackingCap_Position - )) { // Capabilities we require. - qDebug() << "Could not start Rift motion sensor."; - throw; - } - - resize(hmd->Resolution.w, hmd->Resolution.h); - - // Configure stereo settings. - ovrSizei recommenedTex0Size = ovrHmd_GetFovTextureSize(hmd, ovrEye_Left, - hmd->DefaultEyeFov[0], 1.0f); - ovrSizei recommenedTex1Size = ovrHmd_GetFovTextureSize(hmd, ovrEye_Right, - hmd->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 - basePosition = SbVec3f(0.0f, 0.0f, 5.0f); - - 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(basePosition); - 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]. - eyeRenderDesc[0].Eye = ovrEye_Left; - eyeRenderDesc[1].Eye = ovrEye_Right; - eyeRenderDesc[0].Fov = hmd->DefaultEyeFov[0]; - eyeRenderDesc[1].Fov = hmd->DefaultEyeFov[1]; -#ifdef USE_SO_OFFSCREEN_RENDERER - eyeTexture[0].Header.TextureSize.w = renderer->getViewportRegion().getViewportSizePixels().getValue()[0]; - eyeTexture[0].Header.TextureSize.h = renderer->getViewportRegion().getViewportSizePixels().getValue()[1]; - eyeTexture[1].Header.TextureSize = eyeTexture[0].Header.TextureSize; -#endif -#ifdef USE_FRAMEBUFFER - eyeTexture[0].Header.TextureSize = recommenedTex0Size; - eyeTexture[1].Header.TextureSize = recommenedTex1Size; -#endif - eyeTexture[0].Header.RenderViewport.Pos.x = 0; - eyeTexture[0].Header.RenderViewport.Pos.y = 0; - eyeTexture[0].Header.RenderViewport.Size = eyeTexture[0].Header.TextureSize; - eyeTexture[1].Header.RenderViewport.Pos = eyeTexture[0].Header.RenderViewport.Pos; - eyeTexture[1].Header.RenderViewport.Size = eyeTexture[1].Header.TextureSize; - - const int backBufferMultisample = 0; // TODO This is a guess? - ovrGLConfig cfg; - cfg.OGL.Header.API = ovrRenderAPI_OpenGL; - cfg.OGL.Header.RTSize = hmd->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.DC = wglGetCurrentDC(); - qDebug() << "Window:" << cfg.OGL.Window; - //qDebug() << "Context:" << cfg.OGL.WglContext; - qDebug() << "DC:" << cfg.OGL.DC; - - int DistortionCaps = 0; - DistortionCaps |= ovrDistortionCap_Chromatic; -// DistortionCaps |= ovrDistortionCap_TimeWarp; // Produces black screen... - DistortionCaps |= ovrDistortionCap_Vignette; - DistortionCaps |= ovrDistortionCap_HqDistortion; - - bool VSyncEnabled(false); // TODO This is a guess. - if (!ovrHmd_ConfigureRendering( hmd, - &cfg.Config, - /*(VSyncEnabled ? 0 : ovrHmdCap_NoVSync),*/ - DistortionCaps, - hmd->DefaultEyeFov,//eyes, - eyeRenderDesc)) { - qDebug() << "Could not configure OVR rendering."; - exit(3); - } - - for (int eye = 0; eye < 2; eye++) { - camera[eye]->aspectRatio.setValue((eyeRenderDesc[eye].Fov.LeftTan + eyeRenderDesc[eye].Fov.RightTan) / - (eyeRenderDesc[eye].Fov.UpTan + eyeRenderDesc[eye].Fov.DownTan)); - camera[eye]->nearDistance.setValue(1.0f); - camera[eye]->farDistance.setValue(100.0f); - camera[eye]->left.setValue(-eyeRenderDesc[eye].Fov.LeftTan); - camera[eye]->right.setValue(eyeRenderDesc[eye].Fov.RightTan); - camera[eye]->top.setValue(eyeRenderDesc[eye].Fov.UpTan); - camera[eye]->bottom.setValue(-eyeRenderDesc[eye].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::glBindFramebuffer == 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::glGenFramebuffers(1, &frameBufferID[eye]); - OVR::CAPI::GL::glBindFramebuffer(GL_FRAMEBUFFER_EXT, frameBufferID[eye]); - // Create the render buffer. - // TODO: need to check for OpenGl 3 or higher and load the functions JR 2014 - /*OVR::CAPI::GL::*/glGenRenderbuffers(1, &depthBufferID[eye]); - /*OVR::CAPI::GL::*/glBindRenderbuffer(GL_RENDERBUFFER_EXT, depthBufferID[eye]); - /*OVR::CAPI::GL::*/glRenderbufferStorage(GL_RENDERBUFFER_EXT, - GL_DEPTH_COMPONENT16, - eyeTexture[eye].Header.TextureSize.w, - eyeTexture[eye].Header.TextureSize.h); - // Attach renderbuffer to framebuffer. - OVR::CAPI::GL::glFramebufferRenderbuffer(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 = eyeTexture[eye].Header.TextureSize; - texData->Header.RenderViewport = eyeTexture[eye].Header.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, eyeTexture[eye].Header.TextureSize.w, eyeTexture[eye].Header.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::glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, - GL_COLOR_ATTACHMENT0_EXT, - GL_TEXTURE_2D, texData->TexId, 0); - if (OVR::CAPI::GL::glCheckFramebufferStatus(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::glBindFramebuffer(GL_FRAMEBUFFER_EXT, oldfb); -#endif - doneCurrent(); -} - - -void CoinRiftWidget::paintGL() -{ - const int ms(1000 / 75 /*fps*/); - QTimer::singleShot(ms, this, SLOT(updateGL())); - - // handling the sfety warning - handlingSafetyWarning(); - - makeCurrent(); - - ovrPosef eyePose[2]; - - glEnable(GL_TEXTURE_2D); - - ovrFrameTiming hmdFrameTiming = ovrHmd_BeginFrame(hmd, 0); - for (int eyeIndex = 0; eyeIndex < ovrEye_Count; eyeIndex++) { - ovrEyeType eye = hmd->EyeRenderOrder[eyeIndex]; - eyePose[eye] = ovrHmd_GetEyePose(hmd, eye); - - camera[eye]->orientation.setValue(eyePose[eye].Orientation.x, - eyePose[eye].Orientation.y, - eyePose[eye].Orientation.z, - eyePose[eye].Orientation.w); - - SbVec3f riftPosition = SbVec3f(eyePose[eye].Position.x, - eyePose[eye].Position.y, - eyePose[eye].Position.z); - - //SbVec3f originalPosition(camera[eye]->position.getValue()); - - camera[eye]->position.setValue(basePosition - SbVec3f(eyeRenderDesc[eye].ViewAdjust.x, - eyeRenderDesc[eye].ViewAdjust.y, - eyeRenderDesc[eye].ViewAdjust.z) + riftPosition); - -#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, - eyeTexture[eye].Header.TextureSize.w, - eyeTexture[eye].Header.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::glBindFramebuffer(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::glBindFramebuffer(GL_FRAMEBUFFER_EXT, oldfb); - Q_ASSERT(!glGetError()); -#endif - - //camera[eye]->position.setValue(originalPosition); - - } - - // Submit the texture for distortion. - ovrHmd_EndFrame(hmd, eyePose, eyeTexture); - - // 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(); -} - -void CoinRiftWidget::handlingSafetyWarning(void) -{ - // Health and Safety Warning display state. - ovrHSWDisplayState hswDisplayState; - ovrHmd_GetHSWDisplayState(hmd, &hswDisplayState); - if (hswDisplayState.Displayed) - { - // Dismiss the warning if the user pressed the appropriate key or if the user - // is tapping the side of the HMD. - // If the user has requested to dismiss the warning via keyboard or controller input... - //if (Util_GetAndResetHSWDismissedState()) - ovrHmd_DismissHSWDisplay(hmd); - //else - //{ - // // Detect a moderate tap on the side of the HMD. - // ovrTrackingState ts = ovrHmd_GetTrackingState(hmd, ovr_GetTimeInSeconds()); - // if (ts.StatusFlags & ovrStatus_OrientationTracked) - // { - // const OVR::Vector3f v(ts.RawSensorData.Accelerometer.x, - // ts.RawSensorData.Accelerometer.y, - // ts.RawSensorData.Accelerometer.z); - // // Arbitrary value and representing moderate tap on the side of the DK2 Rift. - // if (v.LengthSq() > 250.f) - // ovrHmd_DismissHSWDisplay(hmd); - // } - //} - } - -} - - - static CoinRiftWidget *window=0; +static View3DInventorRiftViewer *window=0; void oculusStop() @@ -504,7 +65,7 @@ int oculusStart(void) return 0; } - window = new CoinRiftWidget; + window = new View3DInventorRiftViewer; window->show(); // An example scene. diff --git a/src/Gui/View3DInventorRiftViewer.h b/src/Gui/View3DInventorRiftViewer.h new file mode 100644 index 000000000..3f08b720c --- /dev/null +++ b/src/Gui/View3DInventorRiftViewer.h @@ -0,0 +1,42 @@ +/*************************************************************************** + * Copyright (c) 2014 Juergen Riegel * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library 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 Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + +#ifndef GUI_View3DInventorRiftViewer_H +#define GUI_View3DInventorRiftViewer_H + +#if BUILD_VR + +#include "CoinRiftWidget.h" + +namespace Gui { + +class View3DInventorRiftViewer : public CoinRiftWidget +{ + +}; + + +} //namespace Gui + +#endif //BUILD_VR + +#endif //GUI_View3DInventorRiftViewer_H \ No newline at end of file