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/cmake/externals/boostconfig/CMakeLists.txt b/cmake/externals/boostconfig/CMakeLists.txt index 8785e0d7c7..8494bb0114 100644 --- a/cmake/externals/boostconfig/CMakeLists.txt +++ b/cmake/externals/boostconfig/CMakeLists.txt @@ -3,13 +3,13 @@ string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER) include(ExternalProject) ExternalProject_Add( - ${EXTERNAL_NAME} - URL https://github.com/boostorg/config/archive/boost-1.58.0.zip - URL_MD5 42fa673bae2b7645a22736445e80eb8d - CONFIGURE_COMMAND "" - BUILD_COMMAND "" - INSTALL_COMMAND "" - LOG_DOWNLOAD 1 + ${EXTERNAL_NAME} + URL https://github.com/boostorg/config/archive/boost-1.58.0.zip + URL_MD5 42fa673bae2b7645a22736445e80eb8d + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND "" + LOG_DOWNLOAD 1 ) ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR) diff --git a/cmake/externals/oglplus/CMakeLists.txt b/cmake/externals/oglplus/CMakeLists.txt index 1413edce34..23ba0d515e 100644 --- a/cmake/externals/oglplus/CMakeLists.txt +++ b/cmake/externals/oglplus/CMakeLists.txt @@ -3,13 +3,13 @@ string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER) include(ExternalProject) ExternalProject_Add( - ${EXTERNAL_NAME} - URL http://softlayer-dal.dl.sourceforge.net/project/oglplus/oglplus-0.61.x/oglplus-0.61.0.zip - URL_MD5 bb55038c36c660d2b6c7be380414fa60 - CONFIGURE_COMMAND "" - BUILD_COMMAND "" - INSTALL_COMMAND "" - LOG_DOWNLOAD 1 + ${EXTERNAL_NAME} + GIT_REPOSITORY https://github.com/jherico/oglplus.git + GIT_TAG 470d8e56fd6bf3913ceec03d82f42d3bafab2cbe + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND "" + LOG_DOWNLOAD 1 ) ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR) diff --git a/cmake/macros/SetupHifiOpenGL.cmake b/cmake/macros/SetupHifiOpenGL.cmake new file mode 100644 index 0000000000..c62e43c27e --- /dev/null +++ b/cmake/macros/SetupHifiOpenGL.cmake @@ -0,0 +1,43 @@ + + +macro(SETUP_HIFI_OPENGL) + + if (APPLE) + + # link in required OS X frameworks and include the right GL headers + find_library(OpenGL OpenGL) + target_link_libraries(${TARGET_NAME} ${OpenGL}) + + elseif (WIN32) + + add_dependency_external_projects(glew) + find_package(GLEW REQUIRED) + target_include_directories(${TARGET_NAME} PUBLIC ${GLEW_INCLUDE_DIRS}) + target_link_libraries(${TARGET_NAME} ${GLEW_LIBRARIES} opengl32.lib) + + if (USE_NSIGHT) + # try to find the Nsight package and add it to the build if we find it + find_package(NSIGHT) + if (NSIGHT_FOUND) + include_directories(${NSIGHT_INCLUDE_DIRS}) + add_definitions(-DNSIGHT_FOUND) + target_link_libraries(${TARGET_NAME} "${NSIGHT_LIBRARIES}") + endif() + endif() + + elseif(ANDROID) + + target_link_libraries(${TARGET_NAME} "-lGLESv3" "-lEGL") + + else() + + find_package(OpenGL REQUIRED) + if (${OPENGL_INCLUDE_DIR}) + include_directories(SYSTEM "${OPENGL_INCLUDE_DIR}") + endif() + target_link_libraries(${TARGET_NAME} "${OPENGL_LIBRARY}") + target_include_directories(${TARGET_NAME} PUBLIC ${OPENGL_INCLUDE_DIR}) + + endif() + +endmacro() diff --git a/interface/resources/images/address-bar.svg b/interface/resources/images/address-bar.svg index 0a472cbe4e..dd907aa6c9 100644 --- a/interface/resources/images/address-bar.svg +++ b/interface/resources/images/address-bar.svg @@ -15,7 +15,7 @@ viewBox="0 0 1440 200" id="svg4136" inkscape:version="0.91 r13725" - sodipodi:docname="address-bar.svg"> + sodipodi:docname="address-bar.002.svg"> @@ -39,14 +39,14 @@ guidetolerance="10" inkscape:pageopacity="0" inkscape:pageshadow="2" - inkscape:window-width="1840" + inkscape:window-width="1835" inkscape:window-height="1057" id="namedview4140" showgrid="false" - inkscape:zoom="0.8671875" - inkscape:cx="707.02439" + inkscape:zoom="0.61319416" + inkscape:cx="132.58366" inkscape:cy="52.468468" - inkscape:window-x="72" + inkscape:window-x="77" inkscape:window-y="-8" inkscape:window-maximized="1" inkscape:current-layer="svg4136" /> @@ -59,6 +59,15 @@ y="30" rx="16.025024" ry="17.019567" /> + + diff --git a/interface/resources/images/darkgreyarrow.png b/interface/resources/images/darkgreyarrow.png new file mode 100644 index 0000000000..4c9a8a2bbf Binary files /dev/null and b/interface/resources/images/darkgreyarrow.png differ diff --git a/interface/resources/images/darkgreyarrow.svg b/interface/resources/images/darkgreyarrow.svg new file mode 100644 index 0000000000..2d049d90d7 --- /dev/null +++ b/interface/resources/images/darkgreyarrow.svg @@ -0,0 +1,11 @@ + + + + + + + + + diff --git a/interface/resources/images/left-arrow.svg b/interface/resources/images/left-arrow.svg new file mode 100644 index 0000000000..cede9fa959 --- /dev/null +++ b/interface/resources/images/left-arrow.svg @@ -0,0 +1,50 @@ + + + +image/svg+xml \ No newline at end of file diff --git a/interface/resources/images/lightgreyarrow.png b/interface/resources/images/lightgreyarrow.png new file mode 100644 index 0000000000..1e221f3c73 Binary files /dev/null and b/interface/resources/images/lightgreyarrow.png differ diff --git a/interface/resources/images/lightgreyarrow.svg b/interface/resources/images/lightgreyarrow.svg new file mode 100644 index 0000000000..fbe697c3e9 --- /dev/null +++ b/interface/resources/images/lightgreyarrow.svg @@ -0,0 +1,11 @@ + + + + + + + + + diff --git a/interface/resources/images/sepline.png b/interface/resources/images/sepline.png new file mode 100644 index 0000000000..959fcee72f Binary files /dev/null and b/interface/resources/images/sepline.png differ diff --git a/interface/resources/images/sepline.svg b/interface/resources/images/sepline.svg new file mode 100644 index 0000000000..32afaf7148 --- /dev/null +++ b/interface/resources/images/sepline.svg @@ -0,0 +1,3 @@ + + +2015-06-12 18:23ZCanvas 1 Navi Bar diff --git a/interface/resources/qml/AddressBarDialog.qml b/interface/resources/qml/AddressBarDialog.qml index 3377b20d87..70cb22dc4d 100644 --- a/interface/resources/qml/AddressBarDialog.qml +++ b/interface/resources/qml/AddressBarDialog.qml @@ -45,19 +45,64 @@ DialogContainer { property int inputAreaHeight: 56.0 * root.scale // Height of the background's input area property int inputAreaStep: (height - inputAreaHeight) / 2 + Image { + id: backArrow + + source: "../images/left-arrow.svg" + scale: 0.9 + + anchors { + fill: parent + leftMargin: parent.height + hifi.layout.spacing + 6 + rightMargin: parent.height + hifi.layout.spacing * 60 + topMargin: parent.inputAreaStep + parent.inputAreaStep + hifi.layout.spacing + bottomMargin: parent.inputAreaStep + parent.inputAreaStep + hifi.layout.spacing + } + + MouseArea { + anchors.fill: parent + acceptedButtons: Qt.LeftButton + onClicked: { + addressBarDialog.loadBack() + } + } + } + + Image { + id: forwardArrow + + source: "../images/darkgreyarrow.svg" + + anchors { + fill: parent + leftMargin: parent.height + hifi.layout.spacing * 9 + rightMargin: parent.height + hifi.layout.spacing * 53 + topMargin: parent.inputAreaStep + parent.inputAreaStep + hifi.layout.spacing + bottomMargin: parent.inputAreaStep + parent.inputAreaStep + hifi.layout.spacing + } + + MouseArea { + anchors.fill: parent + acceptedButtons: Qt.LeftButton + onClicked: { + addressBarDialog.loadForward() + } + } + } + TextInput { id: addressLine anchors { fill: parent - leftMargin: parent.height + hifi.layout.spacing * 2 + leftMargin: parent.height + parent.height + hifi.layout.spacing * 5 rightMargin: hifi.layout.spacing * 2 topMargin: parent.inputAreaStep + hifi.layout.spacing bottomMargin: parent.inputAreaStep + hifi.layout.spacing } - font.pixelSize: hifi.fonts.pixelSize * root.scale + font.pixelSize: hifi.fonts.pixelSize * root.scale * 0.75 helperText: "Go to: place, @user, /path, network address" @@ -66,7 +111,7 @@ DialogContainer { addressBarDialog.loadAddress(addressLine.text) } } - + MouseArea { // Drag the icon width: parent.height @@ -82,6 +127,7 @@ DialogContainer { } } + /* MouseArea { // Drag the input rectangle width: parent.width - parent.height @@ -95,7 +141,7 @@ DialogContainer { maximumX: root.parent ? root.maximumX : 0 maximumY: root.parent ? root.maximumY + parent.inputAreaStep : 0 } - } + }*/ } } diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 651e343087..9e29791a05 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1930,11 +1930,15 @@ void Application::setEnableVRMode(bool enableVRMode) { // attempt to reconnect the Oculus manager - it's possible this was a workaround // for the sixense crash OculusManager::disconnect(); - OculusManager::connect(); + OculusManager::connect(_glWidget->context()->contextHandle()); + _glWidget->setFocus(); + _glWidget->makeCurrent(); + glClear(GL_COLOR_BUFFER_BIT); } OculusManager::recalibrate(); } else { OculusManager::abandonCalibration(); + OculusManager::disconnect(); _mirrorCamera.setHmdPosition(glm::vec3()); _mirrorCamera.setHmdRotation(glm::quat()); @@ -2170,13 +2174,6 @@ void Application::init() { _mirrorCamera.setMode(CAMERA_MODE_MIRROR); - OculusManager::connect(); - if (OculusManager::isConnected()) { - QMetaObject::invokeMethod(Menu::getInstance()->getActionForOption(MenuOption::Fullscreen), - "trigger", - Qt::QueuedConnection); - } - TV3DManager::connect(); if (TV3DManager::isConnected()) { QMetaObject::invokeMethod(Menu::getInstance()->getActionForOption(MenuOption::Fullscreen), diff --git a/interface/src/devices/OculusManager.cpp b/interface/src/devices/OculusManager.cpp index a7383ae4bb..de007f6c19 100644 --- a/interface/src/devices/OculusManager.cpp +++ b/interface/src/devices/OculusManager.cpp @@ -25,6 +25,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -34,7 +37,6 @@ #include "InterfaceLogging.h" #include "Application.h" -#include template void for_each_eye(Function function) { @@ -53,27 +55,133 @@ void for_each_eye(const ovrHmd & hmd, Function function) { } } -#ifdef OVR_CLIENT_DISTORTION -ProgramObject OculusManager::_program; -int OculusManager::_textureLocation; -int OculusManager::_eyeToSourceUVScaleLocation; -int OculusManager::_eyeToSourceUVOffsetLocation; -int OculusManager::_eyeRotationStartLocation; -int OculusManager::_eyeRotationEndLocation; -int OculusManager::_positionAttributeLocation; -int OculusManager::_colorAttributeLocation; -int OculusManager::_texCoord0AttributeLocation; -int OculusManager::_texCoord1AttributeLocation; -int OculusManager::_texCoord2AttributeLocation; -ovrVector2f OculusManager::_UVScaleOffset[ovrEye_Count][2]; -GLuint OculusManager::_vertices[ovrEye_Count] = { 0, 0 }; -GLuint OculusManager::_indices[ovrEye_Count] = { 0, 0 }; -GLsizei OculusManager::_meshSize[ovrEye_Count] = { 0, 0 }; -ovrFrameTiming OculusManager::_hmdFrameTiming; -bool OculusManager::_programInitialized = false; -#endif + +#ifdef Q_OS_WIN + +// 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) { + color = 0; + depth = 0; + }; + + void Resize(const uvec2 & size) { + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, oglplus::GetName(fbo)); + glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); + this->size = size; + initColor(); + initDone(); + } + +protected: + virtual void initDepth() override final { + } +}; + +// 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 SwapFramebufferWrapper : public RiftFramebufferWrapper { + SwapFramebufferWrapper(const ovrHmd & hmd) + : RiftFramebufferWrapper(hmd) { + } + + ~SwapFramebufferWrapper() { + if (color) { + ovrHmd_DestroySwapTextureSet(hmd, color); + color = nullptr; + } + } + + void Increment() { + ++color->CurrentIndex; + color->CurrentIndex %= color->TextureCount; + } + +protected: + virtual void initColor() override { + if (color) { + ovrHmd_DestroySwapTextureSet(hmd, color); + color = nullptr; + } + + ovrResult result = ovrHmd_CreateSwapTextureSetGL(hmd, GL_RGBA, size.x, size.y, &color); + Q_ASSERT(OVR_SUCCESS(result)); + + 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() override { + } + + virtual void onBind(oglplus::Framebuffer::Target target) override { + ovrGLTexture& tex = (ovrGLTexture&)(color->Textures[color->CurrentIndex]); + glFramebufferTexture2D(toEnum(target), GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex.OGL.TexId, 0); + } + + virtual void onUnbind(oglplus::Framebuffer::Target target) override { + glFramebufferTexture2D(toEnum(target), GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); + } +}; + + +// 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 { + MirrorFramebufferWrapper(const ovrHmd & hmd) + : RiftFramebufferWrapper(hmd) { + } + + virtual ~MirrorFramebufferWrapper() { + if (color) { + ovrHmd_DestroyMirrorTexture(hmd, (ovrTexture*)color); + color = nullptr; + } + } + +private: + void initColor() override { + if (color) { + ovrHmd_DestroyMirrorTexture(hmd, (ovrTexture*)color); + color = nullptr; + } + ovrResult result = ovrHmd_CreateMirrorTextureGL(hmd, GL_RGBA, size.x, size.y, (ovrTexture**)&color); + Q_ASSERT(OVR_SUCCESS(result)); + } + + void initDone() override { + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, oglplus::GetName(fbo)); + glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color->OGL.TexId, 0); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); + } +}; + +SwapFramebufferWrapper* OculusManager::_swapFbo{ nullptr }; +MirrorFramebufferWrapper* OculusManager::_mirrorFbo{ nullptr }; +ovrLayerEyeFov OculusManager::_sceneLayer; + +#else ovrTexture OculusManager::_eyeTextures[ovrEye_Count]; +GlWindow* OculusManager::_outputWindow{ nullptr }; + +#endif + bool OculusManager::_isConnected = false; ovrHmd OculusManager::_ovrHmd; ovrFovPort OculusManager::_eyeFov[ovrEye_Count]; @@ -104,146 +212,177 @@ bool OculusManager::_eyePerFrameMode = false; ovrEyeType OculusManager::_lastEyeRendered = ovrEye_Count; ovrSizei OculusManager::_recommendedTexSize = { 0, 0 }; float OculusManager::_offscreenRenderScale = 1.0; - - -void OculusManager::initSdk() { - ovr_Initialize(); - _ovrHmd = ovrHmd_Create(0); - if (!_ovrHmd) { - _ovrHmd = ovrHmd_CreateDebug(ovrHmd_DK2); - } -} - -void OculusManager::shutdownSdk() { - if (_ovrHmd) { - ovrHmd_Destroy(_ovrHmd); - _ovrHmd = nullptr; - ovr_Shutdown(); - } -} +ovrRecti OculusManager::_eyeViewports[ovrEye_Count]; void OculusManager::init() { -#ifdef OVR_DIRECT_MODE - initSdk(); -#endif } void OculusManager::deinit() { -#ifdef OVR_DIRECT_MODE - shutdownSdk(); -#endif } -void OculusManager::connect() { -#ifndef OVR_DIRECT_MODE - initSdk(); -#endif - _calibrationState = UNCALIBRATED; +void OculusManager::connect(QOpenGLContext* shareContext) { qCDebug(interfaceapp) << "Oculus SDK" << OVR_VERSION_STRING; - if (_ovrHmd) { - if (!_isConnected) { - UserActivityLogger::getInstance().connectedDevice("hmd", "oculus"); - } - _isConnected = true; - for_each_eye([&](ovrEyeType eye) { - _eyeFov[eye] = _ovrHmd->DefaultEyeFov[eye]; - }); + ovrInitParams initParams; memset(&initParams, 0, sizeof(initParams)); - ovrGLConfig cfg; - memset(&cfg, 0, sizeof(cfg)); - cfg.OGL.Header.API = ovrRenderAPI_OpenGL; - cfg.OGL.Header.BackBufferSize = _ovrHmd->Resolution; - cfg.OGL.Header.Multisample = 1; - - int distortionCaps = 0 - | ovrDistortionCap_Vignette - | ovrDistortionCap_Overdrive - | ovrDistortionCap_TimeWarp; - - int configResult = ovrHmd_ConfigureRendering(_ovrHmd, &cfg.Config, - distortionCaps, _eyeFov, _eyeRenderDesc); - assert(configResult); - - - _recommendedTexSize = ovrHmd_GetFovTextureSize(_ovrHmd, ovrEye_Left, _eyeFov[ovrEye_Left], 1.0f); - _renderTargetSize = { _recommendedTexSize.w * 2, _recommendedTexSize.h }; - for_each_eye([&](ovrEyeType eye) { - //Get texture size - _eyeTextures[eye].Header.API = ovrRenderAPI_OpenGL; - _eyeTextures[eye].Header.TextureSize = _renderTargetSize; - _eyeTextures[eye].Header.RenderViewport.Pos = { 0, 0 }; - }); - _eyeTextures[ovrEye_Right].Header.RenderViewport.Pos.x = _recommendedTexSize.w; - - ovrHmd_SetEnabledCaps(_ovrHmd, ovrHmdCap_LowPersistence | ovrHmdCap_DynamicPrediction); - - ovrHmd_ConfigureTracking(_ovrHmd, ovrTrackingCap_Orientation | ovrTrackingCap_Position | - ovrTrackingCap_MagYawCorrection, - ovrTrackingCap_Orientation); - - if (!_camera) { - _camera = new Camera; - configureCamera(*_camera); // no need to use screen dimensions; they're ignored - } -#ifdef OVR_CLIENT_DISTORTION - if (!_programInitialized) { - // Shader program - _programInitialized = true; - _program.addShaderFromSourceFile(QGLShader::Vertex, PathUtils::resourcesPath() + "shaders/oculus.vert"); - _program.addShaderFromSourceFile(QGLShader::Fragment, PathUtils::resourcesPath() + "shaders/oculus.frag"); - _program.link(); - - // Uniforms - _textureLocation = _program.uniformLocation("texture"); - _eyeToSourceUVScaleLocation = _program.uniformLocation("EyeToSourceUVScale"); - _eyeToSourceUVOffsetLocation = _program.uniformLocation("EyeToSourceUVOffset"); - _eyeRotationStartLocation = _program.uniformLocation("EyeRotationStart"); - _eyeRotationEndLocation = _program.uniformLocation("EyeRotationEnd"); - - // Attributes - _positionAttributeLocation = _program.attributeLocation("position"); - _colorAttributeLocation = _program.attributeLocation("color"); - _texCoord0AttributeLocation = _program.attributeLocation("texCoord0"); - _texCoord1AttributeLocation = _program.attributeLocation("texCoord1"); - _texCoord2AttributeLocation = _program.attributeLocation("texCoord2"); - } - - //Generate the distortion VBOs - generateDistortionMesh(); +#ifdef DEBUG + initParams.Flags |= ovrInit_Debug; #endif - } else { + + ovr_Initialize(&initParams); + +#ifdef Q_OS_WIN + + ovrResult res = ovrHmd_Create(0, &_ovrHmd); +#ifdef DEBUG + if (!OVR_SUCCESS(res)) { + res = ovrHmd_CreateDebug(ovrHmd_DK2, &_ovrHmd); + Q_ASSERT(OVR_SUCCESS(res)); + } +#endif + +#else + + _ovrHmd = ovrHmd_Create(0); +#ifdef DEBUG + if (!_ovrHmd) { + _ovrHmd = ovrHmd_CreateDebug(ovrHmd_DK2); + } +#endif + +#endif + + if (!_ovrHmd) { _isConnected = false; - // we're definitely not in "VR mode" so tell the menu that Menu::getInstance()->getActionForOption(MenuOption::EnableVRMode)->setChecked(false); + ovr_Shutdown(); + return; + } + + _calibrationState = UNCALIBRATED; + if (!_isConnected) { + UserActivityLogger::getInstance().connectedDevice("hmd", "oculus"); + } + _isConnected = true; + + for_each_eye([&](ovrEyeType eye) { + _eyeFov[eye] = _ovrHmd->DefaultEyeFov[eye]; + }); + + _recommendedTexSize = ovrHmd_GetFovTextureSize(_ovrHmd, ovrEye_Left, _eyeFov[ovrEye_Left], 1.0f); + _renderTargetSize = { _recommendedTexSize.w * 2, _recommendedTexSize.h }; + +#ifdef Q_OS_WIN + + _mirrorFbo = new MirrorFramebufferWrapper(_ovrHmd); + _swapFbo = new SwapFramebufferWrapper(_ovrHmd); + _swapFbo->Init(toGlm(_renderTargetSize)); + _sceneLayer.ColorTexture[0] = _swapFbo->color; + _sceneLayer.ColorTexture[1] = nullptr; + _sceneLayer.Viewport[0].Pos = { 0, 0 }; + _sceneLayer.Viewport[0].Size = _recommendedTexSize; + _sceneLayer.Viewport[1].Pos = { _recommendedTexSize.w, 0 }; + _sceneLayer.Viewport[1].Size = _recommendedTexSize; + _sceneLayer.Header.Type = ovrLayerType_EyeFov; + _sceneLayer.Header.Flags = ovrLayerFlag_TextureOriginAtBottomLeft; + for_each_eye([&](ovrEyeType eye) { + _eyeViewports[eye] = _sceneLayer.Viewport[eye]; + _sceneLayer.Fov[eye] = _eyeFov[eye]; + }); + + + +#else + _outputWindow = new GlWindow(shareContext); + _outputWindow->show(); +// _outputWindow->setFlags(Qt::FramelessWindowHint ); +// _outputWindow->resize(_ovrHmd->Resolution.w, _ovrHmd->Resolution.h); +// _outputWindow->setPosition(_ovrHmd->WindowsPos.x, _ovrHmd->WindowsPos.y); + ivec2 desiredPosition = toGlm(_ovrHmd->WindowsPos); + foreach(QScreen* screen, qGuiApp->screens()) { + ivec2 screenPosition = toGlm(screen->geometry().topLeft()); + if (screenPosition == desiredPosition) { + _outputWindow->setScreen(screen); + break; + } + } + _outputWindow->showFullScreen(); + _outputWindow->makeCurrent(); + + ovrGLConfig cfg; + memset(&cfg, 0, sizeof(cfg)); + cfg.OGL.Header.API = ovrRenderAPI_OpenGL; + cfg.OGL.Header.BackBufferSize = _ovrHmd->Resolution; + cfg.OGL.Header.Multisample = 0; + + int distortionCaps = 0 + | ovrDistortionCap_Vignette + | ovrDistortionCap_Overdrive + | ovrDistortionCap_TimeWarp; + + int configResult = ovrHmd_ConfigureRendering(_ovrHmd, &cfg.Config, + distortionCaps, _eyeFov, _eyeRenderDesc); + assert(configResult); + _outputWindow->doneCurrent(); + + for_each_eye([&](ovrEyeType eye) { + //Get texture size + _eyeTextures[eye].Header.API = ovrRenderAPI_OpenGL; + _eyeTextures[eye].Header.TextureSize = _renderTargetSize; + _eyeTextures[eye].Header.RenderViewport.Pos = { 0, 0 }; + _eyeTextures[eye].Header.RenderViewport.Size = _renderTargetSize; + _eyeTextures[eye].Header.RenderViewport.Size.w /= 2; + }); + _eyeTextures[ovrEye_Right].Header.RenderViewport.Pos.x = _recommendedTexSize.w; + for_each_eye([&](ovrEyeType eye) { + _eyeViewports[eye] = _eyeTextures[eye].Header.RenderViewport; + }); +#endif + + ovrHmd_SetEnabledCaps(_ovrHmd, + ovrHmdCap_LowPersistence | ovrHmdCap_DynamicPrediction); + + ovrHmd_ConfigureTracking(_ovrHmd, + ovrTrackingCap_Orientation | ovrTrackingCap_Position | ovrTrackingCap_MagYawCorrection, + ovrTrackingCap_Orientation); + + if (!_camera) { + _camera = new Camera; + configureCamera(*_camera); // no need to use screen dimensions; they're ignored } } //Disconnects and deallocates the OR void OculusManager::disconnect() { if (_isConnected) { + +#ifdef Q_OS_WIN + if (_swapFbo) { + delete _swapFbo; + _swapFbo = nullptr; + } + + if (_mirrorFbo) { + delete _mirrorFbo; + _mirrorFbo = nullptr; + } +#else + _outputWindow->showNormal(); + _outputWindow->deleteLater(); + _outputWindow = nullptr; +#endif + + if (_ovrHmd) { + ovrHmd_Destroy(_ovrHmd); + _ovrHmd = nullptr; + } + ovr_Shutdown(); + _isConnected = false; // Prepare to potentially have to dismiss the HSW again // if the user re-enables VR _hswDismissed = false; -#ifndef OVR_DIRECT_MODE - shutdownSdk(); -#endif - -#ifdef OVR_CLIENT_DISTORTION - //Free the distortion mesh data - for (int i = 0; i < ovrEye_Count; i++) { - if (_vertices[i] != 0) { - glDeleteBuffers(1, &(_vertices[i])); - _vertices[i] = 0; - } - if (_indices[i] != 0) { - glDeleteBuffers(1, &(_indices[i])); - _indices[i] = 0; - } - } -#endif } } @@ -346,7 +485,6 @@ void OculusManager::calibrate(glm::vec3 position, glm::quat orientation) { break; default: break; - } } @@ -363,64 +501,8 @@ void OculusManager::abandonCalibration() { } } -#ifdef OVR_CLIENT_DISTORTION -void OculusManager::generateDistortionMesh() { - - //Check if we already have the distortion mesh - if (_vertices[0] != 0) { - printf("WARNING: Tried to generate Oculus distortion mesh twice without freeing the VBOs."); - return; - } - - for (int eyeNum = 0; eyeNum < ovrEye_Count; eyeNum++) { - // Allocate and generate distortion mesh vertices - ovrDistortionMesh meshData; - ovrHmd_CreateDistortionMesh(_ovrHmd, _eyeRenderDesc[eyeNum].Eye, _eyeRenderDesc[eyeNum].Fov, _ovrHmd->DistortionCaps, &meshData); - - // Parse the vertex data and create a render ready vertex buffer - DistortionVertex* pVBVerts = new DistortionVertex[meshData.VertexCount]; - _meshSize[eyeNum] = meshData.IndexCount; - - // Convert the oculus vertex data to the DistortionVertex format. - DistortionVertex* v = pVBVerts; - ovrDistortionVertex* ov = meshData.pVertexData; - for (unsigned int vertNum = 0; vertNum < meshData.VertexCount; vertNum++) { - v->pos.x = ov->ScreenPosNDC.x; - v->pos.y = ov->ScreenPosNDC.y; - v->texR.x = ov->TanEyeAnglesR.x; - v->texR.y = ov->TanEyeAnglesR.y; - v->texG.x = ov->TanEyeAnglesG.x; - v->texG.y = ov->TanEyeAnglesG.y; - v->texB.x = ov->TanEyeAnglesB.x; - v->texB.y = ov->TanEyeAnglesB.y; - v->color.r = v->color.g = v->color.b = (GLubyte)(ov->VignetteFactor * 255.99f); - v->color.a = (GLubyte)(ov->TimeWarpFactor * 255.99f); - v++; - ov++; - } - - //vertices - glGenBuffers(1, &(_vertices[eyeNum])); - glBindBuffer(GL_ARRAY_BUFFER, _vertices[eyeNum]); - glBufferData(GL_ARRAY_BUFFER, sizeof(DistortionVertex) * meshData.VertexCount, pVBVerts, GL_STATIC_DRAW); - glBindBuffer(GL_ARRAY_BUFFER, 0); - - //indices - glGenBuffers(1, &(_indices[eyeNum])); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indices[eyeNum]); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned short) * meshData.IndexCount, meshData.pIndexData, GL_STATIC_DRAW); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - - //Now that we have the VBOs we can get rid of the mesh data - delete [] pVBVerts; - ovrHmd_DestroyDistortionMesh(&meshData); - } - -} -#endif - bool OculusManager::isConnected() { - return _isConnected && Menu::getInstance()->isOptionChecked(MenuOption::EnableVRMode); + return _isConnected; } //Begins the frame timing for oculus prediction purposes @@ -428,10 +510,6 @@ void OculusManager::beginFrameTiming() { if (_frameTimingActive) { printf("WARNING: Called OculusManager::beginFrameTiming() twice in a row, need to call OculusManager::endFrameTiming()."); } - -#ifdef OVR_CLIENT_DISTORTION - _hmdFrameTiming = ovrHmd_BeginFrameTiming(_ovrHmd, _frameIndex); -#endif _frameTimingActive = true; } @@ -441,9 +519,6 @@ bool OculusManager::allowSwap() { //Ends frame timing void OculusManager::endFrameTiming() { -#ifdef OVR_CLIENT_DISTORTION - ovrHmd_EndFrameTiming(_ovrHmd); -#endif _frameIndex++; _frameTimingActive = false; } @@ -473,40 +548,8 @@ void OculusManager::display(QGLWidget * glCanvas, RenderArgs* renderArgs, const assert(oldFrameIndex == -1 || (unsigned int)oldFrameIndex == _frameIndex - 1); oldFrameIndex = _frameIndex; #endif - - // Every so often do some additional timing calculations and debug output - bool debugFrame = 0 == _frameIndex % 400; -#if 0 - // Try to measure the amount of time taken to do the distortion - // (does not seem to work on OSX with SDK based distortion) - // FIXME can't use a static object here, because it will cause a crash when the - // query attempts deconstruct after the GL context is gone. - static bool timerActive = false; - static QOpenGLTimerQuery timerQuery; - if (!timerQuery.isCreated()) { - timerQuery.create(); - } - - if (timerActive && timerQuery.isResultAvailable()) { - auto result = timerQuery.waitForResult(); - if (result) { qCDebug(interfaceapp) << "Distortion took " << result << "ns"; }; - timerActive = false; - } -#endif - -#ifdef OVR_DIRECT_MODE - static bool attached = false; - if (!attached) { - attached = true; - void * nativeWindowHandle = (void*)(size_t)glCanvas->effectiveWinId(); - if (nullptr != nativeWindowHandle) { - ovrHmd_AttachToWindow(_ovrHmd, nativeWindowHandle, nullptr, nullptr); - } - } -#endif - -#ifndef OVR_CLIENT_DISTORTION +#ifndef Q_OS_WIN // FIXME: we need a better way of responding to the HSW. In particular // we need to ensure that it's only displayed once per session, rather than // every time the user toggles VR mode, and we need to hook it up to actual @@ -522,7 +565,6 @@ void OculusManager::display(QGLWidget * glCanvas, RenderArgs* renderArgs, const } } #endif - //beginFrameTiming must be called before display if (!_frameTimingActive) { @@ -565,7 +607,9 @@ void OculusManager::display(QGLWidget * glCanvas, RenderArgs* renderArgs, const static ovrVector3f eyeOffsets[2] = { { 0, 0, 0 }, { 0, 0, 0 } }; ovrPosef eyePoses[ovrEye_Count]; ovrHmd_GetEyePoses(_ovrHmd, _frameIndex, eyeOffsets, eyePoses, nullptr); +#ifndef Q_OS_WIN ovrHmd_BeginFrame(_ovrHmd, _frameIndex); +#endif static ovrPosef eyeRenderPose[ovrEye_Count]; //Render each eye into an fbo for_each_eye(_ovrHmd, [&](ovrEyeType eye){ @@ -607,10 +651,9 @@ void OculusManager::display(QGLWidget * glCanvas, RenderArgs* renderArgs, const glMatrixMode(GL_MODELVIEW); glLoadIdentity(); - ovrRecti & vp = _eyeTextures[eye].Header.RenderViewport; + ovrRecti & vp = _eyeViewports[eye]; vp.Size.h = _recommendedTexSize.h * _offscreenRenderScale; vp.Size.w = _recommendedTexSize.w * _offscreenRenderScale; - glViewport(vp.Pos.x, vp.Pos.y, vp.Size.w, vp.Size.h); renderArgs->_renderSide = RenderArgs::MONO; @@ -638,142 +681,58 @@ void OculusManager::display(QGLWidget * glCanvas, RenderArgs* renderArgs, const // restore our normal viewport glViewport(0, 0, deviceSize.width(), deviceSize.height()); -#if 0 - if (debugFrame && !timerActive) { - timerQuery.begin(); - } -#endif +#ifdef Q_OS_WIN + auto srcFboSize = finalFbo->getSize(); -#ifdef OVR_CLIENT_DISTORTION - - //Wait till time-warp to reduce latency - ovr_WaitTillTime(_hmdFrameTiming.TimewarpPointSeconds); - -#ifdef DEBUG_RENDER_WITHOUT_DISTORTION - auto fboSize = finalFbo->getSize(); + // Blit to the oculus provided texture glBindFramebuffer(GL_READ_FRAMEBUFFER, gpu::GLBackend::getFramebufferID(finalFbo)); + _swapFbo->Bound(oglplus::Framebuffer::Target::Draw, [&] { + glBlitFramebuffer( + 0, 0, srcFboSize.x, srcFboSize.y, + 0, 0, _swapFbo->size.x, _swapFbo->size.y, + GL_COLOR_BUFFER_BIT, GL_NEAREST); + }); + + // Blit to the onscreen window + auto destWindowSize = qApp->getDeviceSize(); glBlitFramebuffer( - 0, 0, fboSize.x, fboSize.y, - 0, 0, deviceSize.width(), deviceSize.height(), + 0, 0, srcFboSize.x, srcFboSize.y, + 0, 0, destWindowSize.width(), destWindowSize.height(), GL_COLOR_BUFFER_BIT, GL_NEAREST); + glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); + + // Submit the frame to the Oculus SDK for timewarp and distortion + for_each_eye([&](ovrEyeType eye) { + _sceneLayer.RenderPose[eye] = eyeRenderPose[eye]; + }); + auto header = &_sceneLayer.Header; + ovrResult res = ovrHmd_SubmitFrame(_ovrHmd, _frameIndex, nullptr, &header, 1); + Q_ASSERT(OVR_SUCCESS(res)); + _swapFbo->Increment(); #else - //Clear the color buffer to ensure that there isnt any residual color - //Left over from when OR was not connected. - glClear(GL_COLOR_BUFFER_BIT); - glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(finalFbo->getRenderBuffer(0))); - //Renders the distorted mesh onto the screen - renderDistortionMesh(eyeRenderPose); - glBindTexture(GL_TEXTURE_2D, 0); -#endif - glCanvas->swapBuffers(); + GLsync syncObject = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); + glFlush(); -#else + _outputWindow->makeCurrent(); + // force the compositing context to wait for the texture + // rendering to complete before it starts the distortion rendering, + // but without triggering a CPU/GPU synchronization + glWaitSync(syncObject, 0, GL_TIMEOUT_IGNORED); + GLuint textureId = gpu::GLBackend::getTextureID(finalFbo->getRenderBuffer(0)); for_each_eye([&](ovrEyeType eye) { ovrGLTexture & glEyeTexture = reinterpret_cast(_eyeTextures[eye]); - glEyeTexture.OGL.TexId = finalFbo->texture(); - + glEyeTexture.OGL.TexId = textureId; }); + // restore our normal viewport ovrHmd_EndFrame(_ovrHmd, eyeRenderPose, _eyeTextures); - + glCanvas->makeCurrent(); #endif - -#if 0 - if (debugFrame && !timerActive) { - timerQuery.end(); - timerActive = true; - } -#endif - - // No DK2, no message. - { - float latencies[5] = {}; - if (debugFrame && ovrHmd_GetFloatArray(_ovrHmd, "DK2Latency", latencies, 5) == 5) - { - bool nonZero = false; - for (int i = 0; i < 5; ++i) - { - nonZero |= (latencies[i] != 0.f); - } - - if (nonZero) - { - qCDebug(interfaceapp) << QString().sprintf("M2P Latency: Ren: %4.2fms TWrp: %4.2fms PostPresent: %4.2fms Err: %4.2fms %4.2fms", - latencies[0], latencies[1], latencies[2], latencies[3], latencies[4]); - } - } - } + } -#ifdef OVR_CLIENT_DISTORTION -void OculusManager::renderDistortionMesh(ovrPosef eyeRenderPose[ovrEye_Count]) { - - glLoadIdentity(); - auto deviceSize = qApp->getDeviceSize(); - glOrtho(0, deviceSize.width(), 0, deviceSize.height(), -1.0, 1.0); - - glDisable(GL_DEPTH_TEST); - - glDisable(GL_BLEND); - _program.bind(); - _program.setUniformValue(_textureLocation, 0); - - _program.enableAttributeArray(_positionAttributeLocation); - _program.enableAttributeArray(_colorAttributeLocation); - _program.enableAttributeArray(_texCoord0AttributeLocation); - _program.enableAttributeArray(_texCoord1AttributeLocation); - _program.enableAttributeArray(_texCoord2AttributeLocation); - - //Render the distortion meshes for each eye - for (int eyeNum = 0; eyeNum < ovrEye_Count; eyeNum++) { - - ovrHmd_GetRenderScaleAndOffset(_eyeRenderDesc[eyeNum].Fov, _renderTargetSize, _eyeTextures[eyeNum].Header.RenderViewport, - _UVScaleOffset[eyeNum]); - - GLfloat uvScale[2] = { _UVScaleOffset[eyeNum][0].x, _UVScaleOffset[eyeNum][0].y }; - _program.setUniformValueArray(_eyeToSourceUVScaleLocation, uvScale, 1, 2); - GLfloat uvOffset[2] = { _UVScaleOffset[eyeNum][1].x, 1.0f - _UVScaleOffset[eyeNum][1].y }; - _program.setUniformValueArray(_eyeToSourceUVOffsetLocation, uvOffset, 1, 2); - - ovrMatrix4f timeWarpMatrices[2]; - glm::mat4 transposeMatrices[2]; - //Grabs the timewarp matrices to be used in the shader - ovrHmd_GetEyeTimewarpMatrices(_ovrHmd, (ovrEyeType)eyeNum, eyeRenderPose[eyeNum], timeWarpMatrices); - //Have to transpose the matrices before using them - transposeMatrices[0] = glm::transpose(toGlm(timeWarpMatrices[0])); - transposeMatrices[1] = glm::transpose(toGlm(timeWarpMatrices[1])); - - glUniformMatrix4fv(_eyeRotationStartLocation, 1, GL_FALSE, (GLfloat *)&transposeMatrices[0][0][0]); - glUniformMatrix4fv(_eyeRotationEndLocation, 1, GL_FALSE, (GLfloat *)&transposeMatrices[1][0][0]); - - glBindBuffer(GL_ARRAY_BUFFER, _vertices[eyeNum]); - - //Set vertex attribute pointers - glVertexAttribPointer(_positionAttributeLocation, 2, GL_FLOAT, GL_FALSE, sizeof(DistortionVertex), (void *)0); - glVertexAttribPointer(_texCoord0AttributeLocation, 2, GL_FLOAT, GL_FALSE, sizeof(DistortionVertex), (void *)8); - glVertexAttribPointer(_texCoord1AttributeLocation, 2, GL_FLOAT, GL_FALSE, sizeof(DistortionVertex), (void *)16); - glVertexAttribPointer(_texCoord2AttributeLocation, 2, GL_FLOAT, GL_FALSE, sizeof(DistortionVertex), (void *)24); - glVertexAttribPointer(_colorAttributeLocation, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(DistortionVertex), (void *)32); - - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indices[eyeNum]); - glDrawElements(GL_TRIANGLES, _meshSize[eyeNum], GL_UNSIGNED_SHORT, 0); - } - - _program.disableAttributeArray(_positionAttributeLocation); - _program.disableAttributeArray(_colorAttributeLocation); - _program.disableAttributeArray(_texCoord0AttributeLocation); - _program.disableAttributeArray(_texCoord1AttributeLocation); - _program.disableAttributeArray(_texCoord2AttributeLocation); - - glEnable(GL_BLEND); - glEnable(GL_DEPTH_TEST); - _program.release(); - glBindBuffer(GL_ARRAY_BUFFER, 0); -} -#endif - //Tries to reconnect to the sensors void OculusManager::reset() { if (_isConnected) { @@ -781,21 +740,6 @@ void OculusManager::reset() { } } -//Gets the current predicted angles from the oculus sensors -void OculusManager::getEulerAngles(float& yaw, float& pitch, float& roll) { - ovrTrackingState ts = ovrHmd_GetTrackingState(_ovrHmd, ovr_GetTimeInSeconds()); - if (ts.StatusFlags & (ovrStatus_OrientationTracked | ovrStatus_PositionTracked)) { - glm::vec3 euler = glm::eulerAngles(toGlm(ts.HeadPose.ThePose.Orientation)); - yaw = euler.y; - pitch = euler.x; - roll = euler.z; - } else { - yaw = 0.0f; - pitch = 0.0f; - roll = 0.0f; - } -} - glm::vec3 OculusManager::getRelativePosition() { ovrTrackingState trackingState = ovrHmd_GetTrackingState(_ovrHmd, ovr_GetTimeInSeconds()); return toGlm(trackingState.HeadPose.ThePose.Position); @@ -826,6 +770,9 @@ void OculusManager::overrideOffAxisFrustum(float& left, float& right, float& bot } int OculusManager::getHMDScreen() { +#ifdef Q_OS_WIN + return -1; +#else int hmdScreenIndex = -1; // unknown // TODO: it might be smarter to handle multiple HMDs connected in this case. but for now, // we will simply assume the initialization code that set up _ovrHmd picked the best hmd @@ -876,5 +823,6 @@ int OculusManager::getHMDScreen() { } } return hmdScreenIndex; +#endif } diff --git a/interface/src/devices/OculusManager.h b/interface/src/devices/OculusManager.h index 799f07ea35..b82379a7b3 100644 --- a/interface/src/devices/OculusManager.h +++ b/interface/src/devices/OculusManager.h @@ -22,30 +22,16 @@ #include "RenderArgs.h" +class QOpenGLContext; + class Camera; +class GlWindow; class PalmData; class Text3DOverlay; -// Uncomment this to enable client side distortion. NOT recommended since -// the Oculus SDK will ideally provide the best practices for distortion in -// in terms of performance and quality, and by using it we will get updated -// best practices for free with new runtime releases. -#define OVR_CLIENT_DISTORTION 1 - - -// Direct HMD mode is currently only supported on windows and some linux systems will -// misbehave if we try to enable the Oculus SDK at all, so isolate support for Direct -// mode only to windows for now #ifdef Q_OS_WIN -// On Win32 platforms, enabling Direct HMD requires that the SDK be -// initialized before the GL context is set up, but this breaks v-sync -// for any application that has a Direct mode enable Rift connected -// but is not rendering to it. For the time being I'm setting this as -// a macro enabled mechanism which changes where the SDK is initialized. -// To enable Direct HMD mode, you can un-comment this, but with the -// caveat that it will break v-sync in NON-VR mode if you have an Oculus -// Rift connect and in Direct mode -#define OVR_DIRECT_MODE 1 +struct SwapFramebufferWrapper; +struct MirrorFramebufferWrapper; #endif @@ -54,7 +40,7 @@ class OculusManager { public: static void init(); static void deinit(); - static void connect(); + static void connect(QOpenGLContext* shareContext); static void disconnect(); static bool isConnected(); static void recalibrate(); @@ -66,10 +52,6 @@ public: static void display(QGLWidget * glCanvas, RenderArgs* renderArgs, const glm::quat &bodyOrientation, const glm::vec3 &position, Camera& whichCamera); static void reset(); - /// param \yaw[out] yaw in radians - /// param \pitch[out] pitch in radians - /// param \roll[out] roll in radians - static void getEulerAngles(float& yaw, float& pitch, float& roll); static glm::vec3 getRelativePosition(); static glm::quat getOrientation(); static QSize getRenderTargetSize(); @@ -85,44 +67,7 @@ public: private: static void initSdk(); static void shutdownSdk(); -#ifdef OVR_CLIENT_DISTORTION - static void generateDistortionMesh(); - static void renderDistortionMesh(ovrPosef eyeRenderPose[ovrEye_Count]); - struct DistortionVertex { - glm::vec2 pos; - glm::vec2 texR; - glm::vec2 texG; - glm::vec2 texB; - struct { - GLubyte r; - GLubyte g; - GLubyte b; - GLubyte a; - } color; - }; - static ProgramObject _program; - //Uniforms - static int _textureLocation; - static int _eyeToSourceUVScaleLocation; - static int _eyeToSourceUVOffsetLocation; - static int _eyeRotationStartLocation; - static int _eyeRotationEndLocation; - //Attributes - static int _positionAttributeLocation; - static int _colorAttributeLocation; - static int _texCoord0AttributeLocation; - static int _texCoord1AttributeLocation; - static int _texCoord2AttributeLocation; - static ovrVector2f _UVScaleOffset[ovrEye_Count][2]; - static GLuint _vertices[ovrEye_Count]; - static GLuint _indices[ovrEye_Count]; - static GLsizei _meshSize[ovrEye_Count]; - static ovrFrameTiming _hmdFrameTiming; - static bool _programInitialized; -#endif - - static ovrTexture _eyeTextures[ovrEye_Count]; static bool _isConnected; static glm::vec3 _eyePositions[ovrEye_Count]; static ovrHmd _ovrHmd; @@ -130,6 +75,7 @@ private: static ovrVector3f _eyeOffset[ovrEye_Count]; static glm::mat4 _eyeProjection[ovrEye_Count]; static ovrEyeRenderDesc _eyeRenderDesc[ovrEye_Count]; + static ovrRecti _eyeViewports[ovrEye_Count]; static ovrSizei _renderTargetSize; static unsigned int _frameIndex; static bool _frameTimingActive; @@ -162,6 +108,14 @@ private: static float _offscreenRenderScale; static bool _eyePerFrameMode; static ovrEyeType _lastEyeRendered; +#ifdef Q_OS_WIN + static SwapFramebufferWrapper* _swapFbo; + static MirrorFramebufferWrapper* _mirrorFbo; + static ovrLayerEyeFov _sceneLayer; +#else + static ovrTexture _eyeTextures[ovrEye_Count]; + static GlWindow* _outputWindow; +#endif }; @@ -181,6 +135,10 @@ inline glm::vec2 toGlm(const ovrVector2f & ov) { return glm::make_vec2(&ov.x); } +inline glm::ivec2 toGlm(const ovrVector2i & ov) { + return glm::ivec2(ov.x, ov.y); +} + inline glm::uvec2 toGlm(const ovrSizei & ov) { return glm::uvec2(ov.w, ov.h); } diff --git a/interface/src/ui/AddressBarDialog.cpp b/interface/src/ui/AddressBarDialog.cpp index 3c3a843586..80f51ff906 100644 --- a/interface/src/ui/AddressBarDialog.cpp +++ b/interface/src/ui/AddressBarDialog.cpp @@ -35,6 +35,16 @@ void AddressBarDialog::loadAddress(const QString& address) { } } +void AddressBarDialog::loadBack() { + qDebug() << "Called LoadBack"; + DependencyManager::get()->goBack(); +} + +void AddressBarDialog::loadForward() { + qDebug() << "Called LoadForward"; + DependencyManager::get()->goForward(); +} + void AddressBarDialog::displayAddressOfflineMessage() { OffscreenUi::error("That user or place is currently offline"); } diff --git a/interface/src/ui/AddressBarDialog.h b/interface/src/ui/AddressBarDialog.h index 395cf3c725..da54e29929 100644 --- a/interface/src/ui/AddressBarDialog.h +++ b/interface/src/ui/AddressBarDialog.h @@ -28,6 +28,8 @@ protected: void hide(); Q_INVOKABLE void loadAddress(const QString& address); + Q_INVOKABLE void loadBack(); + Q_INVOKABLE void loadForward(); }; #endif diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index 0c1783f8ac..4b5e81b6dc 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -376,7 +376,7 @@ void ApplicationOverlay::displayOverlayTextureHmd(Camera& whichCamera) { textureAspectRatio = _textureAspectRatio; _overlays.buildVBO(_textureFov, _textureAspectRatio, 80, 80); - } + } with_each_texture(_overlays.getTexture(), _newUiTexture, [&] { _overlays.render(); @@ -605,7 +605,6 @@ void ApplicationOverlay::renderPointers() { _lastMouseMove = usecTimestampNow(); } else if (usecTimestampNow() - _lastMouseMove > MAX_IDLE_TIME * USECS_PER_SECOND) { //float pitch = 0.0f, yaw = 0.0f, roll = 0.0f; // radians - //OculusManager::getEulerAngles(yaw, pitch, roll); glm::quat orientation = qApp->getHeadOrientation(); // (glm::vec3(pitch, yaw, roll)); glm::vec3 result; diff --git a/interface/src/ui/HMDToolsDialog.cpp b/interface/src/ui/HMDToolsDialog.cpp index 0dfbb202da..9afd0f51c7 100644 --- a/interface/src/ui/HMDToolsDialog.cpp +++ b/interface/src/ui/HMDToolsDialog.cpp @@ -56,8 +56,6 @@ HMDToolsDialog::HMDToolsDialog(QWidget* parent) : this->QDialog::setLayout(form); - _wasMoved = false; - _previousRect = Application::getInstance()->getWindow()->rect(); Application::getInstance()->getWindow()->activateWindow(); // watch for our application window moving screens. If it does we want to update our screen details @@ -136,24 +134,6 @@ void HMDToolsDialog::enterHDMMode() { if (!_inHDMMode) { _switchModeButton->setText("Leave HMD Mode"); _debugDetails->setText(getDebugDetails()); - - _hmdScreenNumber = OculusManager::getHMDScreen(); - - if (_hmdScreenNumber >= 0) { - QWindow* mainWindow = Application::getInstance()->getWindow()->windowHandle(); - _hmdScreen = QGuiApplication::screens()[_hmdScreenNumber]; - - _previousRect = Application::getInstance()->getWindow()->rect(); - _previousRect = QRect(mainWindow->mapToGlobal(_previousRect.topLeft()), - mainWindow->mapToGlobal(_previousRect.bottomRight())); - _previousScreen = mainWindow->screen(); - QRect rect = QApplication::desktop()->screenGeometry(_hmdScreenNumber); - mainWindow->setScreen(_hmdScreen); - mainWindow->setGeometry(rect); - - _wasMoved = true; - } - // if we're on a single screen setup, then hide our tools window when entering HMD mode if (QApplication::desktop()->screenCount() == 1) { @@ -161,58 +141,21 @@ void HMDToolsDialog::enterHDMMode() { } Application::getInstance()->setEnableVRMode(true); - - const int SLIGHT_DELAY = 500; - // If we go to fullscreen immediately, it ends up on the primary monitor, - // even though we've already moved the window. By adding this delay, the - // fullscreen target screen ends up correct. - QTimer::singleShot(SLIGHT_DELAY, this, [&]{ - Application::getInstance()->setFullscreen(true); - activateWindowAfterEnterMode(); - }); - + _inHDMMode = true; } } -void HMDToolsDialog::activateWindowAfterEnterMode() { - Application::getInstance()->getWindow()->activateWindow(); - - // center the cursor on the main application window - centerCursorOnWidget(Application::getInstance()->getWindow()); -} - void HMDToolsDialog::leaveHDMMode() { if (_inHDMMode) { _switchModeButton->setText("Enter HMD Mode"); _debugDetails->setText(getDebugDetails()); - Application::getInstance()->setEnableVRMode(false); - Application::getInstance()->setFullscreen(false); Application::getInstance()->getWindow()->activateWindow(); - - if (_wasMoved) { - QWindow* mainWindow = Application::getInstance()->getWindow()->windowHandle(); - mainWindow->setScreen(_previousScreen); - mainWindow->setGeometry(_previousRect); - - const int SLIGHT_DELAY = 1500; - QTimer::singleShot(SLIGHT_DELAY, this, SLOT(moveWindowAfterLeaveMode())); - } - _wasMoved = false; _inHDMMode = false; } } -void HMDToolsDialog::moveWindowAfterLeaveMode() { - QWindow* mainWindow = Application::getInstance()->getWindow()->windowHandle(); - mainWindow->setScreen(_previousScreen); - mainWindow->setGeometry(_previousRect); - Application::getInstance()->getWindow()->activateWindow(); - Application::getInstance()->resetSensors(); -} - - void HMDToolsDialog::reject() { // Just regularly close upon ESC close(); @@ -244,13 +187,15 @@ void HMDToolsDialog::hideEvent(QHideEvent* event) { void HMDToolsDialog::aboutToQuit() { if (_inHDMMode) { + // FIXME this is ineffective because it doesn't trigger the menu to + // save the fact that VR Mode is not checked. leaveHDMMode(); } } void HMDToolsDialog::screenCountChanged(int newCount) { if (!OculusManager::isConnected()) { - OculusManager::connect(); + //OculusManager::connect(); } int hmdScreenNumber = OculusManager::getHMDScreen(); diff --git a/interface/src/ui/HMDToolsDialog.h b/interface/src/ui/HMDToolsDialog.h index 10dc1c5c80..c16957f2d7 100644 --- a/interface/src/ui/HMDToolsDialog.h +++ b/interface/src/ui/HMDToolsDialog.h @@ -35,8 +35,6 @@ signals: public slots: void reject(); void switchModeClicked(bool checked); - void activateWindowAfterEnterMode(); - void moveWindowAfterLeaveMode(); void applicationWindowScreenChanged(QScreen* screen); void aboutToQuit(); void screenCountChanged(int newCount); @@ -51,8 +49,6 @@ private: void enterHDMMode(); void leaveHDMMode(); - bool _wasMoved; - QRect _previousRect; QScreen* _previousScreen; QScreen* _hmdScreen; int _hmdScreenNumber; diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 3e83c6f559..e1bd01547e 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -48,6 +48,9 @@ #include "RenderablePolyVoxEntityItem.h" #include "EntitiesRendererLogging.h" +#include "DependencyManager.h" +#include "AddressManager.h" + EntityTreeRenderer::EntityTreeRenderer(bool wantScripts, AbstractViewStateInterface* viewState, AbstractScriptingServicesInterface* scriptingServices) : OctreeRenderer(), @@ -911,15 +914,13 @@ void EntityTreeRenderer::mouseMoveEvent(QMouseEvent* event, unsigned int deviceI bool precisionPicking = false; // for mouse moves we do not do precision picking RayToEntityIntersectionResult rayPickResult = findRayIntersectionWorker(ray, Octree::TryLock, precisionPicking); if (rayPickResult.intersects) { + //qCDebug(entitiesrenderer) << "mouseReleaseEvent over entity:" << rayPickResult.entityID; QScriptValueList entityScriptArgs = createMouseEventArgs(rayPickResult.entityID, event, deviceID); - // load the entity script if needed... QScriptValue entityScript = loadEntityScript(rayPickResult.entity); if (entityScript.property("mouseMoveEvent").isValid()) { entityScript.property("mouseMoveEvent").call(entityScript, entityScriptArgs); } - - //qCDebug(entitiesrenderer) << "mouseMoveEvent over entity:" << rayPickResult.entityID; emit mouseMoveOnEntity(rayPickResult, event, deviceID); if (entityScript.property("mouseMoveOnEntity").isValid()) { entityScript.property("mouseMoveOnEntity").call(entityScript, entityScriptArgs); diff --git a/libraries/entities/src/DeleteEntityOperator.cpp b/libraries/entities/src/DeleteEntityOperator.cpp index 051accc732..bb96b9698d 100644 --- a/libraries/entities/src/DeleteEntityOperator.cpp +++ b/libraries/entities/src/DeleteEntityOperator.cpp @@ -95,6 +95,7 @@ bool DeleteEntityOperator::preRecursion(OctreeElement* element) { EntityItemPointer theEntity = details.entity; bool entityDeleted = entityTreeElement->removeEntityItem(theEntity); // remove it from the element assert(entityDeleted); + (void)entityDeleted; // quite warning _tree->setContainingElement(details.entity->getEntityItemID(), NULL); // update or id to element lookup _foundCount++; } diff --git a/libraries/gpu/src/gpu/GLBackendTransform.cpp b/libraries/gpu/src/gpu/GLBackendTransform.cpp index 3f760e4cc8..2e3c2dca70 100755 --- a/libraries/gpu/src/gpu/GLBackendTransform.cpp +++ b/libraries/gpu/src/gpu/GLBackendTransform.cpp @@ -75,6 +75,8 @@ void GLBackend::syncTransformStateCache() { } void GLBackend::updateTransform() { + GLint originalMatrixMode; + glGetIntegerv(GL_MATRIX_MODE, &originalMatrixMode); // Check all the dirty flags and update the state accordingly if (_transform._invalidProj) { _transform._transformCamera._projection = _transform._projection; @@ -132,12 +134,13 @@ void GLBackend::updateTransform() { (void) CHECK_GL_ERROR(); } + if (_transform._invalidModel || _transform._invalidView) { + if (_transform._lastMode != GL_MODELVIEW) { + glMatrixMode(GL_MODELVIEW); + _transform._lastMode = GL_MODELVIEW; + } if (!_transform._model.isIdentity()) { - if (_transform._lastMode != GL_MODELVIEW) { - glMatrixMode(GL_MODELVIEW); - _transform._lastMode = GL_MODELVIEW; - } Transform::Mat4 modelView; if (!_transform._view.isIdentity()) { Transform mvx; @@ -147,19 +150,12 @@ void GLBackend::updateTransform() { _transform._model.getMatrix(modelView); } glLoadMatrixf(reinterpret_cast< const GLfloat* >(&modelView)); + } else if (!_transform._view.isIdentity()) { + Transform::Mat4 modelView; + _transform._view.getInverseMatrix(modelView); + glLoadMatrixf(reinterpret_cast< const GLfloat* >(&modelView)); } else { - if (!_transform._view.isIdentity()) { - if (_transform._lastMode != GL_MODELVIEW) { - glMatrixMode(GL_MODELVIEW); - _transform._lastMode = GL_MODELVIEW; - } - Transform::Mat4 modelView; - _transform._view.getInverseMatrix(modelView); - glLoadMatrixf(reinterpret_cast< const GLfloat* >(&modelView)); - } else { - // TODO: eventually do something about the matrix when neither view nor model is specified? - // glLoadIdentity(); - } + glLoadIdentity(); } (void) CHECK_GL_ERROR(); } @@ -167,6 +163,7 @@ void GLBackend::updateTransform() { // Flags are clean _transform._invalidView = _transform._invalidProj = _transform._invalidModel = false; + glMatrixMode(originalMatrixMode); } diff --git a/libraries/octree/src/OctreePacketData.cpp b/libraries/octree/src/OctreePacketData.cpp index 7c977210fc..db2e2953c0 100644 --- a/libraries/octree/src/OctreePacketData.cpp +++ b/libraries/octree/src/OctreePacketData.cpp @@ -384,10 +384,12 @@ bool OctreePacketData::appendValue(const glm::vec3& value) { bool OctreePacketData::appendValue(const QVector& value) { uint16_t qVecSize = value.size(); bool success = appendValue(qVecSize); - success = append((const unsigned char*)value.constData(), qVecSize * sizeof(glm::vec3)); if (success) { - _bytesOfValues += qVecSize * sizeof(glm::vec3); - _totalBytesOfValues += qVecSize * sizeof(glm::vec3); + success = append((const unsigned char*)value.constData(), qVecSize * sizeof(glm::vec3)); + if (success) { + _bytesOfValues += qVecSize * sizeof(glm::vec3); + _totalBytesOfValues += qVecSize * sizeof(glm::vec3); + } } return success; } diff --git a/libraries/physics/src/MeshMassProperties.cpp b/libraries/physics/src/MeshMassProperties.cpp index ee2945422d..d18c068d26 100644 --- a/libraries/physics/src/MeshMassProperties.cpp +++ b/libraries/physics/src/MeshMassProperties.cpp @@ -270,7 +270,9 @@ void MeshMassProperties::computeMassProperties(const VectorOfPoints& points, con } // create some variables to hold temporary results + #ifndef NDEBUG uint32_t numPoints = points.size(); + #endif const btVector3 p0(0.0f, 0.0f, 0.0f); btMatrix3x3 tetraInertia; btMatrix3x3 doubleDebugInertia; @@ -281,9 +283,11 @@ void MeshMassProperties::computeMassProperties(const VectorOfPoints& points, con uint32_t numTriangles = triangleIndices.size() / 3; for (uint32_t i = 0; i < numTriangles; ++i) { uint32_t t = 3 * i; + #ifndef NDEBUG assert(triangleIndices[t] < numPoints); assert(triangleIndices[t + 1] < numPoints); assert(triangleIndices[t + 2] < numPoints); + #endif // extract raw vertices tetraPoints[0] = p0; diff --git a/libraries/render-utils/CMakeLists.txt b/libraries/render-utils/CMakeLists.txt index 373279b299..7feb48a52b 100644 --- a/libraries/render-utils/CMakeLists.txt +++ b/libraries/render-utils/CMakeLists.txt @@ -1,27 +1,37 @@ -set(TARGET_NAME render-utils) - -AUTOSCRIBE_SHADER_LIB(gpu model render) - -# pull in the resources.qrc file -qt5_add_resources(QT_RESOURCES_FILE "${CMAKE_CURRENT_SOURCE_DIR}/res/fonts/fonts.qrc") - -# use setup_hifi_library macro to setup our project and link appropriate Qt modules -setup_hifi_library(Widgets OpenGL Network Qml Quick Script) - -add_dependency_external_projects(glm) -find_package(GLM REQUIRED) -target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS}) - -if (WIN32) - if (USE_NSIGHT) - # try to find the Nsight package and add it to the build if we find it - find_package(NSIGHT) - if (NSIGHT_FOUND) - include_directories(${NSIGHT_INCLUDE_DIRS}) - add_definitions(-DNSIGHT_FOUND) - target_link_libraries(${TARGET_NAME} "${NSIGHT_LIBRARIES}") - endif () - endif() -endif (WIN32) - -link_hifi_libraries(animation fbx shared gpu model render) +set(TARGET_NAME render-utils) + +AUTOSCRIBE_SHADER_LIB(gpu model render) + +# pull in the resources.qrc file +qt5_add_resources(QT_RESOURCES_FILE "${CMAKE_CURRENT_SOURCE_DIR}/res/fonts/fonts.qrc") + +# use setup_hifi_library macro to setup our project and link appropriate Qt modules +setup_hifi_library(Widgets OpenGL Network Qml Quick Script) + +setup_hifi_opengl() + +add_dependency_external_projects(glm) +find_package(GLM REQUIRED) +target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS}) + +if (WIN32) + if (USE_NSIGHT) + # try to find the Nsight package and add it to the build if we find it + find_package(NSIGHT) + if (NSIGHT_FOUND) + include_directories(${NSIGHT_INCLUDE_DIRS}) + add_definitions(-DNSIGHT_FOUND) + target_link_libraries(${TARGET_NAME} "${NSIGHT_LIBRARIES}") + endif () + endif() + + add_dependency_external_projects(boostconfig) + find_package(BoostConfig REQUIRED) + target_include_directories(${TARGET_NAME} PUBLIC ${BOOSTCONFIG_INCLUDE_DIRS}) + + add_dependency_external_projects(oglplus) + find_package(OGLPLUS REQUIRED) + target_include_directories(${TARGET_NAME} PUBLIC ${OGLPLUS_INCLUDE_DIRS}) +endif (WIN32) + +link_hifi_libraries(animation fbx shared gpu model render) diff --git a/libraries/render-utils/src/OglplusHelpers.cpp b/libraries/render-utils/src/OglplusHelpers.cpp new file mode 100644 index 0000000000..47f9778cac --- /dev/null +++ b/libraries/render-utils/src/OglplusHelpers.cpp @@ -0,0 +1,325 @@ +#ifdef Q_OS_WIN + +// +// Created by Bradley Austin Davis on 2015/05/29 +// 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 "OglplusHelpers.h" + +using namespace oglplus; +using namespace oglplus::shapes; + +static const char * SIMPLE_TEXTURED_VS = R"VS(#version 410 core +#pragma line __LINE__ + +uniform mat4 Projection = mat4(1); +uniform mat4 ModelView = mat4(1); + +layout(location = 0) in vec3 Position; +layout(location = 1) in vec2 TexCoord; + +out vec2 vTexCoord; + +void main() { + gl_Position = Projection * ModelView * vec4(Position, 1); + vTexCoord = TexCoord; +} + +)VS"; + +static const char * SIMPLE_TEXTURED_FS = R"FS(#version 410 core +#pragma line __LINE__ + +uniform sampler2D sampler; +uniform float Alpha = 1.0; + +in vec2 vTexCoord; +out vec4 vFragColor; + +void main() { + vec4 c = texture(sampler, vTexCoord); + c.a = min(Alpha, c.a); + vFragColor = c; +} + +)FS"; + + +ProgramPtr loadDefaultShader() { + ProgramPtr result; + compileProgram(result, SIMPLE_TEXTURED_VS, SIMPLE_TEXTURED_FS); + return result; +} + +void compileProgram(ProgramPtr & result, const std::string& vs, const std::string& fs) { + using namespace oglplus; + try { + result = ProgramPtr(new Program()); + // attach the shaders to the program + result->AttachShader( + VertexShader() + .Source(GLSLSource(vs)) + .Compile() + ); + result->AttachShader( + FragmentShader() + .Source(GLSLSource(fs)) + .Compile() + ); + result->Link(); + } catch (ProgramBuildError & err) { + Q_UNUSED(err); + Q_ASSERT_X(false, "compileProgram", "Failed to build shader program"); + qFatal((const char*)err.Message); + result.reset(); + } +} + + +ShapeWrapperPtr loadPlane(ProgramPtr program, float aspect) { + using namespace oglplus; + Vec3f a(1, 0, 0); + Vec3f b(0, 1, 0); + if (aspect > 1) { + b[1] /= aspect; + } else { + a[0] *= aspect; + } + return ShapeWrapperPtr( + new shapes::ShapeWrapper({ "Position", "TexCoord" }, shapes::Plane(a, b), *program) + ); +} + +// Return a point's cartesian coordinates on a sphere from pitch and yaw +static glm::vec3 getPoint(float yaw, float pitch) { + return glm::vec3(glm::cos(-pitch) * (-glm::sin(yaw)), + glm::sin(-pitch), + glm::cos(-pitch) * (-glm::cos(yaw))); +} + + +class SphereSection : public DrawingInstructionWriter, public DrawMode { +public: + using IndexArray = std::vector; + using PosArray = std::vector; + using TexArray = std::vector; + /// The type of the index container returned by Indices() + // vertex positions + PosArray _pos_data; + // vertex tex coords + TexArray _tex_data; + IndexArray _idx_data; + unsigned int _prim_count{ 0 }; + +public: + SphereSection( + const float fov, + const float aspectRatio, + const int slices_, + const int stacks_) { + //UV mapping source: http://www.mvps.org/directx/articles/spheremap.htm + if (fov >= PI) { + qDebug() << "TexturedHemisphere::buildVBO(): FOV greater or equal than Pi will create issues"; + } + + int gridSize = std::max(slices_, stacks_); + int gridSizeLog2 = 1; + while (1 << gridSizeLog2 < gridSize) { + ++gridSizeLog2; + } + gridSize = (1 << gridSizeLog2) + 1; + // Compute number of vertices needed + int vertices = gridSize * gridSize; + _pos_data.resize(vertices * 3); + _tex_data.resize(vertices * 2); + + // Compute vertices positions and texture UV coordinate + for (int y = 0; y <= gridSize; ++y) { + for (int x = 0; x <= gridSize; ++x) { + + } + } + for (int i = 0; i < gridSize; i++) { + float stacksRatio = (float)i / (float)(gridSize - 1); // First stack is 0.0f, last stack is 1.0f + // abs(theta) <= fov / 2.0f + float pitch = -fov * (stacksRatio - 0.5f); + for (int j = 0; j < gridSize; j++) { + float slicesRatio = (float)j / (float)(gridSize - 1); // First slice is 0.0f, last slice is 1.0f + // abs(phi) <= fov * aspectRatio / 2.0f + float yaw = -fov * aspectRatio * (slicesRatio - 0.5f); + int vertex = i * gridSize + j; + int posOffset = vertex * 3; + int texOffset = vertex * 2; + vec3 pos = getPoint(yaw, pitch); + _pos_data[posOffset] = pos.x; + _pos_data[posOffset + 1] = pos.y; + _pos_data[posOffset + 2] = pos.z; + _tex_data[texOffset] = slicesRatio; + _tex_data[texOffset + 1] = stacksRatio; + } + } // done with vertices + + int rowLen = gridSize; + + // gridsize now refers to the triangles, not the vertices, so reduce by one + // or die by fencepost error http://en.wikipedia.org/wiki/Off-by-one_error + --gridSize; + int quads = gridSize * gridSize; + for (int t = 0; t < quads; ++t) { + int x = + ((t & 0x0001) >> 0) | + ((t & 0x0004) >> 1) | + ((t & 0x0010) >> 2) | + ((t & 0x0040) >> 3) | + ((t & 0x0100) >> 4) | + ((t & 0x0400) >> 5) | + ((t & 0x1000) >> 6) | + ((t & 0x4000) >> 7); + int y = + ((t & 0x0002) >> 1) | + ((t & 0x0008) >> 2) | + ((t & 0x0020) >> 3) | + ((t & 0x0080) >> 4) | + ((t & 0x0200) >> 5) | + ((t & 0x0800) >> 6) | + ((t & 0x2000) >> 7) | + ((t & 0x8000) >> 8); + int i = x * (rowLen) + y; + + _idx_data.push_back(i); + _idx_data.push_back(i + 1); + _idx_data.push_back(i + rowLen + 1); + + _idx_data.push_back(i + rowLen + 1); + _idx_data.push_back(i + rowLen); + _idx_data.push_back(i); + } + _prim_count = quads * 2; + } + + /// Returns the winding direction of faces + FaceOrientation FaceWinding(void) const { + return FaceOrientation::CCW; + } + + typedef GLuint(SphereSection::*VertexAttribFunc)(std::vector&) const; + + /// Makes the vertex positions and returns the number of values per vertex + template + GLuint Positions(std::vector& dest) const { + dest.clear(); + dest.insert(dest.begin(), _pos_data.begin(), _pos_data.end()); + return 3; + } + + /// Makes the vertex normals and returns the number of values per vertex + template + GLuint Normals(std::vector& dest) const { + dest.clear(); + return 3; + } + + /// Makes the vertex tangents and returns the number of values per vertex + template + GLuint Tangents(std::vector& dest) const { + dest.clear(); + return 3; + } + + /// Makes the vertex bi-tangents and returns the number of values per vertex + template + GLuint Bitangents(std::vector& dest) const { + dest.clear(); + return 3; + } + + /// Makes the texture coordinates returns the number of values per vertex + template + GLuint TexCoordinates(std::vector& dest) const { + dest.clear(); + dest.insert(dest.begin(), _tex_data.begin(), _tex_data.end()); + return 2; + } + + typedef VertexAttribsInfo< + SphereSection, + std::tuple< + VertexPositionsTag, + VertexNormalsTag, + VertexTangentsTag, + VertexBitangentsTag, + VertexTexCoordinatesTag + > + > VertexAttribs; + + Spheref MakeBoundingSphere(void) const { + GLfloat min_x = _pos_data[3], max_x = _pos_data[3]; + GLfloat min_y = _pos_data[4], max_y = _pos_data[4]; + GLfloat min_z = _pos_data[5], max_z = _pos_data[5]; + for (std::size_t v = 0, vn = _pos_data.size() / 3; v != vn; ++v) { + GLfloat x = _pos_data[v * 3 + 0]; + GLfloat y = _pos_data[v * 3 + 1]; + GLfloat z = _pos_data[v * 3 + 2]; + + if (min_x > x) min_x = x; + if (min_y > y) min_y = y; + if (min_z > z) min_z = z; + if (max_x < x) max_x = x; + if (max_y < y) max_y = y; + if (max_z < z) max_z = z; + } + + Vec3f c( + (min_x + max_x) * 0.5f, + (min_y + max_y) * 0.5f, + (min_z + max_z) * 0.5f + ); + + return Spheref( + c.x(), c.y(), c.z(), + Distance(c, Vec3f(min_x, min_y, min_z)) + ); + } + + /// Queries the bounding sphere coordinates and dimensions + template + void BoundingSphere(oglplus::Sphere& bounding_sphere) const { + bounding_sphere = oglplus::Sphere(MakeBoundingSphere()); + } + + + /// Returns element indices that are used with the drawing instructions + const IndexArray & Indices(Default = Default()) const { + return _idx_data; + } + + /// Returns the instructions for rendering of faces + DrawingInstructions Instructions(PrimitiveType primitive) const { + DrawingInstructions instr = this->MakeInstructions(); + DrawOperation operation; + operation.method = DrawOperation::Method::DrawElements; + operation.mode = primitive; + operation.first = 0; + operation.count = _prim_count * 3; + operation.restart_index = DrawOperation::NoRestartIndex(); + operation.phase = 0; + this->AddInstruction(instr, operation); + return std::move(instr); + } + + /// Returns the instructions for rendering of faces + DrawingInstructions Instructions(Default = Default()) const { + return Instructions(PrimitiveType::Triangles); + } +}; + +ShapeWrapperPtr loadSphereSection(ProgramPtr program, float fov, float aspect, int slices, int stacks) { + using namespace oglplus; + return ShapeWrapperPtr( + new shapes::ShapeWrapper({ "Position", "TexCoord" }, SphereSection(fov, aspect, slices, stacks), *program) + ); +} +#endif \ No newline at end of file diff --git a/libraries/render-utils/src/OglplusHelpers.h b/libraries/render-utils/src/OglplusHelpers.h new file mode 100644 index 0000000000..47e7331ce0 --- /dev/null +++ b/libraries/render-utils/src/OglplusHelpers.h @@ -0,0 +1,173 @@ +// +// 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 + +// FIXME support oglplus on all platforms +// For now it's a convenient helper for Windows + +#include + +#ifdef Q_OS_WIN +#include "GLMHelpers.h" + +#define OGLPLUS_USE_GLCOREARB_H 0 + +#if defined(__APPLE__) + +#define OGLPLUS_USE_GL3_H 1 + +#elif defined(WIN32) + +#define OGLPLUS_USE_GLEW 1 +#pragma warning(disable : 4068) + +#elif defined(ANDROID) + +#else + +#define OGLPLUS_USE_GLCOREARB_H 1 + +#endif + + + +#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 "NumericalConstants.h" + +using FramebufferPtr = std::shared_ptr; +using ShapeWrapperPtr = std::shared_ptr; +using BufferPtr = std::shared_ptr; +using VertexArrayPtr = std::shared_ptr; +using ProgramPtr = std::shared_ptr; +using Mat4Uniform = oglplus::Uniform; + +ProgramPtr loadDefaultShader(); +void compileProgram(ProgramPtr & result, const std::string& vs, const std::string& fs); +ShapeWrapperPtr loadPlane(ProgramPtr program, float aspect = 1.0f); +ShapeWrapperPtr loadSphereSection(ProgramPtr program, float fov = PI / 3.0f * 2.0f, float aspect = 16.0f / 9.0f, int slices = 32, int stacks = 32); + + +// 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 < + typename C, + typename D +> +struct FramebufferWrapper { + uvec2 size; + oglplus::Framebuffer fbo; + C color; + D depth; + + FramebufferWrapper() {} + + virtual ~FramebufferWrapper() { + } + + virtual void Init(const uvec2 & size) { + this->size = size; + initColor(); + initDepth(); + initDone(); + } + + template + void Bound(F f) { + Bound(oglplus::Framebuffer::Target::Draw, f); + } + + template + void Bound(oglplus::Framebuffer::Target target , F f) { + fbo.Bind(target); + onBind(target); + f(); + onUnbind(target); + oglplus::DefaultFramebuffer().Bind(target); + } + + void Viewport() { + oglplus::Context::Viewport(size.x, size.y); + } + +protected: + virtual void onBind(oglplus::Framebuffer::Target target) {} + virtual void onUnbind(oglplus::Framebuffer::Target target) {} + + static GLenum toEnum(oglplus::Framebuffer::Target target) { + switch (target) { + case oglplus::Framebuffer::Target::Draw: + return GL_DRAW_FRAMEBUFFER; + case oglplus::Framebuffer::Target::Read: + return GL_READ_FRAMEBUFFER; + default: + Q_ASSERT(false); + return GL_FRAMEBUFFER; + } + } + + virtual void initDepth() {} + + virtual void initColor() {} + + virtual void initDone() = 0; +}; + +struct BasicFramebufferWrapper : public FramebufferWrapper { +protected: + virtual void initDepth() override { + using namespace oglplus; + Context::Bound(Renderbuffer::Target::Renderbuffer, depth) + .Storage( + PixelDataInternalFormat::DepthComponent, + size.x, size.y); + } + + virtual void initColor() override { + using namespace oglplus; + Context::Bound(oglplus::Texture::Target::_2D, color) + .MinFilter(TextureMinFilter::Linear) + .MagFilter(TextureMagFilter::Linear) + .WrapS(TextureWrap::ClampToEdge) + .WrapT(TextureWrap::ClampToEdge) + .Image2D( + 0, PixelDataInternalFormat::RGBA8, + size.x, size.y, + 0, PixelDataFormat::RGB, PixelDataType::UnsignedByte, nullptr + ); + } + + virtual void initDone() override { + using namespace oglplus; + static const Framebuffer::Target target = Framebuffer::Target::Draw; + Bound(target, [&] { + fbo.AttachTexture(target, FramebufferAttachment::Color, color, 0); + fbo.AttachRenderbuffer(target, FramebufferAttachment::Depth, depth); + fbo.Complete(target); + }); + } +}; + +using BasicFramebufferWrapperPtr = std::shared_ptr; +#endif diff --git a/libraries/render-utils/src/TextRenderer3D.cpp b/libraries/render-utils/src/TextRenderer3D.cpp index 0eb560bf72..2f898542b9 100644 --- a/libraries/render-utils/src/TextRenderer3D.cpp +++ b/libraries/render-utils/src/TextRenderer3D.cpp @@ -451,7 +451,6 @@ TextRenderer3D::TextRenderer3D(const char* family, float pointSize, int weight, EffectType effect, int effectThickness, const QColor& color) : _effectType(effect), _effectThickness(effectThickness), - _pointSize(pointSize), _color(toGlm(color)), _font(loadFont3D(family)) { if (!_font) { diff --git a/libraries/render-utils/src/TextRenderer3D.h b/libraries/render-utils/src/TextRenderer3D.h index e61203b06f..9f6a16d743 100644 --- a/libraries/render-utils/src/TextRenderer3D.h +++ b/libraries/render-utils/src/TextRenderer3D.h @@ -65,8 +65,6 @@ private: // the thickness of the effect const int _effectThickness; - const float _pointSize; - // text color const glm::vec4 _color; diff --git a/libraries/shared/CMakeLists.txt b/libraries/shared/CMakeLists.txt index 9785994a29..8deda7f4b1 100644 --- a/libraries/shared/CMakeLists.txt +++ b/libraries/shared/CMakeLists.txt @@ -6,4 +6,5 @@ setup_hifi_library(Gui Network Script Widgets) add_dependency_external_projects(glm) find_package(GLM REQUIRED) -target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS}) \ No newline at end of file +target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS}) + diff --git a/libraries/shared/src/MatrixStack.h b/libraries/shared/src/MatrixStack.h index a02e284725..fdfea2b3cb 100644 --- a/libraries/shared/src/MatrixStack.h +++ b/libraries/shared/src/MatrixStack.h @@ -118,11 +118,15 @@ public: template void withPush(Function f) { + #ifndef NDEBUG size_t startingDepth = size(); + #endif push(); f(); pop(); - assert(startingDepth = size()); + #ifndef NDEBUG + assert(startingDepth == size()); + #endif } template diff --git a/libraries/shared/src/PhysicsCollisionGroups.h b/libraries/shared/src/PhysicsCollisionGroups.h index cce9637cd4..08d83a29ca 100644 --- a/libraries/shared/src/PhysicsCollisionGroups.h +++ b/libraries/shared/src/PhysicsCollisionGroups.h @@ -55,7 +55,7 @@ const int16_t COLLISION_GROUP_COLLISIONLESS = 1 << 15; const int16_t COLLISION_MASK_DEFAULT = ~ COLLISION_GROUP_COLLISIONLESS; // STATIC also doesn't collide with other STATIC -const int16_t COLLISION_MASK_STATIC = ~ (COLLISION_GROUP_COLLISIONLESS | COLLISION_MASK_STATIC); +const int16_t COLLISION_MASK_STATIC = ~ (COLLISION_GROUP_COLLISIONLESS | COLLISION_GROUP_STATIC); const int16_t COLLISION_MASK_KINEMATIC = COLLISION_MASK_DEFAULT; diff --git a/libraries/shared/src/VariantMapToScriptValue.cpp b/libraries/shared/src/VariantMapToScriptValue.cpp index 6c21557325..c0d21e9995 100644 --- a/libraries/shared/src/VariantMapToScriptValue.cpp +++ b/libraries/shared/src/VariantMapToScriptValue.cpp @@ -13,35 +13,61 @@ #include "SharedLogging.h" #include "VariantMapToScriptValue.h" + +QScriptValue variantToScriptValue(QVariant& qValue, QScriptEngine& scriptEngine) { + switch(qValue.type()) { + case QVariant::Bool: + return qValue.toBool(); + break; + case QVariant::Int: + return qValue.toInt(); + break; + case QVariant::Double: + return qValue.toDouble(); + break; + case QVariant::String: { + return scriptEngine.newVariant(qValue); + break; + } + case QVariant::Map: { + QVariantMap childMap = qValue.toMap(); + return variantMapToScriptValue(childMap, scriptEngine); + break; + } + case QVariant::List: { + QVariantList childList = qValue.toList(); + return variantListToScriptValue(childList, scriptEngine); + break; + } + default: + qCDebug(shared) << "unhandled QScript type" << qValue.type(); + break; + } + + return QScriptValue(); +} + + QScriptValue variantMapToScriptValue(QVariantMap& variantMap, QScriptEngine& scriptEngine) { QScriptValue scriptValue = scriptEngine.newObject(); for (QVariantMap::const_iterator iter = variantMap.begin(); iter != variantMap.end(); ++iter) { QString key = iter.key(); QVariant qValue = iter.value(); - - switch(qValue.type()) { - case QVariant::Bool: - scriptValue.setProperty(key, qValue.toBool()); - break; - case QVariant::Int: - scriptValue.setProperty(key, qValue.toInt()); - break; - case QVariant::Double: - scriptValue.setProperty(key, qValue.toDouble()); - break; - case QVariant::String: { - scriptValue.setProperty(key, scriptEngine.newVariant(qValue)); - break; - } - case QVariant::Map: { - QVariantMap childMap = qValue.toMap(); - scriptValue.setProperty(key, variantMapToScriptValue(childMap, scriptEngine)); - break; - } - default: - qCDebug(shared) << "unhandled QScript type" << qValue.type(); - } + scriptValue.setProperty(key, variantToScriptValue(qValue, scriptEngine)); + } + + return scriptValue; +} + + +QScriptValue variantListToScriptValue(QVariantList& variantList, QScriptEngine& scriptEngine) { + QScriptValue scriptValue = scriptEngine.newObject(); + + scriptValue.setProperty("length", variantList.size()); + int i = 0; + foreach (QVariant v, variantList) { + scriptValue.setProperty(i++, variantToScriptValue(v, scriptEngine)); } return scriptValue; diff --git a/libraries/shared/src/VariantMapToScriptValue.h b/libraries/shared/src/VariantMapToScriptValue.h index 503f8c6490..ea65cccb3d 100644 --- a/libraries/shared/src/VariantMapToScriptValue.h +++ b/libraries/shared/src/VariantMapToScriptValue.h @@ -13,4 +13,6 @@ #include #include +QScriptValue variantToScriptValue(QVariant& qValue, QScriptEngine& scriptEngine); QScriptValue variantMapToScriptValue(QVariantMap& variantMap, QScriptEngine& scriptEngine); +QScriptValue variantListToScriptValue(QVariantList& variantList, QScriptEngine& scriptEngine); diff --git a/libraries/ui/src/VrMenu.cpp b/libraries/ui/src/VrMenu.cpp index b6cb0b136b..1b402ff2a3 100644 --- a/libraries/ui/src/VrMenu.cpp +++ b/libraries/ui/src/VrMenu.cpp @@ -135,8 +135,8 @@ void VrMenu::setRootMenu(QObject* rootMenu) { void VrMenu::addMenu(QMenu* menu) { Q_ASSERT(!MenuUserData::forObject(menu)); - QObject * parent = menu->parent(); - QObject * qmlParent; + QObject* parent = menu->parent(); + QObject* qmlParent = nullptr; if (dynamic_cast(parent)) { MenuUserData* userData = MenuUserData::forObject(parent); qmlParent = findMenuObject(userData->uuid.toString()); diff --git a/tools/vhacd-util/src/VHACDUtilApp.cpp b/tools/vhacd-util/src/VHACDUtilApp.cpp index ed4dab020f..2af6bca337 100644 --- a/tools/vhacd-util/src/VHACDUtilApp.cpp +++ b/tools/vhacd-util/src/VHACDUtilApp.cpp @@ -322,6 +322,7 @@ VHACDUtilApp::VHACDUtilApp(int argc, char* argv[]) : QString outputFileName = baseFileName + "-" + QString::number(count) + ".obj"; writeOBJ(outputFileName, fbx, outputCentimeters, count); count++; + (void)meshPart; // quiet warning } } }