From a921f7ae74e8005f7499bfe7c957a6e38a70f3ec Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Sat, 31 Jan 2015 19:44:23 -0800 Subject: [PATCH 01/41] Updating API usage to Oculus 0.4.4 --- interface/src/devices/OculusManager.cpp | 22 ++++++++++++++++------ interface/src/devices/OculusManager.h | 1 + 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/interface/src/devices/OculusManager.cpp b/interface/src/devices/OculusManager.cpp index 256c09f602..d25d19aa7c 100644 --- a/interface/src/devices/OculusManager.cpp +++ b/interface/src/devices/OculusManager.cpp @@ -50,6 +50,7 @@ ovrHmd OculusManager::_ovrHmd; ovrHmdDesc OculusManager::_ovrHmdDesc; ovrFovPort OculusManager::_eyeFov[ovrEye_Count]; ovrEyeRenderDesc OculusManager::_eyeRenderDesc[ovrEye_Count]; +ovrVector3f OculusManager::_eyeOffset[ovrEye_Count]; ovrSizei OculusManager::_renderTargetSize; ovrVector2f OculusManager::_UVScaleOffset[ovrEye_Count][2]; GLuint OculusManager::_vertices[ovrEye_Count] = { 0, 0 }; @@ -114,6 +115,8 @@ void OculusManager::connect() { _eyeRenderDesc[0] = ovrHmd_GetRenderDesc(_ovrHmd, ovrEye_Left, _eyeFov[0]); _eyeRenderDesc[1] = ovrHmd_GetRenderDesc(_ovrHmd, ovrEye_Right, _eyeFov[1]); + _eyeOffset[0] = _eyeRenderDesc[0].HmdToEyeViewOffset; + _eyeOffset[1] = _eyeRenderDesc[1].HmdToEyeViewOffset; #if defined(__APPLE__) || defined(_WIN32) ovrHmd_SetEnabledCaps(_ovrHmd, ovrHmdCap_LowPersistence); @@ -433,6 +436,12 @@ void OculusManager::configureCamera(Camera& camera, int screenWidth, int screenH #endif } +#ifdef HAVE_LIBOVR +glm::vec3 toGlm(const ovrVector3f & v) { + return std::move(glm::vec3(v.x, v.y, v.z)); +} +#endif + //Displays everything for the oculus, frame timing must be active void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &position, Camera& whichCamera) { #ifdef HAVE_LIBOVR @@ -481,8 +490,12 @@ void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &p trackerPosition = bodyOrientation * trackerPosition; #endif - + + // void ovrHmd_GetEyePoses(ovrHmd hmd, unsigned int frameIndex, ovrVector3f hmdToEyeViewOffset[2], + // ovrPosef outEyePoses[2], ovrTrackingState* outHmdTrackingState); + //Render each eye into an fbo + ovrHmd_GetEyePoses(_ovrHmd, 0, _eyeOffset, eyeRenderPose, nullptr); for (int eyeIndex = 0; eyeIndex < ovrEye_Count; eyeIndex++) { _activeEyeIndex = eyeIndex; @@ -492,7 +505,6 @@ void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &p ovrEyeType eye = _ovrHmdDesc.EyeRenderOrder[eyeIndex]; #endif // Set the camera rotation for this eye - eyeRenderPose[eye] = ovrHmd_GetEyePose(_ovrHmd, eye); orientation.x = eyeRenderPose[eye].Orientation.x; orientation.y = eyeRenderPose[eye].Orientation.y; orientation.z = eyeRenderPose[eye].Orientation.z; @@ -507,9 +519,7 @@ void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &p _camera->setPosition(whichCamera.getPosition()); // Store the latest left and right eye render locations for things that need to know - glm::vec3 thisEyePosition = position + trackerPosition + - (bodyOrientation * glm::quat(orientation.x, orientation.y, orientation.z, orientation.w) * - glm::vec3(_eyeRenderDesc[eye].ViewAdjust.x, _eyeRenderDesc[eye].ViewAdjust.y, _eyeRenderDesc[eye].ViewAdjust.z)); + glm::vec3 thisEyePosition = position + trackerPosition + toGlm(eyeRenderPose[eye].Position); RenderArgs::RenderSide renderSide = RenderArgs::STEREO_LEFT; if (eyeIndex == 0) { @@ -538,7 +548,7 @@ void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &p // HACK: instead of passing the stereo eye offset directly in the matrix, pass it in the camera offset //glTranslatef(_eyeRenderDesc[eye].ViewAdjust.x, _eyeRenderDesc[eye].ViewAdjust.y, _eyeRenderDesc[eye].ViewAdjust.z); - _camera->setEyeOffsetPosition(glm::vec3(-_eyeRenderDesc[eye].ViewAdjust.x, -_eyeRenderDesc[eye].ViewAdjust.y, -_eyeRenderDesc[eye].ViewAdjust.z)); + //_camera->setEyeOffsetPosition(glm::vec3(-_eyeRenderDesc[eye].ViewAdjust.x, -_eyeRenderDesc[eye].ViewAdjust.y, -_eyeRenderDesc[eye].ViewAdjust.z)); Application::getInstance()->displaySide(*_camera, false, RenderArgs::MONO); applicationOverlay.displayOverlayTextureOculus(*_camera); diff --git a/interface/src/devices/OculusManager.h b/interface/src/devices/OculusManager.h index 71fc08c8f9..104d844855 100644 --- a/interface/src/devices/OculusManager.h +++ b/interface/src/devices/OculusManager.h @@ -92,6 +92,7 @@ private: static ovrHmdDesc _ovrHmdDesc; static ovrFovPort _eyeFov[ovrEye_Count]; static ovrEyeRenderDesc _eyeRenderDesc[ovrEye_Count]; + static ovrVector3f _eyeOffset[ovrEye_Count]; static ovrSizei _renderTargetSize; static ovrVector2f _UVScaleOffset[ovrEye_Count][2]; static GLuint _vertices[ovrEye_Count]; From 16feaceab5f8df123433b5ebc923736a970b56e5 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Fri, 20 Feb 2015 09:32:25 -0800 Subject: [PATCH 02/41] Working on oculus build --- cmake/externals/LibOVR/CMakeLists.txt | 22 ++ cmake/modules/FindLibOVR.cmake | 70 +--- interface/CMakeLists.txt | 7 +- interface/external/libovr/readme.txt | 16 - interface/src/devices/OculusManager.cpp | 430 ++++++++++++------------ interface/src/devices/OculusManager.h | 63 +++- 6 files changed, 311 insertions(+), 297 deletions(-) create mode 100644 cmake/externals/LibOVR/CMakeLists.txt delete mode 100644 interface/external/libovr/readme.txt diff --git a/cmake/externals/LibOVR/CMakeLists.txt b/cmake/externals/LibOVR/CMakeLists.txt new file mode 100644 index 0000000000..1a2e3f4435 --- /dev/null +++ b/cmake/externals/LibOVR/CMakeLists.txt @@ -0,0 +1,22 @@ +set(EXTERNAL_NAME LibOVR) + +include(ExternalProject) +ExternalProject_Add( + ${EXTERNAL_NAME} + PREFIX ${EXTERNAL_NAME} + GIT_REPOSITORY https://github.com/jherico/OculusSDK.git + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH= + LOG_DOWNLOAD ON +) + +ExternalProject_Get_Property(${EXTERNAL_NAME} INSTALL_DIR) + +string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER) + +set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${INSTALL_DIR}/include CACHE TYPE STRING) + +if (WIN32) + set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${INSTALL_DIR}/lib/ovr.lib CACHE TYPE STRING) +else () + set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${INSTALL_DIR}/lib/libovr.a CACHE TYPE STRING) +endif () diff --git a/cmake/modules/FindLibOVR.cmake b/cmake/modules/FindLibOVR.cmake index 62d8313d63..acd0b04f82 100644 --- a/cmake/modules/FindLibOVR.cmake +++ b/cmake/modules/FindLibOVR.cmake @@ -24,42 +24,15 @@ hifi_library_search_hints("libovr") include(SelectLibraryConfigurations) if (NOT ANDROID) + include("${MACRO_DIR}/HifiLibrarySearchHints.cmake") + hifi_library_search_hints("libovr") + + find_path(LIBOVR_INCLUDE_DIRS OVR_CAPI.h PATH_SUFFIXES include HINTS ${LIBOVR_SEARCH_DIRS}) + find_library(LIBOVR_LIBRARIES ovr PATH_SUFFIXES lib HINTS ${LIBOVR_SEARCH_DIRS}) + + include(FindPackageHandleStandardArgs) + find_package_handle_standard_args(LIBOVR DEFAULT_MSG LIBOVR_INCLUDE_DIRS LIBOVR_LIBRARIES) - find_path(LIBOVR_INCLUDE_DIRS OVR.h PATH_SUFFIXES Include HINTS ${LIBOVR_SEARCH_DIRS}) - find_path(LIBOVR_SRC_DIR Util_Render_Stereo.h PATH_SUFFIXES Src/Util HINTS ${LIBOVR_SEARCH_DIRS}) - - if (APPLE) - find_library(LIBOVR_LIBRARY_DEBUG NAMES ovr PATH_SUFFIXES Lib/Mac/Debug HINTS ${LIBOVR_SEARCH_DIRS}) - find_library(LIBOVR_LIBRARY_RELEASE NAMES ovr PATH_SUFFIXES Lib/Mac/Release HINTS ${LIBOVR_SEARCH_DIRS}) - find_library(ApplicationServices ApplicationServices) - find_library(IOKit IOKit) - elseif (UNIX) - find_library(UDEV_LIBRARY_RELEASE udev /usr/lib/x86_64-linux-gnu/) - find_library(XINERAMA_LIBRARY_RELEASE Xinerama /usr/lib/x86_64-linux-gnu/) - - if (CMAKE_CL_64) - set(LINUX_ARCH_DIR "i386") - else() - set(LINUX_ARCH_DIR "x86_64") - endif() - - find_library(LIBOVR_LIBRARY_DEBUG NAMES ovr PATH_SUFFIXES Lib/Linux/Debug/${LINUX_ARCH_DIR} HINTS ${LIBOVR_SEARCH_DIRS}) - find_library(LIBOVR_LIBRARY_RELEASE NAMES ovr PATH_SUFFIXES Lib/Linux/Release/${LINUX_ARCH_DIR} HINTS ${LIBOVR_SEARCH_DIRS}) - - select_library_configurations(UDEV) - select_library_configurations(XINERAMA) - - elseif (WIN32) - if (MSVC10) - find_library(LIBOVR_LIBRARY_DEBUG NAMES libovrd PATH_SUFFIXES Lib/Win32/VS2010 HINTS ${LIBOVR_SEARCH_DIRS}) - find_library(LIBOVR_LIBRARY_RELEASE NAMES libovr PATH_SUFFIXES Lib/Win32/VS2010 HINTS ${LIBOVR_SEARCH_DIRS}) - elseif (MSVC12) - find_library(LIBOVR_LIBRARY_DEBUG NAMES libovrd PATH_SUFFIXES Lib/Win32/VS2013 HINTS ${LIBOVR_SEARCH_DIRS}) - find_library(LIBOVR_LIBRARY_RELEASE NAMES libovr PATH_SUFFIXES Lib/Win32/VS2013 HINTS ${LIBOVR_SEARCH_DIRS}) - endif () - find_package(ATL) - endif () - else (NOT ANDROID) set(_VRLIB_JNI_DIR "VRLib/jni") set(_VRLIB_LIBS_DIR "VRLib/obj/local/armeabi-v7a") @@ -76,31 +49,4 @@ else (NOT ANDROID) find_library(TURBOJPEG_LIBRARY NAMES jpeg PATH_SUFFIXES 3rdParty/turbojpeg HINTS ${LIBOVR_SEARCH_DIRS}) endif (NOT ANDROID) -select_library_configurations(LIBOVR) -set(LIBOVR_LIBRARIES ${LIBOVR_LIBRARY}) - -list(APPEND LIBOVR_ARGS_LIST LIBOVR_INCLUDE_DIRS LIBOVR_SRC_DIR LIBOVR_LIBRARY) - -if (APPLE) - list(APPEND LIBOVR_LIBRARIES ${IOKit} ${ApplicationServices}) - list(APPEND LIBOVR_ARGS_LIST IOKit ApplicationServices) -elseif (ANDROID) - - list(APPEND LIBOVR_ANDROID_LIBRARIES "-lGLESv3" "-lEGL" "-landroid" "-lOpenMAXAL" "-llog" "-lz" "-lOpenSLES") - list(APPEND LIBOVR_ARGS_LIST LIBOVR_ANDROID_LIBRARIES LIBOVR_VRLIB_DIR MINIZIP_DIR JNI_DIR TURBOJPEG_LIBRARY) -elseif (UNIX) - list(APPEND LIBOVR_LIBRARIES "${UDEV_LIBRARY}" "${XINERAMA_LIBRARY}") - list(APPEND LIBOVR_ARGS_LIST UDEV_LIBRARY XINERAMA_LIBRARY) -elseif (WIN32) - list(APPEND LIBOVR_LIBRARIES ${ATL_LIBRARIES}) - list(APPEND LIBOVR_ARGS_LIST ATL_LIBRARIES) -endif () - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(LibOVR DEFAULT_MSG ${LIBOVR_ARGS_LIST}) - -if (ANDROID) - list(APPEND LIBOVR_INCLUDE_DIRS ${LIBOVR_SRC_DIR} ${MINIZIP_DIR} ${JNI_DIR}) -endif () - mark_as_advanced(LIBOVR_INCLUDE_DIRS LIBOVR_LIBRARIES LIBOVR_SEARCH_DIRS) diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 7d581284e5..2514fdb9e9 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -2,7 +2,7 @@ set(TARGET_NAME interface) project(${TARGET_NAME}) # set a default root dir for each of our optional externals if it was not passed -set(OPTIONAL_EXTERNALS "Faceshift" "LibOVR" "PrioVR" "Sixense" "LeapMotion" "RtMidi" "Qxmpp" "SDL2" "RSSDK") +set(OPTIONAL_EXTERNALS "Faceshift" "PrioVR" "Sixense" "LeapMotion" "RtMidi" "Qxmpp" "SDL2" "RSSDK") foreach(EXTERNAL ${OPTIONAL_EXTERNALS}) string(TOUPPER ${EXTERNAL} ${EXTERNAL}_UPPERCASE) if (NOT ${${EXTERNAL}_UPPERCASE}_ROOT_DIR) @@ -112,6 +112,11 @@ add_dependency_external_project(glm) find_package(GLM REQUIRED) target_include_directories(${TARGET_NAME} PRIVATE ${GLM_INCLUDE_DIRS}) +add_dependency_external_project(LibOVR) +find_package(LibOVR REQUIRED) +target_include_directories(${TARGET_NAME} PRIVATE ${LIBOVR_INCLUDE_DIRS}) +target_link_libraries(${TARGET_NAME} ${LIBOVR_LIBRARIES}) + # link required hifi libraries link_hifi_libraries(shared octree environment gpu model fbx metavoxels networking entities avatars audio audio-client animation script-engine physics diff --git a/interface/external/libovr/readme.txt b/interface/external/libovr/readme.txt deleted file mode 100644 index f9db808d88..0000000000 --- a/interface/external/libovr/readme.txt +++ /dev/null @@ -1,16 +0,0 @@ - -Instructions for adding the Oculus library (LibOVR) to Interface -Stephen Birarda, March 6, 2014 - -You can download the Oculus SDK from https://developer.oculusvr.com/ (account creation required). Interface has been tested with SDK version 0.4.1. - -1. Copy the Oculus SDK folders from the LibOVR directory (Lib, Include, Src) into the interface/externals/libovr folder. - This readme.txt should be there as well. - - You may optionally choose to copy the SDK folders to a location outside the repository (so you can re-use with different checkouts and different projects). - If so our CMake find module expects you to set the ENV variable 'HIFI_LIB_DIR' to a directory containing a subfolder 'oculus' that contains the three folders mentioned above. - - NOTE: For Windows users, you should copy libovr.lib and libovrd.lib from the \oculus\Lib\Win32\VS2010 directory to the \libovr\Lib\Win32\ directory. - -2. Clear your build directory, run cmake and build, and you should be all set. - diff --git a/interface/src/devices/OculusManager.cpp b/interface/src/devices/OculusManager.cpp index d63305e870..a15b606e17 100644 --- a/interface/src/devices/OculusManager.cpp +++ b/interface/src/devices/OculusManager.cpp @@ -335,9 +335,9 @@ void OculusManager::generateDistortionMesh() { } //Viewport for the render target for each eye - _eyeRenderViewport[0].Pos = Vector2i(0, 0); - _eyeRenderViewport[0].Size = Sizei(_renderTargetSize.w / 2, _renderTargetSize.h); - _eyeRenderViewport[1].Pos = Vector2i((_renderTargetSize.w + 1) / 2, 0); + _eyeRenderViewport[0].Pos = { 0, 0 }; // = Vector2i(0, 0); + _eyeRenderViewport[0].Size = { _renderTargetSize.w / 2, _renderTargetSize.h }; + _eyeRenderViewport[1].Pos = { (_renderTargetSize.w + 1) / 2, 0 }; _eyeRenderViewport[1].Size = _eyeRenderViewport[0].Size; for (int eyeNum = 0; eyeNum < ovrEye_Count; eyeNum++) { @@ -349,7 +349,7 @@ void OculusManager::generateDistortionMesh() { _UVScaleOffset[eyeNum]); // Parse the vertex data and create a render ready vertex buffer - DistortionVertex* pVBVerts = (DistortionVertex*)OVR_ALLOC(sizeof(DistortionVertex) * meshData.VertexCount); + DistortionVertex* pVBVerts = new DistortionVertex[meshData.VertexCount]; _meshSize[eyeNum] = meshData.IndexCount; // Convert the oculus vertex data to the DistortionVertex format. @@ -394,7 +394,7 @@ void OculusManager::generateDistortionMesh() { glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); //Now that we have the VBOs we can get rid of the mesh data - OVR_FREE(pVBVerts); + delete [] pVBVerts; ovrHmd_DestroyDistortionMesh(&meshData); } @@ -439,223 +439,217 @@ void OculusManager::configureCamera(Camera& camera, int screenWidth, int screenH #endif } -#ifdef HAVE_LIBOVR -glm::vec3 toGlm(const ovrVector3f & v) { - return std::move(glm::vec3(v.x, v.y, v.z)); -} -#endif - //Displays everything for the oculus, frame timing must be active void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &position, Camera& whichCamera) { #ifdef HAVE_LIBOVR - //beginFrameTiming must be called before display - if (!_frameTimingActive) { - printf("WARNING: Called OculusManager::display() without calling OculusManager::beginFrameTiming() first."); - return; - } - - ApplicationOverlay& applicationOverlay = Application::getInstance()->getApplicationOverlay(); - - // We only need to render the overlays to a texture once, then we just render the texture on the hemisphere - // PrioVR will only work if renderOverlay is called, calibration is connected to Application::renderingOverlay() - applicationOverlay.renderOverlay(true); - - //Bind our framebuffer object. If we are rendering the glow effect, we let the glow effect shader take care of it - if (Menu::getInstance()->isOptionChecked(MenuOption::EnableGlowEffect)) { - DependencyManager::get()->prepare(); - } else { - DependencyManager::get()->getPrimaryFramebufferObject()->bind(); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - } - - ovrPosef eyeRenderPose[ovrEye_Count]; - - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - - glm::quat orientation; - glm::vec3 trackerPosition; - -#if defined(__APPLE__) || defined(_WIN32) - ovrTrackingState ts = ovrHmd_GetTrackingState(_ovrHmd, ovr_GetTimeInSeconds()); - ovrVector3f ovrHeadPosition = ts.HeadPose.ThePose.Position; - - trackerPosition = glm::vec3(ovrHeadPosition.x, ovrHeadPosition.y, ovrHeadPosition.z); - - if (_calibrationState != CALIBRATED) { - ovrQuatf ovrHeadOrientation = ts.HeadPose.ThePose.Orientation; - orientation = glm::quat(ovrHeadOrientation.w, ovrHeadOrientation.x, ovrHeadOrientation.y, ovrHeadOrientation.z); - calibrate(trackerPosition, orientation); - } - - trackerPosition = bodyOrientation * trackerPosition; -#endif - - // void ovrHmd_GetEyePoses(ovrHmd hmd, unsigned int frameIndex, ovrVector3f hmdToEyeViewOffset[2], - // ovrPosef outEyePoses[2], ovrTrackingState* outHmdTrackingState); - - //Render each eye into an fbo - ovrHmd_GetEyePoses(_ovrHmd, 0, _eyeOffset, eyeRenderPose, nullptr); - for (int eyeIndex = 0; eyeIndex < ovrEye_Count; eyeIndex++) { - _activeEyeIndex = eyeIndex; - -#if defined(__APPLE__) || defined(_WIN32) - ovrEyeType eye = _ovrHmd->EyeRenderOrder[eyeIndex]; -#else - ovrEyeType eye = _ovrHmdDesc.EyeRenderOrder[eyeIndex]; -#endif - // Set the camera rotation for this eye - orientation.x = eyeRenderPose[eye].Orientation.x; - orientation.y = eyeRenderPose[eye].Orientation.y; - orientation.z = eyeRenderPose[eye].Orientation.z; - orientation.w = eyeRenderPose[eye].Orientation.w; - - // Update the application camera with the latest HMD position - whichCamera.setHmdPosition(trackerPosition); - whichCamera.setHmdRotation(orientation); - - // Update our camera to what the application camera is doing - _camera->setRotation(whichCamera.getRotation()); - _camera->setPosition(whichCamera.getPosition()); - - // Store the latest left and right eye render locations for things that need to know - glm::vec3 thisEyePosition = position + trackerPosition + toGlm(eyeRenderPose[eye].Position); - - RenderArgs::RenderSide renderSide = RenderArgs::STEREO_LEFT; - if (eyeIndex == 0) { - _leftEyePosition = thisEyePosition; - } else { - _rightEyePosition = thisEyePosition; - renderSide = RenderArgs::STEREO_RIGHT; - } - - _camera->update(1.0f / Application::getInstance()->getFps()); - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - const ovrFovPort& port = _eyeFov[_activeEyeIndex]; - float nearClip = whichCamera.getNearClip(), farClip = whichCamera.getFarClip(); - glFrustum(-nearClip * port.LeftTan, nearClip * port.RightTan, -nearClip * port.DownTan, - nearClip * port.UpTan, nearClip, farClip); - - glViewport(_eyeRenderViewport[eye].Pos.x, _eyeRenderViewport[eye].Pos.y, - _eyeRenderViewport[eye].Size.w, _eyeRenderViewport[eye].Size.h); - - - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - - // HACK: instead of passing the stereo eye offset directly in the matrix, pass it in the camera offset - //glTranslatef(_eyeRenderDesc[eye].ViewAdjust.x, _eyeRenderDesc[eye].ViewAdjust.y, _eyeRenderDesc[eye].ViewAdjust.z); - - //_camera->setEyeOffsetPosition(glm::vec3(-_eyeRenderDesc[eye].ViewAdjust.x, -_eyeRenderDesc[eye].ViewAdjust.y, -_eyeRenderDesc[eye].ViewAdjust.z)); - Application::getInstance()->displaySide(*_camera, false, RenderArgs::MONO); - - applicationOverlay.displayOverlayTextureOculus(*_camera); - _activeEyeIndex = -1; - } - - //Wait till time-warp to reduce latency - ovr_WaitTillTime(_hmdFrameTiming.TimewarpPointSeconds); - - glPopMatrix(); - - //Full texture viewport for glow effect - glViewport(0, 0, _renderTargetSize.w, _renderTargetSize.h); - - //Bind the output texture from the glow shader. If glow effect is disabled, we just grab the texture - if (Menu::getInstance()->isOptionChecked(MenuOption::EnableGlowEffect)) { - QOpenGLFramebufferObject* fbo = DependencyManager::get()->render(true); - glBindTexture(GL_TEXTURE_2D, fbo->texture()); - } else { - DependencyManager::get()->getPrimaryFramebufferObject()->release(); - glBindTexture(GL_TEXTURE_2D, DependencyManager::get()->getPrimaryFramebufferObject()->texture()); - } - - // restore our normal viewport - auto glCanvas = DependencyManager::get(); - glViewport(0, 0, glCanvas->getDeviceWidth(), glCanvas->getDeviceHeight()); - - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - - //Renders the distorted mesh onto the screen - renderDistortionMesh(eyeRenderPose); - - glBindTexture(GL_TEXTURE_2D, 0); - +// //beginFrameTiming must be called before display +// if (!_frameTimingActive) { +// printf("WARNING: Called OculusManager::display() without calling OculusManager::beginFrameTiming() first."); +// return; +// } +// +// ApplicationOverlay& applicationOverlay = Application::getInstance()->getApplicationOverlay(); +// +// // We only need to render the overlays to a texture once, then we just render the texture on the hemisphere +// // PrioVR will only work if renderOverlay is called, calibration is connected to Application::renderingOverlay() +// applicationOverlay.renderOverlay(true); +// +// //Bind our framebuffer object. If we are rendering the glow effect, we let the glow effect shader take care of it +// if (Menu::getInstance()->isOptionChecked(MenuOption::EnableGlowEffect)) { +// DependencyManager::get()->prepare(); +// } else { +// DependencyManager::get()->getPrimaryFramebufferObject()->bind(); +// glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); +// } +// +// ovrPosef eyeRenderPose[ovrEye_Count]; +// +// glMatrixMode(GL_PROJECTION); +// glPushMatrix(); +// +// glMatrixMode(GL_MODELVIEW); +// glPushMatrix(); +// +// glm::quat orientation; +// glm::vec3 trackerPosition; +// +//#if defined(__APPLE__) || defined(_WIN32) +// ovrTrackingState ts = ovrHmd_GetTrackingState(_ovrHmd, ovr_GetTimeInSeconds()); +// ovrVector3f ovrHeadPosition = ts.HeadPose.ThePose.Position; +// +// trackerPosition = glm::vec3(ovrHeadPosition.x, ovrHeadPosition.y, ovrHeadPosition.z); +// +// if (_calibrationState != CALIBRATED) { +// ovrQuatf ovrHeadOrientation = ts.HeadPose.ThePose.Orientation; +// orientation = glm::quat(ovrHeadOrientation.w, ovrHeadOrientation.x, ovrHeadOrientation.y, ovrHeadOrientation.z); +// calibrate(trackerPosition, orientation); +// } +// +// trackerPosition = bodyOrientation * trackerPosition; +//#endif +// +// // void ovrHmd_GetEyePoses(ovrHmd hmd, unsigned int frameIndex, ovrVector3f hmdToEyeViewOffset[2], +// // ovrPosef outEyePoses[2], ovrTrackingState* outHmdTrackingState); +// +// //Render each eye into an fbo +// ovrHmd_GetEyePoses(_ovrHmd, 0, _eyeOffset, eyeRenderPose, nullptr); +// for (int eyeIndex = 0; eyeIndex < ovrEye_Count; eyeIndex++) { +// _activeEyeIndex = eyeIndex; +// +//#if defined(__APPLE__) || defined(_WIN32) +// ovrEyeType eye = _ovrHmd->EyeRenderOrder[eyeIndex]; +//#else +// ovrEyeType eye = _ovrHmdDesc.EyeRenderOrder[eyeIndex]; +//#endif +// // Set the camera rotation for this eye +// orientation.x = eyeRenderPose[eye].Orientation.x; +// orientation.y = eyeRenderPose[eye].Orientation.y; +// orientation.z = eyeRenderPose[eye].Orientation.z; +// orientation.w = eyeRenderPose[eye].Orientation.w; +// +// // Update the application camera with the latest HMD position +// whichCamera.setHmdPosition(trackerPosition); +// whichCamera.setHmdRotation(orientation); +// +// // Update our camera to what the application camera is doing +// _camera->setRotation(whichCamera.getRotation()); +// _camera->setPosition(whichCamera.getPosition()); +// +// // Store the latest left and right eye render locations for things that need to know +// glm::vec3 thisEyePosition = position + trackerPosition + toGlm(eyeRenderPose[eye].Position); +// +// RenderArgs::RenderSide renderSide = RenderArgs::STEREO_LEFT; +// if (eyeIndex == 0) { +// _leftEyePosition = thisEyePosition; +// } else { +// _rightEyePosition = thisEyePosition; +// renderSide = RenderArgs::STEREO_RIGHT; +// } +// +// _camera->update(1.0f / Application::getInstance()->getFps()); +// +// glMatrixMode(GL_PROJECTION); +// glLoadIdentity(); +// const ovrFovPort& port = _eyeFov[_activeEyeIndex]; +// float nearClip = whichCamera.getNearClip(), farClip = whichCamera.getFarClip(); +// glFrustum(-nearClip * port.LeftTan, nearClip * port.RightTan, -nearClip * port.DownTan, +// nearClip * port.UpTan, nearClip, farClip); +// +// glViewport(_eyeRenderViewport[eye].Pos.x, _eyeRenderViewport[eye].Pos.y, +// _eyeRenderViewport[eye].Size.w, _eyeRenderViewport[eye].Size.h); +// +// +// glMatrixMode(GL_MODELVIEW); +// glLoadIdentity(); +// +// // HACK: instead of passing the stereo eye offset directly in the matrix, pass it in the camera offset +// //glTranslatef(_eyeRenderDesc[eye].ViewAdjust.x, _eyeRenderDesc[eye].ViewAdjust.y, _eyeRenderDesc[eye].ViewAdjust.z); +// +// //_camera->setEyeOffsetPosition(glm::vec3(-_eyeRenderDesc[eye].ViewAdjust.x, -_eyeRenderDesc[eye].ViewAdjust.y, -_eyeRenderDesc[eye].ViewAdjust.z)); +// Application::getInstance()->displaySide(*_camera, false, RenderArgs::MONO); +// +// applicationOverlay.displayOverlayTextureOculus(*_camera); +// _activeEyeIndex = -1; +// } +// +// //Wait till time-warp to reduce latency +// ovr_WaitTillTime(_hmdFrameTiming.TimewarpPointSeconds); +// +// glPopMatrix(); +// +// //Full texture viewport for glow effect +// glViewport(0, 0, _renderTargetSize.w, _renderTargetSize.h); +// +// //Bind the output texture from the glow shader. If glow effect is disabled, we just grab the texture +// if (Menu::getInstance()->isOptionChecked(MenuOption::EnableGlowEffect)) { +// QOpenGLFramebufferObject* fbo = DependencyManager::get()->render(true); +// glBindTexture(GL_TEXTURE_2D, fbo->texture()); +// } else { +// DependencyManager::get()->getPrimaryFramebufferObject()->release(); +// glBindTexture(GL_TEXTURE_2D, DependencyManager::get()->getPrimaryFramebufferObject()->texture()); +// } +// +// // restore our normal viewport +// auto glCanvas = DependencyManager::get(); +// glViewport(0, 0, glCanvas->getDeviceWidth(), glCanvas->getDeviceHeight()); +// +// glMatrixMode(GL_PROJECTION); +// glPopMatrix(); +// +// //Renders the distorted mesh onto the screen +// renderDistortionMesh(eyeRenderPose); +// +// glBindTexture(GL_TEXTURE_2D, 0); +// #endif } -#ifdef HAVE_LIBOVR -void OculusManager::renderDistortionMesh(ovrPosef eyeRenderPose[ovrEye_Count]) { - - glLoadIdentity(); - auto glCanvas = DependencyManager::get(); - glOrtho(0, glCanvas->getDeviceWidth(), 0, glCanvas->getDeviceHeight(), -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++) { - GLfloat uvScale[2] = { _UVScaleOffset[eyeNum][0].x, _UVScaleOffset[eyeNum][0].y }; - _program.setUniformValueArray(_eyeToSourceUVScaleLocation, uvScale, 1, 2); - GLfloat uvOffset[2] = { _UVScaleOffset[eyeNum][1].x, _UVScaleOffset[eyeNum][1].y }; - _program.setUniformValueArray(_eyeToSourceUVOffsetLocation, uvOffset, 1, 2); - - ovrMatrix4f timeWarpMatrices[2]; - Matrix4f transposeMatrices[2]; - //Grabs the timewarp matrices to be used in the shader - ovrHmd_GetEyeTimewarpMatrices(_ovrHmd, (ovrEyeType)eyeNum, eyeRenderPose[eyeNum], timeWarpMatrices); - transposeMatrices[0] = Matrix4f(timeWarpMatrices[0]); - transposeMatrices[1] = Matrix4f(timeWarpMatrices[1]); - - //Have to transpose the matrices before using them - transposeMatrices[0].Transpose(); - transposeMatrices[1].Transpose(); - - glUniformMatrix4fv(_eyeRotationStartLocation, 1, GL_FALSE, (GLfloat *)transposeMatrices[0].M); - glUniformMatrix4fv(_eyeRotationEndLocation, 1, GL_FALSE, (GLfloat *)transposeMatrices[1].M); - - 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 +//#ifdef HAVE_LIBOVR +//void OculusManager::renderDistortionMesh(ovrPosef eyeRenderPose[ovrEye_Count]) { +// +// glLoadIdentity(); +// auto glCanvas = DependencyManager::get(); +// glOrtho(0, glCanvas->getDeviceWidth(), 0, glCanvas->getDeviceHeight(), -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++) { +// GLfloat uvScale[2] = { _UVScaleOffset[eyeNum][0].x, _UVScaleOffset[eyeNum][0].y }; +// _program.setUniformValueArray(_eyeToSourceUVScaleLocation, uvScale, 1, 2); +// GLfloat uvOffset[2] = { _UVScaleOffset[eyeNum][1].x, _UVScaleOffset[eyeNum][1].y }; +// _program.setUniformValueArray(_eyeToSourceUVOffsetLocation, uvOffset, 1, 2); +// +// ovrMatrix4f timeWarpMatrices[2]; +// Matrix4f transposeMatrices[2]; +// //Grabs the timewarp matrices to be used in the shader +// ovrHmd_GetEyeTimewarpMatrices(_ovrHmd, (ovrEyeType)eyeNum, eyeRenderPose[eyeNum], timeWarpMatrices); +// transposeMatrices[0] = Matrix4f(timeWarpMatrices[0]); +// transposeMatrices[1] = Matrix4f(timeWarpMatrices[1]); +// +// //Have to transpose the matrices before using them +// transposeMatrices[0].Transpose(); +// transposeMatrices[1].Transpose(); +// +// glUniformMatrix4fv(_eyeRotationStartLocation, 1, GL_FALSE, (GLfloat *)transposeMatrices[0].M); +// glUniformMatrix4fv(_eyeRotationEndLocation, 1, GL_FALSE, (GLfloat *)transposeMatrices[1].M); +// +// 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() { @@ -685,8 +679,10 @@ void OculusManager::getEulerAngles(float& yaw, float& pitch, float& roll) { #else ovrPosef headPose = ss.Predicted.Pose; #endif - Quatf orientation = Quatf(headPose.Orientation); - orientation.GetEulerAngles(&yaw, &pitch, &roll); + glm::vec3 angles = safeEulerAngles(toGlm(headPose.Orientation)); + yaw = angles.y; + pitch = angles.x; + roll = angles.z; } else { yaw = 0.0f; pitch = 0.0f; diff --git a/interface/src/devices/OculusManager.h b/interface/src/devices/OculusManager.h index 104d844855..9be2d16496 100644 --- a/interface/src/devices/OculusManager.h +++ b/interface/src/devices/OculusManager.h @@ -13,11 +13,18 @@ #ifndef hifi_OculusManager_h #define hifi_OculusManager_h +#define HAVE_LIBOVR 1 #ifdef HAVE_LIBOVR -#include +#include +#include +#include +#include #endif #include +#include +#include +#include class Camera; class PalmData; @@ -135,4 +142,58 @@ private: }; + +inline glm::mat4 toGlm(const ovrMatrix4f & om) { + return glm::transpose(glm::make_mat4(&om.M[0][0])); +} + +inline glm::mat4 toGlm(const ovrFovPort & fovport, float nearPlane = 0.01f, float farPlane = 10000.0f) { + return toGlm(ovrMatrix4f_Projection(fovport, nearPlane, farPlane, true)); +} + +inline glm::vec3 toGlm(const ovrVector3f & ov) { + return glm::make_vec3(&ov.x); +} + +inline glm::vec2 toGlm(const ovrVector2f & ov) { + return glm::make_vec2(&ov.x); +} + +inline glm::uvec2 toGlm(const ovrSizei & ov) { + return glm::uvec2(ov.w, ov.h); +} + +inline glm::quat toGlm(const ovrQuatf & oq) { + return glm::make_quat(&oq.x); +} + +inline glm::mat4 toGlm(const ovrPosef & op) { + glm::mat4 orientation = glm::mat4_cast(toGlm(op.Orientation)); + glm::mat4 translation = glm::translate(glm::mat4(), toGlm(op.Position)); + return translation * orientation; +} + +inline ovrMatrix4f ovrFromGlm(const glm::mat4 & m) { + ovrMatrix4f result; + glm::mat4 transposed(glm::transpose(m)); + memcpy(result.M, &(transposed[0][0]), sizeof(float) * 16); + return result; +} + +inline ovrVector3f ovrFromGlm(const glm::vec3 & v) { + return{ v.x, v.y, v.z }; +} + +inline ovrVector2f ovrFromGlm(const glm::vec2 & v) { + return{ v.x, v.y }; +} + +inline ovrSizei ovrFromGlm(const glm::uvec2 & v) { + return{ v.x, v.y }; +} + +inline ovrQuatf ovrFromGlm(const glm::quat & q) { + return{ q.x, q.y, q.z, q.w }; +} + #endif // hifi_OculusManager_h From 06b9b9cc8814f4de3ac483b41ff057965212a20f Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Sat, 21 Feb 2015 00:15:12 -0800 Subject: [PATCH 03/41] Getting SDK based rendering and Direct HMD mode working --- interface/src/GLCanvas.cpp | 23 +- interface/src/devices/OculusManager.cpp | 669 +++++++----------------- interface/src/devices/OculusManager.h | 57 +- interface/src/main.cpp | 7 +- 4 files changed, 211 insertions(+), 545 deletions(-) diff --git a/interface/src/GLCanvas.cpp b/interface/src/GLCanvas.cpp index 10090de51a..2fd79c1b06 100644 --- a/interface/src/GLCanvas.cpp +++ b/interface/src/GLCanvas.cpp @@ -57,15 +57,13 @@ void GLCanvas::initializeGL() { void GLCanvas::paintGL() { if (!_throttleRendering && !Application::getInstance()->getWindow()->isMinimized()) { //Need accurate frame timing for the oculus rift - if (OculusManager::isConnected()) { - OculusManager::beginFrameTiming(); - } - Application::getInstance()->paintGL(); - swapBuffers(); - if (OculusManager::isConnected()) { - OculusManager::endFrameTiming(); + // FIXME abstract the functionality of various display modes out + // to enable supporting various HMDs as well as 2D screens through + // a single interface + if (!OculusManager::isConnected()) { + swapBuffers(); } } } @@ -126,16 +124,9 @@ void GLCanvas::activeChanged(Qt::ApplicationState state) { void GLCanvas::throttleRender() { _frameTimer.start(_idleRenderInterval); if (!Application::getInstance()->getWindow()->isMinimized()) { - //Need accurate frame timing for the oculus rift - if (OculusManager::isConnected()) { - OculusManager::beginFrameTiming(); - } - Application::getInstance()->paintGL(); - swapBuffers(); - - if (OculusManager::isConnected()) { - OculusManager::endFrameTiming(); + if (!OculusManager::isConnected()) { + swapBuffers(); } } } diff --git a/interface/src/devices/OculusManager.cpp b/interface/src/devices/OculusManager.cpp index a15b606e17..978f75d6a2 100644 --- a/interface/src/devices/OculusManager.cpp +++ b/interface/src/devices/OculusManager.cpp @@ -28,38 +28,24 @@ #include #include #include - #include "Application.h" -#ifdef HAVE_LIBOVR - using namespace OVR; -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; -bool OculusManager::_isConnected = false; +template +void for_each_eye(Function function) { + for (ovrEyeType eye = ovrEyeType::ovrEye_Left; + eye < ovrEyeType::ovrEye_Count; + eye = static_cast(eye + 1)) { + function(eye); + } +} ovrHmd OculusManager::_ovrHmd; -ovrHmdDesc OculusManager::_ovrHmdDesc; ovrFovPort OculusManager::_eyeFov[ovrEye_Count]; -ovrEyeRenderDesc OculusManager::_eyeRenderDesc[ovrEye_Count]; ovrVector3f OculusManager::_eyeOffset[ovrEye_Count]; ovrSizei OculusManager::_renderTargetSize; -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; -ovrRecti OculusManager::_eyeRenderViewport[ovrEye_Count]; +glm::mat4 OculusManager::_eyeProjection[ovrEye_Count]; unsigned int OculusManager::_frameIndex = 0; bool OculusManager::_frameTimingActive = false; bool OculusManager::_programInitialized = false; @@ -77,131 +63,97 @@ glm::vec3 OculusManager::_calibrationPosition; glm::quat OculusManager::_calibrationOrientation; quint64 OculusManager::_calibrationStartTime; int OculusManager::_calibrationMessage = NULL; +glm::vec3 OculusManager::_eyePositions[ovrEye_Count]; -#endif - -glm::vec3 OculusManager::_leftEyePosition = glm::vec3(); -glm::vec3 OculusManager::_rightEyePosition = glm::vec3(); - -void OculusManager::connect() { -#ifdef HAVE_LIBOVR - _calibrationState = UNCALIBRATED; - qDebug() << "Oculus SDK" << OVR_VERSION_STRING; +void OculusManager::init() { ovr_Initialize(); - _ovrHmd = ovrHmd_Create(0); if (_ovrHmd) { - if (!_isConnected) { - UserActivityLogger::getInstance().connectedDevice("hmd", "oculus"); - } - _isConnected = true; - -#if defined(__APPLE__) || defined(_WIN32) - _eyeFov[0] = _ovrHmd->DefaultEyeFov[0]; - _eyeFov[1] = _ovrHmd->DefaultEyeFov[1]; -#else - ovrHmd_GetDesc(_ovrHmd, &_ovrHmdDesc); - _eyeFov[0] = _ovrHmdDesc.DefaultEyeFov[0]; - _eyeFov[1] = _ovrHmdDesc.DefaultEyeFov[1]; -#endif - //Get texture size - ovrSizei recommendedTex0Size = ovrHmd_GetFovTextureSize(_ovrHmd, ovrEye_Left, - _eyeFov[0], 1.0f); - ovrSizei recommendedTex1Size = ovrHmd_GetFovTextureSize(_ovrHmd, ovrEye_Right, - _eyeFov[1], 1.0f); - _renderTargetSize.w = recommendedTex0Size.w + recommendedTex1Size.w; - _renderTargetSize.h = recommendedTex0Size.h; - if (_renderTargetSize.h < recommendedTex1Size.h) { - _renderTargetSize.h = recommendedTex1Size.h; - } - - _eyeRenderDesc[0] = ovrHmd_GetRenderDesc(_ovrHmd, ovrEye_Left, _eyeFov[0]); - _eyeRenderDesc[1] = ovrHmd_GetRenderDesc(_ovrHmd, ovrEye_Right, _eyeFov[1]); - _eyeOffset[0] = _eyeRenderDesc[0].HmdToEyeViewOffset; - _eyeOffset[1] = _eyeRenderDesc[1].HmdToEyeViewOffset; - -#if defined(__APPLE__) || defined(_WIN32) + // FIXME Not sure this is effective prior to starting rendering ovrHmd_SetEnabledCaps(_ovrHmd, ovrHmdCap_LowPersistence); -#else - ovrHmd_SetEnabledCaps(_ovrHmd, ovrHmdCap_LowPersistence | ovrHmdCap_LatencyTest); -#endif - -#if defined(__APPLE__) || defined(_WIN32) ovrHmd_ConfigureTracking(_ovrHmd, ovrTrackingCap_Orientation | ovrTrackingCap_Position | - ovrTrackingCap_MagYawCorrection, - ovrTrackingCap_Orientation); -#else - ovrHmd_StartSensor(_ovrHmd, ovrSensorCap_Orientation | ovrSensorCap_YawCorrection | - ovrSensorCap_Position, - ovrSensorCap_Orientation); -#endif + ovrTrackingCap_MagYawCorrection, + ovrTrackingCap_Orientation); + + for_each_eye([&](ovrEyeType eye) { + _eyeFov[eye] = _ovrHmd->DefaultEyeFov[eye]; + }); if (!_camera) { _camera = new Camera; configureCamera(*_camera, 0, 0); // no need to use screen dimensions; they're ignored } - - 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(); - } else { - _isConnected = false; - // we're definitely not in "VR mode" so tell the menu that Menu::getInstance()->getActionForOption(MenuOption::EnableVRMode)->setChecked(false); - - ovrHmd_Destroy(_ovrHmd); - ovr_Shutdown(); } -#endif +} + +// FIXME store like the others +ovrGLTexture _eyeTextures[ovrEye_Count]; + +void OculusManager::connect() { + _calibrationState = UNCALIBRATED; + qDebug() << "Oculus SDK" << OVR_VERSION_STRING; + if (_ovrHmd) { + UserActivityLogger::getInstance().connectedDevice("hmd", "oculus"); + + MainWindow* applicationWindow = Application::getInstance()->getWindow(); + + 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_Chromatic + | ovrDistortionCap_Vignette + | ovrDistortionCap_Overdrive + | ovrDistortionCap_TimeWarp; + + ovrEyeRenderDesc eyeRenderDescs[2]; + int configResult = ovrHmd_ConfigureRendering(_ovrHmd, &cfg.Config, + distortionCaps, _eyeFov, eyeRenderDescs); + assert(configResult); + + for_each_eye([&](ovrEyeType eye) { + _eyeFov[eye] = _ovrHmd->DefaultEyeFov[eye]; + }); + + _renderTargetSize = { 0, 0 }; + memset(_eyeTextures, 0, sizeof(_eyeTextures)); + for_each_eye([&](ovrEyeType eye) { + //Get texture size + ovrSizei recommendedTexSize = ovrHmd_GetFovTextureSize(_ovrHmd, eye, _eyeFov[eye], 1.0f); + auto & eyeTexture = _eyeTextures[eye].Texture.Header; + eyeTexture.API = ovrRenderAPI_OpenGL; + eyeTexture.RenderViewport.Size = recommendedTexSize; + eyeTexture.RenderViewport.Pos = { _renderTargetSize.w, 0 }; + + _renderTargetSize.h = std::max(_renderTargetSize.h, recommendedTexSize.h); + _renderTargetSize.w += recommendedTexSize.w; + const ovrEyeRenderDesc & erd = eyeRenderDescs[eye]; + ovrMatrix4f ovrPerspectiveProjection = ovrMatrix4f_Projection(erd.Fov, 0.01f, 100000.0f, true); + _eyeProjection[eye] = toGlm(ovrPerspectiveProjection); + _eyeOffset[eye] = erd.HmdToEyeViewOffset; + }); + + for_each_eye([&](ovrEyeType eye) { + ovrGLTexture & eyeTexture = _eyeTextures[eye]; + eyeTexture.Texture.Header.TextureSize = _renderTargetSize; + }); + } } //Disconnects and deallocates the OR void OculusManager::disconnect() { -#ifdef HAVE_LIBOVR - if (_isConnected) { - _isConnected = false; + if (_ovrHmd) { ovrHmd_Destroy(_ovrHmd); - ovr_Shutdown(); - - //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; - } - } + _ovrHmd = nullptr; } -#endif } -#ifdef HAVE_LIBOVR void OculusManager::positionCalibrationBillboard(Text3DOverlay* billboard) { MyAvatar* myAvatar = DependencyManager::get()->getMyAvatar(); glm::quat headOrientation = myAvatar->getHeadOrientation(); @@ -212,9 +164,7 @@ void OculusManager::positionCalibrationBillboard(Text3DOverlay* billboard) { + headOrientation * glm::vec3(0.0f, 0.0f, -CALIBRATION_MESSAGE_DISTANCE)); billboard->setRotation(headOrientation); } -#endif -#ifdef HAVE_LIBOVR void OculusManager::calibrate(glm::vec3 position, glm::quat orientation) { static QString instructionMessage = "Hold still to calibrate"; static QString progressMessage; @@ -306,379 +256,159 @@ void OculusManager::calibrate(glm::vec3 position, glm::quat orientation) { } } -#endif void OculusManager::recalibrate() { -#ifdef HAVE_LIBOVR _calibrationState = UNCALIBRATED; -#endif } void OculusManager::abandonCalibration() { -#ifdef HAVE_LIBOVR _calibrationState = CALIBRATED; if (_calibrationMessage) { qDebug() << "Abandoned HMD calibration"; Application::getInstance()->getOverlays().deleteOverlay(_calibrationMessage); _calibrationMessage = NULL; } -#endif } -#ifdef HAVE_LIBOVR -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; - } - - //Viewport for the render target for each eye - _eyeRenderViewport[0].Pos = { 0, 0 }; // = Vector2i(0, 0); - _eyeRenderViewport[0].Size = { _renderTargetSize.w / 2, _renderTargetSize.h }; - _eyeRenderViewport[1].Pos = { (_renderTargetSize.w + 1) / 2, 0 }; - _eyeRenderViewport[1].Size = _eyeRenderViewport[0].Size; - - 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, _ovrHmdDesc.DistortionCaps, &meshData); - - ovrHmd_GetRenderScaleAndOffset(_eyeRenderDesc[eyeNum].Fov, _renderTargetSize, _eyeRenderViewport[eyeNum], - _UVScaleOffset[eyeNum]); - - // 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++) { -#if defined(__APPLE__) || defined(_WIN32) - 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; -#else - v->pos.x = ov->Pos.x; - v->pos.y = ov->Pos.y; - v->texR.x = ov->TexR.x; - v->texR.y = ov->TexR.y; - v->texG.x = ov->TexG.x; - v->texG.y = ov->TexG.y; - v->texB.x = ov->TexB.x; - v->texB.y = ov->TexB.y; -#endif - 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() { -#ifdef HAVE_LIBOVR - return _isConnected && Menu::getInstance()->isOptionChecked(MenuOption::EnableVRMode); -#else - return false; -#endif -} - -//Begins the frame timing for oculus prediction purposes -void OculusManager::beginFrameTiming() { -#ifdef HAVE_LIBOVR - - if (_frameTimingActive) { - printf("WARNING: Called OculusManager::beginFrameTiming() twice in a row, need to call OculusManager::endFrameTiming()."); - } - - _hmdFrameTiming = ovrHmd_BeginFrameTiming(_ovrHmd, _frameIndex); - _frameTimingActive = true; -#endif -} - -//Ends frame timing -void OculusManager::endFrameTiming() { -#ifdef HAVE_LIBOVR - ovrHmd_EndFrameTiming(_ovrHmd); - _frameIndex++; - _frameTimingActive = false; -#endif + return _ovrHmd && Menu::getInstance()->isOptionChecked(MenuOption::EnableVRMode); } //Sets the camera FoV and aspect ratio void OculusManager::configureCamera(Camera& camera, int screenWidth, int screenHeight) { -#ifdef HAVE_LIBOVR + // FIXME the oculus projection matrix is assymetrical, this will not work. camera.setAspectRatio(_renderTargetSize.w * 0.5f / _renderTargetSize.h); camera.setFieldOfView(atan(_eyeFov[0].UpTan) * DEGREES_PER_RADIAN * 2.0f); -#endif } +RenderArgs::RenderSide RENDER_SIDES[ovrEye_Count] = { RenderArgs::STEREO_LEFT, RenderArgs::STEREO_RIGHT }; + //Displays everything for the oculus, frame timing must be active void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &position, Camera& whichCamera) { -#ifdef HAVE_LIBOVR -// //beginFrameTiming must be called before display -// if (!_frameTimingActive) { -// printf("WARNING: Called OculusManager::display() without calling OculusManager::beginFrameTiming() first."); -// return; -// } -// -// ApplicationOverlay& applicationOverlay = Application::getInstance()->getApplicationOverlay(); -// -// // We only need to render the overlays to a texture once, then we just render the texture on the hemisphere -// // PrioVR will only work if renderOverlay is called, calibration is connected to Application::renderingOverlay() -// applicationOverlay.renderOverlay(true); -// -// //Bind our framebuffer object. If we are rendering the glow effect, we let the glow effect shader take care of it -// if (Menu::getInstance()->isOptionChecked(MenuOption::EnableGlowEffect)) { -// DependencyManager::get()->prepare(); -// } else { -// DependencyManager::get()->getPrimaryFramebufferObject()->bind(); -// glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); -// } -// -// ovrPosef eyeRenderPose[ovrEye_Count]; -// -// glMatrixMode(GL_PROJECTION); -// glPushMatrix(); -// -// glMatrixMode(GL_MODELVIEW); -// glPushMatrix(); -// -// glm::quat orientation; -// glm::vec3 trackerPosition; -// -//#if defined(__APPLE__) || defined(_WIN32) -// ovrTrackingState ts = ovrHmd_GetTrackingState(_ovrHmd, ovr_GetTimeInSeconds()); -// ovrVector3f ovrHeadPosition = ts.HeadPose.ThePose.Position; -// -// trackerPosition = glm::vec3(ovrHeadPosition.x, ovrHeadPosition.y, ovrHeadPosition.z); -// -// if (_calibrationState != CALIBRATED) { -// ovrQuatf ovrHeadOrientation = ts.HeadPose.ThePose.Orientation; -// orientation = glm::quat(ovrHeadOrientation.w, ovrHeadOrientation.x, ovrHeadOrientation.y, ovrHeadOrientation.z); -// calibrate(trackerPosition, orientation); -// } -// -// trackerPosition = bodyOrientation * trackerPosition; -//#endif -// -// // void ovrHmd_GetEyePoses(ovrHmd hmd, unsigned int frameIndex, ovrVector3f hmdToEyeViewOffset[2], -// // ovrPosef outEyePoses[2], ovrTrackingState* outHmdTrackingState); -// -// //Render each eye into an fbo -// ovrHmd_GetEyePoses(_ovrHmd, 0, _eyeOffset, eyeRenderPose, nullptr); -// for (int eyeIndex = 0; eyeIndex < ovrEye_Count; eyeIndex++) { -// _activeEyeIndex = eyeIndex; -// -//#if defined(__APPLE__) || defined(_WIN32) -// ovrEyeType eye = _ovrHmd->EyeRenderOrder[eyeIndex]; -//#else -// ovrEyeType eye = _ovrHmdDesc.EyeRenderOrder[eyeIndex]; -//#endif -// // Set the camera rotation for this eye -// orientation.x = eyeRenderPose[eye].Orientation.x; -// orientation.y = eyeRenderPose[eye].Orientation.y; -// orientation.z = eyeRenderPose[eye].Orientation.z; -// orientation.w = eyeRenderPose[eye].Orientation.w; -// -// // Update the application camera with the latest HMD position -// whichCamera.setHmdPosition(trackerPosition); -// whichCamera.setHmdRotation(orientation); -// -// // Update our camera to what the application camera is doing -// _camera->setRotation(whichCamera.getRotation()); -// _camera->setPosition(whichCamera.getPosition()); -// -// // Store the latest left and right eye render locations for things that need to know -// glm::vec3 thisEyePosition = position + trackerPosition + toGlm(eyeRenderPose[eye].Position); -// -// RenderArgs::RenderSide renderSide = RenderArgs::STEREO_LEFT; -// if (eyeIndex == 0) { -// _leftEyePosition = thisEyePosition; -// } else { -// _rightEyePosition = thisEyePosition; -// renderSide = RenderArgs::STEREO_RIGHT; -// } -// -// _camera->update(1.0f / Application::getInstance()->getFps()); -// -// glMatrixMode(GL_PROJECTION); -// glLoadIdentity(); -// const ovrFovPort& port = _eyeFov[_activeEyeIndex]; -// float nearClip = whichCamera.getNearClip(), farClip = whichCamera.getFarClip(); -// glFrustum(-nearClip * port.LeftTan, nearClip * port.RightTan, -nearClip * port.DownTan, -// nearClip * port.UpTan, nearClip, farClip); -// -// glViewport(_eyeRenderViewport[eye].Pos.x, _eyeRenderViewport[eye].Pos.y, -// _eyeRenderViewport[eye].Size.w, _eyeRenderViewport[eye].Size.h); -// -// -// glMatrixMode(GL_MODELVIEW); -// glLoadIdentity(); -// -// // HACK: instead of passing the stereo eye offset directly in the matrix, pass it in the camera offset -// //glTranslatef(_eyeRenderDesc[eye].ViewAdjust.x, _eyeRenderDesc[eye].ViewAdjust.y, _eyeRenderDesc[eye].ViewAdjust.z); -// -// //_camera->setEyeOffsetPosition(glm::vec3(-_eyeRenderDesc[eye].ViewAdjust.x, -_eyeRenderDesc[eye].ViewAdjust.y, -_eyeRenderDesc[eye].ViewAdjust.z)); -// Application::getInstance()->displaySide(*_camera, false, RenderArgs::MONO); -// -// applicationOverlay.displayOverlayTextureOculus(*_camera); -// _activeEyeIndex = -1; -// } -// -// //Wait till time-warp to reduce latency -// ovr_WaitTillTime(_hmdFrameTiming.TimewarpPointSeconds); -// -// glPopMatrix(); -// -// //Full texture viewport for glow effect -// glViewport(0, 0, _renderTargetSize.w, _renderTargetSize.h); -// -// //Bind the output texture from the glow shader. If glow effect is disabled, we just grab the texture -// if (Menu::getInstance()->isOptionChecked(MenuOption::EnableGlowEffect)) { -// QOpenGLFramebufferObject* fbo = DependencyManager::get()->render(true); -// glBindTexture(GL_TEXTURE_2D, fbo->texture()); -// } else { -// DependencyManager::get()->getPrimaryFramebufferObject()->release(); -// glBindTexture(GL_TEXTURE_2D, DependencyManager::get()->getPrimaryFramebufferObject()->texture()); -// } -// -// // restore our normal viewport -// auto glCanvas = DependencyManager::get(); -// glViewport(0, 0, glCanvas->getDeviceWidth(), glCanvas->getDeviceHeight()); -// -// glMatrixMode(GL_PROJECTION); -// glPopMatrix(); -// -// //Renders the distorted mesh onto the screen -// renderDistortionMesh(eyeRenderPose); -// -// glBindTexture(GL_TEXTURE_2D, 0); -// -#endif + static const glm::vec2 topLeft(-1.0f, -1.0f); + static const glm::vec2 bottomRight(1.0f, 1.0f); + static const glm::vec2 texCoordTopLeft(0.0f, 0.0f); + static const glm::vec2 texCoordBottomRight(1.0f, 1.0f); + + auto glCanvas = DependencyManager::get(); + + static bool attached = false; + if (!attached) { + attached = true; + void * nativeWindowHandle = (void*)(size_t)glCanvas->effectiveWinId(); + if (nullptr != nativeWindowHandle) { + ovrHmd_AttachToWindow(_ovrHmd, nativeWindowHandle, nullptr, nullptr); + } + } + + ovrHmd_BeginFrame(_ovrHmd, ++_frameIndex); + ApplicationOverlay& applicationOverlay = Application::getInstance()->getApplicationOverlay(); + + // We only need to render the overlays to a texture once, then we just render the texture on the hemisphere + // PrioVR will only work if renderOverlay is called, calibration is connected to Application::renderingOverlay() + applicationOverlay.renderOverlay(true); + + //Bind our framebuffer object. If we are rendering the glow effect, we let the glow effect shader take care of it + if (Menu::getInstance()->isOptionChecked(MenuOption::EnableGlowEffect)) { + DependencyManager::get()->prepare(); + } else { + DependencyManager::get()->getPrimaryFramebufferObject()->bind(); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + } + + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + + if (_calibrationState != CALIBRATED) { + ovrTrackingState ts = ovrHmd_GetTrackingState(_ovrHmd, ovr_GetTimeInSeconds()); + ovrVector3f ovrHeadPosition = ts.HeadPose.ThePose.Position; + glm::vec3 trackerPosition = glm::vec3(ovrHeadPosition.x, ovrHeadPosition.y, ovrHeadPosition.z); + calibrate(trackerPosition, toGlm(ts.HeadPose.ThePose.Orientation)); + trackerPosition = bodyOrientation * trackerPosition; + } + + //Render each eye into an fbo + ovrPosef eyeRenderPose[ovrEye_Count]; + ovrHmd_GetEyePoses(_ovrHmd, 0, _eyeOffset, eyeRenderPose, nullptr); + for_each_eye([&](int i) { + _activeEyeIndex = i; + ovrEyeType eye = _ovrHmd->EyeRenderOrder[_activeEyeIndex]; + const ovrPosef & pose = eyeRenderPose[eye]; + // Update the application camera with the latest HMD position + whichCamera.setHmdPosition(bodyOrientation * toGlm(pose.Position)); + whichCamera.setHmdRotation(toGlm(pose.Orientation)); + + // Update our camera to what the application camera is doing + _camera->setRotation(whichCamera.getRotation()); + _camera->setPosition(whichCamera.getPosition()); + RenderArgs::RenderSide renderSide = RENDER_SIDES[eye]; + glm::vec3 thisEyePosition = position + toGlm(eyeRenderPose[eye].Position); + // Store the latest left and right eye render locations for things that need to know + _eyePositions[eye] = thisEyePosition; + _camera->update(1.0f / Application::getInstance()->getFps()); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + const ovrFovPort& port = _eyeFov[eye]; + float nearClip = whichCamera.getNearClip(), farClip = whichCamera.getFarClip(); + glFrustum(-nearClip * port.LeftTan, nearClip * port.RightTan, -nearClip * port.DownTan, + nearClip * port.UpTan, nearClip, farClip); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + auto vp = _eyeTextures[eye].Texture.Header.RenderViewport; + glViewport(vp.Pos.x, vp.Pos.y, vp.Size.w, vp.Size.h); + // HACK: instead of passing the stereo eye offset directly in the matrix, pass it in the camera offset + //glTranslatef(_eyeRenderDesc[eye].ViewAdjust.x, _eyeRenderDesc[eye].ViewAdjust.y, _eyeRenderDesc[eye].ViewAdjust.z); + //_camera->setEyeOffsetPosition(glm::vec3(-_eyeRenderDesc[eye].ViewAdjust.x, -_eyeRenderDesc[eye].ViewAdjust.y, -_eyeRenderDesc[eye].ViewAdjust.z)); + Application::getInstance()->displaySide(*_camera, false, RenderArgs::MONO); + applicationOverlay.displayOverlayTextureOculus(*_camera); + }); + _activeEyeIndex = -1; + + glPopMatrix(); + //Full texture viewport for glow effect + glViewport(0, 0, _renderTargetSize.w, _renderTargetSize.h); + + int finalTexture = 0; + //Bind the output texture from the glow shader. If glow effect is disabled, we just grab the texture + if (Menu::getInstance()->isOptionChecked(MenuOption::EnableGlowEffect)) { + QOpenGLFramebufferObject* fbo = DependencyManager::get()->render(true); + finalTexture = fbo->texture(); + } else { + DependencyManager::get()->getPrimaryFramebufferObject()->release(); + finalTexture = DependencyManager::get()->getPrimaryFramebufferObject()->texture(); + } + for_each_eye([&](int eye) { + _eyeTextures[eye].OGL.TexId = finalTexture; + }); + + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + + // restore our normal viewport + glViewport(0, 0, glCanvas->getDeviceWidth(), glCanvas->getDeviceHeight()); + + ovrHmd_EndFrame(_ovrHmd, eyeRenderPose, &(_eyeTextures[0].Texture)); } -//#ifdef HAVE_LIBOVR -//void OculusManager::renderDistortionMesh(ovrPosef eyeRenderPose[ovrEye_Count]) { -// -// glLoadIdentity(); -// auto glCanvas = DependencyManager::get(); -// glOrtho(0, glCanvas->getDeviceWidth(), 0, glCanvas->getDeviceHeight(), -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++) { -// GLfloat uvScale[2] = { _UVScaleOffset[eyeNum][0].x, _UVScaleOffset[eyeNum][0].y }; -// _program.setUniformValueArray(_eyeToSourceUVScaleLocation, uvScale, 1, 2); -// GLfloat uvOffset[2] = { _UVScaleOffset[eyeNum][1].x, _UVScaleOffset[eyeNum][1].y }; -// _program.setUniformValueArray(_eyeToSourceUVOffsetLocation, uvOffset, 1, 2); -// -// ovrMatrix4f timeWarpMatrices[2]; -// Matrix4f transposeMatrices[2]; -// //Grabs the timewarp matrices to be used in the shader -// ovrHmd_GetEyeTimewarpMatrices(_ovrHmd, (ovrEyeType)eyeNum, eyeRenderPose[eyeNum], timeWarpMatrices); -// transposeMatrices[0] = Matrix4f(timeWarpMatrices[0]); -// transposeMatrices[1] = Matrix4f(timeWarpMatrices[1]); -// -// //Have to transpose the matrices before using them -// transposeMatrices[0].Transpose(); -// transposeMatrices[1].Transpose(); -// -// glUniformMatrix4fv(_eyeRotationStartLocation, 1, GL_FALSE, (GLfloat *)transposeMatrices[0].M); -// glUniformMatrix4fv(_eyeRotationEndLocation, 1, GL_FALSE, (GLfloat *)transposeMatrices[1].M); -// -// 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() { -#ifdef HAVE_LIBOVR - if (_isConnected) { + if (_ovrHmd) { ovrHmd_RecenterPose(_ovrHmd); } -#endif } //Gets the current predicted angles from the oculus sensors void OculusManager::getEulerAngles(float& yaw, float& pitch, float& roll) { -#ifdef HAVE_LIBOVR -#if defined(__APPLE__) || defined(_WIN32) ovrTrackingState ts = ovrHmd_GetTrackingState(_ovrHmd, ovr_GetTimeInSeconds()); -#else - ovrSensorState ss = ovrHmd_GetSensorState(_ovrHmd, _hmdFrameTiming.ScanoutMidpointSeconds); -#endif -#if defined(__APPLE__) || defined(_WIN32) if (ts.StatusFlags & (ovrStatus_OrientationTracked | ovrStatus_PositionTracked)) { -#else - if (ss.StatusFlags & (ovrStatus_OrientationTracked | ovrStatus_PositionTracked)) { -#endif - -#if defined(__APPLE__) || defined(_WIN32) ovrPosef headPose = ts.HeadPose.ThePose; -#else - ovrPosef headPose = ss.Predicted.Pose; -#endif glm::vec3 angles = safeEulerAngles(toGlm(headPose.Orientation)); yaw = angles.y; pitch = angles.x; @@ -688,40 +418,24 @@ void OculusManager::getEulerAngles(float& yaw, float& pitch, float& roll) { pitch = 0.0f; roll = 0.0f; } -#else - yaw = 0.0f; - pitch = 0.0f; - roll = 0.0f; -#endif } glm::vec3 OculusManager::getRelativePosition() { -#if (defined(__APPLE__) || defined(_WIN32)) && HAVE_LIBOVR ovrTrackingState trackingState = ovrHmd_GetTrackingState(_ovrHmd, ovr_GetTimeInSeconds()); ovrVector3f headPosition = trackingState.HeadPose.ThePose.Position; - return glm::vec3(headPosition.x, headPosition.y, headPosition.z); -#else - // no positional tracking in Linux yet - return glm::vec3(0.0f, 0.0f, 0.0f); -#endif } //Used to set the size of the glow framebuffers QSize OculusManager::getRenderTargetSize() { -#ifdef HAVE_LIBOVR QSize rv; rv.setWidth(_renderTargetSize.w); rv.setHeight(_renderTargetSize.h); return rv; -#else - return QSize(100, 100); -#endif } void OculusManager::overrideOffAxisFrustum(float& left, float& right, float& bottom, float& top, float& nearVal, float& farVal, glm::vec4& nearClipPlane, glm::vec4& farClipPlane) { -#ifdef HAVE_LIBOVR if (_activeEyeIndex != -1) { const ovrFovPort& port = _eyeFov[_activeEyeIndex]; right = nearVal * port.RightTan; @@ -729,12 +443,10 @@ void OculusManager::overrideOffAxisFrustum(float& left, float& right, float& bot top = nearVal * port.UpTan; bottom = -nearVal * port.DownTan; } -#endif } int OculusManager::getHMDScreen() { int hmdScreenIndex = -1; // unknown -#ifdef HAVE_LIBOVR // 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 @@ -783,7 +495,6 @@ int OculusManager::getHMDScreen() { screenNumber++; } } -#endif return hmdScreenIndex; } diff --git a/interface/src/devices/OculusManager.h b/interface/src/devices/OculusManager.h index 9be2d16496..331b43b379 100644 --- a/interface/src/devices/OculusManager.h +++ b/interface/src/devices/OculusManager.h @@ -33,13 +33,14 @@ class Text3DOverlay; /// Handles interaction with the Oculus Rift. class OculusManager { public: + static void init(); static void connect(); static void disconnect(); static bool isConnected(); static void recalibrate(); static void abandonCalibration(); - static void beginFrameTiming(); - static void endFrameTiming(); + //static void beginFrameTiming(); + //static void endFrameTiming(); static void configureCamera(Camera& camera, int screenWidth, int screenHeight); static void display(const glm::quat &bodyOrientation, const glm::vec3 &position, Camera& whichCamera); static void reset(); @@ -54,58 +55,21 @@ public: static void overrideOffAxisFrustum(float& left, float& right, float& bottom, float& top, float& nearVal, float& farVal, glm::vec4& nearClipPlane, glm::vec4& farClipPlane); - static glm::vec3 getLeftEyePosition() { return _leftEyePosition; } - static glm::vec3 getRightEyePosition() { return _rightEyePosition; } + static glm::vec3 getLeftEyePosition() { return _eyePositions[ovrEye_Left]; } + static glm::vec3 getRightEyePosition() { return _eyePositions[ovrEye_Right]; } static int getHMDScreen(); private: -#ifdef HAVE_LIBOVR - static void generateDistortionMesh(); - static void renderDistortionMesh(ovrPosef eyeRenderPose[ovrEye_Count]); - static bool similarNames(const QString& nameA,const QString& nameB); - 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 bool _isConnected; + //static bool _isConnected; static ovrHmd _ovrHmd; - static ovrHmdDesc _ovrHmdDesc; static ovrFovPort _eyeFov[ovrEye_Count]; - static ovrEyeRenderDesc _eyeRenderDesc[ovrEye_Count]; static ovrVector3f _eyeOffset[ovrEye_Count]; + static glm::mat4 _eyeProjection[ovrEye_Count]; static ovrSizei _renderTargetSize; - 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 ovrRecti _eyeRenderViewport[ovrEye_Count]; static unsigned int _frameIndex; static bool _frameTimingActive; @@ -134,12 +98,7 @@ private: static quint64 _calibrationStartTime; static int _calibrationMessage; -#endif - - static glm::vec3 _leftEyePosition; - static glm::vec3 _rightEyePosition; - - + static glm::vec3 _eyePositions[ovrEye_Count]; }; diff --git a/interface/src/main.cpp b/interface/src/main.cpp index 64ecb2b9e7..8ffef64a0c 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -18,6 +18,8 @@ #include "AddressManager.h" #include "Application.h" +#include "devices/OculusManager.h" + #ifdef Q_OS_WIN static BOOL CALLBACK enumWindowsCallback(HWND hWnd, LPARAM lParam) { @@ -92,7 +94,10 @@ int main(int argc, const char* argv[]) { usecTimestampNowForceClockSkew(clockSkew); qDebug("clockSkewOption=%s clockSkew=%d", clockSkewOption, clockSkew); } - + // Oculus initialization MUST PRECEDE OpenGL context creation. + // The nature of the Application constructor means this has to be either here, + // or in the main window ctor, before GL startup. + OculusManager::init(); int exitCode; { QSettings::setDefaultFormat(QSettings::IniFormat); From 1cd4dc4746bf931aed3062c4ac9ab8c85b6c262d Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Mon, 23 Feb 2015 09:15:18 -0800 Subject: [PATCH 04/41] Adding win32 libs, need to fix for cross platform --- cmake/modules/FindLibOVR.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/cmake/modules/FindLibOVR.cmake b/cmake/modules/FindLibOVR.cmake index acd0b04f82..c45aa5b784 100644 --- a/cmake/modules/FindLibOVR.cmake +++ b/cmake/modules/FindLibOVR.cmake @@ -29,6 +29,7 @@ if (NOT ANDROID) find_path(LIBOVR_INCLUDE_DIRS OVR_CAPI.h PATH_SUFFIXES include HINTS ${LIBOVR_SEARCH_DIRS}) find_library(LIBOVR_LIBRARIES ovr PATH_SUFFIXES lib HINTS ${LIBOVR_SEARCH_DIRS}) + list(APPEND LIBOVR_LIBRARIES setupapi winmm ws2_32) include(FindPackageHandleStandardArgs) find_package_handle_standard_args(LIBOVR DEFAULT_MSG LIBOVR_INCLUDE_DIRS LIBOVR_LIBRARIES) From 670a566763c2583817964023a18a1e9e7e9a7f98 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Mon, 23 Feb 2015 22:15:59 -0800 Subject: [PATCH 05/41] Porting oculus rendering to 0.4.4 SDK --- interface/src/GLCanvas.cpp | 25 +- interface/src/devices/OculusManager.cpp | 558 ++++++++++++++++++------ interface/src/devices/OculusManager.h | 118 +++-- interface/src/main.cpp | 7 +- 4 files changed, 488 insertions(+), 220 deletions(-) diff --git a/interface/src/GLCanvas.cpp b/interface/src/GLCanvas.cpp index 2fd79c1b06..10090de51a 100644 --- a/interface/src/GLCanvas.cpp +++ b/interface/src/GLCanvas.cpp @@ -57,13 +57,15 @@ void GLCanvas::initializeGL() { void GLCanvas::paintGL() { if (!_throttleRendering && !Application::getInstance()->getWindow()->isMinimized()) { //Need accurate frame timing for the oculus rift - Application::getInstance()->paintGL(); + if (OculusManager::isConnected()) { + OculusManager::beginFrameTiming(); + } - // FIXME abstract the functionality of various display modes out - // to enable supporting various HMDs as well as 2D screens through - // a single interface - if (!OculusManager::isConnected()) { - swapBuffers(); + Application::getInstance()->paintGL(); + swapBuffers(); + + if (OculusManager::isConnected()) { + OculusManager::endFrameTiming(); } } } @@ -124,9 +126,16 @@ void GLCanvas::activeChanged(Qt::ApplicationState state) { void GLCanvas::throttleRender() { _frameTimer.start(_idleRenderInterval); if (!Application::getInstance()->getWindow()->isMinimized()) { + //Need accurate frame timing for the oculus rift + if (OculusManager::isConnected()) { + OculusManager::beginFrameTiming(); + } + Application::getInstance()->paintGL(); - if (!OculusManager::isConnected()) { - swapBuffers(); + swapBuffers(); + + if (OculusManager::isConnected()) { + OculusManager::endFrameTiming(); } } } diff --git a/interface/src/devices/OculusManager.cpp b/interface/src/devices/OculusManager.cpp index 978f75d6a2..7bb3746fbf 100644 --- a/interface/src/devices/OculusManager.cpp +++ b/interface/src/devices/OculusManager.cpp @@ -28,24 +28,38 @@ #include #include #include + #include "Application.h" +#ifdef HAVE_LIBOVR +#include "OVR_Math.h" +#include "OVR_Version.h" using namespace OVR; -template -void for_each_eye(Function function) { - for (ovrEyeType eye = ovrEyeType::ovrEye_Left; - eye < ovrEyeType::ovrEye_Count; - eye = static_cast(eye + 1)) { - function(eye); - } -} +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; +bool OculusManager::_isConnected = false; ovrHmd OculusManager::_ovrHmd; +ovrHmdDesc OculusManager::_ovrHmdDesc; ovrFovPort OculusManager::_eyeFov[ovrEye_Count]; -ovrVector3f OculusManager::_eyeOffset[ovrEye_Count]; +ovrEyeRenderDesc OculusManager::_eyeRenderDesc[ovrEye_Count]; ovrSizei OculusManager::_renderTargetSize; -glm::mat4 OculusManager::_eyeProjection[ovrEye_Count]; +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; +ovrRecti OculusManager::_eyeRenderViewport[ovrEye_Count]; unsigned int OculusManager::_frameIndex = 0; bool OculusManager::_frameTimingActive = false; bool OculusManager::_programInitialized = false; @@ -63,97 +77,129 @@ glm::vec3 OculusManager::_calibrationPosition; glm::quat OculusManager::_calibrationOrientation; quint64 OculusManager::_calibrationStartTime; int OculusManager::_calibrationMessage = NULL; -glm::vec3 OculusManager::_eyePositions[ovrEye_Count]; -void OculusManager::init() { +#endif + +glm::vec3 OculusManager::_leftEyePosition = glm::vec3(); +glm::vec3 OculusManager::_rightEyePosition = glm::vec3(); + +void OculusManager::connect() { +#ifdef HAVE_LIBOVR + _calibrationState = UNCALIBRATED; + qDebug() << "Oculus SDK" << OVR_VERSION_STRING; ovr_Initialize(); + _ovrHmd = ovrHmd_Create(0); if (_ovrHmd) { - // FIXME Not sure this is effective prior to starting rendering - ovrHmd_SetEnabledCaps(_ovrHmd, ovrHmdCap_LowPersistence); - ovrHmd_ConfigureTracking(_ovrHmd, ovrTrackingCap_Orientation | ovrTrackingCap_Position | - ovrTrackingCap_MagYawCorrection, - ovrTrackingCap_Orientation); + if (!_isConnected) { + UserActivityLogger::getInstance().connectedDevice("hmd", "oculus"); + } + _isConnected = true; + +#if defined(__APPLE__) || defined(_WIN32) + _eyeFov[0] = _ovrHmd->DefaultEyeFov[0]; + _eyeFov[1] = _ovrHmd->DefaultEyeFov[1]; +#else + ovrHmd_GetDesc(_ovrHmd, &_ovrHmdDesc); + _eyeFov[0] = _ovrHmdDesc.DefaultEyeFov[0]; + _eyeFov[1] = _ovrHmdDesc.DefaultEyeFov[1]; +#endif + //Get texture size + ovrSizei recommendedTex0Size = ovrHmd_GetFovTextureSize(_ovrHmd, ovrEye_Left, + _eyeFov[0], 1.0f); + ovrSizei recommendedTex1Size = ovrHmd_GetFovTextureSize(_ovrHmd, ovrEye_Right, + _eyeFov[1], 1.0f); + _renderTargetSize.w = recommendedTex0Size.w + recommendedTex1Size.w; + _renderTargetSize.h = recommendedTex0Size.h; + if (_renderTargetSize.h < recommendedTex1Size.h) { + _renderTargetSize.h = recommendedTex1Size.h; + } - for_each_eye([&](ovrEyeType eye) { - _eyeFov[eye] = _ovrHmd->DefaultEyeFov[eye]; - }); + _eyeRenderDesc[0] = ovrHmd_GetRenderDesc(_ovrHmd, ovrEye_Left, _eyeFov[0]); + _eyeRenderDesc[1] = ovrHmd_GetRenderDesc(_ovrHmd, ovrEye_Right, _eyeFov[1]); + +#if defined(__APPLE__) || defined(_WIN32) + ovrHmd_SetEnabledCaps(_ovrHmd, ovrHmdCap_LowPersistence); +#else + ovrHmd_SetEnabledCaps(_ovrHmd, ovrHmdCap_LowPersistence | ovrHmdCap_LatencyTest); +#endif + +#if defined(__APPLE__) || defined(_WIN32) + ovrHmd_ConfigureTracking(_ovrHmd, ovrTrackingCap_Orientation | ovrTrackingCap_Position | + ovrTrackingCap_MagYawCorrection, + ovrTrackingCap_Orientation); +#else + ovrHmd_StartSensor(_ovrHmd, ovrSensorCap_Orientation | ovrSensorCap_YawCorrection | + ovrSensorCap_Position, + ovrSensorCap_Orientation); +#endif if (!_camera) { _camera = new Camera; configureCamera(*_camera, 0, 0); // no need to use screen dimensions; they're ignored } + + 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(); + } else { + _isConnected = false; + // we're definitely not in "VR mode" so tell the menu that Menu::getInstance()->getActionForOption(MenuOption::EnableVRMode)->setChecked(false); + + ovrHmd_Destroy(_ovrHmd); + ovr_Shutdown(); } -} - -// FIXME store like the others -ovrGLTexture _eyeTextures[ovrEye_Count]; - -void OculusManager::connect() { - _calibrationState = UNCALIBRATED; - qDebug() << "Oculus SDK" << OVR_VERSION_STRING; - if (_ovrHmd) { - UserActivityLogger::getInstance().connectedDevice("hmd", "oculus"); - - MainWindow* applicationWindow = Application::getInstance()->getWindow(); - - 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_Chromatic - | ovrDistortionCap_Vignette - | ovrDistortionCap_Overdrive - | ovrDistortionCap_TimeWarp; - - ovrEyeRenderDesc eyeRenderDescs[2]; - int configResult = ovrHmd_ConfigureRendering(_ovrHmd, &cfg.Config, - distortionCaps, _eyeFov, eyeRenderDescs); - assert(configResult); - - for_each_eye([&](ovrEyeType eye) { - _eyeFov[eye] = _ovrHmd->DefaultEyeFov[eye]; - }); - - _renderTargetSize = { 0, 0 }; - memset(_eyeTextures, 0, sizeof(_eyeTextures)); - for_each_eye([&](ovrEyeType eye) { - //Get texture size - ovrSizei recommendedTexSize = ovrHmd_GetFovTextureSize(_ovrHmd, eye, _eyeFov[eye], 1.0f); - auto & eyeTexture = _eyeTextures[eye].Texture.Header; - eyeTexture.API = ovrRenderAPI_OpenGL; - eyeTexture.RenderViewport.Size = recommendedTexSize; - eyeTexture.RenderViewport.Pos = { _renderTargetSize.w, 0 }; - - _renderTargetSize.h = std::max(_renderTargetSize.h, recommendedTexSize.h); - _renderTargetSize.w += recommendedTexSize.w; - const ovrEyeRenderDesc & erd = eyeRenderDescs[eye]; - ovrMatrix4f ovrPerspectiveProjection = ovrMatrix4f_Projection(erd.Fov, 0.01f, 100000.0f, true); - _eyeProjection[eye] = toGlm(ovrPerspectiveProjection); - _eyeOffset[eye] = erd.HmdToEyeViewOffset; - }); - - for_each_eye([&](ovrEyeType eye) { - ovrGLTexture & eyeTexture = _eyeTextures[eye]; - eyeTexture.Texture.Header.TextureSize = _renderTargetSize; - }); - } +#endif } //Disconnects and deallocates the OR void OculusManager::disconnect() { - if (_ovrHmd) { +#ifdef HAVE_LIBOVR + if (_isConnected) { + _isConnected = false; ovrHmd_Destroy(_ovrHmd); - _ovrHmd = nullptr; + ovr_Shutdown(); + + //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 } +#ifdef HAVE_LIBOVR void OculusManager::positionCalibrationBillboard(Text3DOverlay* billboard) { MyAvatar* myAvatar = DependencyManager::get()->getMyAvatar(); glm::quat headOrientation = myAvatar->getHeadOrientation(); @@ -164,7 +210,9 @@ void OculusManager::positionCalibrationBillboard(Text3DOverlay* billboard) { + headOrientation * glm::vec3(0.0f, 0.0f, -CALIBRATION_MESSAGE_DISTANCE)); billboard->setRotation(headOrientation); } +#endif +#ifdef HAVE_LIBOVR void OculusManager::calibrate(glm::vec3 position, glm::quat orientation) { static QString instructionMessage = "Hold still to calibrate"; static QString progressMessage; @@ -256,54 +304,148 @@ void OculusManager::calibrate(glm::vec3 position, glm::quat orientation) { } } +#endif void OculusManager::recalibrate() { +#ifdef HAVE_LIBOVR _calibrationState = UNCALIBRATED; +#endif } void OculusManager::abandonCalibration() { +#ifdef HAVE_LIBOVR _calibrationState = CALIBRATED; if (_calibrationMessage) { qDebug() << "Abandoned HMD calibration"; Application::getInstance()->getOverlays().deleteOverlay(_calibrationMessage); _calibrationMessage = NULL; } +#endif } +#ifdef HAVE_LIBOVR +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; + } + + //Viewport for the render target for each eye + _eyeRenderViewport[0].Pos = Vector2i(0, 0); + _eyeRenderViewport[0].Size = Sizei(_renderTargetSize.w / 2, _renderTargetSize.h); + _eyeRenderViewport[1].Pos = Vector2i((_renderTargetSize.w + 1) / 2, 0); + _eyeRenderViewport[1].Size = _eyeRenderViewport[0].Size; + + 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, _ovrHmdDesc.DistortionCaps, &meshData); + + ovrHmd_GetRenderScaleAndOffset(_eyeRenderDesc[eyeNum].Fov, _renderTargetSize, _eyeRenderViewport[eyeNum], + _UVScaleOffset[eyeNum]); + + // Parse the vertex data and create a render ready vertex buffer + DistortionVertex* pVBVerts = (DistortionVertex*)OVR_ALLOC(sizeof(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++) { +#if defined(__APPLE__) || defined(_WIN32) + 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; +#else + v->pos.x = ov->Pos.x; + v->pos.y = ov->Pos.y; + v->texR.x = ov->TexR.x; + v->texR.y = ov->TexR.y; + v->texG.x = ov->TexG.x; + v->texG.y = ov->TexG.y; + v->texB.x = ov->TexB.x; + v->texB.y = ov->TexB.y; +#endif + 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 + OVR_FREE(pVBVerts); + ovrHmd_DestroyDistortionMesh(&meshData); + } + +} +#endif bool OculusManager::isConnected() { - return _ovrHmd && Menu::getInstance()->isOptionChecked(MenuOption::EnableVRMode); +#ifdef HAVE_LIBOVR + return _isConnected && Menu::getInstance()->isOptionChecked(MenuOption::EnableVRMode); +#else + return false; +#endif +} + +//Begins the frame timing for oculus prediction purposes +void OculusManager::beginFrameTiming() { +#ifdef HAVE_LIBOVR + + if (_frameTimingActive) { + printf("WARNING: Called OculusManager::beginFrameTiming() twice in a row, need to call OculusManager::endFrameTiming()."); + } + + _hmdFrameTiming = ovrHmd_BeginFrameTiming(_ovrHmd, _frameIndex); + _frameTimingActive = true; +#endif +} + +//Ends frame timing +void OculusManager::endFrameTiming() { +#ifdef HAVE_LIBOVR + ovrHmd_EndFrameTiming(_ovrHmd); + _frameIndex++; + _frameTimingActive = false; +#endif } //Sets the camera FoV and aspect ratio void OculusManager::configureCamera(Camera& camera, int screenWidth, int screenHeight) { - // FIXME the oculus projection matrix is assymetrical, this will not work. +#ifdef HAVE_LIBOVR camera.setAspectRatio(_renderTargetSize.w * 0.5f / _renderTargetSize.h); camera.setFieldOfView(atan(_eyeFov[0].UpTan) * DEGREES_PER_RADIAN * 2.0f); +#endif } -RenderArgs::RenderSide RENDER_SIDES[ovrEye_Count] = { RenderArgs::STEREO_LEFT, RenderArgs::STEREO_RIGHT }; - //Displays everything for the oculus, frame timing must be active void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &position, Camera& whichCamera) { - - static const glm::vec2 topLeft(-1.0f, -1.0f); - static const glm::vec2 bottomRight(1.0f, 1.0f); - static const glm::vec2 texCoordTopLeft(0.0f, 0.0f); - static const glm::vec2 texCoordBottomRight(1.0f, 1.0f); - - auto glCanvas = DependencyManager::get(); - - static bool attached = false; - if (!attached) { - attached = true; - void * nativeWindowHandle = (void*)(size_t)glCanvas->effectiveWinId(); - if (nullptr != nativeWindowHandle) { - ovrHmd_AttachToWindow(_ovrHmd, nativeWindowHandle, nullptr, nullptr); - } +#ifdef HAVE_LIBOVR + //beginFrameTiming must be called before display + if (!_frameTimingActive) { + printf("WARNING: Called OculusManager::display() without calling OculusManager::beginFrameTiming() first."); + return; } - ovrHmd_BeginFrame(_ovrHmd, ++_frameIndex); ApplicationOverlay& applicationOverlay = Application::getInstance()->getApplicationOverlay(); // We only need to render the overlays to a texture once, then we just render the texture on the hemisphere @@ -318,124 +460,263 @@ void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &p glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } + ovrPosef eyeRenderPose[ovrEye_Count]; + glMatrixMode(GL_PROJECTION); glPushMatrix(); glMatrixMode(GL_MODELVIEW); glPushMatrix(); + + glm::quat orientation; + glm::vec3 trackerPosition; + +#if defined(__APPLE__) || defined(_WIN32) + ovrTrackingState ts = ovrHmd_GetTrackingState(_ovrHmd, ovr_GetTimeInSeconds()); + ovrVector3f ovrHeadPosition = ts.HeadPose.ThePose.Position; + + trackerPosition = glm::vec3(ovrHeadPosition.x, ovrHeadPosition.y, ovrHeadPosition.z); if (_calibrationState != CALIBRATED) { - ovrTrackingState ts = ovrHmd_GetTrackingState(_ovrHmd, ovr_GetTimeInSeconds()); - ovrVector3f ovrHeadPosition = ts.HeadPose.ThePose.Position; - glm::vec3 trackerPosition = glm::vec3(ovrHeadPosition.x, ovrHeadPosition.y, ovrHeadPosition.z); - calibrate(trackerPosition, toGlm(ts.HeadPose.ThePose.Orientation)); - trackerPosition = bodyOrientation * trackerPosition; + ovrQuatf ovrHeadOrientation = ts.HeadPose.ThePose.Orientation; + orientation = glm::quat(ovrHeadOrientation.w, ovrHeadOrientation.x, ovrHeadOrientation.y, ovrHeadOrientation.z); + calibrate(trackerPosition, orientation); } + trackerPosition = bodyOrientation * trackerPosition; +#endif + //Render each eye into an fbo - ovrPosef eyeRenderPose[ovrEye_Count]; - ovrHmd_GetEyePoses(_ovrHmd, 0, _eyeOffset, eyeRenderPose, nullptr); - for_each_eye([&](int i) { - _activeEyeIndex = i; - ovrEyeType eye = _ovrHmd->EyeRenderOrder[_activeEyeIndex]; - const ovrPosef & pose = eyeRenderPose[eye]; + for (int eyeIndex = 0; eyeIndex < ovrEye_Count; eyeIndex++) { + _activeEyeIndex = eyeIndex; + +#if defined(__APPLE__) || defined(_WIN32) + ovrEyeType eye = _ovrHmd->EyeRenderOrder[eyeIndex]; +#else + ovrEyeType eye = _ovrHmdDesc.EyeRenderOrder[eyeIndex]; +#endif + // Set the camera rotation for this eye + eyeRenderPose[eye] = ovrHmd_GetHmdPosePerEye(_ovrHmd, eye); + orientation.x = eyeRenderPose[eye].Orientation.x; + orientation.y = eyeRenderPose[eye].Orientation.y; + orientation.z = eyeRenderPose[eye].Orientation.z; + orientation.w = eyeRenderPose[eye].Orientation.w; + // Update the application camera with the latest HMD position - whichCamera.setHmdPosition(bodyOrientation * toGlm(pose.Position)); - whichCamera.setHmdRotation(toGlm(pose.Orientation)); - + whichCamera.setHmdPosition(trackerPosition); + whichCamera.setHmdRotation(orientation); + // Update our camera to what the application camera is doing _camera->setRotation(whichCamera.getRotation()); _camera->setPosition(whichCamera.getPosition()); - RenderArgs::RenderSide renderSide = RENDER_SIDES[eye]; - glm::vec3 thisEyePosition = position + toGlm(eyeRenderPose[eye].Position); + // Store the latest left and right eye render locations for things that need to know - _eyePositions[eye] = thisEyePosition; + glm::vec3 thisEyePosition = position + trackerPosition + + (bodyOrientation * glm::quat(orientation.x, orientation.y, orientation.z, orientation.w) * + glm::vec3(_eyeRenderDesc[eye].HmdToEyeViewOffset.x, _eyeRenderDesc[eye].HmdToEyeViewOffset.y, _eyeRenderDesc[eye].HmdToEyeViewOffset.z)); + + RenderArgs::RenderSide renderSide = RenderArgs::STEREO_LEFT; + if (eyeIndex == 0) { + _leftEyePosition = thisEyePosition; + } else { + _rightEyePosition = thisEyePosition; + renderSide = RenderArgs::STEREO_RIGHT; + } + _camera->update(1.0f / Application::getInstance()->getFps()); glMatrixMode(GL_PROJECTION); glLoadIdentity(); - const ovrFovPort& port = _eyeFov[eye]; + const ovrFovPort& port = _eyeFov[_activeEyeIndex]; float nearClip = whichCamera.getNearClip(), farClip = whichCamera.getFarClip(); glFrustum(-nearClip * port.LeftTan, nearClip * port.RightTan, -nearClip * port.DownTan, nearClip * port.UpTan, nearClip, farClip); + + glViewport(_eyeRenderViewport[eye].Pos.x, _eyeRenderViewport[eye].Pos.y, + _eyeRenderViewport[eye].Size.w, _eyeRenderViewport[eye].Size.h); + glMatrixMode(GL_MODELVIEW); glLoadIdentity(); - auto vp = _eyeTextures[eye].Texture.Header.RenderViewport; - glViewport(vp.Pos.x, vp.Pos.y, vp.Size.w, vp.Size.h); + // HACK: instead of passing the stereo eye offset directly in the matrix, pass it in the camera offset //glTranslatef(_eyeRenderDesc[eye].ViewAdjust.x, _eyeRenderDesc[eye].ViewAdjust.y, _eyeRenderDesc[eye].ViewAdjust.z); - //_camera->setEyeOffsetPosition(glm::vec3(-_eyeRenderDesc[eye].ViewAdjust.x, -_eyeRenderDesc[eye].ViewAdjust.y, -_eyeRenderDesc[eye].ViewAdjust.z)); + + _camera->setEyeOffsetPosition(glm::vec3(-_eyeRenderDesc[eye].HmdToEyeViewOffset.x, -_eyeRenderDesc[eye].HmdToEyeViewOffset.y, -_eyeRenderDesc[eye].HmdToEyeViewOffset.z)); Application::getInstance()->displaySide(*_camera, false, RenderArgs::MONO); + applicationOverlay.displayOverlayTextureOculus(*_camera); - }); - _activeEyeIndex = -1; + _activeEyeIndex = -1; + } + + //Wait till time-warp to reduce latency + ovr_WaitTillTime(_hmdFrameTiming.TimewarpPointSeconds); glPopMatrix(); + //Full texture viewport for glow effect glViewport(0, 0, _renderTargetSize.w, _renderTargetSize.h); - - int finalTexture = 0; + //Bind the output texture from the glow shader. If glow effect is disabled, we just grab the texture if (Menu::getInstance()->isOptionChecked(MenuOption::EnableGlowEffect)) { QOpenGLFramebufferObject* fbo = DependencyManager::get()->render(true); - finalTexture = fbo->texture(); + glBindTexture(GL_TEXTURE_2D, fbo->texture()); } else { DependencyManager::get()->getPrimaryFramebufferObject()->release(); - finalTexture = DependencyManager::get()->getPrimaryFramebufferObject()->texture(); + glBindTexture(GL_TEXTURE_2D, DependencyManager::get()->getPrimaryFramebufferObject()->texture()); } - for_each_eye([&](int eye) { - _eyeTextures[eye].OGL.TexId = finalTexture; - }); + + // restore our normal viewport + auto glCanvas = DependencyManager::get(); + glViewport(0, 0, glCanvas->getDeviceWidth(), glCanvas->getDeviceHeight()); glMatrixMode(GL_PROJECTION); glPopMatrix(); - // restore our normal viewport - glViewport(0, 0, glCanvas->getDeviceWidth(), glCanvas->getDeviceHeight()); + //Renders the distorted mesh onto the screen + renderDistortionMesh(eyeRenderPose); + + glBindTexture(GL_TEXTURE_2D, 0); - ovrHmd_EndFrame(_ovrHmd, eyeRenderPose, &(_eyeTextures[0].Texture)); + +#endif } +#ifdef HAVE_LIBOVR +void OculusManager::renderDistortionMesh(ovrPosef eyeRenderPose[ovrEye_Count]) { + + glLoadIdentity(); + auto glCanvas = DependencyManager::get(); + glOrtho(0, glCanvas->getDeviceWidth(), 0, glCanvas->getDeviceHeight(), -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++) { + GLfloat uvScale[2] = { _UVScaleOffset[eyeNum][0].x, _UVScaleOffset[eyeNum][0].y }; + _program.setUniformValueArray(_eyeToSourceUVScaleLocation, uvScale, 1, 2); + GLfloat uvOffset[2] = { _UVScaleOffset[eyeNum][1].x, _UVScaleOffset[eyeNum][1].y }; + _program.setUniformValueArray(_eyeToSourceUVOffsetLocation, uvOffset, 1, 2); + + ovrMatrix4f timeWarpMatrices[2]; + Matrix4f transposeMatrices[2]; + //Grabs the timewarp matrices to be used in the shader + ovrHmd_GetEyeTimewarpMatrices(_ovrHmd, (ovrEyeType)eyeNum, eyeRenderPose[eyeNum], timeWarpMatrices); + transposeMatrices[0] = Matrix4f(timeWarpMatrices[0]); + transposeMatrices[1] = Matrix4f(timeWarpMatrices[1]); + + //Have to transpose the matrices before using them + transposeMatrices[0].Transpose(); + transposeMatrices[1].Transpose(); + + glUniformMatrix4fv(_eyeRotationStartLocation, 1, GL_FALSE, (GLfloat *)transposeMatrices[0].M); + glUniformMatrix4fv(_eyeRotationEndLocation, 1, GL_FALSE, (GLfloat *)transposeMatrices[1].M); + + 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 (_ovrHmd) { +#ifdef HAVE_LIBOVR + if (_isConnected) { ovrHmd_RecenterPose(_ovrHmd); } +#endif } //Gets the current predicted angles from the oculus sensors void OculusManager::getEulerAngles(float& yaw, float& pitch, float& roll) { +#ifdef HAVE_LIBOVR +#if defined(__APPLE__) || defined(_WIN32) ovrTrackingState ts = ovrHmd_GetTrackingState(_ovrHmd, ovr_GetTimeInSeconds()); +#else + ovrSensorState ss = ovrHmd_GetSensorState(_ovrHmd, _hmdFrameTiming.ScanoutMidpointSeconds); +#endif +#if defined(__APPLE__) || defined(_WIN32) if (ts.StatusFlags & (ovrStatus_OrientationTracked | ovrStatus_PositionTracked)) { +#else + if (ss.StatusFlags & (ovrStatus_OrientationTracked | ovrStatus_PositionTracked)) { +#endif + +#if defined(__APPLE__) || defined(_WIN32) ovrPosef headPose = ts.HeadPose.ThePose; - glm::vec3 angles = safeEulerAngles(toGlm(headPose.Orientation)); - yaw = angles.y; - pitch = angles.x; - roll = angles.z; +#else + ovrPosef headPose = ss.Predicted.Pose; +#endif + Quatf orientation = Quatf(headPose.Orientation); + orientation.GetEulerAngles(&yaw, &pitch, &roll); } else { yaw = 0.0f; pitch = 0.0f; roll = 0.0f; } +#else + yaw = 0.0f; + pitch = 0.0f; + roll = 0.0f; +#endif } glm::vec3 OculusManager::getRelativePosition() { +#if (defined(__APPLE__) || defined(_WIN32)) && HAVE_LIBOVR ovrTrackingState trackingState = ovrHmd_GetTrackingState(_ovrHmd, ovr_GetTimeInSeconds()); ovrVector3f headPosition = trackingState.HeadPose.ThePose.Position; + return glm::vec3(headPosition.x, headPosition.y, headPosition.z); +#else + // no positional tracking in Linux yet + return glm::vec3(0.0f, 0.0f, 0.0f); +#endif } //Used to set the size of the glow framebuffers QSize OculusManager::getRenderTargetSize() { +#ifdef HAVE_LIBOVR QSize rv; rv.setWidth(_renderTargetSize.w); rv.setHeight(_renderTargetSize.h); return rv; +#else + return QSize(100, 100); +#endif } void OculusManager::overrideOffAxisFrustum(float& left, float& right, float& bottom, float& top, float& nearVal, float& farVal, glm::vec4& nearClipPlane, glm::vec4& farClipPlane) { +#ifdef HAVE_LIBOVR if (_activeEyeIndex != -1) { const ovrFovPort& port = _eyeFov[_activeEyeIndex]; right = nearVal * port.RightTan; @@ -443,10 +724,12 @@ void OculusManager::overrideOffAxisFrustum(float& left, float& right, float& bot top = nearVal * port.UpTan; bottom = -nearVal * port.DownTan; } +#endif } int OculusManager::getHMDScreen() { int hmdScreenIndex = -1; // unknown +#ifdef HAVE_LIBOVR // 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 @@ -495,6 +778,7 @@ int OculusManager::getHMDScreen() { screenNumber++; } } +#endif return hmdScreenIndex; } diff --git a/interface/src/devices/OculusManager.h b/interface/src/devices/OculusManager.h index 331b43b379..e4ece6c3d3 100644 --- a/interface/src/devices/OculusManager.h +++ b/interface/src/devices/OculusManager.h @@ -12,19 +12,13 @@ #ifndef hifi_OculusManager_h #define hifi_OculusManager_h - #define HAVE_LIBOVR 1 #ifdef HAVE_LIBOVR -#include -#include #include #include #endif #include -#include -#include -#include class Camera; class PalmData; @@ -33,14 +27,13 @@ class Text3DOverlay; /// Handles interaction with the Oculus Rift. class OculusManager { public: - static void init(); static void connect(); static void disconnect(); static bool isConnected(); static void recalibrate(); static void abandonCalibration(); - //static void beginFrameTiming(); - //static void endFrameTiming(); + static void beginFrameTiming(); + static void endFrameTiming(); static void configureCamera(Camera& camera, int screenWidth, int screenHeight); static void display(const glm::quat &bodyOrientation, const glm::vec3 &position, Camera& whichCamera); static void reset(); @@ -55,21 +48,57 @@ public: static void overrideOffAxisFrustum(float& left, float& right, float& bottom, float& top, float& nearVal, float& farVal, glm::vec4& nearClipPlane, glm::vec4& farClipPlane); - static glm::vec3 getLeftEyePosition() { return _eyePositions[ovrEye_Left]; } - static glm::vec3 getRightEyePosition() { return _eyePositions[ovrEye_Right]; } + static glm::vec3 getLeftEyePosition() { return _leftEyePosition; } + static glm::vec3 getRightEyePosition() { return _rightEyePosition; } static int getHMDScreen(); private: +#ifdef HAVE_LIBOVR + static void generateDistortionMesh(); + static void renderDistortionMesh(ovrPosef eyeRenderPose[ovrEye_Count]); + static bool similarNames(const QString& nameA,const QString& nameB); - //static bool _isConnected; + 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 bool _isConnected; static ovrHmd _ovrHmd; + static ovrHmdDesc _ovrHmdDesc; static ovrFovPort _eyeFov[ovrEye_Count]; - static ovrVector3f _eyeOffset[ovrEye_Count]; - static glm::mat4 _eyeProjection[ovrEye_Count]; + static ovrEyeRenderDesc _eyeRenderDesc[ovrEye_Count]; static ovrSizei _renderTargetSize; + 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 ovrRecti _eyeRenderViewport[ovrEye_Count]; static unsigned int _frameIndex; static bool _frameTimingActive; @@ -98,61 +127,12 @@ private: static quint64 _calibrationStartTime; static int _calibrationMessage; - static glm::vec3 _eyePositions[ovrEye_Count]; +#endif + + static glm::vec3 _leftEyePosition; + static glm::vec3 _rightEyePosition; + + }; - -inline glm::mat4 toGlm(const ovrMatrix4f & om) { - return glm::transpose(glm::make_mat4(&om.M[0][0])); -} - -inline glm::mat4 toGlm(const ovrFovPort & fovport, float nearPlane = 0.01f, float farPlane = 10000.0f) { - return toGlm(ovrMatrix4f_Projection(fovport, nearPlane, farPlane, true)); -} - -inline glm::vec3 toGlm(const ovrVector3f & ov) { - return glm::make_vec3(&ov.x); -} - -inline glm::vec2 toGlm(const ovrVector2f & ov) { - return glm::make_vec2(&ov.x); -} - -inline glm::uvec2 toGlm(const ovrSizei & ov) { - return glm::uvec2(ov.w, ov.h); -} - -inline glm::quat toGlm(const ovrQuatf & oq) { - return glm::make_quat(&oq.x); -} - -inline glm::mat4 toGlm(const ovrPosef & op) { - glm::mat4 orientation = glm::mat4_cast(toGlm(op.Orientation)); - glm::mat4 translation = glm::translate(glm::mat4(), toGlm(op.Position)); - return translation * orientation; -} - -inline ovrMatrix4f ovrFromGlm(const glm::mat4 & m) { - ovrMatrix4f result; - glm::mat4 transposed(glm::transpose(m)); - memcpy(result.M, &(transposed[0][0]), sizeof(float) * 16); - return result; -} - -inline ovrVector3f ovrFromGlm(const glm::vec3 & v) { - return{ v.x, v.y, v.z }; -} - -inline ovrVector2f ovrFromGlm(const glm::vec2 & v) { - return{ v.x, v.y }; -} - -inline ovrSizei ovrFromGlm(const glm::uvec2 & v) { - return{ v.x, v.y }; -} - -inline ovrQuatf ovrFromGlm(const glm::quat & q) { - return{ q.x, q.y, q.z, q.w }; -} - #endif // hifi_OculusManager_h diff --git a/interface/src/main.cpp b/interface/src/main.cpp index 8ffef64a0c..64ecb2b9e7 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -18,8 +18,6 @@ #include "AddressManager.h" #include "Application.h" -#include "devices/OculusManager.h" - #ifdef Q_OS_WIN static BOOL CALLBACK enumWindowsCallback(HWND hWnd, LPARAM lParam) { @@ -94,10 +92,7 @@ int main(int argc, const char* argv[]) { usecTimestampNowForceClockSkew(clockSkew); qDebug("clockSkewOption=%s clockSkew=%d", clockSkewOption, clockSkew); } - // Oculus initialization MUST PRECEDE OpenGL context creation. - // The nature of the Application constructor means this has to be either here, - // or in the main window ctor, before GL startup. - OculusManager::init(); + int exitCode; { QSettings::setDefaultFormat(QSettings::IniFormat); From 7f29a701574fa7ae1df2a63e19132ac0d3aadc8e Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 26 Feb 2015 00:06:59 -0800 Subject: [PATCH 06/41] Switchable between SDK/client distortion --- interface/src/GLCanvas.cpp | 10 +- interface/src/devices/OculusManager.cpp | 321 +++++++++++------------- interface/src/devices/OculusManager.h | 106 ++++++-- interface/src/main.cpp | 5 + 4 files changed, 237 insertions(+), 205 deletions(-) diff --git a/interface/src/GLCanvas.cpp b/interface/src/GLCanvas.cpp index 10090de51a..e724808bdb 100644 --- a/interface/src/GLCanvas.cpp +++ b/interface/src/GLCanvas.cpp @@ -62,9 +62,13 @@ void GLCanvas::paintGL() { } Application::getInstance()->paintGL(); - swapBuffers(); - - if (OculusManager::isConnected()) { + + if (!OculusManager::isConnected()) { + swapBuffers(); + } else { + if (OculusManager::allowSwap()) { + swapBuffers(); + } OculusManager::endFrameTiming(); } } diff --git a/interface/src/devices/OculusManager.cpp b/interface/src/devices/OculusManager.cpp index 7bb3746fbf..9f7b9429fd 100644 --- a/interface/src/devices/OculusManager.cpp +++ b/interface/src/devices/OculusManager.cpp @@ -31,11 +31,28 @@ #include "Application.h" -#ifdef HAVE_LIBOVR #include "OVR_Math.h" #include "OVR_Version.h" using namespace OVR; +template +void for_each_eye(Function function) { + for (ovrEyeType eye = ovrEyeType::ovrEye_Left; + eye < ovrEyeType::ovrEye_Count; + eye = static_cast(eye + 1)) { + function(eye); + } +} + +template +void for_each_eye(const ovrHmd & hmd, Function function) { + for (int i = 0; i < ovrEye_Count; ++i) { + ovrEyeType eye = hmd->EyeRenderOrder[i]; + function(eye); + } +} + +#ifdef CLIENT_DISTORTION ProgramObject OculusManager::_program; int OculusManager::_textureLocation; int OculusManager::_eyeToSourceUVScaleLocation; @@ -47,24 +64,27 @@ int OculusManager::_colorAttributeLocation; int OculusManager::_texCoord0AttributeLocation; int OculusManager::_texCoord1AttributeLocation; int OculusManager::_texCoord2AttributeLocation; -bool OculusManager::_isConnected = false; - -ovrHmd OculusManager::_ovrHmd; -ovrHmdDesc OculusManager::_ovrHmdDesc; -ovrFovPort OculusManager::_eyeFov[ovrEye_Count]; -ovrEyeRenderDesc OculusManager::_eyeRenderDesc[ovrEye_Count]; -ovrSizei OculusManager::_renderTargetSize; 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; -ovrRecti OculusManager::_eyeRenderViewport[ovrEye_Count]; +bool OculusManager::_programInitialized = false; +#else +#endif + +bool OculusManager::_isConnected = false; +ovrGLTexture OculusManager::_eyeTextures[ovrEye_Count]; +ovrHmd OculusManager::_ovrHmd; +ovrFovPort OculusManager::_eyeFov[ovrEye_Count]; +ovrVector3f OculusManager::_eyeOffset[ovrEye_Count]; +ovrEyeRenderDesc OculusManager::_eyeRenderDesc[ovrEye_Count]; +ovrSizei OculusManager::_renderTargetSize; +glm::mat4 OculusManager::_eyeProjection[ovrEye_Count]; unsigned int OculusManager::_frameIndex = 0; bool OculusManager::_frameTimingActive = false; -bool OculusManager::_programInitialized = false; Camera* OculusManager::_camera = NULL; -int OculusManager::_activeEyeIndex = -1; +ovrEyeType OculusManager::_activeEye = ovrEye_Count; float OculusManager::CALIBRATION_DELTA_MINIMUM_LENGTH = 0.02f; float OculusManager::CALIBRATION_DELTA_MINIMUM_ANGLE = 5.0f * RADIANS_PER_DEGREE; @@ -77,68 +97,68 @@ glm::vec3 OculusManager::_calibrationPosition; glm::quat OculusManager::_calibrationOrientation; quint64 OculusManager::_calibrationStartTime; int OculusManager::_calibrationMessage = NULL; +glm::vec3 OculusManager::_eyePositions[ovrEye_Count]; -#endif - -glm::vec3 OculusManager::_leftEyePosition = glm::vec3(); -glm::vec3 OculusManager::_rightEyePosition = glm::vec3(); +void OculusManager::init() { + ovr_Initialize(); + _ovrHmd = ovrHmd_Create(0); +} void OculusManager::connect() { -#ifdef HAVE_LIBOVR _calibrationState = UNCALIBRATED; qDebug() << "Oculus SDK" << OVR_VERSION_STRING; - ovr_Initialize(); - - _ovrHmd = ovrHmd_Create(0); if (_ovrHmd) { if (!_isConnected) { UserActivityLogger::getInstance().connectedDevice("hmd", "oculus"); } _isConnected = true; - -#if defined(__APPLE__) || defined(_WIN32) - _eyeFov[0] = _ovrHmd->DefaultEyeFov[0]; - _eyeFov[1] = _ovrHmd->DefaultEyeFov[1]; -#else - ovrHmd_GetDesc(_ovrHmd, &_ovrHmdDesc); - _eyeFov[0] = _ovrHmdDesc.DefaultEyeFov[0]; - _eyeFov[1] = _ovrHmdDesc.DefaultEyeFov[1]; -#endif - //Get texture size - ovrSizei recommendedTex0Size = ovrHmd_GetFovTextureSize(_ovrHmd, ovrEye_Left, - _eyeFov[0], 1.0f); - ovrSizei recommendedTex1Size = ovrHmd_GetFovTextureSize(_ovrHmd, ovrEye_Right, - _eyeFov[1], 1.0f); - _renderTargetSize.w = recommendedTex0Size.w + recommendedTex1Size.w; - _renderTargetSize.h = recommendedTex0Size.h; - if (_renderTargetSize.h < recommendedTex1Size.h) { - _renderTargetSize.h = recommendedTex1Size.h; - } - _eyeRenderDesc[0] = ovrHmd_GetRenderDesc(_ovrHmd, ovrEye_Left, _eyeFov[0]); - _eyeRenderDesc[1] = ovrHmd_GetRenderDesc(_ovrHmd, ovrEye_Right, _eyeFov[1]); + for_each_eye([&](ovrEyeType eye) { + _eyeFov[eye] = _ovrHmd->DefaultEyeFov[eye]; + }); + + 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_Chromatic + | ovrDistortionCap_Vignette + | ovrDistortionCap_Overdrive + | ovrDistortionCap_TimeWarp; + + int configResult = ovrHmd_ConfigureRendering(_ovrHmd, &cfg.Config, + distortionCaps, _eyeFov, _eyeRenderDesc); + assert(configResult); + + + _renderTargetSize = { 0, 0 }; + for_each_eye([&](ovrEyeType eye) { + //Get texture size + ovrSizei recommendedTexSize = ovrHmd_GetFovTextureSize(_ovrHmd, eye, _eyeFov[eye], 1.0f); + _eyeTextures[eye].Texture.Header.API = ovrRenderAPI_OpenGL; + _eyeTextures[eye].Texture.Header.RenderViewport.Pos = { _renderTargetSize.w, 0 }; + _eyeTextures[eye].Texture.Header.RenderViewport.Size = recommendedTexSize; + _renderTargetSize.w += recommendedTexSize.w; + _renderTargetSize.h = std::max(recommendedTexSize.h, _renderTargetSize.h); + }); + for_each_eye([&](ovrEyeType eye) { + _eyeTextures[eye].Texture.Header.TextureSize = _renderTargetSize; + }); -#if defined(__APPLE__) || defined(_WIN32) ovrHmd_SetEnabledCaps(_ovrHmd, ovrHmdCap_LowPersistence); -#else - ovrHmd_SetEnabledCaps(_ovrHmd, ovrHmdCap_LowPersistence | ovrHmdCap_LatencyTest); -#endif -#if defined(__APPLE__) || defined(_WIN32) ovrHmd_ConfigureTracking(_ovrHmd, ovrTrackingCap_Orientation | ovrTrackingCap_Position | ovrTrackingCap_MagYawCorrection, ovrTrackingCap_Orientation); -#else - ovrHmd_StartSensor(_ovrHmd, ovrSensorCap_Orientation | ovrSensorCap_YawCorrection | - ovrSensorCap_Position, - ovrSensorCap_Orientation); -#endif if (!_camera) { _camera = new Camera; configureCamera(*_camera, 0, 0); // no need to use screen dimensions; they're ignored } - +#ifdef CLIENT_DISTORTION if (!_programInitialized) { // Shader program _programInitialized = true; @@ -163,28 +183,24 @@ void OculusManager::connect() { //Generate the distortion VBOs generateDistortionMesh(); - +#endif } else { _isConnected = false; // we're definitely not in "VR mode" so tell the menu that Menu::getInstance()->getActionForOption(MenuOption::EnableVRMode)->setChecked(false); - - ovrHmd_Destroy(_ovrHmd); - ovr_Shutdown(); } -#endif } //Disconnects and deallocates the OR void OculusManager::disconnect() { -#ifdef HAVE_LIBOVR if (_isConnected) { _isConnected = false; - ovrHmd_Destroy(_ovrHmd); - ovr_Shutdown(); + //ovrHmd_Destroy(_ovrHmd); + //ovr_Shutdown(); //Free the distortion mesh data +#ifdef CLIENT_DISTORTION for (int i = 0; i < ovrEye_Count; i++) { if (_vertices[i] != 0) { glDeleteBuffers(1, &(_vertices[i])); @@ -195,11 +211,10 @@ void OculusManager::disconnect() { _indices[i] = 0; } } - } #endif + } } -#ifdef HAVE_LIBOVR void OculusManager::positionCalibrationBillboard(Text3DOverlay* billboard) { MyAvatar* myAvatar = DependencyManager::get()->getMyAvatar(); glm::quat headOrientation = myAvatar->getHeadOrientation(); @@ -210,9 +225,7 @@ void OculusManager::positionCalibrationBillboard(Text3DOverlay* billboard) { + headOrientation * glm::vec3(0.0f, 0.0f, -CALIBRATION_MESSAGE_DISTANCE)); billboard->setRotation(headOrientation); } -#endif -#ifdef HAVE_LIBOVR void OculusManager::calibrate(glm::vec3 position, glm::quat orientation) { static QString instructionMessage = "Hold still to calibrate"; static QString progressMessage; @@ -304,26 +317,21 @@ void OculusManager::calibrate(glm::vec3 position, glm::quat orientation) { } } -#endif void OculusManager::recalibrate() { -#ifdef HAVE_LIBOVR _calibrationState = UNCALIBRATED; -#endif } void OculusManager::abandonCalibration() { -#ifdef HAVE_LIBOVR _calibrationState = CALIBRATED; if (_calibrationMessage) { qDebug() << "Abandoned HMD calibration"; Application::getInstance()->getOverlays().deleteOverlay(_calibrationMessage); _calibrationMessage = NULL; } -#endif } -#ifdef HAVE_LIBOVR +#ifdef CLIENT_DISTORTION void OculusManager::generateDistortionMesh() { //Check if we already have the distortion mesh @@ -341,7 +349,7 @@ void OculusManager::generateDistortionMesh() { 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, _ovrHmdDesc.DistortionCaps, &meshData); + ovrHmd_CreateDistortionMesh(_ovrHmd, _eyeRenderDesc[eyeNum].Eye, _eyeRenderDesc[eyeNum].Fov, _ovrHmd->DistortionCaps, &meshData); ovrHmd_GetRenderScaleAndOffset(_eyeRenderDesc[eyeNum].Fov, _renderTargetSize, _eyeRenderViewport[eyeNum], _UVScaleOffset[eyeNum]); @@ -354,7 +362,6 @@ void OculusManager::generateDistortionMesh() { DistortionVertex* v = pVBVerts; ovrDistortionVertex* ov = meshData.pVertexData; for (unsigned int vertNum = 0; vertNum < meshData.VertexCount; vertNum++) { -#if defined(__APPLE__) || defined(_WIN32) v->pos.x = ov->ScreenPosNDC.x; v->pos.y = ov->ScreenPosNDC.y; v->texR.x = ov->TanEyeAnglesR.x; @@ -363,16 +370,6 @@ void OculusManager::generateDistortionMesh() { v->texG.y = ov->TanEyeAnglesG.y; v->texB.x = ov->TanEyeAnglesB.x; v->texB.y = ov->TanEyeAnglesB.y; -#else - v->pos.x = ov->Pos.x; - v->pos.y = ov->Pos.y; - v->texR.x = ov->TexR.x; - v->texR.y = ov->TexR.y; - v->texG.x = ov->TexG.x; - v->texG.y = ov->TexG.y; - v->texB.x = ov->TexB.x; - v->texB.y = ov->TexB.y; -#endif v->color.r = v->color.g = v->color.b = (GLubyte)(ov->VignetteFactor * 255.99f); v->color.a = (GLubyte)(ov->TimeWarpFactor * 255.99f); v++; @@ -400,46 +397,57 @@ void OculusManager::generateDistortionMesh() { #endif bool OculusManager::isConnected() { -#ifdef HAVE_LIBOVR return _isConnected && Menu::getInstance()->isOptionChecked(MenuOption::EnableVRMode); -#else - return false; -#endif } //Begins the frame timing for oculus prediction purposes void OculusManager::beginFrameTiming() { -#ifdef HAVE_LIBOVR - if (_frameTimingActive) { printf("WARNING: Called OculusManager::beginFrameTiming() twice in a row, need to call OculusManager::endFrameTiming()."); } - _hmdFrameTiming = ovrHmd_BeginFrameTiming(_ovrHmd, _frameIndex); - _frameTimingActive = true; +#ifdef CLIENT_DISTORTION + _hmdFrameTiming = ovrHmd_BeginFrameTiming(_ovrHmd, _frameIndex); #endif + _frameTimingActive = true; } +bool OculusManager::allowSwap() { +#ifdef CLIENT_DISTORTION + return true; +#else + return false; +#endif + +} //Ends frame timing void OculusManager::endFrameTiming() { -#ifdef HAVE_LIBOVR +#ifdef CLIENT_DISTORTION ovrHmd_EndFrameTiming(_ovrHmd); +#endif _frameIndex++; _frameTimingActive = false; -#endif } //Sets the camera FoV and aspect ratio void OculusManager::configureCamera(Camera& camera, int screenWidth, int screenHeight) { -#ifdef HAVE_LIBOVR camera.setAspectRatio(_renderTargetSize.w * 0.5f / _renderTargetSize.h); camera.setFieldOfView(atan(_eyeFov[0].UpTan) * DEGREES_PER_RADIAN * 2.0f); -#endif } //Displays everything for the oculus, frame timing must be active void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &position, Camera& whichCamera) { -#ifdef HAVE_LIBOVR + auto glCanvas = DependencyManager::get(); + + static bool attached = false; + if (!attached) { + attached = true; + void * nativeWindowHandle = (void*)(size_t)glCanvas->effectiveWinId(); + if (nullptr != nativeWindowHandle) { + ovrHmd_AttachToWindow(_ovrHmd, nativeWindowHandle, nullptr, nullptr); + } + } + //beginFrameTiming must be called before display if (!_frameTimingActive) { printf("WARNING: Called OculusManager::display() without calling OculusManager::beginFrameTiming() first."); @@ -460,7 +468,6 @@ void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &p glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } - ovrPosef eyeRenderPose[ovrEye_Count]; glMatrixMode(GL_PROJECTION); glPushMatrix(); @@ -471,7 +478,6 @@ void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &p glm::quat orientation; glm::vec3 trackerPosition; -#if defined(__APPLE__) || defined(_WIN32) ovrTrackingState ts = ovrHmd_GetTrackingState(_ovrHmd, ovr_GetTimeInSeconds()); ovrVector3f ovrHeadPosition = ts.HeadPose.ThePose.Position; @@ -484,105 +490,99 @@ void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &p } trackerPosition = bodyOrientation * trackerPosition; -#endif - + static ovrVector3f eyeOffsets[2] = { { 0, 0, 0 }, { 0, 0, 0 } }; + ovrPosef eyeRenderPose[ovrEye_Count]; + ovrHmd_GetEyePoses(_ovrHmd, _frameIndex, eyeOffsets, eyeRenderPose, nullptr); + ovrHmd_BeginFrame(_ovrHmd, _frameIndex); //Render each eye into an fbo - for (int eyeIndex = 0; eyeIndex < ovrEye_Count; eyeIndex++) { - _activeEyeIndex = eyeIndex; - -#if defined(__APPLE__) || defined(_WIN32) - ovrEyeType eye = _ovrHmd->EyeRenderOrder[eyeIndex]; -#else - ovrEyeType eye = _ovrHmdDesc.EyeRenderOrder[eyeIndex]; -#endif + for_each_eye(_ovrHmd, [&](ovrEyeType eye){ + _activeEye = eye; // Set the camera rotation for this eye eyeRenderPose[eye] = ovrHmd_GetHmdPosePerEye(_ovrHmd, eye); orientation.x = eyeRenderPose[eye].Orientation.x; orientation.y = eyeRenderPose[eye].Orientation.y; orientation.z = eyeRenderPose[eye].Orientation.z; orientation.w = eyeRenderPose[eye].Orientation.w; - + // Update the application camera with the latest HMD position whichCamera.setHmdPosition(trackerPosition); whichCamera.setHmdRotation(orientation); - + // Update our camera to what the application camera is doing _camera->setRotation(whichCamera.getRotation()); _camera->setPosition(whichCamera.getPosition()); - + // Store the latest left and right eye render locations for things that need to know glm::vec3 thisEyePosition = position + trackerPosition + (bodyOrientation * glm::quat(orientation.x, orientation.y, orientation.z, orientation.w) * glm::vec3(_eyeRenderDesc[eye].HmdToEyeViewOffset.x, _eyeRenderDesc[eye].HmdToEyeViewOffset.y, _eyeRenderDesc[eye].HmdToEyeViewOffset.z)); - - RenderArgs::RenderSide renderSide = RenderArgs::STEREO_LEFT; - if (eyeIndex == 0) { - _leftEyePosition = thisEyePosition; - } else { - _rightEyePosition = thisEyePosition; - renderSide = RenderArgs::STEREO_RIGHT; - } + _eyePositions[eye] = thisEyePosition; _camera->update(1.0f / Application::getInstance()->getFps()); glMatrixMode(GL_PROJECTION); glLoadIdentity(); - const ovrFovPort& port = _eyeFov[_activeEyeIndex]; + const ovrFovPort& port = _eyeFov[_activeEye]; float nearClip = whichCamera.getNearClip(), farClip = whichCamera.getFarClip(); glFrustum(-nearClip * port.LeftTan, nearClip * port.RightTan, -nearClip * port.DownTan, nearClip * port.UpTan, nearClip, farClip); - - glViewport(_eyeRenderViewport[eye].Pos.x, _eyeRenderViewport[eye].Pos.y, - _eyeRenderViewport[eye].Size.w, _eyeRenderViewport[eye].Size.h); - + const ovrRecti & vp = _eyeTextures[eye].Texture.Header.RenderViewport; + glViewport(vp.Pos.x, vp.Pos.y, vp.Size.w, vp.Size.h); + glMatrixMode(GL_MODELVIEW); glLoadIdentity(); - + // HACK: instead of passing the stereo eye offset directly in the matrix, pass it in the camera offset //glTranslatef(_eyeRenderDesc[eye].ViewAdjust.x, _eyeRenderDesc[eye].ViewAdjust.y, _eyeRenderDesc[eye].ViewAdjust.z); - + _camera->setEyeOffsetPosition(glm::vec3(-_eyeRenderDesc[eye].HmdToEyeViewOffset.x, -_eyeRenderDesc[eye].HmdToEyeViewOffset.y, -_eyeRenderDesc[eye].HmdToEyeViewOffset.z)); Application::getInstance()->displaySide(*_camera, false, RenderArgs::MONO); applicationOverlay.displayOverlayTextureOculus(*_camera); - _activeEyeIndex = -1; - } - - //Wait till time-warp to reduce latency - ovr_WaitTillTime(_hmdFrameTiming.TimewarpPointSeconds); + }); + _activeEye = ovrEye_Count; glPopMatrix(); - //Full texture viewport for glow effect - glViewport(0, 0, _renderTargetSize.w, _renderTargetSize.h); - + QOpenGLFramebufferObject * finalFbo = nullptr; //Bind the output texture from the glow shader. If glow effect is disabled, we just grab the texture if (Menu::getInstance()->isOptionChecked(MenuOption::EnableGlowEffect)) { - QOpenGLFramebufferObject* fbo = DependencyManager::get()->render(true); - glBindTexture(GL_TEXTURE_2D, fbo->texture()); + //Full texture viewport for glow effect + glViewport(0, 0, _renderTargetSize.w, _renderTargetSize.h); + finalFbo = DependencyManager::get()->render(true); } else { - DependencyManager::get()->getPrimaryFramebufferObject()->release(); - glBindTexture(GL_TEXTURE_2D, DependencyManager::get()->getPrimaryFramebufferObject()->texture()); + finalFbo = DependencyManager::get()->getPrimaryFramebufferObject(); + finalFbo->release(); } - // restore our normal viewport - auto glCanvas = DependencyManager::get(); - glViewport(0, 0, glCanvas->getDeviceWidth(), glCanvas->getDeviceHeight()); - glMatrixMode(GL_PROJECTION); glPopMatrix(); + // restore our normal viewport + glViewport(0, 0, glCanvas->getDeviceWidth(), glCanvas->getDeviceHeight()); + +#ifdef CLIENT_DISTORTION + //Wait till time-warp to reduce latency + ovr_WaitTillTime(_hmdFrameTiming.TimewarpPointSeconds); + + glBindTexture(GL_TEXTURE_2D, finalFbo->texture()); + //Renders the distorted mesh onto the screen renderDistortionMesh(eyeRenderPose); - + glBindTexture(GL_TEXTURE_2D, 0); +#else + for_each_eye([&](ovrEyeType eye) { + _eyeTextures[eye].OGL.TexId = finalFbo->texture(); + }); + ovrHmd_EndFrame(_ovrHmd, eyeRenderPose, &(_eyeTextures[0].Texture)); #endif } -#ifdef HAVE_LIBOVR +#ifdef CLIENT_DISTORTION void OculusManager::renderDistortionMesh(ovrPosef eyeRenderPose[ovrEye_Count]) { glLoadIdentity(); @@ -650,32 +650,17 @@ void OculusManager::renderDistortionMesh(ovrPosef eyeRenderPose[ovrEye_Count]) { //Tries to reconnect to the sensors void OculusManager::reset() { -#ifdef HAVE_LIBOVR if (_isConnected) { ovrHmd_RecenterPose(_ovrHmd); } -#endif } //Gets the current predicted angles from the oculus sensors void OculusManager::getEulerAngles(float& yaw, float& pitch, float& roll) { -#ifdef HAVE_LIBOVR -#if defined(__APPLE__) || defined(_WIN32) ovrTrackingState ts = ovrHmd_GetTrackingState(_ovrHmd, ovr_GetTimeInSeconds()); -#else - ovrSensorState ss = ovrHmd_GetSensorState(_ovrHmd, _hmdFrameTiming.ScanoutMidpointSeconds); -#endif -#if defined(__APPLE__) || defined(_WIN32) if (ts.StatusFlags & (ovrStatus_OrientationTracked | ovrStatus_PositionTracked)) { -#else - if (ss.StatusFlags & (ovrStatus_OrientationTracked | ovrStatus_PositionTracked)) { -#endif -#if defined(__APPLE__) || defined(_WIN32) ovrPosef headPose = ts.HeadPose.ThePose; -#else - ovrPosef headPose = ss.Predicted.Pose; -#endif Quatf orientation = Quatf(headPose.Orientation); orientation.GetEulerAngles(&yaw, &pitch, &roll); } else { @@ -683,53 +668,36 @@ void OculusManager::getEulerAngles(float& yaw, float& pitch, float& roll) { pitch = 0.0f; roll = 0.0f; } -#else - yaw = 0.0f; - pitch = 0.0f; - roll = 0.0f; -#endif } glm::vec3 OculusManager::getRelativePosition() { -#if (defined(__APPLE__) || defined(_WIN32)) && HAVE_LIBOVR ovrTrackingState trackingState = ovrHmd_GetTrackingState(_ovrHmd, ovr_GetTimeInSeconds()); ovrVector3f headPosition = trackingState.HeadPose.ThePose.Position; return glm::vec3(headPosition.x, headPosition.y, headPosition.z); -#else - // no positional tracking in Linux yet - return glm::vec3(0.0f, 0.0f, 0.0f); -#endif } //Used to set the size of the glow framebuffers QSize OculusManager::getRenderTargetSize() { -#ifdef HAVE_LIBOVR QSize rv; rv.setWidth(_renderTargetSize.w); rv.setHeight(_renderTargetSize.h); return rv; -#else - return QSize(100, 100); -#endif } void OculusManager::overrideOffAxisFrustum(float& left, float& right, float& bottom, float& top, float& nearVal, float& farVal, glm::vec4& nearClipPlane, glm::vec4& farClipPlane) { -#ifdef HAVE_LIBOVR - if (_activeEyeIndex != -1) { - const ovrFovPort& port = _eyeFov[_activeEyeIndex]; + if (_activeEye != ovrEye_Count) { + const ovrFovPort& port = _eyeFov[_activeEye]; right = nearVal * port.RightTan; left = -nearVal * port.LeftTan; top = nearVal * port.UpTan; bottom = -nearVal * port.DownTan; } -#endif } int OculusManager::getHMDScreen() { int hmdScreenIndex = -1; // unknown -#ifdef HAVE_LIBOVR // 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 @@ -778,7 +746,6 @@ int OculusManager::getHMDScreen() { screenNumber++; } } -#endif return hmdScreenIndex; } diff --git a/interface/src/devices/OculusManager.h b/interface/src/devices/OculusManager.h index e4ece6c3d3..35012d37cc 100644 --- a/interface/src/devices/OculusManager.h +++ b/interface/src/devices/OculusManager.h @@ -12,21 +12,27 @@ #ifndef hifi_OculusManager_h #define hifi_OculusManager_h -#define HAVE_LIBOVR 1 -#ifdef HAVE_LIBOVR + +#include +#include #include #include -#endif #include +#include +#include +#include class Camera; class PalmData; class Text3DOverlay; +// #define CLIENT_DISTORTION 1 + /// Handles interaction with the Oculus Rift. class OculusManager { public: + static void init(); static void connect(); static void disconnect(); static bool isConnected(); @@ -34,6 +40,7 @@ public: static void abandonCalibration(); static void beginFrameTiming(); static void endFrameTiming(); + static bool allowSwap(); static void configureCamera(Camera& camera, int screenWidth, int screenHeight); static void display(const glm::quat &bodyOrientation, const glm::vec3 &position, Camera& whichCamera); static void reset(); @@ -48,18 +55,15 @@ public: static void overrideOffAxisFrustum(float& left, float& right, float& bottom, float& top, float& nearVal, float& farVal, glm::vec4& nearClipPlane, glm::vec4& farClipPlane); - static glm::vec3 getLeftEyePosition() { return _leftEyePosition; } - static glm::vec3 getRightEyePosition() { return _rightEyePosition; } + static glm::vec3 getLeftEyePosition() { return _eyePositions[ovrEye_Left]; } + static glm::vec3 getRightEyePosition() { return _eyePositions[ovrEye_Right]; } static int getHMDScreen(); private: -#ifdef HAVE_LIBOVR +#ifdef CLIENT_DISTORTION static void generateDistortionMesh(); static void renderDistortionMesh(ovrPosef eyeRenderPose[ovrEye_Count]); - - static bool similarNames(const QString& nameA,const QString& nameB); - struct DistortionVertex { glm::vec2 pos; glm::vec2 texR; @@ -86,25 +90,29 @@ private: static int _texCoord0AttributeLocation; static int _texCoord1AttributeLocation; static int _texCoord2AttributeLocation; - - static bool _isConnected; - - static ovrHmd _ovrHmd; - static ovrHmdDesc _ovrHmdDesc; - static ovrFovPort _eyeFov[ovrEye_Count]; - static ovrEyeRenderDesc _eyeRenderDesc[ovrEye_Count]; - static ovrSizei _renderTargetSize; 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; static ovrRecti _eyeRenderViewport[ovrEye_Count]; +#else + static ovrGLTexture _eyeTextures[ovrEye_Count]; +#endif + + static bool _isConnected; + static glm::vec3 _eyePositions[ovrEye_Count]; + static ovrHmd _ovrHmd; + static ovrFovPort _eyeFov[ovrEye_Count]; + static ovrVector3f _eyeOffset[ovrEye_Count]; + static glm::mat4 _eyeProjection[ovrEye_Count]; + static ovrEyeRenderDesc _eyeRenderDesc[ovrEye_Count]; + static ovrSizei _renderTargetSize; static unsigned int _frameIndex; static bool _frameTimingActive; - static bool _programInitialized; static Camera* _camera; - static int _activeEyeIndex; + static ovrEyeType _activeEye; static void calibrate(const glm::vec3 position, const glm::quat orientation); enum CalibrationState { @@ -127,12 +135,60 @@ private: static quint64 _calibrationStartTime; static int _calibrationMessage; -#endif - - static glm::vec3 _leftEyePosition; - static glm::vec3 _rightEyePosition; - - }; + +inline glm::mat4 toGlm(const ovrMatrix4f & om) { + return glm::transpose(glm::make_mat4(&om.M[0][0])); +} + +inline glm::mat4 toGlm(const ovrFovPort & fovport, float nearPlane = 0.01f, float farPlane = 10000.0f) { + return toGlm(ovrMatrix4f_Projection(fovport, nearPlane, farPlane, true)); +} + +inline glm::vec3 toGlm(const ovrVector3f & ov) { + return glm::make_vec3(&ov.x); +} + +inline glm::vec2 toGlm(const ovrVector2f & ov) { + return glm::make_vec2(&ov.x); +} + +inline glm::uvec2 toGlm(const ovrSizei & ov) { + return glm::uvec2(ov.w, ov.h); +} + +inline glm::quat toGlm(const ovrQuatf & oq) { + return glm::make_quat(&oq.x); +} + +inline glm::mat4 toGlm(const ovrPosef & op) { + glm::mat4 orientation = glm::mat4_cast(toGlm(op.Orientation)); + glm::mat4 translation = glm::translate(glm::mat4(), toGlm(op.Position)); + return translation * orientation; +} + +inline ovrMatrix4f ovrFromGlm(const glm::mat4 & m) { + ovrMatrix4f result; + glm::mat4 transposed(glm::transpose(m)); + memcpy(result.M, &(transposed[0][0]), sizeof(float) * 16); + return result; +} + +inline ovrVector3f ovrFromGlm(const glm::vec3 & v) { + return{ v.x, v.y, v.z }; +} + +inline ovrVector2f ovrFromGlm(const glm::vec2 & v) { + return{ v.x, v.y }; +} + +inline ovrSizei ovrFromGlm(const glm::uvec2 & v) { + return{ v.x, v.y }; +} + +inline ovrQuatf ovrFromGlm(const glm::quat & q) { + return{ q.x, q.y, q.z, q.w }; +} + #endif // hifi_OculusManager_h diff --git a/interface/src/main.cpp b/interface/src/main.cpp index 64ecb2b9e7..9ee8ab3aae 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -18,6 +18,7 @@ #include "AddressManager.h" #include "Application.h" +#include "devices/OculusManager.h" #ifdef Q_OS_WIN static BOOL CALLBACK enumWindowsCallback(HWND hWnd, LPARAM lParam) { @@ -92,6 +93,10 @@ int main(int argc, const char* argv[]) { usecTimestampNowForceClockSkew(clockSkew); qDebug("clockSkewOption=%s clockSkew=%d", clockSkewOption, clockSkew); } + // Oculus initialization MUST PRECEDE OpenGL context creation. + // The nature of the Application constructor means this has to be either here, + // or in the main window ctor, before GL startup. + OculusManager::init(); int exitCode; { From c1c97fc8b675bac82c1002af62d7b7245e0f9def Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 4 Mar 2015 23:32:27 -0800 Subject: [PATCH 07/41] Updating cmake files after merging from master --- CMakeLists.txt | 2 ++ cmake/externals/LibOVR/CMakeLists.txt | 10 ++++------ cmake/modules/FindLibOVR.cmake | 13 ++++++++++++- interface/CMakeLists.txt | 26 ++++++++++++------------- interface/src/devices/OculusManager.cpp | 9 ++++----- libraries/gpu/CMakeLists.txt | 17 +++++++++------- 6 files changed, 44 insertions(+), 33 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index af707acf57..47c4271815 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -158,6 +158,8 @@ option(GET_GLM "Get GLM library automatically as external project" 1) option(GET_GVERB "Get Gverb library automatically as external project" 1) option(GET_SOXR "Get Soxr library automatically as external project" 1) option(GET_TBB "Get Threading Building Blocks library automatically as external project" 1) +option(GET_LIBOVR "Get LibOVR library automatically as external project" 1) +option(USE_NSIGHT "Attempt to find the nSight libraries" 1) if (WIN32) option(GET_GLEW "Get GLEW library automatically as external project" 1) diff --git a/cmake/externals/LibOVR/CMakeLists.txt b/cmake/externals/LibOVR/CMakeLists.txt index 1a2e3f4435..b85014cec9 100644 --- a/cmake/externals/LibOVR/CMakeLists.txt +++ b/cmake/externals/LibOVR/CMakeLists.txt @@ -11,12 +11,10 @@ ExternalProject_Add( ExternalProject_Get_Property(${EXTERNAL_NAME} INSTALL_DIR) +message(${INSTALL_DIR}) + string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER) set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${INSTALL_DIR}/include CACHE TYPE STRING) - -if (WIN32) - set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${INSTALL_DIR}/lib/ovr.lib CACHE TYPE STRING) -else () - set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${INSTALL_DIR}/lib/libovr.a CACHE TYPE STRING) -endif () +set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${INSTALL_DIR}/lib/ovr.lib CACHE TYPE FILEPATH) +set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG ${INSTALL_DIR}/lib/ovrd.lib CACHE TYPE FILEPATH) diff --git a/cmake/modules/FindLibOVR.cmake b/cmake/modules/FindLibOVR.cmake index c45aa5b784..820acadcf1 100644 --- a/cmake/modules/FindLibOVR.cmake +++ b/cmake/modules/FindLibOVR.cmake @@ -21,7 +21,11 @@ include("${MACRO_DIR}/HifiLibrarySearchHints.cmake") hifi_library_search_hints("libovr") +find_library(LIBOVR_LIBRARY_RELEASE ovr PATH_SUFFIXES "lib" HINTS ${LIBOVR_SEARCH_DIRS}) +find_library(LIBOVR_LIBRARY_DEBUG ovr PATH_SUFFIXES "lib" HINTS ${LIBOVR_SEARCH_DIRS}) + include(SelectLibraryConfigurations) +select_library_configurations(LIBOVR) if (NOT ANDROID) include("${MACRO_DIR}/HifiLibrarySearchHints.cmake") @@ -29,11 +33,18 @@ if (NOT ANDROID) find_path(LIBOVR_INCLUDE_DIRS OVR_CAPI.h PATH_SUFFIXES include HINTS ${LIBOVR_SEARCH_DIRS}) find_library(LIBOVR_LIBRARIES ovr PATH_SUFFIXES lib HINTS ${LIBOVR_SEARCH_DIRS}) - list(APPEND LIBOVR_LIBRARIES setupapi winmm ws2_32) include(FindPackageHandleStandardArgs) find_package_handle_standard_args(LIBOVR DEFAULT_MSG LIBOVR_INCLUDE_DIRS LIBOVR_LIBRARIES) + if (WIN32) + list(APPEND LIBOVR_LIBRARIES setupapi winmm ws2_32) + elseif(APPLE) + find_library(COCOA_LIBRARY Cocoa) + find_library(IOKIT_LIBRARY IOKit) + list(APPEND LIBOVR_LIBRARIES ${COCOA_LIBRARY} ${IOKIT_LIBRARY}) + endif() + else (NOT ANDROID) set(_VRLIB_JNI_DIR "VRLib/jni") set(_VRLIB_LIBS_DIR "VRLib/obj/local/armeabi-v7a") diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 1bb966fa53..3d829020e3 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -2,11 +2,7 @@ set(TARGET_NAME interface) project(${TARGET_NAME}) # set a default root dir for each of our optional externals if it was not passed -<<<<<<< HEAD -set(OPTIONAL_EXTERNALS "Faceshift" "PrioVR" "Sixense" "LeapMotion" "RtMidi" "Qxmpp" "SDL2" "RSSDK") -======= -set(OPTIONAL_EXTERNALS "Faceshift" "LibOVR" "Sixense" "LeapMotion" "RtMidi" "SDL2" "RSSDK") ->>>>>>> upstream/master +set(OPTIONAL_EXTERNALS "Faceshift" "Sixense" "LeapMotion" "RtMidi" "SDL2" "RSSDK") foreach(EXTERNAL ${OPTIONAL_EXTERNALS}) string(TOUPPER ${EXTERNAL} ${EXTERNAL}_UPPERCASE) if (NOT ${${EXTERNAL}_UPPERCASE}_ROOT_DIR) @@ -114,7 +110,7 @@ add_dependency_external_projects(glm bullet) find_package(GLM REQUIRED) target_include_directories(${TARGET_NAME} PRIVATE ${GLM_INCLUDE_DIRS}) -add_dependency_external_project(LibOVR) +add_dependency_external_projects(LibOVR) find_package(LibOVR REQUIRED) target_include_directories(${TARGET_NAME} PRIVATE ${LIBOVR_INCLUDE_DIRS}) target_link_libraries(${TARGET_NAME} ${LIBOVR_LIBRARIES}) @@ -229,15 +225,17 @@ else (APPLE) find_package(GLEW REQUIRED) target_include_directories(${TARGET_NAME} PRIVATE ${GLEW_INCLUDE_DIRS}) - target_link_libraries(${TARGET_NAME} ${GLEW_LIBRARIES} ${NSIGHT_LIBRARIES} wsock32.lib opengl32.lib Winmm.lib) + target_link_libraries(${TARGET_NAME} ${GLEW_LIBRARIES} wsock32.lib opengl32.lib Winmm.lib) - # 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 () + 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() endif (APPLE) diff --git a/interface/src/devices/OculusManager.cpp b/interface/src/devices/OculusManager.cpp index 1a935d14d6..216fd67197 100644 --- a/interface/src/devices/OculusManager.cpp +++ b/interface/src/devices/OculusManager.cpp @@ -31,7 +31,6 @@ #include "Application.h" -#include "OVR_Math.h" #include "OVR_Version.h" using namespace OVR; @@ -659,10 +658,10 @@ void OculusManager::reset() { void OculusManager::getEulerAngles(float& yaw, float& pitch, float& roll) { ovrTrackingState ts = ovrHmd_GetTrackingState(_ovrHmd, ovr_GetTimeInSeconds()); if (ts.StatusFlags & (ovrStatus_OrientationTracked | ovrStatus_PositionTracked)) { - - ovrPosef headPose = ts.HeadPose.ThePose; - Quatf orientation = Quatf(headPose.Orientation); - orientation.GetEulerAngles(&yaw, &pitch, &roll); + 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; diff --git a/libraries/gpu/CMakeLists.txt b/libraries/gpu/CMakeLists.txt index 4a23631dfb..85bef5223b 100644 --- a/libraries/gpu/CMakeLists.txt +++ b/libraries/gpu/CMakeLists.txt @@ -19,13 +19,16 @@ elseif (WIN32) target_link_libraries(${TARGET_NAME} ${GLEW_LIBRARIES} opengl32.lib) - # 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 () + 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 () From e3d48dbb8f97367c2826825822b27a2722ce3fde Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Fri, 6 Mar 2015 12:53:10 -0800 Subject: [PATCH 08/41] Working on Xcode build --- cmake/externals/LibOVR/CMakeLists.txt | 10 ++++++++-- interface/src/devices/OculusManager.h | 2 +- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/cmake/externals/LibOVR/CMakeLists.txt b/cmake/externals/LibOVR/CMakeLists.txt index b85014cec9..878af64053 100644 --- a/cmake/externals/LibOVR/CMakeLists.txt +++ b/cmake/externals/LibOVR/CMakeLists.txt @@ -16,5 +16,11 @@ message(${INSTALL_DIR}) string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER) set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${INSTALL_DIR}/include CACHE TYPE STRING) -set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${INSTALL_DIR}/lib/ovr.lib CACHE TYPE FILEPATH) -set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG ${INSTALL_DIR}/lib/ovrd.lib CACHE TYPE FILEPATH) + +if (WIN32) + set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${INSTALL_DIR}/lib/ovr.lib CACHE TYPE FILEPATH) + set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG ${INSTALL_DIR}/lib/ovrd.lib CACHE TYPE FILEPATH) +else() + set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${INSTALL_DIR}/lib/libovr.a CACHE TYPE FILEPATH) + set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG ${INSTALL_DIR}/lib/libovrd.a CACHE TYPE FILEPATH) +endif() \ No newline at end of file diff --git a/interface/src/devices/OculusManager.h b/interface/src/devices/OculusManager.h index 35012d37cc..bc7ec1ad10 100644 --- a/interface/src/devices/OculusManager.h +++ b/interface/src/devices/OculusManager.h @@ -184,7 +184,7 @@ inline ovrVector2f ovrFromGlm(const glm::vec2 & v) { } inline ovrSizei ovrFromGlm(const glm::uvec2 & v) { - return{ v.x, v.y }; + return{ (int)v.x, (int)v.y }; } inline ovrQuatf ovrFromGlm(const glm::quat & q) { From 1e65324a7b1193aa21c5c7e63b525750a5f04f7d Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Mon, 9 Mar 2015 14:46:43 -0700 Subject: [PATCH 09/41] Updating cmake config to build from pre-compiled Oculus SDK distribution --- cmake/externals/LibOVR/CMakeLists.txt | 84 ++++++++++++++++++++------- cmake/modules/FindLibOVR.cmake | 25 +------- 2 files changed, 66 insertions(+), 43 deletions(-) diff --git a/cmake/externals/LibOVR/CMakeLists.txt b/cmake/externals/LibOVR/CMakeLists.txt index 878af64053..3f5328f4ca 100644 --- a/cmake/externals/LibOVR/CMakeLists.txt +++ b/cmake/externals/LibOVR/CMakeLists.txt @@ -1,26 +1,70 @@ -set(EXTERNAL_NAME LibOVR) - include(ExternalProject) -ExternalProject_Add( - ${EXTERNAL_NAME} - PREFIX ${EXTERNAL_NAME} - GIT_REPOSITORY https://github.com/jherico/OculusSDK.git - CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH= - LOG_DOWNLOAD ON -) +include(SelectLibraryConfigurations) -ExternalProject_Get_Property(${EXTERNAL_NAME} INSTALL_DIR) - -message(${INSTALL_DIR}) +set(EXTERNAL_NAME LibOVR) string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER) -set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${INSTALL_DIR}/include CACHE TYPE STRING) - if (WIN32) - set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${INSTALL_DIR}/lib/ovr.lib CACHE TYPE FILEPATH) - set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG ${INSTALL_DIR}/lib/ovrd.lib CACHE TYPE FILEPATH) -else() - set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${INSTALL_DIR}/lib/libovr.a CACHE TYPE FILEPATH) - set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG ${INSTALL_DIR}/lib/libovrd.a CACHE TYPE FILEPATH) -endif() \ No newline at end of file + + ExternalProject_Add( + ${EXTERNAL_NAME} + URL http://static.oculus.com/sdk-downloads/ovr_sdk_win_0.4.4.zip + URL_MD5 bcc9f41346ce13bd4334a8bc94875728 + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND "" + LOG_DOWNLOAD 1 + ) + + ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR) + + # Different Oculus SDKs have different layouts, so we can't combine the include directories below + set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SOURCE_DIR}/OculusSDK/LibOVR/Include ${SOURCE_DIR}/OculusSDK/LibOVR/Src CACHE TYPE INTERNAL) + + # FIXME need to account for different architectures + set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${SOURCE_DIR}/OculusSDK/LibOVR/Lib/Win32/VS2013/libovr.lib CACHE TYPE INTERNAL) + set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG ${SOURCE_DIR}/OculusSDK/LibOVR/Lib/Win32/VS2013/libovrd.lib CACHE TYPE INTERNAL) + set(${EXTERNAL_NAME_UPPER}_LIBRARY_EXTRAS setupapi winmm ws2_32) + +elseif(APPLE) + + ExternalProject_Add( + ${EXTERNAL_NAME} + URL http://static.oculus.com/sdk-downloads/ovr_sdk_macos_0.4.4.tar.gz + URL_MD5 3cf8576d225798608a2aa7219b7ea11e + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND "" + LOG_DOWNLOAD 1 + ) + + ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR) + + set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SOURCE_DIR}/LibOVR/Include ${SOURCE_DIR}/LibOVR/Src CACHE TYPE INTERNAL) + + set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${SOURCE_DIR}/LibOVR/Lib/Mac/Release/libovr.a CACHE TYPE INTERNAL) + set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG ${SOURCE_DIR}/LibOVR/Lib/Mac/Debug/libovr.a CACHE TYPE INTERNAL) + + find_library(COCOA_LIBRARY Cocoa) + find_library(IOKIT_LIBRARY IOKit) + set(${EXTERNAL_NAME_UPPER}_LIBRARY_EXTRAS ${COCOA_LIBRARY} ${IOKIT_LIBRARY}) + +elseif(NOT ANDROID) + + # http://static.oculus.com/sdk-downloads/ovr_sdk_linux_0.4.4.tar.xz + # ec3bd8cff4a1461b4e21210e7feb0572 + ExternalProject_Add( + ${EXTERNAL_NAME} + PREFIX ${EXTERNAL_NAME} + GIT_REPOSITORY https://github.com/jherico/OculusSDK.git + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH= + LOG_DOWNLOAD ON + ) + +endif() + +select_library_configurations(${EXTERNAL_NAME_UPPER}) + +set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${${EXTERNAL_NAME_UPPER}_LIBRARY} ${${EXTERNAL_NAME_UPPER}_LIBRARY_EXTRAS} CACHE TYPE INTERNAL) + diff --git a/cmake/modules/FindLibOVR.cmake b/cmake/modules/FindLibOVR.cmake index 820acadcf1..df45a639cf 100644 --- a/cmake/modules/FindLibOVR.cmake +++ b/cmake/modules/FindLibOVR.cmake @@ -18,32 +18,11 @@ # See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html # -include("${MACRO_DIR}/HifiLibrarySearchHints.cmake") -hifi_library_search_hints("libovr") - -find_library(LIBOVR_LIBRARY_RELEASE ovr PATH_SUFFIXES "lib" HINTS ${LIBOVR_SEARCH_DIRS}) -find_library(LIBOVR_LIBRARY_DEBUG ovr PATH_SUFFIXES "lib" HINTS ${LIBOVR_SEARCH_DIRS}) - -include(SelectLibraryConfigurations) -select_library_configurations(LIBOVR) if (NOT ANDROID) - include("${MACRO_DIR}/HifiLibrarySearchHints.cmake") - hifi_library_search_hints("libovr") - - find_path(LIBOVR_INCLUDE_DIRS OVR_CAPI.h PATH_SUFFIXES include HINTS ${LIBOVR_SEARCH_DIRS}) - find_library(LIBOVR_LIBRARIES ovr PATH_SUFFIXES lib HINTS ${LIBOVR_SEARCH_DIRS}) - include(FindPackageHandleStandardArgs) - find_package_handle_standard_args(LIBOVR DEFAULT_MSG LIBOVR_INCLUDE_DIRS LIBOVR_LIBRARIES) - - if (WIN32) - list(APPEND LIBOVR_LIBRARIES setupapi winmm ws2_32) - elseif(APPLE) - find_library(COCOA_LIBRARY Cocoa) - find_library(IOKIT_LIBRARY IOKit) - list(APPEND LIBOVR_LIBRARIES ${COCOA_LIBRARY} ${IOKIT_LIBRARY}) - endif() + include(FindPackageHandleStandardArgs) + find_package_handle_standard_args(LIBOVR DEFAULT_MSG LIBOVR_INCLUDE_DIRS LIBOVR_LIBRARIES) else (NOT ANDROID) set(_VRLIB_JNI_DIR "VRLib/jni") From 76ce31d4c3d163f2f995123cd022cb248751f9c0 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Mon, 9 Mar 2015 14:47:33 -0700 Subject: [PATCH 10/41] Limiting app pollution with Oculus headers, ensuring client distortion mode builds --- interface/src/devices/OculusManager.cpp | 55 +++++++++++-------------- interface/src/devices/OculusManager.h | 6 +-- 2 files changed, 25 insertions(+), 36 deletions(-) diff --git a/interface/src/devices/OculusManager.cpp b/interface/src/devices/OculusManager.cpp index 216fd67197..f6260f00e7 100644 --- a/interface/src/devices/OculusManager.cpp +++ b/interface/src/devices/OculusManager.cpp @@ -29,10 +29,10 @@ #include #include -#include "Application.h" +#include +#include -#include "OVR_Version.h" -using namespace OVR; +#include "Application.h" template void for_each_eye(Function function) { @@ -69,11 +69,10 @@ GLuint OculusManager::_indices[ovrEye_Count] = { 0, 0 }; GLsizei OculusManager::_meshSize[ovrEye_Count] = { 0, 0 }; ovrFrameTiming OculusManager::_hmdFrameTiming; bool OculusManager::_programInitialized = false; -#else #endif +ovrTexture OculusManager::_eyeTextures[ovrEye_Count]; bool OculusManager::_isConnected = false; -ovrGLTexture OculusManager::_eyeTextures[ovrEye_Count]; ovrHmd OculusManager::_ovrHmd; ovrFovPort OculusManager::_eyeFov[ovrEye_Count]; ovrVector3f OculusManager::_eyeOffset[ovrEye_Count]; @@ -101,6 +100,9 @@ glm::vec3 OculusManager::_eyePositions[ovrEye_Count]; void OculusManager::init() { ovr_Initialize(); _ovrHmd = ovrHmd_Create(0); + if (!_ovrHmd) { + _ovrHmd = ovrHmd_CreateDebug(ovrHmd_DK2); + } } void OculusManager::connect() { @@ -137,16 +139,16 @@ void OculusManager::connect() { for_each_eye([&](ovrEyeType eye) { //Get texture size ovrSizei recommendedTexSize = ovrHmd_GetFovTextureSize(_ovrHmd, eye, _eyeFov[eye], 1.0f); - _eyeTextures[eye].Texture.Header.API = ovrRenderAPI_OpenGL; - _eyeTextures[eye].Texture.Header.RenderViewport.Pos = { _renderTargetSize.w, 0 }; - _eyeTextures[eye].Texture.Header.RenderViewport.Size = recommendedTexSize; + _eyeTextures[eye].Header.API = ovrRenderAPI_OpenGL; + _eyeTextures[eye].Header.RenderViewport.Pos = { _renderTargetSize.w, 0 }; + _eyeTextures[eye].Header.RenderViewport.Size = recommendedTexSize; _renderTargetSize.w += recommendedTexSize.w; _renderTargetSize.h = std::max(recommendedTexSize.h, _renderTargetSize.h); }); for_each_eye([&](ovrEyeType eye) { - _eyeTextures[eye].Texture.Header.TextureSize = _renderTargetSize; + _eyeTextures[eye].Header.TextureSize = _renderTargetSize; }); - + ovrHmd_SetEnabledCaps(_ovrHmd, ovrHmdCap_LowPersistence); ovrHmd_ConfigureTracking(_ovrHmd, ovrTrackingCap_Orientation | ovrTrackingCap_Position | @@ -339,22 +341,16 @@ void OculusManager::generateDistortionMesh() { return; } - //Viewport for the render target for each eye - _eyeRenderViewport[0].Pos = Vector2i(0, 0); - _eyeRenderViewport[0].Size = Sizei(_renderTargetSize.w / 2, _renderTargetSize.h); - _eyeRenderViewport[1].Pos = Vector2i((_renderTargetSize.w + 1) / 2, 0); - _eyeRenderViewport[1].Size = _eyeRenderViewport[0].Size; - 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); - ovrHmd_GetRenderScaleAndOffset(_eyeRenderDesc[eyeNum].Fov, _renderTargetSize, _eyeRenderViewport[eyeNum], + ovrHmd_GetRenderScaleAndOffset(_eyeRenderDesc[eyeNum].Fov, _renderTargetSize, _eyeTextures[eyeNum].Header.RenderViewport, _UVScaleOffset[eyeNum]); // Parse the vertex data and create a render ready vertex buffer - DistortionVertex* pVBVerts = (DistortionVertex*)OVR_ALLOC(sizeof(DistortionVertex) * meshData.VertexCount); + DistortionVertex* pVBVerts = new DistortionVertex[meshData.VertexCount]; _meshSize[eyeNum] = meshData.IndexCount; // Convert the oculus vertex data to the DistortionVertex format. @@ -388,7 +384,7 @@ void OculusManager::generateDistortionMesh() { glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); //Now that we have the VBOs we can get rid of the mesh data - OVR_FREE(pVBVerts); + delete [] pVBVerts; ovrHmd_DestroyDistortionMesh(&meshData); } @@ -497,7 +493,6 @@ void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &p for_each_eye(_ovrHmd, [&](ovrEyeType eye){ _activeEye = eye; // Set the camera rotation for this eye - eyeRenderPose[eye] = ovrHmd_GetHmdPosePerEye(_ovrHmd, eye); orientation.x = eyeRenderPose[eye].Orientation.x; orientation.y = eyeRenderPose[eye].Orientation.y; orientation.z = eyeRenderPose[eye].Orientation.z; @@ -526,7 +521,7 @@ void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &p glFrustum(-nearClip * port.LeftTan, nearClip * port.RightTan, -nearClip * port.DownTan, nearClip * port.UpTan, nearClip, farClip); - const ovrRecti & vp = _eyeTextures[eye].Texture.Header.RenderViewport; + const ovrRecti & vp = _eyeTextures[eye].Header.RenderViewport; glViewport(vp.Pos.x, vp.Pos.y, vp.Size.w, vp.Size.h); glMatrixMode(GL_MODELVIEW); @@ -574,10 +569,11 @@ void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &p #else for_each_eye([&](ovrEyeType eye) { - _eyeTextures[eye].OGL.TexId = finalFbo->texture(); + ovrGLTexture & glEyeTexture = reinterpret_cast(_eyeTextures[eye]); + glEyeTexture.OGL.TexId = finalFbo->texture(); }); - ovrHmd_EndFrame(_ovrHmd, eyeRenderPose, &(_eyeTextures[0].Texture)); + ovrHmd_EndFrame(_ovrHmd, eyeRenderPose, _eyeTextures); #endif } @@ -608,18 +604,15 @@ void OculusManager::renderDistortionMesh(ovrPosef eyeRenderPose[ovrEye_Count]) { _program.setUniformValueArray(_eyeToSourceUVOffsetLocation, uvOffset, 1, 2); ovrMatrix4f timeWarpMatrices[2]; - Matrix4f transposeMatrices[2]; + glm::mat4 transposeMatrices[2]; //Grabs the timewarp matrices to be used in the shader ovrHmd_GetEyeTimewarpMatrices(_ovrHmd, (ovrEyeType)eyeNum, eyeRenderPose[eyeNum], timeWarpMatrices); - transposeMatrices[0] = Matrix4f(timeWarpMatrices[0]); - transposeMatrices[1] = Matrix4f(timeWarpMatrices[1]); - //Have to transpose the matrices before using them - transposeMatrices[0].Transpose(); - transposeMatrices[1].Transpose(); + transposeMatrices[0] = glm::transpose(toGlm(timeWarpMatrices[0])); + transposeMatrices[1] = glm::transpose(toGlm(timeWarpMatrices[1])); - glUniformMatrix4fv(_eyeRotationStartLocation, 1, GL_FALSE, (GLfloat *)transposeMatrices[0].M); - glUniformMatrix4fv(_eyeRotationEndLocation, 1, GL_FALSE, (GLfloat *)transposeMatrices[1].M); + 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]); diff --git a/interface/src/devices/OculusManager.h b/interface/src/devices/OculusManager.h index bc7ec1ad10..289db38ada 100644 --- a/interface/src/devices/OculusManager.h +++ b/interface/src/devices/OculusManager.h @@ -14,9 +14,7 @@ #define hifi_OculusManager_h #include -#include #include -#include #include #include @@ -96,11 +94,9 @@ private: static GLsizei _meshSize[ovrEye_Count]; static ovrFrameTiming _hmdFrameTiming; static bool _programInitialized; - static ovrRecti _eyeRenderViewport[ovrEye_Count]; -#else - static ovrGLTexture _eyeTextures[ovrEye_Count]; #endif + static ovrTexture _eyeTextures[ovrEye_Count]; static bool _isConnected; static glm::vec3 _eyePositions[ovrEye_Count]; static ovrHmd _ovrHmd; From 2fdb92fc45fb2cfc289337152ccfdceb4cbdcca6 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Mon, 9 Mar 2015 17:07:54 -0700 Subject: [PATCH 11/41] Fixing ubuntu build of libovr --- cmake/externals/LibOVR/CMakeLists.txt | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/cmake/externals/LibOVR/CMakeLists.txt b/cmake/externals/LibOVR/CMakeLists.txt index 3f5328f4ca..e2c7f6ed3a 100644 --- a/cmake/externals/LibOVR/CMakeLists.txt +++ b/cmake/externals/LibOVR/CMakeLists.txt @@ -62,9 +62,32 @@ elseif(NOT ANDROID) LOG_DOWNLOAD ON ) + + ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR) + ExternalProject_Get_Property(${EXTERNAL_NAME} INSTALL_DIR) + set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SOURCE_DIR}/LibOVR/Include ${SOURCE_DIR}/LibOVR/Src CACHE TYPE INTERNAL) + set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${INSTALL_DIR}/lib/libovr.a CACHE TYPE INTERNAL) + set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG "" CACHE TYPE INTERNAL) + + find_package(Threads REQUIRED) + find_package(X11 REQUIRED) + + # Check for XRandR (modern resolution switching and gamma control) + if (NOT X11_Xrandr_FOUND) + message(FATAL_ERROR "The RandR library and headers were not found") + endif() + + set(${EXTERNAL_NAME_UPPER}_LIBRARY_EXTRAS rt udev ${CMAKE_THREAD_LIBS_INIT} ${X11_X11_LIB} ${X11_Xrandr_LIB}) + endif() select_library_configurations(${EXTERNAL_NAME_UPPER}) set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${${EXTERNAL_NAME_UPPER}_LIBRARY} ${${EXTERNAL_NAME_UPPER}_LIBRARY_EXTRAS} CACHE TYPE INTERNAL) +# Helpful for debugging the external libs +#message("Include: " ${${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS}) +#foreach(l ${${EXTERNAL_NAME_UPPER}_LIBRARIES}) +# message("Library: " ${l}) +#endforeach() + From adb6a6ee54f8e502be12578fcc999c32d9a0c35e Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Mon, 9 Mar 2015 17:27:10 -0700 Subject: [PATCH 12/41] Hopefully fixing win32 build --- cmake/externals/LibOVR/CMakeLists.txt | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/cmake/externals/LibOVR/CMakeLists.txt b/cmake/externals/LibOVR/CMakeLists.txt index e2c7f6ed3a..86adbc2efd 100644 --- a/cmake/externals/LibOVR/CMakeLists.txt +++ b/cmake/externals/LibOVR/CMakeLists.txt @@ -19,9 +19,6 @@ if (WIN32) ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR) - # Different Oculus SDKs have different layouts, so we can't combine the include directories below - set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SOURCE_DIR}/OculusSDK/LibOVR/Include ${SOURCE_DIR}/OculusSDK/LibOVR/Src CACHE TYPE INTERNAL) - # FIXME need to account for different architectures set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${SOURCE_DIR}/OculusSDK/LibOVR/Lib/Win32/VS2013/libovr.lib CACHE TYPE INTERNAL) set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG ${SOURCE_DIR}/OculusSDK/LibOVR/Lib/Win32/VS2013/libovrd.lib CACHE TYPE INTERNAL) @@ -41,8 +38,6 @@ elseif(APPLE) ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR) - set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SOURCE_DIR}/LibOVR/Include ${SOURCE_DIR}/LibOVR/Src CACHE TYPE INTERNAL) - set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${SOURCE_DIR}/LibOVR/Lib/Mac/Release/libovr.a CACHE TYPE INTERNAL) set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG ${SOURCE_DIR}/LibOVR/Lib/Mac/Debug/libovr.a CACHE TYPE INTERNAL) @@ -65,7 +60,7 @@ elseif(NOT ANDROID) ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR) ExternalProject_Get_Property(${EXTERNAL_NAME} INSTALL_DIR) - set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SOURCE_DIR}/LibOVR/Include ${SOURCE_DIR}/LibOVR/Src CACHE TYPE INTERNAL) + set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${INSTALL_DIR}/lib/libovr.a CACHE TYPE INTERNAL) set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG "" CACHE TYPE INTERNAL) @@ -83,11 +78,6 @@ endif() select_library_configurations(${EXTERNAL_NAME_UPPER}) +set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SOURCE_DIR}/LibOVR/Include ${SOURCE_DIR}/LibOVR/Src CACHE TYPE INTERNAL) set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${${EXTERNAL_NAME_UPPER}_LIBRARY} ${${EXTERNAL_NAME_UPPER}_LIBRARY_EXTRAS} CACHE TYPE INTERNAL) -# Helpful for debugging the external libs -#message("Include: " ${${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS}) -#foreach(l ${${EXTERNAL_NAME_UPPER}_LIBRARIES}) -# message("Library: " ${l}) -#endforeach() - From c512c5f2e9e503259d92a2c26131dd5d8e9d9e0e Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Mon, 9 Mar 2015 19:26:32 -0700 Subject: [PATCH 13/41] LibOVR: Really fixing the Win32 build this time --- cmake/externals/LibOVR/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/externals/LibOVR/CMakeLists.txt b/cmake/externals/LibOVR/CMakeLists.txt index 86adbc2efd..176cc3c89b 100644 --- a/cmake/externals/LibOVR/CMakeLists.txt +++ b/cmake/externals/LibOVR/CMakeLists.txt @@ -20,8 +20,8 @@ if (WIN32) ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR) # FIXME need to account for different architectures - set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${SOURCE_DIR}/OculusSDK/LibOVR/Lib/Win32/VS2013/libovr.lib CACHE TYPE INTERNAL) - set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG ${SOURCE_DIR}/OculusSDK/LibOVR/Lib/Win32/VS2013/libovrd.lib CACHE TYPE INTERNAL) + set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${SOURCE_DIR}/LibOVR/Lib/Win32/VS2013/libovr.lib CACHE TYPE INTERNAL) + set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG ${SOURCE_DIR}/LibOVR/Lib/Win32/VS2013/libovrd.lib CACHE TYPE INTERNAL) set(${EXTERNAL_NAME_UPPER}_LIBRARY_EXTRAS setupapi winmm ws2_32) elseif(APPLE) From 5aa4277d9b2ec390c4c0c64b83569c96e49bc021 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Mon, 16 Mar 2015 12:22:35 -0700 Subject: [PATCH 14/41] Removing a superfluous clear from Application.cpp. It's only required in client distortion mode --- interface/src/Application.cpp | 4 ---- interface/src/devices/OculusManager.cpp | 4 ++++ 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 0c27ecb7de..b2faafe452 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -747,10 +747,6 @@ void Application::paintGL() { } if (OculusManager::isConnected()) { - //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); - //When in mirror mode, use camera rotation. Otherwise, use body rotation if (_myCamera.getMode() == CAMERA_MODE_MIRROR) { OculusManager::display(_myCamera.getRotation(), _myCamera.getPosition(), _myCamera); diff --git a/interface/src/devices/OculusManager.cpp b/interface/src/devices/OculusManager.cpp index f6260f00e7..9d7ea8f782 100644 --- a/interface/src/devices/OculusManager.cpp +++ b/interface/src/devices/OculusManager.cpp @@ -560,6 +560,10 @@ void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &p //Wait till time-warp to reduce latency ovr_WaitTillTime(_hmdFrameTiming.TimewarpPointSeconds); + //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, finalFbo->texture()); //Renders the distorted mesh onto the screen From c4c6cf82a2fd9676ad410dd24c755650f9e2972d Mon Sep 17 00:00:00 2001 From: Bradley Austin Davis Date: Tue, 31 Mar 2015 13:27:11 -0700 Subject: [PATCH 15/41] Working on migration to SDK 0.5.0.1 --- cmake/externals/LibOVR/CMakeLists.txt | 75 ++++++++++++++----------- interface/src/devices/OculusManager.cpp | 4 +- interface/src/devices/OculusManager.h | 1 - 3 files changed, 42 insertions(+), 38 deletions(-) diff --git a/cmake/externals/LibOVR/CMakeLists.txt b/cmake/externals/LibOVR/CMakeLists.txt index 176cc3c89b..d24c1771d1 100644 --- a/cmake/externals/LibOVR/CMakeLists.txt +++ b/cmake/externals/LibOVR/CMakeLists.txt @@ -24,12 +24,17 @@ if (WIN32) set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG ${SOURCE_DIR}/LibOVR/Lib/Win32/VS2013/libovrd.lib CACHE TYPE INTERNAL) set(${EXTERNAL_NAME_UPPER}_LIBRARY_EXTRAS setupapi winmm ws2_32) + select_library_configurations(${EXTERNAL_NAME_UPPER}) + + set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SOURCE_DIR}/LibOVR/Include ${SOURCE_DIR}/LibOVR/Src CACHE TYPE INTERNAL) + set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${${EXTERNAL_NAME_UPPER}_LIBRARY} ${${EXTERNAL_NAME_UPPER}_LIBRARY_EXTRAS} CACHE TYPE INTERNAL) + elseif(APPLE) ExternalProject_Add( ${EXTERNAL_NAME} - URL http://static.oculus.com/sdk-downloads/ovr_sdk_macos_0.4.4.tar.gz - URL_MD5 3cf8576d225798608a2aa7219b7ea11e + URL http://static.oculus.com/sdk-downloads/ovr_sdk_macos_0.5.0.1.tar.gz + URL_MD5 0a0785a04fb285f64f62267388344ad6 CONFIGURE_COMMAND "" BUILD_COMMAND "" INSTALL_COMMAND "" @@ -37,47 +42,49 @@ elseif(APPLE) ) ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR) + # In theory we should use the Headers path inside the framework, as seen here + # but unfortunately Oculus doesn't seem to have figured out automated testing + # so they released a framework with missing headers. + #set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SOURCE_DIR}/LibOVR/Lib/Mac/Release/LibOVR.framework/Headers/ CACHE TYPE INTERNAL) + + # Work around the broken framework by using a different path for the headers. + set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SOURCE_DIR}/LibOVR/Include CACHE TYPE INTERNAL) + set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${SOURCE_DIR}/LibOVR/Lib/Mac/Release/LibOVR.framework/LibOVR CACHE TYPE INTERNAL) - set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${SOURCE_DIR}/LibOVR/Lib/Mac/Release/libovr.a CACHE TYPE INTERNAL) - set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG ${SOURCE_DIR}/LibOVR/Lib/Mac/Debug/libovr.a CACHE TYPE INTERNAL) - find_library(COCOA_LIBRARY Cocoa) - find_library(IOKIT_LIBRARY IOKit) - set(${EXTERNAL_NAME_UPPER}_LIBRARY_EXTRAS ${COCOA_LIBRARY} ${IOKIT_LIBRARY}) elseif(NOT ANDROID) - # http://static.oculus.com/sdk-downloads/ovr_sdk_linux_0.4.4.tar.xz - # ec3bd8cff4a1461b4e21210e7feb0572 - ExternalProject_Add( - ${EXTERNAL_NAME} - PREFIX ${EXTERNAL_NAME} - GIT_REPOSITORY https://github.com/jherico/OculusSDK.git - CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH= - LOG_DOWNLOAD ON - ) - - - ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR) - ExternalProject_Get_Property(${EXTERNAL_NAME} INSTALL_DIR) + # http://static.oculus.com/sdk-downloads/ovr_sdk_linux_0.4.4.tar.xz + # ec3bd8cff4a1461b4e21210e7feb0572 + ExternalProject_Add( + ${EXTERNAL_NAME} + PREFIX ${EXTERNAL_NAME} + GIT_REPOSITORY https://github.com/jherico/OculusSDK.git + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH= + LOG_DOWNLOAD ON + ) + + ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR) + ExternalProject_Get_Property(${EXTERNAL_NAME} INSTALL_DIR) - set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${INSTALL_DIR}/lib/libovr.a CACHE TYPE INTERNAL) - set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG "" CACHE TYPE INTERNAL) + set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${INSTALL_DIR}/lib/libovr.a CACHE TYPE INTERNAL) + set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG "" CACHE TYPE INTERNAL) - find_package(Threads REQUIRED) - find_package(X11 REQUIRED) + find_package(Threads REQUIRED) + find_package(X11 REQUIRED) - # Check for XRandR (modern resolution switching and gamma control) - if (NOT X11_Xrandr_FOUND) - message(FATAL_ERROR "The RandR library and headers were not found") - endif() + # Check for XRandR (modern resolution switching and gamma control) + if (NOT X11_Xrandr_FOUND) + message(FATAL_ERROR "The RandR library and headers were not found") + endif() - set(${EXTERNAL_NAME_UPPER}_LIBRARY_EXTRAS rt udev ${CMAKE_THREAD_LIBS_INIT} ${X11_X11_LIB} ${X11_Xrandr_LIB}) - + set(${EXTERNAL_NAME_UPPER}_LIBRARY_EXTRAS rt udev ${CMAKE_THREAD_LIBS_INIT} ${X11_X11_LIB} ${X11_Xrandr_LIB}) + + select_library_configurations(${EXTERNAL_NAME_UPPER}) + + set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SOURCE_DIR}/LibOVR/Include ${SOURCE_DIR}/LibOVR/Src CACHE TYPE INTERNAL) + set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${${EXTERNAL_NAME_UPPER}_LIBRARY} ${${EXTERNAL_NAME_UPPER}_LIBRARY_EXTRAS} CACHE TYPE INTERNAL) endif() -select_library_configurations(${EXTERNAL_NAME_UPPER}) - -set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SOURCE_DIR}/LibOVR/Include ${SOURCE_DIR}/LibOVR/Src CACHE TYPE INTERNAL) -set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${${EXTERNAL_NAME_UPPER}_LIBRARY} ${${EXTERNAL_NAME_UPPER}_LIBRARY_EXTRAS} CACHE TYPE INTERNAL) diff --git a/interface/src/devices/OculusManager.cpp b/interface/src/devices/OculusManager.cpp index 9d7ea8f782..16dccf61a1 100644 --- a/interface/src/devices/OculusManager.cpp +++ b/interface/src/devices/OculusManager.cpp @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include @@ -29,7 +29,6 @@ #include #include -#include #include #include "Application.h" @@ -125,7 +124,6 @@ void OculusManager::connect() { cfg.OGL.Header.Multisample = 1; int distortionCaps = 0 - | ovrDistortionCap_Chromatic | ovrDistortionCap_Vignette | ovrDistortionCap_Overdrive | ovrDistortionCap_TimeWarp; diff --git a/interface/src/devices/OculusManager.h b/interface/src/devices/OculusManager.h index 289db38ada..bc85c33981 100644 --- a/interface/src/devices/OculusManager.h +++ b/interface/src/devices/OculusManager.h @@ -13,7 +13,6 @@ #ifndef hifi_OculusManager_h #define hifi_OculusManager_h -#include #include #include From 6757dfcc0cca6628428d842247e68f1c783b6ac4 Mon Sep 17 00:00:00 2001 From: Bradley Austin Davis Date: Tue, 31 Mar 2015 14:52:21 -0700 Subject: [PATCH 16/41] Working on 0.5.0.1 port and addressing the direct HMD/v-sync conflict --- interface/src/devices/OculusManager.cpp | 63 ++++++++++++++++++++----- interface/src/devices/OculusManager.h | 23 ++++++++- 2 files changed, 72 insertions(+), 14 deletions(-) diff --git a/interface/src/devices/OculusManager.cpp b/interface/src/devices/OculusManager.cpp index 16dccf61a1..b04c8ae227 100644 --- a/interface/src/devices/OculusManager.cpp +++ b/interface/src/devices/OculusManager.cpp @@ -50,7 +50,7 @@ void for_each_eye(const ovrHmd & hmd, Function function) { } } -#ifdef CLIENT_DISTORTION +#ifdef OVR_CLIENT_DISTORTION ProgramObject OculusManager::_program; int OculusManager::_textureLocation; int OculusManager::_eyeToSourceUVScaleLocation; @@ -82,6 +82,7 @@ unsigned int OculusManager::_frameIndex = 0; bool OculusManager::_frameTimingActive = false; Camera* OculusManager::_camera = NULL; ovrEyeType OculusManager::_activeEye = ovrEye_Count; +bool OculusManager::_hswDismissed = false; float OculusManager::CALIBRATION_DELTA_MINIMUM_LENGTH = 0.02f; float OculusManager::CALIBRATION_DELTA_MINIMUM_ANGLE = 5.0f * RADIANS_PER_DEGREE; @@ -96,7 +97,7 @@ quint64 OculusManager::_calibrationStartTime; int OculusManager::_calibrationMessage = NULL; glm::vec3 OculusManager::_eyePositions[ovrEye_Count]; -void OculusManager::init() { +void OculusManager::initSdk() { ovr_Initialize(); _ovrHmd = ovrHmd_Create(0); if (!_ovrHmd) { @@ -104,7 +105,21 @@ void OculusManager::init() { } } +void OculusManager::shutdownSdk() { + ovrHmd_Destroy(_ovrHmd); + ovr_Shutdown(); +} + +void OculusManager::init() { +#ifdef OVR_DIRECT_MODE + initSdk(); +#endif +} + void OculusManager::connect() { +#ifndef OVR_DIRECT_MODE + initSdk(); +#endif _calibrationState = UNCALIBRATED; qDebug() << "Oculus SDK" << OVR_VERSION_STRING; if (_ovrHmd) { @@ -157,7 +172,7 @@ void OculusManager::connect() { _camera = new Camera; configureCamera(*_camera, 0, 0); // no need to use screen dimensions; they're ignored } -#ifdef CLIENT_DISTORTION +#ifdef OVR_CLIENT_DISTORTION if (!_programInitialized) { // Shader program _programInitialized = true; @@ -195,11 +210,15 @@ void OculusManager::connect() { void OculusManager::disconnect() { if (_isConnected) { _isConnected = false; - //ovrHmd_Destroy(_ovrHmd); - //ovr_Shutdown(); + // 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 -#ifdef CLIENT_DISTORTION for (int i = 0; i < ovrEye_Count; i++) { if (_vertices[i] != 0) { glDeleteBuffers(1, &(_vertices[i])); @@ -330,7 +349,7 @@ void OculusManager::abandonCalibration() { } } -#ifdef CLIENT_DISTORTION +#ifdef OVR_CLIENT_DISTORTION void OculusManager::generateDistortionMesh() { //Check if we already have the distortion mesh @@ -399,14 +418,14 @@ void OculusManager::beginFrameTiming() { printf("WARNING: Called OculusManager::beginFrameTiming() twice in a row, need to call OculusManager::endFrameTiming()."); } -#ifdef CLIENT_DISTORTION +#ifdef OVR_CLIENT_DISTORTION _hmdFrameTiming = ovrHmd_BeginFrameTiming(_ovrHmd, _frameIndex); #endif _frameTimingActive = true; } bool OculusManager::allowSwap() { -#ifdef CLIENT_DISTORTION +#ifdef OVR_CLIENT_DISTORTION return true; #else return false; @@ -415,7 +434,7 @@ bool OculusManager::allowSwap() { } //Ends frame timing void OculusManager::endFrameTiming() { -#ifdef CLIENT_DISTORTION +#ifdef OVR_CLIENT_DISTORTION ovrHmd_EndFrameTiming(_ovrHmd); #endif _frameIndex++; @@ -432,6 +451,7 @@ void OculusManager::configureCamera(Camera& camera, int screenWidth, int screenH void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &position, Camera& whichCamera) { auto glCanvas = Application::getInstance()->getGLWidget(); +#ifdef OVR_DIRECT_MODE static bool attached = false; if (!attached) { attached = true; @@ -440,6 +460,25 @@ void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &p ovrHmd_AttachToWindow(_ovrHmd, nativeWindowHandle, nullptr, nullptr); } } +#endif + +#ifndef OVR_CLIENT_DISTORTION + // 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 + // keyboard input. OVR claim they are refactoring HSW + // https://forums.oculus.com/viewtopic.php?f=20&t=21720#p258599 + static ovrHSWDisplayState hasWarningState; + if (!_hswDismissed) { + ovrHmd_GetHSWDisplayState(_ovrHmd, &hasWarningState); + if (hasWarningState.Displayed) { + ovrHmd_DismissHSWDisplay(_ovrHmd); + } else { + _hswDismissed = true; + } + } +#endif + //beginFrameTiming must be called before display if (!_frameTimingActive) { @@ -554,7 +593,7 @@ void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &p // restore our normal viewport glViewport(0, 0, glCanvas->getDeviceWidth(), glCanvas->getDeviceHeight()); -#ifdef CLIENT_DISTORTION +#ifdef OVR_CLIENT_DISTORTION //Wait till time-warp to reduce latency ovr_WaitTillTime(_hmdFrameTiming.TimewarpPointSeconds); @@ -579,7 +618,7 @@ void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &p #endif } -#ifdef CLIENT_DISTORTION +#ifdef OVR_CLIENT_DISTORTION void OculusManager::renderDistortionMesh(ovrPosef eyeRenderPose[ovrEye_Count]) { glLoadIdentity(); diff --git a/interface/src/devices/OculusManager.h b/interface/src/devices/OculusManager.h index bc85c33981..e0ec36f78a 100644 --- a/interface/src/devices/OculusManager.h +++ b/interface/src/devices/OculusManager.h @@ -23,7 +23,23 @@ class Camera; class PalmData; class Text3DOverlay; -// #define CLIENT_DISTORTION 1 + +// 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 + + +// 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 /// Handles interaction with the Oculus Rift. @@ -58,7 +74,9 @@ public: static int getHMDScreen(); private: -#ifdef CLIENT_DISTORTION + static void initSdk(); + static void shutdownSdk(); +#ifdef OVR_CLIENT_DISTORTION static void generateDistortionMesh(); static void renderDistortionMesh(ovrPosef eyeRenderPose[ovrEye_Count]); struct DistortionVertex { @@ -108,6 +126,7 @@ private: static bool _frameTimingActive; static Camera* _camera; static ovrEyeType _activeEye; + static bool _hswDismissed; static void calibrate(const glm::vec3 position, const glm::quat orientation); enum CalibrationState { From 0a55bcb0c55203527e808de2d2179c5731e498d8 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Tue, 31 Mar 2015 16:56:04 -0700 Subject: [PATCH 17/41] Remove XMLHttpRequest's facility to read local files --- .../script-engine/src/XMLHttpRequestClass.cpp | 160 +++--------------- .../script-engine/src/XMLHttpRequestClass.h | 2 - 2 files changed, 27 insertions(+), 135 deletions(-) diff --git a/libraries/script-engine/src/XMLHttpRequestClass.cpp b/libraries/script-engine/src/XMLHttpRequestClass.cpp index 3054472a3c..75f51d1cdf 100644 --- a/libraries/script-engine/src/XMLHttpRequestClass.cpp +++ b/libraries/script-engine/src/XMLHttpRequestClass.cpp @@ -13,14 +13,13 @@ // #include -#include #include +#include #include -#include -#include "XMLHttpRequestClass.h" #include "ScriptEngine.h" +#include "XMLHttpRequestClass.h" const QString METAVERSE_API_URL = "https://metaverse.highfidelity.com/api/"; @@ -41,7 +40,6 @@ XMLHttpRequestClass::XMLHttpRequestClass(QScriptEngine* engine) : _onReadyStateChange(QScriptValue::NullValue), _readyState(XMLHttpRequestClass::UNSENT), _errorCode(QNetworkReply::NoError), - _file(NULL), _timeout(0), _timer(this), _numRedirects(0) { @@ -62,22 +60,6 @@ QScriptValue XMLHttpRequestClass::getStatus() const { if (_reply) { return QScriptValue(_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt()); } - if(_url.isLocalFile()) { - switch (_errorCode) { - case QNetworkReply::NoError: - return QScriptValue(200); - case QNetworkReply::ContentNotFoundError: - return QScriptValue(404); - case QNetworkReply::ContentConflictError: - return QScriptValue(409); - case QNetworkReply::TimeoutError: - return QScriptValue(408); - case QNetworkReply::ContentOperationNotPermittedError: - return QScriptValue(501); - default: - break; - } - } return QScriptValue(0); } @@ -85,22 +67,6 @@ QString XMLHttpRequestClass::getStatusText() const { if (_reply) { return _reply->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString(); } - if (_url.isLocalFile()) { - switch (_errorCode) { - case QNetworkReply::NoError: - return "OK"; - case QNetworkReply::ContentNotFoundError: - return "Not Found"; - case QNetworkReply::ContentConflictError: - return "Conflict"; - case QNetworkReply::TimeoutError: - return "Timeout"; - case QNetworkReply::ContentOperationNotPermittedError: - return "Not Implemented"; - default: - break; - } - } return ""; } @@ -146,13 +112,6 @@ QScriptValue XMLHttpRequestClass::getAllResponseHeaders() const { } return QString(headers.data()); } - if (_url.isLocalFile()) { - QString headers = QString("Content-Type: application/octet-stream\n"); - headers.append("Content-Length: "); - headers.append(QString("%1").arg(_rawResponseData.length())); - headers.append("\n"); - return headers; - } return QScriptValue(""); } @@ -160,14 +119,6 @@ QScriptValue XMLHttpRequestClass::getResponseHeader(const QString& name) const { if (_reply && _reply->hasRawHeader(name.toLatin1())) { return QScriptValue(QString(_reply->rawHeader(name.toLatin1()))); } - if (_url.isLocalFile()) { - if (name.toLower() == "content-type") { - return QString("application/octet-stream"); - } - if (name.toLower() == "content-length") { - return QString("%1").arg(_rawResponseData.length()); - } - } return QScriptValue::NullValue; } @@ -187,47 +138,24 @@ void XMLHttpRequestClass::open(const QString& method, const QString& url, bool a _url.setUrl(url); _async = async; - if (_url.isLocalFile()) { - if (_method.toUpper() == "GET" && !_async && username.isEmpty() && password.isEmpty()) { - _file = new QFile(_url.toLocalFile()); - if (!_file->exists()) { - qDebug() << "Can't find file " << _url.fileName(); - abortRequest(); - _errorCode = QNetworkReply::ContentNotFoundError; - setReadyState(DONE); - emit requestComplete(); - } else if (!_file->open(QIODevice::ReadOnly)) { - qDebug() << "Can't open file " << _url.fileName(); - abortRequest(); - _errorCode = QNetworkReply::ContentConflictError; - setReadyState(DONE); - emit requestComplete(); - } else { - setReadyState(OPENED); - } - } else { - notImplemented(); - } - } else { - if (url.toLower().left(METAVERSE_API_URL.length()) == METAVERSE_API_URL) { - AccountManager& accountManager = AccountManager::getInstance(); + if (url.toLower().left(METAVERSE_API_URL.length()) == METAVERSE_API_URL) { + AccountManager& accountManager = AccountManager::getInstance(); - if (accountManager.hasValidAccessToken()) { - QUrlQuery urlQuery(_url.query()); - urlQuery.addQueryItem("access_token", accountManager.getAccountInfo().getAccessToken().token); - _url.setQuery(urlQuery); - } + if (accountManager.hasValidAccessToken()) { + QUrlQuery urlQuery(_url.query()); + urlQuery.addQueryItem("access_token", accountManager.getAccountInfo().getAccessToken().token); + _url.setQuery(urlQuery); + } - } - if (!username.isEmpty()) { - _url.setUserName(username); - } - if (!password.isEmpty()) { - _url.setPassword(password); - } - _request.setUrl(_url); - setReadyState(OPENED); } + if (!username.isEmpty()) { + _url.setUserName(username); + } + if (!password.isEmpty()) { + _url.setPassword(password); + } + _request.setUrl(_url); + setReadyState(OPENED); } } @@ -238,23 +166,18 @@ void XMLHttpRequestClass::send() { void XMLHttpRequestClass::send(const QScriptValue& data) { if (_readyState == OPENED && !_reply) { if (!data.isNull()) { - if (_url.isLocalFile()) { - notImplemented(); - return; + _sendData = new QBuffer(this); + if (data.isObject()) { + QByteArray ba = qscriptvalue_cast(data); + _sendData->setData(ba); } else { - _sendData = new QBuffer(this); - if (data.isObject()) { - QByteArray ba = qscriptvalue_cast(data); - _sendData->setData(ba); - } else { - _sendData->setData(data.toString().toUtf8()); - } + _sendData->setData(data.toString().toUtf8()); } } doSend(); - if (!_async && !_url.isLocalFile()) { + if (!_async) { QEventLoop loop; connect(this, SIGNAL(requestComplete()), &loop, SLOT(quit())); loop.exec(); @@ -264,23 +187,13 @@ void XMLHttpRequestClass::send(const QScriptValue& data) { void XMLHttpRequestClass::doSend() { - if (!_url.isLocalFile()) { - _reply = NetworkAccessManager::getInstance().sendCustomRequest(_request, _method.toLatin1(), _sendData); - connectToReply(_reply); - } + _reply = NetworkAccessManager::getInstance().sendCustomRequest(_request, _method.toLatin1(), _sendData); + connectToReply(_reply); if (_timeout > 0) { _timer.start(_timeout); connect(&_timer, SIGNAL(timeout()), this, SLOT(requestTimeout())); } - - if (_url.isLocalFile()) { - setReadyState(HEADERS_RECEIVED); - setReadyState(LOADING); - _rawResponseData = _file->readAll(); - _file->close(); - requestFinished(); - } } void XMLHttpRequestClass::requestTimeout() { @@ -299,16 +212,10 @@ void XMLHttpRequestClass::requestError(QNetworkReply::NetworkError code) { void XMLHttpRequestClass::requestFinished() { disconnect(&_timer, SIGNAL(timeout()), this, SLOT(requestTimeout())); - if (!_url.isLocalFile()) { - _errorCode = _reply->error(); - } else { - _errorCode = QNetworkReply::NoError; - } + _errorCode = _reply->error(); if (_errorCode == QNetworkReply::NoError) { - if (!_url.isLocalFile()) { - _rawResponseData.append(_reply->readAll()); - } + _rawResponseData.append(_reply->readAll()); if (_responseType == "json") { _responseData = _engine->evaluate("(" + QString(_rawResponseData.data()) + ")"); @@ -337,19 +244,6 @@ void XMLHttpRequestClass::abortRequest() { _reply->deleteLater(); _reply = NULL; } - - if (_file != NULL) { - _file->close(); - _file = NULL; - } -} - -void XMLHttpRequestClass::notImplemented() { - abortRequest(); - //_errorCode = QNetworkReply::OperationNotImplementedError; TODO: Use this status code when update to Qt 5.3 - _errorCode = QNetworkReply::ContentOperationNotPermittedError; - setReadyState(DONE); - emit requestComplete(); } void XMLHttpRequestClass::connectToReply(QNetworkReply* reply) { diff --git a/libraries/script-engine/src/XMLHttpRequestClass.h b/libraries/script-engine/src/XMLHttpRequestClass.h index 55bf646476..c79859e895 100644 --- a/libraries/script-engine/src/XMLHttpRequestClass.h +++ b/libraries/script-engine/src/XMLHttpRequestClass.h @@ -97,7 +97,6 @@ private: void connectToReply(QNetworkReply* reply); void disconnectFromReply(QNetworkReply* reply); void abortRequest(); - void notImplemented(); QScriptEngine* _engine; bool _async; @@ -113,7 +112,6 @@ private: QScriptValue _onReadyStateChange; ReadyState _readyState; QNetworkReply::NetworkError _errorCode; - QFile* _file; int _timeout; QTimer _timer; int _numRedirects; From edaa4cdc65da85d47b5a4d3c9106950ba43e92df Mon Sep 17 00:00:00 2001 From: David Rowe Date: Tue, 31 Mar 2015 16:57:15 -0700 Subject: [PATCH 18/41] Remove local file reading from scripts --- examples/edit.js | 2 - examples/libraries/modelUploader.js | 693 ------------------ .../utilities/diagnostics/XMLHttpRequest.js | 95 --- 3 files changed, 790 deletions(-) delete mode 100644 examples/libraries/modelUploader.js diff --git a/examples/edit.js b/examples/edit.js index 08a2c4f3f7..156cf44fa0 100644 --- a/examples/edit.js +++ b/examples/edit.js @@ -16,8 +16,6 @@ HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/"; Script.include([ "libraries/stringHelpers.js", "libraries/dataviewHelpers.js", - "libraries/httpMultiPart.js", - "libraries/modelUploader.js", "libraries/toolBars.js", "libraries/progressDialog.js", diff --git a/examples/libraries/modelUploader.js b/examples/libraries/modelUploader.js deleted file mode 100644 index 64a9e91203..0000000000 --- a/examples/libraries/modelUploader.js +++ /dev/null @@ -1,693 +0,0 @@ -// -// modelUploader.js -// examples/libraries -// -// Copyright 2014 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 -// - - -modelUploader = (function () { - var that = {}, - modelFile, - modelName, - modelURL, - modelCallback, - isProcessing, - fstBuffer, - fbxBuffer, - //svoBuffer, - mapping, - geometry, - API_URL = "https://metaverse.highfidelity.com/api/v1/models", - MODEL_URL = "http://public.highfidelity.com/models/content", - NAME_FIELD = "name", - SCALE_FIELD = "scale", - FILENAME_FIELD = "filename", - TEXDIR_FIELD = "texdir", - MAX_TEXTURE_SIZE = 1024; - - function info(message) { - if (progressDialog.isOpen()) { - progressDialog.update(message); - } else { - progressDialog.open(message); - } - print(message); - } - - function error(message) { - if (progressDialog.isOpen()) { - progressDialog.close(); - } - print(message); - Window.alert(message); - } - - function randomChar(length) { - var characters = "0123457689abcdefghijklmnopqrstuvwxyz", - string = "", - i; - - for (i = 0; i < length; i += 1) { - string += characters[Math.floor(Math.random() * 36)]; - } - - return string; - } - - function resetDataObjects() { - fstBuffer = null; - fbxBuffer = null; - //svoBuffer = null; - mapping = {}; - geometry = {}; - geometry.textures = []; - geometry.embedded = []; - } - - function readFile(filename) { - var url = "file:///" + filename, - req = new XMLHttpRequest(); - - req.open("GET", url, false); - req.responseType = "arraybuffer"; - req.send(); - if (req.status !== 200) { - error("Could not read file: " + filename + " : " + req.statusText); - return null; - } - - return { - filename: filename.fileName(), - buffer: req.response - }; - } - - function readMapping(buffer) { - var dv = new DataView(buffer.buffer), - lines, - line, - tokens, - i, - name, - value, - remainder, - existing; - - mapping = {}; // { name : value | name : { value : [remainder] } } - lines = dv.string(0, dv.byteLength).split(/\r\n|\r|\n/); - for (i = 0; i < lines.length; i += 1) { - line = lines[i].trim(); - if (line.length > 0 && line[0] !== "#") { - tokens = line.split(/\s*=\s*/); - if (tokens.length > 1) { - name = tokens[0]; - value = tokens[1]; - if (tokens.length > 2) { - remainder = tokens.slice(2, tokens.length).join(" = "); - } else { - remainder = null; - } - if (tokens.length === 2 && mapping[name] === undefined) { - mapping[name] = value; - } else { - if (mapping[name] === undefined) { - mapping[name] = {}; - - } else if (typeof mapping[name] !== "object") { - existing = mapping[name]; - mapping[name] = { existing : null }; - } - - if (mapping[name][value] === undefined) { - mapping[name][value] = []; - } - mapping[name][value].push(remainder); - } - } - } - } - } - - function writeMapping(buffer) { - var name, - value, - remainder, - i, - string = ""; - - for (name in mapping) { - if (mapping.hasOwnProperty(name)) { - if (typeof mapping[name] === "object") { - for (value in mapping[name]) { - if (mapping[name].hasOwnProperty(value)) { - remainder = mapping[name][value]; - if (remainder === null) { - string += (name + " = " + value + "\n"); - } else { - for (i = 0; i < remainder.length; i += 1) { - string += (name + " = " + value + " = " + remainder[i] + "\n"); - } - } - } - } - } else { - string += (name + " = " + mapping[name] + "\n"); - } - } - } - - buffer.buffer = string.toArrayBuffer(); - } - - function readGeometry(fbxBuffer) { - var textures, - view, - index, - EOF, - previousNodeFilename; - - // Reference: - // http://code.blender.org/index.php/2013/08/fbx-binary-file-format-specification/ - - textures = {}; - view = new DataView(fbxBuffer.buffer); - EOF = false; - - function parseBinaryFBX() { - var endOffset, - numProperties, - propertyListLength, - nameLength, - name, - filename; - - endOffset = view.getUint32(index, true); - numProperties = view.getUint32(index + 4, true); - propertyListLength = view.getUint32(index + 8, true); - nameLength = view.getUint8(index + 12); - index += 13; - - if (endOffset === 0) { - return; - } - if (endOffset < index || endOffset > view.byteLength) { - EOF = true; - return; - } - - name = view.string(index, nameLength).toLowerCase(); - index += nameLength; - - if (name === "content" && previousNodeFilename !== "") { - // Blender 2.71 exporter "embeds" external textures as empty binary blobs so ignore these - if (propertyListLength > 5) { - geometry.embedded.push(previousNodeFilename); - } - } - - if (name === "relativefilename") { - filename = view.string(index + 5, view.getUint32(index + 1, true)).fileName(); - if (!textures.hasOwnProperty(filename)) { - textures[filename] = ""; - geometry.textures.push(filename); - } - previousNodeFilename = filename; - } else { - previousNodeFilename = ""; - } - - index += (propertyListLength); - - while (index < endOffset && !EOF) { - parseBinaryFBX(); - } - } - - function readTextFBX() { - var line, - view, - viewLength, - charCode, - charCodes, - numCharCodes, - filename, - relativeFilename = "", - MAX_CHAR_CODES = 250; - - view = new Uint8Array(fbxBuffer.buffer); - viewLength = view.byteLength; - charCodes = []; - numCharCodes = 0; - - for (index = 0; index < viewLength; index += 1) { - charCode = view[index]; - if (charCode !== 9 && charCode !== 32) { - if (charCode === 10) { // EOL. Can ignore EOF. - line = String.fromCharCode.apply(String, charCodes).toLowerCase(); - // For embedded textures, "Content:" line immediately follows "RelativeFilename:" line. - if (line.slice(0, 8) === "content:" && relativeFilename !== "") { - geometry.embedded.push(relativeFilename); - } - if (line.slice(0, 17) === "relativefilename:") { - filename = line.slice(line.indexOf("\""), line.lastIndexOf("\"") - line.length).fileName(); - if (!textures.hasOwnProperty(filename)) { - textures[filename] = ""; - geometry.textures.push(filename); - } - relativeFilename = filename; - } else { - relativeFilename = ""; - } - charCodes = []; - numCharCodes = 0; - } else { - if (numCharCodes < MAX_CHAR_CODES) { // Only interested in start of line - charCodes.push(charCode); - numCharCodes += 1; - } - } - } - } - } - - - - readTextFBX(); - - - } - - function readModel() { - var fbxFilename, - //svoFilename, - fileType; - - info("Reading model file"); - print("Model file: " + modelFile); - - if (modelFile.toLowerCase().fileType() === "fst") { - fstBuffer = readFile(modelFile); - if (fstBuffer === null) { - return false; - } - readMapping(fstBuffer); - fileType = mapping[FILENAME_FIELD].toLowerCase().fileType(); - if (mapping.hasOwnProperty(FILENAME_FIELD)) { - if (fileType === "fbx") { - fbxFilename = modelFile.path() + "\\" + mapping[FILENAME_FIELD]; - //} else if (fileType === "svo") { - // svoFilename = modelFile.path() + "\\" + mapping[FILENAME_FIELD]; - } else { - error("Unrecognized model type in FST file!"); - return false; - } - } else { - error("Model file name not found in FST file!"); - return false; - } - } else { - fstBuffer = { - filename: "Interface." + randomChar(6), // Simulate avatar model uploading behaviour - buffer: null - }; - - if (modelFile.toLowerCase().fileType() === "fbx") { - fbxFilename = modelFile; - mapping[FILENAME_FIELD] = modelFile.fileName(); - - //} else if (modelFile.toLowerCase().fileType() === "svo") { - // svoFilename = modelFile; - // mapping[FILENAME_FIELD] = modelFile.fileName(); - - } else { - error("Unrecognized file type: " + modelFile); - return false; - } - } - - if (!isProcessing) { return false; } - - if (fbxFilename) { - fbxBuffer = readFile(fbxFilename); - if (fbxBuffer === null) { - return false; - } - - if (!isProcessing) { return false; } - - readGeometry(fbxBuffer); - } - - //if (svoFilename) { - // svoBuffer = readFile(svoFilename); - // if (svoBuffer === null) { - // return false; - // } - //} - - // Add any missing basic mappings - if (!mapping.hasOwnProperty(NAME_FIELD)) { - mapping[NAME_FIELD] = modelFile.fileName().fileBase(); - } - if (!mapping.hasOwnProperty(TEXDIR_FIELD)) { - mapping[TEXDIR_FIELD] = "."; - } - if (!mapping.hasOwnProperty(SCALE_FIELD)) { - mapping[SCALE_FIELD] = 1.0; - } - - return true; - } - - function setProperties() { - var form = [], - directory, - displayAs, - validateAs; - - progressDialog.close(); - print("Setting model properties"); - - form.push({ label: "Name:", value: mapping[NAME_FIELD] }); - - directory = modelFile.path() + "/" + mapping[TEXDIR_FIELD]; - displayAs = new RegExp("^" + modelFile.path().regExpEscape() + "[\\\\\\\/](.*)"); - validateAs = new RegExp("^" + modelFile.path().regExpEscape() + "([\\\\\\\/].*)?"); - - form.push({ - label: "Texture directory:", - directory: modelFile.path() + "/" + mapping[TEXDIR_FIELD], - title: "Choose Texture Directory", - displayAs: displayAs, - validateAs: validateAs, - errorMessage: "Texture directory must be subdirectory of the model directory." - }); - - form.push({ button: "Cancel" }); - - if (!Window.form("Set Model Properties", form)) { - print("User cancelled uploading model"); - return false; - } - - mapping[NAME_FIELD] = form[0].value; - mapping[TEXDIR_FIELD] = form[1].directory.slice(modelFile.path().length + 1); - if (mapping[TEXDIR_FIELD] === "") { - mapping[TEXDIR_FIELD] = "."; - } - - writeMapping(fstBuffer); - - return true; - } - - function createHttpMessage(callback) { - var multiparts = [], - lodCount, - lodFile, - lodBuffer, - textureBuffer, - textureSourceFormat, - textureTargetFormat, - embeddedTextures, - i; - - info("Preparing to send model"); - - // Model name - if (mapping.hasOwnProperty(NAME_FIELD)) { - multiparts.push({ - name : "model_name", - string : mapping[NAME_FIELD] - }); - } else { - error("Model name is missing"); - httpMultiPart.clear(); - return; - } - - // FST file - if (fstBuffer) { - multiparts.push({ - name : "fst", - buffer: fstBuffer - }); - } - - // FBX file - if (fbxBuffer) { - multiparts.push({ - name : "fbx", - buffer: fbxBuffer - }); - } - - // SVO file - //if (svoBuffer) { - // multiparts.push({ - // name : "svo", - // buffer: svoBuffer - // }); - //} - - // LOD files - lodCount = 0; - for (lodFile in mapping.lod) { - if (mapping.lod.hasOwnProperty(lodFile)) { - lodBuffer = readFile(modelFile.path() + "\/" + lodFile); - if (lodBuffer === null) { - return; - } - multiparts.push({ - name: "lod" + lodCount, - buffer: lodBuffer - }); - lodCount += 1; - } - if (!isProcessing) { return; } - } - - // Textures - embeddedTextures = "|" + geometry.embedded.join("|") + "|"; - for (i = 0; i < geometry.textures.length; i += 1) { - if (embeddedTextures.indexOf("|" + geometry.textures[i].fileName() + "|") === -1) { - textureBuffer = readFile(modelFile.path() + "\/" - + (mapping[TEXDIR_FIELD] !== "." ? mapping[TEXDIR_FIELD] + "\/" : "") - + geometry.textures[i]); - if (textureBuffer === null) { - return; - } - - textureSourceFormat = geometry.textures[i].fileType().toLowerCase(); - textureTargetFormat = (textureSourceFormat === "jpg" ? "jpg" : "png"); - textureBuffer.buffer = - textureBuffer.buffer.recodeImage(textureSourceFormat, textureTargetFormat, MAX_TEXTURE_SIZE); - textureBuffer.filename = textureBuffer.filename.slice(0, -textureSourceFormat.length) + textureTargetFormat; - - multiparts.push({ - name: "texture" + i, - buffer: textureBuffer - }); - } - - if (!isProcessing) { return; } - } - - // Model category - multiparts.push({ - name : "model_category", - string : "content" - }); - - // Create HTTP message - httpMultiPart.clear(); - Script.setTimeout(function addMultipart() { - var multipart = multiparts.shift(); - httpMultiPart.add(multipart); - - if (!isProcessing) { return; } - - if (multiparts.length > 0) { - Script.setTimeout(addMultipart, 25); - } else { - callback(); - } - }, 25); - } - - function sendToHighFidelity() { - var req, - uploadedChecks, - HTTP_GET_TIMEOUT = 60, // 1 minute - HTTP_SEND_TIMEOUT = 900, // 15 minutes - UPLOADED_CHECKS = 30, - CHECK_UPLOADED_TIMEOUT = 1, // 1 second - handleCheckUploadedResponses, - handleUploadModelResponses, - handleRequestUploadResponses; - - function uploadTimedOut() { - error("Model upload failed: Internet request timed out!"); - } - - function debugResponse() { - print("req.errorCode = " + req.errorCode); - print("req.readyState = " + req.readyState); - print("req.status = " + req.status); - print("req.statusText = " + req.statusText); - print("req.responseType = " + req.responseType); - print("req.responseText = " + req.responseText); - print("req.response = " + req.response); - print("req.getAllResponseHeaders() = " + req.getAllResponseHeaders()); - } - - function checkUploaded() { - if (!isProcessing) { return; } - - info("Checking uploaded model"); - - req = new XMLHttpRequest(); - req.open("HEAD", modelURL, true); - req.timeout = HTTP_GET_TIMEOUT * 1000; - req.onreadystatechange = handleCheckUploadedResponses; - req.ontimeout = uploadTimedOut; - req.send(); - } - - handleCheckUploadedResponses = function () { - //debugResponse(); - if (req.readyState === req.DONE) { - if (req.status === 200) { - // Note: Unlike avatar models, for content models we don't need to refresh texture cache. - print("Model uploaded: " + modelURL); - progressDialog.close(); - if (Window.confirm("Your model has been uploaded as: " + modelURL + "\nDo you want to rez it?")) { - modelCallback(modelURL); - } - } else if (req.status === 404) { - if (uploadedChecks > 0) { - uploadedChecks -= 1; - Script.setTimeout(checkUploaded, CHECK_UPLOADED_TIMEOUT * 1000); - } else { - print("Error: " + req.status + " " + req.statusText); - error("We could not verify that your model was successfully uploaded but it may have been at: " - + modelURL); - } - } else { - print("Error: " + req.status + " " + req.statusText); - error("There was a problem with your upload, please try again later."); - } - } - }; - - function uploadModel(method) { - var url; - - if (!isProcessing) { return; } - - req = new XMLHttpRequest(); - if (method === "PUT") { - url = API_URL + "\/" + modelName; - req.open("PUT", url, true); //print("PUT " + url); - } else { - url = API_URL; - req.open("POST", url, true); //print("POST " + url); - } - req.setRequestHeader("Content-Type", "multipart/form-data; boundary=\"" + httpMultiPart.boundary() + "\""); - req.timeout = HTTP_SEND_TIMEOUT * 1000; - req.onreadystatechange = handleUploadModelResponses; - req.ontimeout = uploadTimedOut; - req.send(httpMultiPart.response().buffer); - } - - handleUploadModelResponses = function () { - //debugResponse(); - if (req.readyState === req.DONE) { - if (req.status === 200) { - uploadedChecks = UPLOADED_CHECKS; - checkUploaded(); - } else { - print("Error: " + req.status + " " + req.statusText); - error("There was a problem with your upload, please try again later."); - } - } - }; - - function requestUpload() { - var url; - - if (!isProcessing) { return; } - - url = API_URL + "\/" + modelName; // XMLHttpRequest automatically handles authorization of API requests. - req = new XMLHttpRequest(); - req.open("GET", url, true); //print("GET " + url); - req.responseType = "json"; - req.timeout = HTTP_GET_TIMEOUT * 1000; - req.onreadystatechange = handleRequestUploadResponses; - req.ontimeout = uploadTimedOut; - req.send(); - } - - handleRequestUploadResponses = function () { - var response; - - //debugResponse(); - if (req.readyState === req.DONE) { - if (req.status === 200) { - if (req.responseType === "json") { - response = JSON.parse(req.responseText); - if (response.status === "success") { - if (response.exists === false) { - uploadModel("POST"); - } else if (response.can_update === true) { - uploadModel("PUT"); - } else { - error("This model file already exists and is owned by someone else!"); - } - return; - } - } - } else { - print("Error: " + req.status + " " + req.statusText); - } - error("Model upload failed! Something went wrong at the data server."); - } - }; - - info("Sending model to High Fidelity"); - - requestUpload(); - } - - that.upload = function (file, callback) { - - modelFile = file; - modelCallback = callback; - - isProcessing = true; - - progressDialog.onCancel = function () { - print("User cancelled uploading model"); - isProcessing = false; - }; - - resetDataObjects(); - - if (readModel()) { - if (setProperties()) { - modelName = mapping[NAME_FIELD]; - modelURL = MODEL_URL + "\/" + mapping[NAME_FIELD] + ".fst"; // All models are uploaded as an FST - - createHttpMessage(sendToHighFidelity); - } - } - - resetDataObjects(); - }; - - return that; -}()); diff --git a/examples/utilities/diagnostics/XMLHttpRequest.js b/examples/utilities/diagnostics/XMLHttpRequest.js index fb25cb4fad..76374749ac 100644 --- a/examples/utilities/diagnostics/XMLHttpRequest.js +++ b/examples/utilities/diagnostics/XMLHttpRequest.js @@ -145,98 +145,3 @@ test("Test timeout", function() { this.assertEquals(0, req.status, "status should be `0`"); this.assertEquals(4, req.errorCode, "4 is the timeout error code for QNetworkReply::NetworkError"); }); - - -var localFile = Window.browse("Find defaultScripts.js file ...", "", "defaultScripts.js (defaultScripts.js)"); - -if (localFile !== null) { - - localFile = "file:///" + localFile; - - test("Test GET local file synchronously", function () { - var req = new XMLHttpRequest(); - - var statesVisited = [true, false, false, false, false] - req.onreadystatechange = function () { - statesVisited[req.readyState] = true; - }; - - req.open("GET", localFile, false); - req.send(); - - this.assertEquals(req.DONE, req.readyState, "readyState should be DONE"); - this.assertEquals(200, req.status, "status should be `200`"); - this.assertEquals("OK", req.statusText, "statusText should be `OK`"); - this.assertEquals(0, req.errorCode); - this.assertNotEquals("", req.getAllResponseHeaders(), "headers should not be null"); - this.assertContains("High Fidelity", req.response.substring(0, 100), "expected text not found in response") - - for (var i = 0; i <= req.DONE; i++) { - this.assertEquals(true, statesVisited[i], i + " should be set"); - } - }); - - test("Test GET nonexistent local file", function () { - var nonexistentFile = localFile.replace(".js", "NoExist.js"); - - var req = new XMLHttpRequest(); - req.open("GET", nonexistentFile, false); - req.send(); - - this.assertEquals(req.DONE, req.readyState, "readyState should be DONE"); - this.assertEquals(404, req.status, "status should be `404`"); - this.assertEquals("Not Found", req.statusText, "statusText should be `Not Found`"); - this.assertNotEquals(0, req.errorCode); - }); - - test("Test GET local file already open", function () { - // Can't open file exclusively in order to test. - }); - - test("Test GET local file with data not implemented", function () { - var req = new XMLHttpRequest(); - req.open("GET", localFile, true); - req.send("data"); - - this.assertEquals(req.DONE, req.readyState, "readyState should be DONE"); - this.assertEquals(501, req.status, "status should be `501`"); - this.assertEquals("Not Implemented", req.statusText, "statusText should be `Not Implemented`"); - this.assertNotEquals(0, req.errorCode); - }); - - test("Test GET local file asynchronously not implemented", function () { - var req = new XMLHttpRequest(); - req.open("GET", localFile, true); - req.send(); - - this.assertEquals(req.DONE, req.readyState, "readyState should be DONE"); - this.assertEquals(501, req.status, "status should be `501`"); - this.assertEquals("Not Implemented", req.statusText, "statusText should be `Not Implemented`"); - this.assertNotEquals(0, req.errorCode); - }); - - test("Test POST local file not implemented", function () { - var req = new XMLHttpRequest(); - req.open("POST", localFile, false); - req.send(); - - this.assertEquals(req.DONE, req.readyState, "readyState should be DONE"); - this.assertEquals(501, req.status, "status should be `501`"); - this.assertEquals("Not Implemented", req.statusText, "statusText should be `Not Implemented`"); - this.assertNotEquals(0, req.errorCode); - }); - - test("Test local file username and password not implemented", function () { - var req = new XMLHttpRequest(); - req.open("GET", localFile, false, "username", "password"); - req.send(); - - this.assertEquals(req.DONE, req.readyState, "readyState should be DONE"); - this.assertEquals(501, req.status, "status should be `501`"); - this.assertEquals("Not Implemented", req.statusText, "statusText should be `Not Implemented`"); - this.assertNotEquals(0, req.errorCode); - }); - -} else { - print("Local file operation not tested"); -} From eb816f7f6a4cef683236f783d02ae4df098287d9 Mon Sep 17 00:00:00 2001 From: Bradley Austin Davis Date: Tue, 31 Mar 2015 18:24:58 -0700 Subject: [PATCH 19/41] Adding support for eye per frame mode and offscreen render scaling --- interface/src/devices/OculusManager.cpp | 51 ++++++++++++++++--------- interface/src/devices/OculusManager.h | 8 +++- 2 files changed, 39 insertions(+), 20 deletions(-) diff --git a/interface/src/devices/OculusManager.cpp b/interface/src/devices/OculusManager.cpp index b04c8ae227..f5a4fb17e3 100644 --- a/interface/src/devices/OculusManager.cpp +++ b/interface/src/devices/OculusManager.cpp @@ -96,6 +96,12 @@ glm::quat OculusManager::_calibrationOrientation; quint64 OculusManager::_calibrationStartTime; int OculusManager::_calibrationMessage = NULL; glm::vec3 OculusManager::_eyePositions[ovrEye_Count]; +// TODO expose this as a developer toggle +bool OculusManager::_eyePerFrameMode = false; +ovrEyeType OculusManager::_lastEyeRendered = ovrEye_Count; +ovrSizei OculusManager::_recommendedTexSize = { 0, 0 }; +float OculusManager::_offscreenRenderScale = 1.0; + void OculusManager::initSdk() { ovr_Initialize(); @@ -148,20 +154,16 @@ void OculusManager::connect() { assert(configResult); - _renderTargetSize = { 0, 0 }; + _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 - ovrSizei recommendedTexSize = ovrHmd_GetFovTextureSize(_ovrHmd, eye, _eyeFov[eye], 1.0f); _eyeTextures[eye].Header.API = ovrRenderAPI_OpenGL; - _eyeTextures[eye].Header.RenderViewport.Pos = { _renderTargetSize.w, 0 }; - _eyeTextures[eye].Header.RenderViewport.Size = recommendedTexSize; - _renderTargetSize.w += recommendedTexSize.w; - _renderTargetSize.h = std::max(recommendedTexSize.h, _renderTargetSize.h); - }); - for_each_eye([&](ovrEyeType eye) { _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); ovrHmd_ConfigureTracking(_ovrHmd, ovrTrackingCap_Orientation | ovrTrackingCap_Position | @@ -362,9 +364,6 @@ void OculusManager::generateDistortionMesh() { // Allocate and generate distortion mesh vertices ovrDistortionMesh meshData; ovrHmd_CreateDistortionMesh(_ovrHmd, _eyeRenderDesc[eyeNum].Eye, _eyeRenderDesc[eyeNum].Fov, _ovrHmd->DistortionCaps, &meshData); - - ovrHmd_GetRenderScaleAndOffset(_eyeRenderDesc[eyeNum].Fov, _renderTargetSize, _eyeTextures[eyeNum].Header.RenderViewport, - _UVScaleOffset[eyeNum]); // Parse the vertex data and create a render ready vertex buffer DistortionVertex* pVBVerts = new DistortionVertex[meshData.VertexCount]; @@ -523,12 +522,20 @@ void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &p trackerPosition = bodyOrientation * trackerPosition; static ovrVector3f eyeOffsets[2] = { { 0, 0, 0 }, { 0, 0, 0 } }; - ovrPosef eyeRenderPose[ovrEye_Count]; - ovrHmd_GetEyePoses(_ovrHmd, _frameIndex, eyeOffsets, eyeRenderPose, nullptr); + ovrPosef eyePoses[ovrEye_Count]; + ovrHmd_GetEyePoses(_ovrHmd, _frameIndex, eyeOffsets, eyePoses, nullptr); ovrHmd_BeginFrame(_ovrHmd, _frameIndex); + static ovrPosef eyeRenderPose[ovrEye_Count]; //Render each eye into an fbo for_each_eye(_ovrHmd, [&](ovrEyeType eye){ - _activeEye = eye; + // If we're in eye-per-frame mode, only render one eye + // per call to display, and allow timewarp to correct for + // the other eye. Poor man's perf improvement + if (_eyePerFrameMode && eye == _lastEyeRendered) { + return; + } + _lastEyeRendered = _activeEye = eye; + eyeRenderPose[eye] = eyePoses[eye]; // Set the camera rotation for this eye orientation.x = eyeRenderPose[eye].Orientation.x; orientation.y = eyeRenderPose[eye].Orientation.y; @@ -558,7 +565,10 @@ void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &p glFrustum(-nearClip * port.LeftTan, nearClip * port.RightTan, -nearClip * port.DownTan, nearClip * port.UpTan, nearClip, farClip); - const ovrRecti & vp = _eyeTextures[eye].Header.RenderViewport; + ovrRecti & vp = _eyeTextures[eye].Header.RenderViewport; + 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); glMatrixMode(GL_MODELVIEW); @@ -602,7 +612,7 @@ void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &p glClear(GL_COLOR_BUFFER_BIT); glBindTexture(GL_TEXTURE_2D, finalFbo->texture()); - + //Renders the distorted mesh onto the screen renderDistortionMesh(eyeRenderPose); @@ -612,6 +622,7 @@ void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &p for_each_eye([&](ovrEyeType eye) { ovrGLTexture & glEyeTexture = reinterpret_cast(_eyeTextures[eye]); glEyeTexture.OGL.TexId = finalFbo->texture(); + }); ovrHmd_EndFrame(_ovrHmd, eyeRenderPose, _eyeTextures); @@ -639,9 +650,13 @@ void OculusManager::renderDistortionMesh(ovrPosef eyeRenderPose[ovrEye_Count]) { //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, _UVScaleOffset[eyeNum][1].y }; + GLfloat uvOffset[2] = { _UVScaleOffset[eyeNum][1].x, 1.0f - _UVScaleOffset[eyeNum][1].y }; _program.setUniformValueArray(_eyeToSourceUVOffsetLocation, uvOffset, 1, 2); ovrMatrix4f timeWarpMatrices[2]; diff --git a/interface/src/devices/OculusManager.h b/interface/src/devices/OculusManager.h index e0ec36f78a..e3fffb49f1 100644 --- a/interface/src/devices/OculusManager.h +++ b/interface/src/devices/OculusManager.h @@ -28,7 +28,7 @@ class Text3DOverlay; // 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 +#define OVR_CLIENT_DISTORTION 1 // On Win32 platforms, enabling Direct HMD requires that the SDK be @@ -148,7 +148,11 @@ private: static glm::quat _calibrationOrientation; static quint64 _calibrationStartTime; static int _calibrationMessage; - + // TODO drop this variable and use the existing 'Developer | Render | Scale Resolution' value + static ovrSizei _recommendedTexSize; + static float _offscreenRenderScale; + static bool _eyePerFrameMode; + static ovrEyeType _lastEyeRendered; }; From f22c7396429e66f2bd5e1999eb66c69fbe5ac284 Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Wed, 1 Apr 2015 16:26:55 +0200 Subject: [PATCH 20/41] updated gunscript --- examples/controllers/hydra/gun.js | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/examples/controllers/hydra/gun.js b/examples/controllers/hydra/gun.js index 8bea5d623e..da10b48634 100644 --- a/examples/controllers/hydra/gun.js +++ b/examples/controllers/hydra/gun.js @@ -4,6 +4,7 @@ // // Created by Brad Hefta-Gaub on 12/31/13. // Modified by Philip on 3/3/14 +// Modified by Thijs Wenker on 3/31/15 // Copyright 2013 High Fidelity, Inc. // // This is an example script that turns the hydra controllers and mouse into a entity gun. @@ -66,7 +67,7 @@ var impactSound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Guns/BulletIm var targetHitSound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Space%20Invaders/hit.raw"); var targetLaunchSound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Space%20Invaders/shoot.raw"); -var gunModel = "http://public.highfidelity.io/models/attachments/HaloGun.fst"; +var gunModel = "https://s3.amazonaws.com/hifi-public/cozza13/gun/m1911-handgun+1.fbx?v=4"; var audioOptions = { volume: 0.9 @@ -97,7 +98,7 @@ var reticle = Overlays.addOverlay("image", { y: screenSize.y / 2 - 16, width: 32, height: 32, - imageURL: HIFI_PUBLIC_BUCKET + "images/billiardsReticle.png", + imageURL: HIFI_PUBLIC_BUCKET + "images/gun/crosshairs.svg", color: { red: 255, green: 255, blue: 255}, alpha: 1 }); @@ -107,7 +108,7 @@ var offButton = Overlays.addOverlay("image", { y: 96, width: 32, height: 32, - imageURL: HIFI_PUBLIC_BUCKET + "images/close.png", + imageURL: HIFI_PUBLIC_BUCKET + "images/gun/close.svg", color: { red: 255, green: 255, blue: 255}, alpha: 1 }); @@ -117,7 +118,7 @@ var platformButton = Overlays.addOverlay("image", { y: 130, width: 32, height: 32, - imageURL: HIFI_PUBLIC_BUCKET + "images/city.png", + imageURL: HIFI_PUBLIC_BUCKET + "images/gun/platform-targets.svg", color: { red: 255, green: 255, blue: 255}, alpha: 1 }); @@ -126,7 +127,7 @@ var gridButton = Overlays.addOverlay("image", { y: 164, width: 32, height: 32, - imageURL: HIFI_PUBLIC_BUCKET + "images/blocks.png", + imageURL: HIFI_PUBLIC_BUCKET + "images/gun/floating-targets.svg", color: { red: 255, green: 255, blue: 255}, alpha: 1 }); @@ -163,7 +164,7 @@ function shootBullet(position, velocity, grenade) { { type: "Sphere", position: position, dimensions: { x: bSize, y: bSize, z: bSize }, - color: { red: 255, green: 0, blue: 0 }, + color: { red: 0, green: 0, blue: 0 }, velocity: bVelocity, lifetime: BULLET_LIFETIME, gravity: { x: 0, y: bGravity, z: 0 }, @@ -260,6 +261,7 @@ function makeGrid(type, scale, size) { } } } + function makePlatform(gravity, scale, size) { var separation = scale * 2; var pos = Vec3.sum(Camera.getPosition(), Vec3.multiply(10.0 * scale * separation, Quat.getFront(Camera.getOrientation()))); @@ -372,8 +374,8 @@ function takeFiringPose() { } } -MyAvatar.attach(gunModel, "RightHand", {x:0.02, y: 0.11, z: 0.04}, Quat.fromPitchYawRollDegrees(-0, -160, -79), 0.20); -MyAvatar.attach(gunModel, "LeftHand", {x:-0.02, y: 0.11, z: 0.04}, Quat.fromPitchYawRollDegrees(0, 0, 79), 0.20); +MyAvatar.attach(gunModel, "RightHand", {x:0.04, y: 0.22, z: 0.02}, Quat.fromPitchYawRollDegrees(-172, -85, 79), 0.40); +MyAvatar.attach(gunModel, "LeftHand", {x:-0.04, y: 0.22, z: 0.02}, Quat.fromPitchYawRollDegrees(-172, 85, -79), 0.40); // Give a bit of time to load before playing sound Script.setTimeout(playLoadSound, 2000); From cebd2705c487e9d814625201ba112b6ca0540b9b Mon Sep 17 00:00:00 2001 From: Bradley Austin Davis Date: Wed, 1 Apr 2015 11:06:22 -0700 Subject: [PATCH 21/41] Updating windows Oculus SDK to 0.5.0.1 --- cmake/externals/LibOVR/CMakeLists.txt | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/cmake/externals/LibOVR/CMakeLists.txt b/cmake/externals/LibOVR/CMakeLists.txt index d24c1771d1..650943db95 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.4.4.zip - URL_MD5 bcc9f41346ce13bd4334a8bc94875728 + URL http://static.oculus.com/sdk-downloads/ovr_sdk_win_0.5.0.1.zip + URL_MD5 d3fc4c02db9be5ff08af4ef4c97b32f9 CONFIGURE_COMMAND "" BUILD_COMMAND "" INSTALL_COMMAND "" @@ -20,14 +20,8 @@ if (WIN32) ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR) # FIXME need to account for different architectures - set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${SOURCE_DIR}/LibOVR/Lib/Win32/VS2013/libovr.lib CACHE TYPE INTERNAL) - set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG ${SOURCE_DIR}/LibOVR/Lib/Win32/VS2013/libovrd.lib CACHE TYPE INTERNAL) - set(${EXTERNAL_NAME_UPPER}_LIBRARY_EXTRAS setupapi winmm ws2_32) - - select_library_configurations(${EXTERNAL_NAME_UPPER}) - - set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SOURCE_DIR}/LibOVR/Include ${SOURCE_DIR}/LibOVR/Src CACHE TYPE INTERNAL) - set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${${EXTERNAL_NAME_UPPER}_LIBRARY} ${${EXTERNAL_NAME_UPPER}_LIBRARY_EXTRAS} CACHE TYPE INTERNAL) + set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SOURCE_DIR}/LibOVR/Include CACHE TYPE INTERNAL) + set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${SOURCE_DIR}/LibOVR/Lib/Windows/Win32/Release/VS2013/LibOVR.lib CACHE TYPE INTERNAL) elseif(APPLE) From e3ae6354c4a6b231316f0cee90a39c31f686e9b9 Mon Sep 17 00:00:00 2001 From: Bradley Austin Davis Date: Wed, 1 Apr 2015 11:08:13 -0700 Subject: [PATCH 22/41] Tie the Linux Oculus SDK to a given commit ID, so it can't invisibly break in the background in the repo is updted --- cmake/externals/LibOVR/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/cmake/externals/LibOVR/CMakeLists.txt b/cmake/externals/LibOVR/CMakeLists.txt index 650943db95..4fb584a8e0 100644 --- a/cmake/externals/LibOVR/CMakeLists.txt +++ b/cmake/externals/LibOVR/CMakeLists.txt @@ -55,6 +55,7 @@ elseif(NOT ANDROID) ${EXTERNAL_NAME} PREFIX ${EXTERNAL_NAME} GIT_REPOSITORY https://github.com/jherico/OculusSDK.git + GIT_TAG ed26cbafdd1d1d7cac0bc809147af15d161306ad CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH= LOG_DOWNLOAD ON ) From 71233780e9e7b6a6fbb4b55a61631961ac0640dc Mon Sep 17 00:00:00 2001 From: Bradley Austin Davis Date: Wed, 1 Apr 2015 11:26:24 -0700 Subject: [PATCH 23/41] Pointing to an Oculus SDK build that works on linux (I hope) --- cmake/externals/LibOVR/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/externals/LibOVR/CMakeLists.txt b/cmake/externals/LibOVR/CMakeLists.txt index 4fb584a8e0..2710548ebf 100644 --- a/cmake/externals/LibOVR/CMakeLists.txt +++ b/cmake/externals/LibOVR/CMakeLists.txt @@ -55,7 +55,7 @@ elseif(NOT ANDROID) ${EXTERNAL_NAME} PREFIX ${EXTERNAL_NAME} GIT_REPOSITORY https://github.com/jherico/OculusSDK.git - GIT_TAG ed26cbafdd1d1d7cac0bc809147af15d161306ad + GIT_TAG 915ecd363f4205364886642057eeb6b1259b2d3d CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH= LOG_DOWNLOAD ON ) From eb7d940ed9f1a27b2b9f3f9f4f0bc2530404f513 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 1 Apr 2015 11:36:05 -0700 Subject: [PATCH 24/41] Update edit.js lineHeight property handling --- examples/html/entityProperties.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/html/entityProperties.html b/examples/html/entityProperties.html index 1c5fd58084..df3836a3f5 100644 --- a/examples/html/entityProperties.html +++ b/examples/html/entityProperties.html @@ -312,7 +312,7 @@ } elTextText.value = properties.text; - elTextLineHeight.value = properties.lineHeight; + elTextLineHeight.value = properties.lineHeight.toFixed(4); elTextTextColorRed.value = properties.textColor.red; elTextTextColorGreen.value = properties.textColor.green; elTextTextColorBlue.value = properties.textColor.blue; @@ -723,7 +723,7 @@
Line Height
- +
From 51d3aba71c608fc36f5f14d564c9dd3a9b0ba1f5 Mon Sep 17 00:00:00 2001 From: Bradley Austin Davis Date: Wed, 1 Apr 2015 12:10:25 -0700 Subject: [PATCH 25/41] Restoring SDK install target --- cmake/externals/LibOVR/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/externals/LibOVR/CMakeLists.txt b/cmake/externals/LibOVR/CMakeLists.txt index 2710548ebf..ef437921d4 100644 --- a/cmake/externals/LibOVR/CMakeLists.txt +++ b/cmake/externals/LibOVR/CMakeLists.txt @@ -55,7 +55,7 @@ elseif(NOT ANDROID) ${EXTERNAL_NAME} PREFIX ${EXTERNAL_NAME} GIT_REPOSITORY https://github.com/jherico/OculusSDK.git - GIT_TAG 915ecd363f4205364886642057eeb6b1259b2d3d + GIT_TAG b9832379a401640c5f615ed75a60edaf09be64ef CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH= LOG_DOWNLOAD ON ) From 3b92910a9174d9f39421f7770aaa885f6ecec32f Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Wed, 1 Apr 2015 12:22:35 -0700 Subject: [PATCH 26/41] Adding the cookies sciprt that provide a simple ui useful for debug and exemple, complete the interface on the scene script interface to provide the getters --- examples/example/misc/sunLightExample.js | 97 +++++++++++++++---- interface/src/Application.cpp | 5 +- libraries/model/src/model/Stage.cpp | 4 +- .../src/SceneScriptingInterface.cpp | 27 ++++++ .../src/SceneScriptingInterface.h | 9 ++ libraries/script-engine/src/ScriptEngine.cpp | 3 - 6 files changed, 118 insertions(+), 27 deletions(-) diff --git a/examples/example/misc/sunLightExample.js b/examples/example/misc/sunLightExample.js index 42837c6836..e6c06bb1ae 100644 --- a/examples/example/misc/sunLightExample.js +++ b/examples/example/misc/sunLightExample.js @@ -8,27 +8,82 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -var intensity = 1.0; -var day = 0.0; -var hour = 12.0; -var longitude = 115.0; -var latitude = 31.0; -var stageOrientation = Quat.fromPitchYawRollDegrees(0.0, 180.0, 0.0); +Script.include("../../utilities/tools/cookies.js"); -Scene.setStageDayTime(hour); -Scene.setStageOrientation(stageOrientation); -Scene.setStageLocation(longitude, latitude, 0.0); -/* -function ticktack() { - hour += 0.1; - //Scene.setSunIntensity(Math.cos(time)); - if (hour > 24.0) { - hour = 0.0; - day++; - Scene.setStageYearTime(day); +var panel = new Panel(10, 400); + +panel.newSlider("Origin Longitude", -180, 180, + function(value) { Scene.setStageLocation(value, Scene.getStageLocationLatitude(), Scene.getStageLocationAltitude()); }, + function() { return Scene.getStageLocationLongitude(); }, + function(value) { return value.toFixed(0) + " deg"; } +); + +panel.newSlider("Origin Latitude", -90, 90, + function(value) { Scene.setStageLocation(Scene.getStageLocationLongitude(), value, Scene.getStageLocationAltitude()); }, + function() { return Scene.getStageLocationLatitude(); }, + function(value) { return value.toFixed(0) + " deg"; } +); + +panel.newSlider("Origin Altitude", 0, 1000, + function(value) { Scene.setStageLocation(Scene.getStageLocationLongitude(), Scene.getStageLocationLatitude(), value); }, + function() { return Scene.getStageLocationAltitude(); }, + function(value) { return (value).toFixed(0) + " km"; } +); + +panel.newSlider("Year Time", 0, 364, + function(value) { Scene.setStageYearTime(value); }, + function() { return Scene.getStageYearTime(); }, + function(value) { + var numDaysPerMonth = 365.0 / 12.0; + var monthly = (value / numDaysPerMonth); + var month = Math.floor(monthly); + return (month + 1).toFixed(0) + "/" + Math.ceil(0.5 + (monthly - month)*Math.ceil(numDaysPerMonth)).toFixed(0); } +); + +panel.newSlider("Day Time", 0, 24, + function(value) { Scene.setStageDayTime(value); }, + function() { return Scene.getStageDayTime(); }, + function(value) { + var hour = Math.floor(value); + return (hour).toFixed(0) + ":" + ((value - hour)*60.0).toFixed(0); } - Scene.setStageDayTime(hour); -} +); -Script.setInterval(ticktack, 41); -*/ \ No newline at end of file +var tickTackPeriod = 50; +var tickTackSpeed = 0.0; +panel.newSlider("Tick tack time", -1.0, 1.0, + function(value) { tickTackSpeed = value; }, + function() { return tickTackSpeed; }, + function(value) { return (value).toFixed(2); } +); + +function runStageTime() { + if (tickTackSpeed != 0.0) { + var hour = panel.get("Day Time"); + hour += tickTackSpeed; + panel.set("Day Time", hour); + + if (hour >= 24.0) { + panel.set("Year Time", panel.get("Year Time") + 1); + } else if (hour < 0.0) { + panel.set("Year Time", panel.get("Year Time") - 1); + } + } +} +Script.setInterval(runStageTime, tickTackPeriod); + +panel.newSlider("Light Intensity", 0.0, 5, + function(value) { Scene.setSunIntensity(value); }, + function() { return Scene.getSunIntensity(); }, + function(value) { return (value).toFixed(2); } +); + +Controller.mouseMoveEvent.connect(function panelMouseMoveEvent(event) { return panel.mouseMoveEvent(event); }); +Controller.mousePressEvent.connect( function panelMousePressEvent(event) { return panel.mousePressEvent(event); }); +Controller.mouseReleaseEvent.connect(function(event) { return panel.mouseReleaseEvent(event); }); + +function scriptEnding() { + Menu.removeMenu("Developer > Scene"); + panel.destroy(); +} +Script.scriptEnding.connect(scriptEnding); diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 7bab72ff0d..8aecd34f79 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -256,7 +256,8 @@ bool setupEssentials(int& argc, char** argv) { auto speechRecognizer = DependencyManager::set(); #endif auto discoverabilityManager = DependencyManager::set(); - + auto sceneScriptingInterface = DependencyManager::set(); + return true; } @@ -3586,6 +3587,8 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri scriptEngine->registerFunction(hmdInterface, "getHUDLookAtPosition2D", HMDScriptingInterface::getHUDLookAtPosition2D, 0); scriptEngine->registerFunction(hmdInterface, "getHUDLookAtPosition3D", HMDScriptingInterface::getHUDLookAtPosition3D, 0); + scriptEngine->registerGlobalObject("Scene", DependencyManager::get().data()); + #ifdef HAVE_RTMIDI scriptEngine->registerGlobalObject("MIDI", &MIDIManager::getInstance()); #endif diff --git a/libraries/model/src/model/Stage.cpp b/libraries/model/src/model/Stage.cpp index 1c171eee76..096ec273eb 100644 --- a/libraries/model/src/model/Stage.cpp +++ b/libraries/model/src/model/Stage.cpp @@ -92,8 +92,8 @@ void EarthSunModel::setSurfaceOrientation(const Quat& orientation) { double moduloRange(double val, double minVal, double maxVal) { double range = maxVal - minVal; double rval = (val - minVal) / range; - double intval; - return modf(rval, &intval) * range + minVal; + rval = rval - floor(rval); + return rval * range + minVal; } const float MAX_LONGITUDE = 180.0f; diff --git a/libraries/script-engine/src/SceneScriptingInterface.cpp b/libraries/script-engine/src/SceneScriptingInterface.cpp index 9cac521225..855701f536 100644 --- a/libraries/script-engine/src/SceneScriptingInterface.cpp +++ b/libraries/script-engine/src/SceneScriptingInterface.cpp @@ -20,20 +20,47 @@ void SceneScriptingInterface::setStageLocation(float longitude, float latitude, _skyStage->setOriginLocation(longitude, latitude, altitude); } +float SceneScriptingInterface::getStageLocationLongitude() const { + return _skyStage->getOriginLongitude(); +} +float SceneScriptingInterface::getStageLocationLatitude() const { + return _skyStage->getOriginLatitude(); +} +float SceneScriptingInterface::getStageLocationAltitude() const { + return _skyStage->getOriginSurfaceAltitude(); +} + void SceneScriptingInterface::setStageDayTime(float hour) { _skyStage->setDayTime(hour); } + +float SceneScriptingInterface::getStageDayTime() const { + return _skyStage->getDayTime(); +} + void SceneScriptingInterface::setStageYearTime(int day) { _skyStage->setYearTime(day); } +int SceneScriptingInterface::getStageYearTime() const { + return _skyStage->getYearTime(); +} + void SceneScriptingInterface::setSunColor(const glm::vec3& color) { _skyStage->setSunColor(color); } + +const glm::vec3& SceneScriptingInterface::getSunColor() const { + return _skyStage->getSunColor(); +} + void SceneScriptingInterface::setSunIntensity(float intensity) { _skyStage->setSunIntensity(intensity); } +float SceneScriptingInterface::getSunIntensity() const { + return _skyStage->getSunIntensity(); +} model::SunSkyStagePointer SceneScriptingInterface::getSkyStage() const { return _skyStage; diff --git a/libraries/script-engine/src/SceneScriptingInterface.h b/libraries/script-engine/src/SceneScriptingInterface.h index 8ae9424c95..0c36b303e9 100644 --- a/libraries/script-engine/src/SceneScriptingInterface.h +++ b/libraries/script-engine/src/SceneScriptingInterface.h @@ -24,12 +24,21 @@ class SceneScriptingInterface : public QObject, public Dependency { public: Q_INVOKABLE void setStageOrientation(const glm::quat& orientation); + Q_INVOKABLE void setStageLocation(float longitude, float latitude, float altitude); + Q_INVOKABLE float getStageLocationLongitude() const; + Q_INVOKABLE float getStageLocationLatitude() const; + Q_INVOKABLE float getStageLocationAltitude() const; + Q_INVOKABLE void setStageDayTime(float hour); + Q_INVOKABLE float getStageDayTime() const; Q_INVOKABLE void setStageYearTime(int day); + Q_INVOKABLE int getStageYearTime() const; Q_INVOKABLE void setSunColor(const glm::vec3& color); + Q_INVOKABLE const glm::vec3& getSunColor() const; Q_INVOKABLE void setSunIntensity(float intensity); + Q_INVOKABLE float getSunIntensity() const; model::SunSkyStagePointer getSkyStage() const; diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index c31f5be46a..390b889579 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -305,8 +305,6 @@ void ScriptEngine::init() { _isInitialized = true; - auto sceneScriptingInterface = DependencyManager::set(); - auto entityScriptingInterface = DependencyManager::get(); entityScriptingInterface->init(); @@ -350,7 +348,6 @@ void ScriptEngine::init() { registerGlobalObject("Vec3", &_vec3Library); registerGlobalObject("Uuid", &_uuidLibrary); registerGlobalObject("AnimationCache", DependencyManager::get().data()); - registerGlobalObject("Scene", DependencyManager::get().data()); // constants globalObject().setProperty("TREE_SCALE", newVariant(QVariant(TREE_SCALE))); From 695a5bcfd7551d8bd1d554e18b61eb273ad87a34 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Wed, 1 Apr 2015 12:23:31 -0700 Subject: [PATCH 27/41] Adding the cookies sciprt that provide a simple ui useful for debug and example, complete the interface on the scene script interface to provide the getters --- examples/utilities/tools/cookies.js | 278 ++++++++++++++++++++++++++++ 1 file changed, 278 insertions(+) create mode 100755 examples/utilities/tools/cookies.js diff --git a/examples/utilities/tools/cookies.js b/examples/utilities/tools/cookies.js new file mode 100755 index 0000000000..541f3b16f9 --- /dev/null +++ b/examples/utilities/tools/cookies.js @@ -0,0 +1,278 @@ +// +// cookies.js +// +// version 1.0 +// +// Created by Sam Gateau, 4/1/2015 +// A simple ui panel that present a list of porperties and the proper widget to edit it +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +// The Slider class +Slider = function(x,y,width,thumbSize) { + + this.thumb = Overlays.addOverlay("text", { + backgroundColor: { red: 255, green: 255, blue: 255 }, + x: x, + y: y, + width: thumbSize, + height: thumbSize, + alpha: 1.0, + backgroundAlpha: 1.0, + visible: true + }); + this.background = Overlays.addOverlay("text", { + backgroundColor: { red: 125, green: 125, blue: 255 }, + x: x, + y: y, + width: width, + height: thumbSize, + alpha: 1.0, + backgroundAlpha: 0.5, + visible: true + }); + + this.thumbSize = thumbSize; + this.thumbHalfSize = 0.5 * thumbSize; + + this.minThumbX = x + this.thumbHalfSize; + this.maxThumbX = x + width - this.thumbHalfSize; + this.thumbX = this.minThumbX; + + this.minValue = 0.0; + this.maxValue = 1.0; + + this.clickOffsetX = 0; + this.isMoving = false; + + this.updateThumb = function() { + thumbTruePos = this.thumbX - 0.5 * this.thumbSize; + Overlays.editOverlay(this.thumb, { x: thumbTruePos } ); + }; + + this.onMouseMoveEvent = function(event) { + if (this.isMoving) { + newThumbX = event.x - this.clickOffsetX; + if (newThumbX < this.minThumbX) { + newThumbX = this.minThumbX; + } + if (newThumbX > this.maxThumbX) { + newThumbX = this.maxThumbX; + } + this.thumbX = newThumbX; + this.updateThumb(); + this.onValueChanged(this.getValue()); + } + }; + + this.onMousePressEvent = function(event) { + this.isMoving = true; + var clickOffset = event.x - this.thumbX; + if ((clickOffset > -this.thumbHalfSize) && (clickOffset < this.thumbHalfSize)) { + this.clickOffsetX = clickOffset; + } else { + this.clickOffsetX = 0; + this.thumbX = event.x; + this.updateThumb(); + this.onValueChanged(this.getValue()); + } + + }; + + this.onMouseReleaseEvent = function(event) { + this.isMoving = false; + }; + + // Public members: + + this.setNormalizedValue = function(value) { + if (value < 0.0) { + this.thumbX = this.minThumbX; + } else if (value > 1.0) { + this.thumbX = this.maxThumbX; + } else { + this.thumbX = value * (this.maxThumbX - this.minThumbX) + this.minThumbX; + } + this.updateThumb(); + }; + this.getNormalizedValue = function() { + return (this.thumbX - this.minThumbX) / (this.maxThumbX - this.minThumbX); + }; + + this.setValue = function(value) { + var normValue = (value - this.minValue) / (this.maxValue - this.minValue); + this.setNormalizedValue(normValue); + }; + + this.getValue = function() { + return this.getNormalizedValue() * (this.maxValue - this.minValue) + this.minValue; + }; + + this.onValueChanged = function(value) {}; + + this.destroy = function() { + Overlays.deleteOverlay(this.background); + Overlays.deleteOverlay(this.thumb); + }; +} + + +var textFontSize = 16; + +function PanelItem(name, setter, getter, displayer, x, y, textWidth, valueWidth, height) { + this.name = name; + + + this.displayer = typeof displayer !== 'undefined' ? displayer : function(value) { return value.toFixed(2); }; + + var topMargin = (height - textFontSize); + this.title = Overlays.addOverlay("text", { + backgroundColor: { red: 255, green: 255, blue: 255 }, + x: x, + y: y, + width: textWidth, + height: height, + alpha: 1.0, + backgroundAlpha: 0.5, + visible: true, + text: name, + font: {size: textFontSize}, + topMargin: topMargin, + }); + + this.value = Overlays.addOverlay("text", { + backgroundColor: { red: 255, green: 255, blue: 255 }, + x: x + textWidth, + y: y, + width: valueWidth, + height: height, + alpha: 1.0, + backgroundAlpha: 0.5, + visible: true, + text: this.displayer(getter()), + font: {size: textFontSize}, + topMargin: topMargin + + }); + this.getter = getter; + + this.setter = function(value) { + setter(value); + Overlays.editOverlay(this.value, {text: this.displayer(getter())}); + if (this.widget) { + this.widget.setValue(value); + } + }; + this.setterFromWidget = function(value) { + setter(value); + Overlays.editOverlay(this.value, {text: this.displayer(getter())}); + }; + + + this.widget = null; + + this.destroy = function() { + Overlays.deleteOverlay(this.title); + Overlays.deleteOverlay(this.value); + if (this.widget != null) { + this.widget.destroy(); + } + } +} + +var textWidth = 180; +var valueWidth = 100; +var widgetWidth = 300; +var rawHeight = 20; +var rawYDelta = rawHeight * 1.5; + +Panel = function(x, y) { + + this.x = x; + this.y = y; + this.nextY = y; + + this.widgetX = x + textWidth + valueWidth; + + this.items = new Array(); + this.activeWidget = null; + + this.mouseMoveEvent = function(event) { + if (this.activeWidget) { + this.activeWidget.onMouseMoveEvent(event); + } + }; + + // we also handle click detection in our mousePressEvent() + this.mousePressEvent = function(event) { + // Make sure we quitted previous widget + if (this.activeWidget) { + this.activeWidget.onMouseReleaseEvent(event); + } + this.activeWidget = null; + + var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y}); + + // If the user clicked any of the slider background then... + for (i in this.items) { + widget = this.items[i].widget; + + if (clickedOverlay == widget.background) { + this.activeWidget = widget; + this.activeWidget.onMousePressEvent(event); + // print("clicked... widget=" + i); + break; + } + } + }; + + this.mouseReleaseEvent = function(event) { + if (this.activeWidget) { + this.activeWidget.onMouseReleaseEvent(event); + } + this.activeWidget = null; + }; + + this.newSlider = function(name, minValue, maxValue, setValue, getValue, displayValue) { + + var sliderItem = new PanelItem(name, setValue, getValue, displayValue, this.x, this.nextY, textWidth, valueWidth, rawHeight); + + var slider = new Slider(this.widgetX, this.nextY, widgetWidth, rawHeight); + slider.minValue = minValue; + slider.maxValue = maxValue; + slider.onValueChanged = function(value) { sliderItem.setterFromWidget(value); }; + + + sliderItem.widget = slider; + sliderItem.setter(getValue()); + this.items[name] = sliderItem; + this.nextY += rawYDelta; + // print("created Item... slider=" + name); + }; + + this.destroy = function() { + for (i in this.items) { + this.items[i].destroy(); + } + } + + this.set = function(name, value) { + var item = this.items[name]; + if (item != null) { + return item.setter(value); + } + return null; + } + + this.get = function(name) { + var item = this.items[name]; + if (item != null) { + return item.getter(); + } + return null; + } +}; + + From c835fb63c391fcf99b95d850c55140403b1647f2 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 1 Apr 2015 12:52:46 -0700 Subject: [PATCH 28/41] Add select all on focus behavior to entity properties window --- examples/html/entityProperties.html | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/examples/html/entityProperties.html b/examples/html/entityProperties.html index 1c5fd58084..cdd0fa4773 100644 --- a/examples/html/entityProperties.html +++ b/examples/html/entityProperties.html @@ -477,6 +477,28 @@ ev.initEvent("change", true, true); document.activeElement.dispatchEvent(ev); } + + // For input and textarea elements, select all of the text on focus + // WebKit-based browsers, such as is used with QWebView, have a quirk + // where the mouseup event comes after the focus event, causing the + // text to be deselected immediately after selecting all of the text. + // To make this work we block the first mouseup event after the elements + // received focus. If we block all mouseup events the user will not + // be able to click within the selected text. + var els = document.querySelectorAll("input, textarea"); + for (var i = 0; i < els.length; i++) { + var clicked = false; + els[i].onfocus = function() { + this.select(); + clicked = false; + }; + els[i].onmouseup = function(e) { + if (!clicked) { + e.preventDefault(); + clicked = true; + } + }; + } } From a7dc1d26e6548695785bbc074c17a64d929d40ad Mon Sep 17 00:00:00 2001 From: Bradley Austin Davis Date: Wed, 1 Apr 2015 13:23:55 -0700 Subject: [PATCH 29/41] Working on SDK vs client distortion performance differences --- interface/src/devices/OculusManager.cpp | 30 ++++++++++++++++++++----- interface/src/devices/OculusManager.h | 2 +- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/interface/src/devices/OculusManager.cpp b/interface/src/devices/OculusManager.cpp index f5a4fb17e3..2aa32fcc29 100644 --- a/interface/src/devices/OculusManager.cpp +++ b/interface/src/devices/OculusManager.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include @@ -424,13 +425,9 @@ void OculusManager::beginFrameTiming() { } bool OculusManager::allowSwap() { -#ifdef OVR_CLIENT_DISTORTION - return true; -#else return false; -#endif - } + //Ends frame timing void OculusManager::endFrameTiming() { #ifdef OVR_CLIENT_DISTORTION @@ -446,9 +443,18 @@ void OculusManager::configureCamera(Camera& camera, int screenWidth, int screenH camera.setFieldOfView(atan(_eyeFov[0].UpTan) * DEGREES_PER_RADIAN * 2.0f); } +static bool timerActive = false; //Displays everything for the oculus, frame timing must be active void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &position, Camera& whichCamera) { auto glCanvas = Application::getInstance()->getGLWidget(); + static QOpenGLTimerQuery timerQuery; + if (!timerQuery.isCreated()) { + timerQuery.create(); + } + if (timerActive && timerQuery.isResultAvailable()) { + qDebug() << timerQuery.waitForResult(); + timerActive = false; + } #ifdef OVR_DIRECT_MODE static bool attached = false; @@ -602,8 +608,13 @@ void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &p // restore our normal viewport glViewport(0, 0, glCanvas->getDeviceWidth(), glCanvas->getDeviceHeight()); - + + if (!timerActive) { + timerQuery.begin(); + } + #ifdef OVR_CLIENT_DISTORTION + //Wait till time-warp to reduce latency ovr_WaitTillTime(_hmdFrameTiming.TimewarpPointSeconds); @@ -617,8 +628,10 @@ void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &p renderDistortionMesh(eyeRenderPose); glBindTexture(GL_TEXTURE_2D, 0); + glCanvas->swapBuffers(); #else + for_each_eye([&](ovrEyeType eye) { ovrGLTexture & glEyeTexture = reinterpret_cast(_eyeTextures[eye]); glEyeTexture.OGL.TexId = finalFbo->texture(); @@ -626,7 +639,12 @@ void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &p }); ovrHmd_EndFrame(_ovrHmd, eyeRenderPose, _eyeTextures); + #endif + if (!timerActive) { + timerQuery.end(); + timerActive = true; + } } #ifdef OVR_CLIENT_DISTORTION diff --git a/interface/src/devices/OculusManager.h b/interface/src/devices/OculusManager.h index e3fffb49f1..6c23776e18 100644 --- a/interface/src/devices/OculusManager.h +++ b/interface/src/devices/OculusManager.h @@ -39,7 +39,7 @@ class Text3DOverlay; // 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 +#define OVR_DIRECT_MODE 1 /// Handles interaction with the Oculus Rift. From 9918357724b887fbc11b8b52832b0fdbd19f04ab Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Wed, 1 Apr 2015 13:37:41 -0700 Subject: [PATCH 30/41] fix var declaration issues --- examples/utilities/tools/cookies.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/utilities/tools/cookies.js b/examples/utilities/tools/cookies.js index 541f3b16f9..205b19c9f9 100755 --- a/examples/utilities/tools/cookies.js +++ b/examples/utilities/tools/cookies.js @@ -216,8 +216,8 @@ Panel = function(x, y) { var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y}); // If the user clicked any of the slider background then... - for (i in this.items) { - widget = this.items[i].widget; + for (var i in this.items) { + var widget = this.items[i].widget; if (clickedOverlay == widget.background) { this.activeWidget = widget; @@ -253,7 +253,7 @@ Panel = function(x, y) { }; this.destroy = function() { - for (i in this.items) { + for (var i in this.items) { this.items[i].destroy(); } } From aac824fb993a4b69e108e8ea393abbce7cad5c37 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 1 Apr 2015 13:47:25 -0700 Subject: [PATCH 31/41] fix crash on shutdown --- interface/src/Application.cpp | 3 +++ libraries/entities-renderer/src/EntityTreeRenderer.cpp | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 7bab72ff0d..6311c0afef 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -566,6 +566,9 @@ void Application::aboutToQuit() { } void Application::cleanupBeforeQuit() { + + _entities.clear(); // this will allow entity scripts to properly shutdown + _datagramProcessor->shutdown(); // tell the datagram processor we're shutting down, so it can short circuit _entities.shutdown(); // tell the entities system we're shutting down, so it will stop running scripts ScriptEngine::stopAllScripts(this); // stop all currently running global scripts diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 95ca30a90f..be87d2c993 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -969,6 +969,10 @@ void EntityTreeRenderer::checkAndCallUnload(const EntityItemID& entityID) { QScriptValueList entityArgs = createEntityArgs(entityID); entityScript.property("unload").call(entityScript, entityArgs); } + + // In the event that the entity script connected to any of our signals + // we want to disconnect it so we don't have anything dangling + _entitiesScriptEngine->disconnect(entityScript.toQObject()); } } From d6f43287dc8dace01b7516d132babac770691a67 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 1 Apr 2015 14:21:43 -0700 Subject: [PATCH 32/41] pull the lobby from default scripts to avoid permanent iron man --- examples/defaultScripts.js | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/defaultScripts.js b/examples/defaultScripts.js index 05ffb0bd3f..9d2a74fe56 100644 --- a/examples/defaultScripts.js +++ b/examples/defaultScripts.js @@ -14,7 +14,6 @@ Script.load("selectAudioDevice.js"); Script.load("controllers/hydra/hydraMove.js"); Script.load("headMove.js"); Script.load("inspect.js"); -Script.load("lobby.js"); Script.load("notifications.js"); Script.load("look.js"); Script.load("users.js"); From d7188bac0bc5ccd39713f14fd701da4ebb1b52fe Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 1 Apr 2015 14:38:01 -0700 Subject: [PATCH 33/41] another approach --- libraries/entities-renderer/src/EntityTreeRenderer.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index be87d2c993..972a385b49 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -81,6 +81,7 @@ void EntityTreeRenderer::clear() { } OctreeRenderer::clear(); _entityScripts.clear(); + _entitiesScriptEngine->disconnect(); } void EntityTreeRenderer::init() { @@ -969,10 +970,6 @@ void EntityTreeRenderer::checkAndCallUnload(const EntityItemID& entityID) { QScriptValueList entityArgs = createEntityArgs(entityID); entityScript.property("unload").call(entityScript, entityArgs); } - - // In the event that the entity script connected to any of our signals - // we want to disconnect it so we don't have anything dangling - _entitiesScriptEngine->disconnect(entityScript.toQObject()); } } From c66db5d8e4510207ae2eb26ab90779ecce4e810a Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 1 Apr 2015 14:43:27 -0700 Subject: [PATCH 34/41] another approach --- libraries/entities-renderer/src/EntityTreeRenderer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 972a385b49..666304f5ca 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -2,7 +2,7 @@ // EntityTreeRenderer.cpp // interface/src // -// Created by Brad Hefta-Gaub on 12/6/13. +// Created by Brad Hefta>Gaub on 12/6/13. // Copyright 2013 High Fidelity, Inc. // // Distributed under the Apache License, Version 2.0. @@ -81,7 +81,6 @@ void EntityTreeRenderer::clear() { } OctreeRenderer::clear(); _entityScripts.clear(); - _entitiesScriptEngine->disconnect(); } void EntityTreeRenderer::init() { @@ -108,6 +107,7 @@ void EntityTreeRenderer::init() { } void EntityTreeRenderer::shutdown() { + _entitiesScriptEngine->disconnect(); // disconnect all slots/signals from the script engine _shuttingDown = true; } From 526c9217a13d0a0b9edd436ef4dad6687a59ab81 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 1 Apr 2015 14:43:56 -0700 Subject: [PATCH 35/41] fix signup link from login dialog --- interface/src/ui/LoginDialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/ui/LoginDialog.cpp b/interface/src/ui/LoginDialog.cpp index e83b06e144..b134f7f230 100644 --- a/interface/src/ui/LoginDialog.cpp +++ b/interface/src/ui/LoginDialog.cpp @@ -24,7 +24,7 @@ #include "LoginDialog.h" #include "UIUtil.h" -const QString CREATE_ACCOUNT_URL = NetworkingConstants::METAVERSE_SERVER_URL.toString() + "/create"; +const QString CREATE_ACCOUNT_URL = NetworkingConstants::METAVERSE_SERVER_URL.toString() + "/signup"; const QString FORGOT_PASSWORD_URL = NetworkingConstants::METAVERSE_SERVER_URL.toString() + "/users/password/new"; LoginDialog::LoginDialog(QWidget* parent) : From d87fe9efffbb730432b15fd8468daf24271ad798 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 1 Apr 2015 14:47:04 -0700 Subject: [PATCH 36/41] fix typo --- libraries/entities-renderer/src/EntityTreeRenderer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 666304f5ca..5c35a9c256 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -2,7 +2,7 @@ // EntityTreeRenderer.cpp // interface/src // -// Created by Brad Hefta>Gaub on 12/6/13. +// Created by Brad Hefta-Gaub on 12/6/13. // Copyright 2013 High Fidelity, Inc. // // Distributed under the Apache License, Version 2.0. From fd47d4f3a57ca4e8aaa9012737f0b6133a5ccb02 Mon Sep 17 00:00:00 2001 From: Bradley Austin Davis Date: Wed, 1 Apr 2015 15:47:51 -0700 Subject: [PATCH 37/41] Working on putting some more timing measurement into the code --- interface/src/devices/OculusManager.cpp | 44 ++++++++++++++++++++++--- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/interface/src/devices/OculusManager.cpp b/interface/src/devices/OculusManager.cpp index 2aa32fcc29..cf319b5671 100644 --- a/interface/src/devices/OculusManager.cpp +++ b/interface/src/devices/OculusManager.cpp @@ -165,7 +165,7 @@ void OculusManager::connect() { }); _eyeTextures[ovrEye_Right].Header.RenderViewport.Pos.x = _recommendedTexSize.w; - ovrHmd_SetEnabledCaps(_ovrHmd, ovrHmdCap_LowPersistence); + ovrHmd_SetEnabledCaps(_ovrHmd, ovrHmdCap_LowPersistence | ovrHmdCap_DynamicPrediction); ovrHmd_ConfigureTracking(_ovrHmd, ovrTrackingCap_Orientation | ovrTrackingCap_Position | ovrTrackingCap_MagYawCorrection, @@ -447,12 +447,27 @@ static bool timerActive = false; //Displays everything for the oculus, frame timing must be active void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &position, Camera& whichCamera) { auto glCanvas = Application::getInstance()->getGLWidget(); + +#ifdef DEBUG + // Ensure the frame counter always increments by exactly 1 + static int oldFrameIndex = -1; + assert(oldFrameIndex == -1 || oldFrameIndex == _frameIndex - 1); + oldFrameIndex = _frameIndex; +#endif + + // Every so often do some additional timing calculations and debug output + bool debugFrame = 0 == _frameIndex % 400; + + // Try to measure the amount of time taken to do the distortion + // (does not seem to work on OSX with SDK based distortion) static QOpenGLTimerQuery timerQuery; if (!timerQuery.isCreated()) { timerQuery.create(); } + if (timerActive && timerQuery.isResultAvailable()) { - qDebug() << timerQuery.waitForResult(); + auto result = timerQuery.waitForResult(); + if (result) { qDebug() << "Distortion took " << result << "ns"; }; timerActive = false; } @@ -609,7 +624,7 @@ void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &p // restore our normal viewport glViewport(0, 0, glCanvas->getDeviceWidth(), glCanvas->getDeviceHeight()); - if (!timerActive) { + if (debugFrame && !timerActive) { timerQuery.begin(); } @@ -641,10 +656,31 @@ void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &p ovrHmd_EndFrame(_ovrHmd, eyeRenderPose, _eyeTextures); #endif - if (!timerActive) { + if (debugFrame && !timerActive) { timerQuery.end(); timerActive = true; } + + // No DK2, no message. + char latency2Text[128] = ""; + { + 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) + { + qDebug() << 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 From 4a6046b07c00efdfa4483a89209f33c638b38016 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Wed, 1 Apr 2015 15:50:04 -0700 Subject: [PATCH 38/41] tweak the default specular value for the Primitive entities (sphere and cubes) so they do not shine so much --- interface/src/Application.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 8aecd34f79..5275b8c529 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2766,7 +2766,7 @@ void Application::updateShadowMap() { const GLfloat WORLD_AMBIENT_COLOR[] = { 0.525f, 0.525f, 0.6f }; const GLfloat WORLD_DIFFUSE_COLOR[] = { 0.6f, 0.525f, 0.525f }; -const GLfloat WORLD_SPECULAR_COLOR[] = { 0.94f, 0.94f, 0.737f, 1.0f }; +const GLfloat WORLD_SPECULAR_COLOR[] = { 0.08f, 0.08f, 0.08f, 1.0f }; const glm::vec3 GLOBAL_LIGHT_COLOR = { 0.6f, 0.525f, 0.525f }; From 0f518b6dbd0d760c7c6c72064d61fc74f7aaf7cb Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 1 Apr 2015 16:02:21 -0700 Subject: [PATCH 39/41] Update styling of property spinners in edit.js --- examples/html/style.css | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/examples/html/style.css b/examples/html/style.css index baa159df74..de71fe6dda 100644 --- a/examples/html/style.css +++ b/examples/html/style.css @@ -275,3 +275,36 @@ td { font-weight: bold; font-style: italic; } + +input[type="number"] { + position: relative; +} + +/* Spin Buttons modified - credit for original implementation goes to http://jsfiddle.net/Volker_E/WwfW9/ */ +input[type="number"]::-webkit-outer-spin-button, +input[type="number"]::-webkit-inner-spin-button { + -webkit-appearance: none; + background: #FFF url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAJCAYAAADgkQYQAAAAKUlEQVQYlWNgwAT/sYhhKPiPT+F/LJgEsHv37v+EMGkmkuImoh2NoQAANlcun/q4OoYAAAAASUVORK5CYII=) no-repeat center center; + width: 0.9em; + height: 4px; + opacity: 0.5; /* shows Spin Buttons per default (Chrome >= 39) */ + top: 0; + right: 0; + bottom: 0; + border-top-left-radius: 3px; + border-top-right-radius: 3px; + border-bottom-right-radius: 3px; + border-bottom-left-radius: 3px; +} + +input[type="number"]::-webkit-inner-spin-button:hover, +input[type="number"]::-webkit-inner-spin-button:active{ + opacity: .8; +} + +/* Override browser form filling */ +input:-webkit-autofill { + background: black; + color: red; +} + From 775bbdaebb245e10f8fa4cc882010a4cb43ee579 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 1 Apr 2015 16:04:52 -0700 Subject: [PATCH 40/41] Remove unnecessary css --- examples/html/style.css | 7 ------- 1 file changed, 7 deletions(-) diff --git a/examples/html/style.css b/examples/html/style.css index de71fe6dda..02f02b9649 100644 --- a/examples/html/style.css +++ b/examples/html/style.css @@ -301,10 +301,3 @@ input[type="number"]::-webkit-inner-spin-button:hover, input[type="number"]::-webkit-inner-spin-button:active{ opacity: .8; } - -/* Override browser form filling */ -input:-webkit-autofill { - background: black; - color: red; -} - From 58908f44ef35876475d91776401c27e2f9cce890 Mon Sep 17 00:00:00 2001 From: Bradley Austin Davis Date: Wed, 1 Apr 2015 16:05:46 -0700 Subject: [PATCH 41/41] Fixing crash on exit when using (or used) VR mode --- interface/src/devices/OculusManager.cpp | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/interface/src/devices/OculusManager.cpp b/interface/src/devices/OculusManager.cpp index cf319b5671..db10298583 100644 --- a/interface/src/devices/OculusManager.cpp +++ b/interface/src/devices/OculusManager.cpp @@ -458,8 +458,11 @@ void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &p // 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 QOpenGLTimerQuery timerQuery; if (!timerQuery.isCreated()) { timerQuery.create(); @@ -470,7 +473,8 @@ void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &p if (result) { qDebug() << "Distortion took " << result << "ns"; }; timerActive = false; } - +#endif + #ifdef OVR_DIRECT_MODE static bool attached = false; if (!attached) { @@ -623,11 +627,13 @@ void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &p // restore our normal viewport glViewport(0, 0, glCanvas->getDeviceWidth(), glCanvas->getDeviceHeight()); - + +#if 0 if (debugFrame && !timerActive) { timerQuery.begin(); } - +#endif + #ifdef OVR_CLIENT_DISTORTION //Wait till time-warp to reduce latency @@ -656,11 +662,14 @@ void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &p ovrHmd_EndFrame(_ovrHmd, eyeRenderPose, _eyeTextures); #endif + +#if 0 if (debugFrame && !timerActive) { timerQuery.end(); timerActive = true; } - +#endif + // No DK2, no message. char latency2Text[128] = ""; {