From d3b37684cd0d14948529328004b9f00fdd84d33a Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 2 Oct 2014 20:02:51 -0700 Subject: [PATCH 01/22] Add VR display auto-calibration logic --- interface/src/Application.cpp | 4 ++ interface/src/Application.h | 3 +- interface/src/devices/OculusManager.cpp | 79 +++++++++++++++++++++++++ interface/src/devices/OculusManager.h | 21 +++++++ 4 files changed, 106 insertions(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index d41b50a232..da7dd5bb25 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1082,6 +1082,9 @@ void Application::keyPressEvent(QKeyEvent* event) { case Qt::Key_Equal: _myAvatar->resetSize(); break; + case Qt::Key_Escape: + OculusManager::abandonCalibration(); + break; default: event->ignore(); break; @@ -1474,6 +1477,7 @@ void Application::setEnableVRMode(bool enableVRMode) { OculusManager::disconnect(); OculusManager::connect(); } + OculusManager::recalibrate(); } resizeGL(_glWidget->getDeviceWidth(), _glWidget->getDeviceHeight()); diff --git a/interface/src/Application.h b/interface/src/Application.h index ca26cffab8..fa0733f5e3 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -365,6 +365,8 @@ public slots: void domainSettingsReceived(const QJsonObject& domainSettingsObject); + void resetSensors(); + private slots: void timer(); void idle(); @@ -381,7 +383,6 @@ private slots: void closeMirrorView(); void restoreMirrorView(); void shrinkMirrorView(); - void resetSensors(); void parseVersionXml(); diff --git a/interface/src/devices/OculusManager.cpp b/interface/src/devices/OculusManager.cpp index 65518b839c..99892e98be 100644 --- a/interface/src/devices/OculusManager.cpp +++ b/interface/src/devices/OculusManager.cpp @@ -55,6 +55,16 @@ bool OculusManager::_programInitialized = false; Camera* OculusManager::_camera = NULL; int OculusManager::_activeEyeIndex = -1; +float OculusManager::CALIBRATION_DELTA_MINIMUM_LENGTH = 0.02f; +float OculusManager::CALIBRATION_DELTA_MINIMUM_ANGLE = 5.f * RADIANS_PER_DEGREE; +float OculusManager::CALIBRATION_ZERO_MAXIMUM_LENGTH = 0.01f; +float OculusManager::CALIBRATION_ZERO_MAXIMUM_ANGLE = 0.5f * RADIANS_PER_DEGREE; +quint64 OculusManager::CALIBRATION_ZERO_HOLD_TIME = 3000000; // usec +OculusManager::CalibrationState OculusManager::_calibrationState; +glm::vec3 OculusManager::_calibrationPosition; +glm::quat OculusManager::_calibrationOrientation; +quint64 OculusManager::_calibrationStartTime; + #endif glm::vec3 OculusManager::_leftEyePosition = glm::vec3(); @@ -62,6 +72,8 @@ glm::vec3 OculusManager::_rightEyePosition = glm::vec3(); void OculusManager::connect() { #ifdef HAVE_LIBOVR + _calibrationState = UNCALIBRATED; + ovr_Initialize(); _ovrHmd = ovrHmd_Create(0); @@ -172,6 +184,67 @@ void OculusManager::disconnect() { #endif } +void OculusManager::calibrate(glm::vec3 position, glm::quat orientation) { +#ifdef HAVE_LIBOVR + switch (_calibrationState) { + + case UNCALIBRATED: + if (position != glm::vec3() && orientation != glm::quat()) { // Handle zero values at start-up. + _calibrationPosition = position; + _calibrationOrientation = orientation; + _calibrationState = WAITING_FOR_DELTA; + } + break; + + case WAITING_FOR_DELTA: + if (glm::length(position - _calibrationPosition) > CALIBRATION_DELTA_MINIMUM_LENGTH + || glm::angle(orientation * glm::inverse(_calibrationOrientation)) > CALIBRATION_DELTA_MINIMUM_ANGLE) { + _calibrationPosition = position; + _calibrationOrientation = orientation; + _calibrationState = WAITING_FOR_ZERO; + } + break; + + case WAITING_FOR_ZERO: + if (glm::length(position - _calibrationPosition) < CALIBRATION_ZERO_MAXIMUM_LENGTH + && glm::angle(orientation * glm::inverse(_calibrationOrientation)) < CALIBRATION_ZERO_MAXIMUM_ANGLE) { + _calibrationStartTime = usecTimestampNow(); + _calibrationState = WAITING_FOR_ZERO_HELD; + } else { + _calibrationPosition = position; + _calibrationOrientation = orientation; + } + break; + + case WAITING_FOR_ZERO_HELD: + if (glm::length(position - _calibrationPosition) < CALIBRATION_ZERO_MAXIMUM_LENGTH + && glm::angle(orientation * glm::inverse(_calibrationOrientation)) < CALIBRATION_ZERO_MAXIMUM_ANGLE) { + if ((usecTimestampNow() - _calibrationStartTime) > CALIBRATION_ZERO_HOLD_TIME) { + _calibrationState = CALIBRATED; + Application::getInstance()->resetSensors(); + } + } else { + _calibrationPosition = position; + _calibrationOrientation = orientation; + _calibrationState = WAITING_FOR_ZERO; + } + break; + } +#endif +} + +void OculusManager::recalibrate() { +#ifdef HAVE_LIBOVR + _calibrationState = UNCALIBRATED; +#endif +} + +void OculusManager::abandonCalibration() { +#ifdef HAVE_LIBOVR + _calibrationState = CALIBRATED; +#endif +} + #ifdef HAVE_LIBOVR void OculusManager::generateDistortionMesh() { @@ -330,6 +403,12 @@ void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &p trackerPosition = glm::vec3(ovrHeadPosition.x, ovrHeadPosition.y, ovrHeadPosition.z); trackerPosition = bodyOrientation * trackerPosition; + + if (_calibrationState != CALIBRATED) { + ovrQuatf ovrHeadOrientation = ts.HeadPose.ThePose.Orientation; + orientation = glm::quat(ovrHeadOrientation.w, ovrHeadOrientation.x, ovrHeadOrientation.y, ovrHeadOrientation.z); + calibrate(trackerPosition, orientation); + } #endif //Render each eye into an fbo diff --git a/interface/src/devices/OculusManager.h b/interface/src/devices/OculusManager.h index 604580a24e..15d5c73b7b 100644 --- a/interface/src/devices/OculusManager.h +++ b/interface/src/devices/OculusManager.h @@ -30,6 +30,8 @@ public: static void connect(); static void disconnect(); static bool isConnected(); + static void recalibrate(); + static void abandonCalibration(); static void beginFrameTiming(); static void endFrameTiming(); static void configureCamera(Camera& camera, int screenWidth, int screenHeight); @@ -99,6 +101,25 @@ private: static bool _programInitialized; static Camera* _camera; static int _activeEyeIndex; + + static void calibrate(glm::vec3 position, glm::quat orientation); + enum CalibrationState { + UNCALIBRATED, + WAITING_FOR_DELTA, + WAITING_FOR_ZERO, + WAITING_FOR_ZERO_HELD, + CALIBRATED + }; + static float CALIBRATION_DELTA_MINIMUM_LENGTH; + static float CALIBRATION_DELTA_MINIMUM_ANGLE; + static float CALIBRATION_ZERO_MAXIMUM_LENGTH; + static float CALIBRATION_ZERO_MAXIMUM_ANGLE; + static quint64 CALIBRATION_ZERO_HOLD_TIME; + static CalibrationState _calibrationState; + static glm::vec3 _calibrationPosition; + static glm::quat _calibrationOrientation; + static quint64 _calibrationStartTime; + #endif static glm::vec3 _leftEyePosition; From 0a4bc2bc4883a92035c2abbf2d87b482fa1d99b2 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 3 Oct 2014 13:14:39 -0700 Subject: [PATCH 02/22] Add VR display auto-calibration user message calculations --- interface/src/devices/OculusManager.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/interface/src/devices/OculusManager.cpp b/interface/src/devices/OculusManager.cpp index 99892e98be..59283dbc67 100644 --- a/interface/src/devices/OculusManager.cpp +++ b/interface/src/devices/OculusManager.cpp @@ -186,6 +186,8 @@ void OculusManager::disconnect() { void OculusManager::calibrate(glm::vec3 position, glm::quat orientation) { #ifdef HAVE_LIBOVR + static QString progressMessage; + switch (_calibrationState) { case UNCALIBRATED: @@ -210,6 +212,8 @@ void OculusManager::calibrate(glm::vec3 position, glm::quat orientation) { && glm::angle(orientation * glm::inverse(_calibrationOrientation)) < CALIBRATION_ZERO_MAXIMUM_ANGLE) { _calibrationStartTime = usecTimestampNow(); _calibrationState = WAITING_FOR_ZERO_HELD; + qDebug() << "Progress box: Hold still to calibrate"; + progressMessage = ""; } else { _calibrationPosition = position; _calibrationOrientation = orientation; @@ -221,7 +225,19 @@ void OculusManager::calibrate(glm::vec3 position, glm::quat orientation) { && glm::angle(orientation * glm::inverse(_calibrationOrientation)) < CALIBRATION_ZERO_MAXIMUM_ANGLE) { if ((usecTimestampNow() - _calibrationStartTime) > CALIBRATION_ZERO_HOLD_TIME) { _calibrationState = CALIBRATED; + qDebug() << "Delete progress box"; Application::getInstance()->resetSensors(); + } else { + // 3...2...1... + quint64 quarterSeconds = (usecTimestampNow() - _calibrationStartTime) / 250000; + if (quarterSeconds + 1 > progressMessage.length()) { + if (quarterSeconds == 4 * (quarterSeconds / 4)) { + progressMessage += QString::number(CALIBRATION_ZERO_HOLD_TIME / 1000000 - quarterSeconds / 4); + } else { + progressMessage += "."; + } + qDebug() << progressMessage; + } } } else { _calibrationPosition = position; From fc24d96947bcdf65608284b88defe596c1871b53 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sat, 4 Oct 2014 19:31:52 -0700 Subject: [PATCH 03/22] Make overlays accessible from C++ code --- interface/src/ui/overlays/Overlays.cpp | 73 ++++++++------------------ interface/src/ui/overlays/Overlays.h | 3 ++ 2 files changed, 24 insertions(+), 52 deletions(-) diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index fe9a9edca0..922c6a0408 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -124,90 +124,59 @@ void Overlays::render3D() { unsigned int Overlays::addOverlay(const QString& type, const QScriptValue& properties) { unsigned int thisID = 0; - bool created = false; - bool is3D = false; Overlay* thisOverlay = NULL; + bool created = true; if (type == "image") { thisOverlay = new ImageOverlay(); - thisOverlay->init(_parent); - thisOverlay->setProperties(properties); - created = true; } else if (type == "text") { thisOverlay = new TextOverlay(); - thisOverlay->init(_parent); - thisOverlay->setProperties(properties); - created = true; } else if (type == "cube") { thisOverlay = new Cube3DOverlay(); - thisOverlay->init(_parent); - thisOverlay->setProperties(properties); - created = true; - is3D = true; } else if (type == "sphere") { thisOverlay = new Sphere3DOverlay(); - thisOverlay->init(_parent); - thisOverlay->setProperties(properties); - created = true; - is3D = true; } else if (type == "circle3d") { thisOverlay = new Circle3DOverlay(); - thisOverlay->init(_parent); - thisOverlay->setProperties(properties); - created = true; - is3D = true; } else if (type == "rectangle3d") { thisOverlay = new Rectangle3DOverlay(); - thisOverlay->init(_parent); - thisOverlay->setProperties(properties); - created = true; - is3D = true; } else if (type == "line3d") { thisOverlay = new Line3DOverlay(); - thisOverlay->init(_parent); - thisOverlay->setProperties(properties); - created = true; - is3D = true; } else if (type == "localvoxels") { thisOverlay = new LocalVoxelsOverlay(); - thisOverlay->init(_parent); - thisOverlay->setProperties(properties); - created = true; - is3D = true; } else if (type == "localmodels") { thisOverlay = new LocalModelsOverlay(Application::getInstance()->getEntityClipboardRenderer()); - thisOverlay->init(_parent); - thisOverlay->setProperties(properties); - created = true; - is3D = true; } else if (type == "model") { thisOverlay = new ModelOverlay(); - thisOverlay->init(_parent); - thisOverlay->setProperties(properties); - created = true; - is3D = true; } else if (type == "billboard") { thisOverlay = new BillboardOverlay(); - thisOverlay->init(_parent); - thisOverlay->setProperties(properties); - created = true; - is3D = true; + } else { + created = false; } if (created) { - QWriteLocker lock(&_lock); - thisID = _nextOverlayID; - _nextOverlayID++; - if (is3D) { - _overlays3D[thisID] = thisOverlay; - } else { - _overlays2D[thisID] = thisOverlay; - } + thisOverlay->setProperties(properties); + thisID = addOverlay(thisOverlay); } return thisID; } +unsigned int Overlays::addOverlay(Overlay* overlay) { + overlay->init(_parent); + + QWriteLocker lock(&_lock); + unsigned int thisID = _nextOverlayID; + _nextOverlayID++; + bool is3D = typeid(*overlay) != typeid(ImageOverlay) && typeid(*overlay) != typeid(TextOverlay); + if (is3D) { + _overlays3D[thisID] = overlay; + } else { + _overlays2D[thisID] = overlay; + } + + return thisID; +} + bool Overlays::editOverlay(unsigned int id, const QScriptValue& properties) { Overlay* thisOverlay = NULL; QWriteLocker lock(&_lock); diff --git a/interface/src/ui/overlays/Overlays.h b/interface/src/ui/overlays/Overlays.h index 6676994eed..4851b1f9dc 100644 --- a/interface/src/ui/overlays/Overlays.h +++ b/interface/src/ui/overlays/Overlays.h @@ -44,6 +44,9 @@ public slots: /// adds an overlay with the specific properties unsigned int addOverlay(const QString& type, const QScriptValue& properties); + /// adds an overlay that's already been created + unsigned int addOverlay(Overlay* overlay); + /// edits an overlay updating only the included properties, will return the identified OverlayID in case of /// successful edit, if the input id is for an unknown overlay this function will have no effect bool editOverlay(unsigned int id, const QScriptValue& properties); From 614f5314f20e82c1eba50735d4fbf7a345116203 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sat, 4 Oct 2014 19:32:20 -0700 Subject: [PATCH 04/22] Add some property setters to the billboard overlay --- interface/src/ui/overlays/BillboardOverlay.cpp | 4 ++++ interface/src/ui/overlays/BillboardOverlay.h | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/interface/src/ui/overlays/BillboardOverlay.cpp b/interface/src/ui/overlays/BillboardOverlay.cpp index 4f9e7c84f6..08d2652849 100644 --- a/interface/src/ui/overlays/BillboardOverlay.cpp +++ b/interface/src/ui/overlays/BillboardOverlay.cpp @@ -150,6 +150,10 @@ void BillboardOverlay::setProperties(const QScriptValue &properties) { } } +void BillboardOverlay::setURL(const QString url) { + setBillboardURL(url); +} + void BillboardOverlay::setBillboardURL(const QUrl url) { _isLoaded = false; QNetworkReply* reply = NetworkAccessManager::getInstance().get(QNetworkRequest(url)); diff --git a/interface/src/ui/overlays/BillboardOverlay.h b/interface/src/ui/overlays/BillboardOverlay.h index a0b76869b3..85af2a3c66 100644 --- a/interface/src/ui/overlays/BillboardOverlay.h +++ b/interface/src/ui/overlays/BillboardOverlay.h @@ -24,6 +24,12 @@ public: BillboardOverlay(); virtual void render(); + + // setters + void setURL(const QString url); + void setScale(float scale) { _scale = scale; } + void setIsFacingAvatar(bool isFacingAvatar) { _isFacingAvatar = isFacingAvatar; } + virtual void setProperties(const QScriptValue& properties); void setClipFromSource(const QRect& bounds) { _fromImage = bounds; } From 817da8ca05061bd74e080154bb30327d5a35249e Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sat, 4 Oct 2014 19:33:24 -0700 Subject: [PATCH 05/22] Display a static billboard prompting user to hold still to calibrate HMD --- interface/src/devices/OculusManager.cpp | 48 ++++++++++++++++++++++--- interface/src/devices/OculusManager.h | 6 ++++ 2 files changed, 49 insertions(+), 5 deletions(-) diff --git a/interface/src/devices/OculusManager.cpp b/interface/src/devices/OculusManager.cpp index 59283dbc67..123b02edf2 100644 --- a/interface/src/devices/OculusManager.cpp +++ b/interface/src/devices/OculusManager.cpp @@ -58,12 +58,16 @@ int OculusManager::_activeEyeIndex = -1; float OculusManager::CALIBRATION_DELTA_MINIMUM_LENGTH = 0.02f; float OculusManager::CALIBRATION_DELTA_MINIMUM_ANGLE = 5.f * RADIANS_PER_DEGREE; float OculusManager::CALIBRATION_ZERO_MAXIMUM_LENGTH = 0.01f; -float OculusManager::CALIBRATION_ZERO_MAXIMUM_ANGLE = 0.5f * RADIANS_PER_DEGREE; +float OculusManager::CALIBRATION_ZERO_MAXIMUM_ANGLE = 2.0f * RADIANS_PER_DEGREE; quint64 OculusManager::CALIBRATION_ZERO_HOLD_TIME = 3000000; // usec +float OculusManager::CALIBRATION_MESSAGE_DISTANCE = 2.5f; OculusManager::CalibrationState OculusManager::_calibrationState; glm::vec3 OculusManager::_calibrationPosition; glm::quat OculusManager::_calibrationOrientation; quint64 OculusManager::_calibrationStartTime; +int OculusManager::_calibrationMessage = 0; +QString OculusManager::CALIBRATION_BILLBOARD_URL = "http://ctrlaltstudio.com/hifi/hold-to-calibrate.svg"; // TODO: Update with final URL +float OculusManager::CALIBRATION_BILLBOARD_SCALE = 2.f; #endif @@ -184,9 +188,20 @@ void OculusManager::disconnect() { #endif } +void OculusManager::positionCalibrationBillboard(BillboardOverlay* billboard) { + glm::quat headOrientation = Application::getInstance()->getAvatar()->getHeadOrientation(); + headOrientation.x = 0; + headOrientation.z = 0; + glm::normalize(headOrientation); + billboard->setPosition(Application::getInstance()->getAvatar()->getHeadPosition() + + headOrientation * glm::vec3(0.f, 0.f, -CALIBRATION_MESSAGE_DISTANCE)); + billboard->setRotation(headOrientation); +} + void OculusManager::calibrate(glm::vec3 position, glm::quat orientation) { #ifdef HAVE_LIBOVR static QString progressMessage; + static BillboardOverlay* billboard; switch (_calibrationState) { @@ -212,7 +227,19 @@ void OculusManager::calibrate(glm::vec3 position, glm::quat orientation) { && glm::angle(orientation * glm::inverse(_calibrationOrientation)) < CALIBRATION_ZERO_MAXIMUM_ANGLE) { _calibrationStartTime = usecTimestampNow(); _calibrationState = WAITING_FOR_ZERO_HELD; - qDebug() << "Progress box: Hold still to calibrate"; + + if (_calibrationMessage == 0) { + qDebug() << "Calibration message: Hold still to calibrate"; + + billboard = new BillboardOverlay(); + billboard->setURL(CALIBRATION_BILLBOARD_URL); + billboard->setScale(CALIBRATION_BILLBOARD_SCALE); + billboard->setIsFacingAvatar(false); + positionCalibrationBillboard(billboard); + + _calibrationMessage = Application::getInstance()->getOverlays().addOverlay(billboard); + } + progressMessage = ""; } else { _calibrationPosition = position; @@ -225,14 +252,22 @@ void OculusManager::calibrate(glm::vec3 position, glm::quat orientation) { && glm::angle(orientation * glm::inverse(_calibrationOrientation)) < CALIBRATION_ZERO_MAXIMUM_ANGLE) { if ((usecTimestampNow() - _calibrationStartTime) > CALIBRATION_ZERO_HOLD_TIME) { _calibrationState = CALIBRATED; - qDebug() << "Delete progress box"; + qDebug() << "Delete calibration message"; + Application::getInstance()->getOverlays().deleteOverlay(_calibrationMessage); + _calibrationMessage = 0; Application::getInstance()->resetSensors(); } else { - // 3...2...1... quint64 quarterSeconds = (usecTimestampNow() - _calibrationStartTime) / 250000; if (quarterSeconds + 1 > progressMessage.length()) { + // 3...2...1... if (quarterSeconds == 4 * (quarterSeconds / 4)) { - progressMessage += QString::number(CALIBRATION_ZERO_HOLD_TIME / 1000000 - quarterSeconds / 4); + quint64 wholeSeconds = CALIBRATION_ZERO_HOLD_TIME / 1000000 - quarterSeconds / 4; + + if (wholeSeconds == 2) { + positionCalibrationBillboard(billboard); + } + + progressMessage += QString::number(wholeSeconds); } else { progressMessage += "."; } @@ -258,6 +293,9 @@ void OculusManager::recalibrate() { void OculusManager::abandonCalibration() { #ifdef HAVE_LIBOVR _calibrationState = CALIBRATED; + qDebug() << "Delete calibration message"; + Application::getInstance()->getOverlays().deleteOverlay(_calibrationMessage); + _calibrationMessage = 0; #endif } diff --git a/interface/src/devices/OculusManager.h b/interface/src/devices/OculusManager.h index 15d5c73b7b..967c8b7139 100644 --- a/interface/src/devices/OculusManager.h +++ b/interface/src/devices/OculusManager.h @@ -18,6 +18,7 @@ #endif #include "renderer/ProgramObject.h" +#include "ui/overlays/BillboardOverlay.h" const float DEFAULT_OCULUS_UI_ANGULAR_SIZE = 72.0f; @@ -110,15 +111,20 @@ private: WAITING_FOR_ZERO_HELD, CALIBRATED }; + static void OculusManager::positionCalibrationBillboard(BillboardOverlay* billboard); static float CALIBRATION_DELTA_MINIMUM_LENGTH; static float CALIBRATION_DELTA_MINIMUM_ANGLE; static float CALIBRATION_ZERO_MAXIMUM_LENGTH; static float CALIBRATION_ZERO_MAXIMUM_ANGLE; static quint64 CALIBRATION_ZERO_HOLD_TIME; + static float CALIBRATION_MESSAGE_DISTANCE; static CalibrationState _calibrationState; static glm::vec3 _calibrationPosition; static glm::quat _calibrationOrientation; static quint64 _calibrationStartTime; + static int _calibrationMessage; + static QString CALIBRATION_BILLBOARD_URL; + static float CALIBRATION_BILLBOARD_SCALE; #endif From 6992b41c5c349525303703136fbba5a8f788859e Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sat, 4 Oct 2014 19:53:00 -0700 Subject: [PATCH 06/22] Fix avatar rotation erroneously initiating HMD calibration --- interface/src/devices/OculusManager.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/interface/src/devices/OculusManager.cpp b/interface/src/devices/OculusManager.cpp index 123b02edf2..cfeca9bb9a 100644 --- a/interface/src/devices/OculusManager.cpp +++ b/interface/src/devices/OculusManager.cpp @@ -456,13 +456,14 @@ void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &p ovrVector3f ovrHeadPosition = ts.HeadPose.ThePose.Position; trackerPosition = glm::vec3(ovrHeadPosition.x, ovrHeadPosition.y, ovrHeadPosition.z); - trackerPosition = bodyOrientation * trackerPosition; 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 //Render each eye into an fbo From 32399d8620253f382e6aef88d8f94384de415014 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sat, 4 Oct 2014 20:07:37 -0700 Subject: [PATCH 07/22] Delete calibration message if exit VR display while calibrating --- interface/src/Application.cpp | 2 ++ interface/src/devices/OculusManager.cpp | 8 +++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index da7dd5bb25..c135fd86f3 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1478,6 +1478,8 @@ void Application::setEnableVRMode(bool enableVRMode) { OculusManager::connect(); } OculusManager::recalibrate(); + } else { + OculusManager::abandonCalibration(); } resizeGL(_glWidget->getDeviceWidth(), _glWidget->getDeviceHeight()); diff --git a/interface/src/devices/OculusManager.cpp b/interface/src/devices/OculusManager.cpp index cfeca9bb9a..6dad7006d9 100644 --- a/interface/src/devices/OculusManager.cpp +++ b/interface/src/devices/OculusManager.cpp @@ -293,9 +293,11 @@ void OculusManager::recalibrate() { void OculusManager::abandonCalibration() { #ifdef HAVE_LIBOVR _calibrationState = CALIBRATED; - qDebug() << "Delete calibration message"; - Application::getInstance()->getOverlays().deleteOverlay(_calibrationMessage); - _calibrationMessage = 0; + if (_calibrationMessage > 0) { + qDebug() << "Delete calibration message"; + Application::getInstance()->getOverlays().deleteOverlay(_calibrationMessage); + _calibrationMessage = 0; + } #endif } From ebf615fc30b9f0a01a0141d7b057f8e7618e8e90 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Mon, 6 Oct 2014 17:25:40 -0700 Subject: [PATCH 08/22] Fix header declaration --- interface/src/devices/OculusManager.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/devices/OculusManager.h b/interface/src/devices/OculusManager.h index 967c8b7139..e46f1673a0 100644 --- a/interface/src/devices/OculusManager.h +++ b/interface/src/devices/OculusManager.h @@ -111,7 +111,7 @@ private: WAITING_FOR_ZERO_HELD, CALIBRATED }; - static void OculusManager::positionCalibrationBillboard(BillboardOverlay* billboard); + static void positionCalibrationBillboard(BillboardOverlay* billboard); static float CALIBRATION_DELTA_MINIMUM_LENGTH; static float CALIBRATION_DELTA_MINIMUM_ANGLE; static float CALIBRATION_ZERO_MAXIMUM_LENGTH; From 05915ae134b15e0dfdd0409f4fdd73c5ad13ef10 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 8 Oct 2014 11:53:07 -0700 Subject: [PATCH 09/22] Make calibration message update its location more often --- interface/src/devices/OculusManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/devices/OculusManager.cpp b/interface/src/devices/OculusManager.cpp index 6dad7006d9..8078c2666b 100644 --- a/interface/src/devices/OculusManager.cpp +++ b/interface/src/devices/OculusManager.cpp @@ -263,7 +263,7 @@ void OculusManager::calibrate(glm::vec3 position, glm::quat orientation) { if (quarterSeconds == 4 * (quarterSeconds / 4)) { quint64 wholeSeconds = CALIBRATION_ZERO_HOLD_TIME / 1000000 - quarterSeconds / 4; - if (wholeSeconds == 2) { + if (wholeSeconds == 3) { positionCalibrationBillboard(billboard); } From 0fce89a62796724021a1e5bc51ad32baef4c0ee9 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 9 Oct 2014 16:22:16 -0700 Subject: [PATCH 10/22] Add gamepad.js --- examples/gamepad.js | 266 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 266 insertions(+) create mode 100644 examples/gamepad.js diff --git a/examples/gamepad.js b/examples/gamepad.js new file mode 100644 index 0000000000..1911e71a25 --- /dev/null +++ b/examples/gamepad.js @@ -0,0 +1,266 @@ +// +// controller.js +// examples +// +// Created by Ryan Huffman on 10/9/14. +// 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 +// + +gamepad = Joysticks.joystickWithName("Wireless 360 Controller"); + +if (!gamepad) { + print("No gamepad found."); +} + +// Controller axis/button mappings +var GAMEPAD = { + AXES: { + LEFT_JOYSTICK_X: 0, + LEFT_JOYSTICK_Y: 1, + + RIGHT_JOYSTICK_X: 2, + RIGHT_JOYSTICK_Y: 3, + + LEFT_TRIGGER: 4, + RIGHT_TRIGGER: 5, + }, + BUTTONS: { + DPAD_UP: 0, + DPAD_DOWN: 1, + DPAD_LEFT: 2, + DPAD_RIGHT: 3, + + LEFT_JOYSTICK: 6, + RIGHT_JOYSTICK: 7, + + LEFT_BUMPER: 8, + RIGHT_BUMPER: 9, + + // Face buttons, ABXY on an XBOX controller + FACE_BOTTOM: 11, + FACE_RIGHT: 12, + FACE_LEFT: 13, + FACE_TOP: 14, + } +} + +// Button/axis mappings +var AXIS_STRAFE = GAMEPAD.AXES.LEFT_JOYSTICK_X; +var AXIS_FORWARD = GAMEPAD.AXES.LEFT_JOYSTICK_Y; +var AXIS_ROTATE = GAMEPAD.AXES.RIGHT_JOYSTICK_X; + +var BUTTON_TURN_AROUND = GAMEPAD.BUTTONS.RIGHT_JOYSTICK; + +var BUTTON_FLY_UP = GAMEPAD.BUTTONS.RIGHT_BUMPER; +var BUTTON_FLY_DOWN = GAMEPAD.BUTTONS.LEFT_BUMPER +var BUTTON_WARP = GAMEPAD.BUTTONS.FACE_BOTTOM; + +var BUTTON_WARP_FORWARD = GAMEPAD.BUTTONS.DPAD_UP; +var BUTTON_WARP_BACKWARD = GAMEPAD.BUTTONS.DPAD_DOWN; +var BUTTON_WARP_LEFT = GAMEPAD.BUTTONS.DPAD_LEFT; +var BUTTON_WARP_RIGHT = GAMEPAD.BUTTONS.DPAD_RIGHT; + +// Distance in meters to warp via BUTTON_WARP_* +var WARP_DISTANCE = 1; + +// Walk speed in m/s +var MOVE_SPEED = 2; + +// Amount to rotate in radians +var ROTATE_INCREMENT = Math.PI / 8; + +// Pick from above where we want to warp +var WARP_PICK_OFFSET = { x: 0, y: 10, z: 0 }; + +// When warping, the warp position will snap to a target below the current warp position. +// This is the max distance it will snap to. +var WARP_PICK_MAX_DISTANCE = 100; + +var flyDownButtonState = false; +var flyUpButtonState = false; + +// Current move direction, axis aligned - that is, looking down and moving forward +// will not move you into the ground, but instead will keep you on the horizontal plane. +var moveDirection = { x: 0, y: 0, z: 0 }; + +var warpActive = false; +var warpPosition = { x: 0, y: 0, z: 0 }; + +var WARP_SPHERE_SIZE = 1; +var warpSphere = Overlays.addOverlay("sphere", { + position: { x: 0, y: 0, z: 0 }, + size: WARP_SPHERE_SIZE, + color: { red: 0, green: 255, blue: 0 }, + alpha: 1.0, + solid: true, + visible: false, +}); + +var WARP_LINE_HEIGHT = 10; +var warpLine = Overlays.addOverlay("line3d", { + position: { x: 0, y: 0, z:0 }, + end: { x: 0, y: 0, z: 0 }, + color: { red: 0, green: 255, blue: 255}, + alpha: 1, + lineWidth: 5, + visible: false, +}); + +function copyVec3(vec) { + return { x: vec.x, y: vec.y, z: vec.z }; +} + +function activateWarp() { + if (warpActive) return; + warpActive = true; + + updateWarp(); +} + +function updateWarp() { + if (!warpActive) return; + + var look = Quat.getFront(Camera.getOrientation()); + var pitch = Math.asin(look.y); + + // Get relative to looking straight down + pitch += Math.PI / 2; + + // Scale up + pitch *= 2; + var distance = pitch * pitch * pitch; + + var warpDirection = Vec3.normalize({ x: look.x, y: 0, z: look.z }); + warpPosition = Vec3.multiply(warpDirection, distance); + warpPosition = Vec3.sum(MyAvatar.position, warpPosition); + + var pickRay = { + origin: Vec3.sum(warpPosition, WARP_PICK_OFFSET), + direction: { x: 0, y: -1, z: 0 } + }; + + var intersection = Voxels.findRayIntersection(pickRay); + + if (intersection.intersects && intersection.distance < WARP_PICK_MAX_DISTANCE) { + // Warp 1 meter above the object - this is an approximation + // TODO Get the actual offset to the Avatar's feet and plant them to + // the object. + warpPosition = Vec3.sum(intersection.intersection, { x: 0, y: 1, z:0 }); + } + + // Adjust overlays to match warp position + Overlays.editOverlay(warpSphere, { + position: warpPosition, + visible: true, + }); + Overlays.editOverlay(warpLine, { + position: warpPosition, + end: Vec3.sum(warpPosition, { x: 0, y: WARP_LINE_HEIGHT, z: 0 }), + visible: true, + }); +} + +function finishWarp() { + if (!warpActive) return; + warpActive = false; + Overlays.editOverlay(warpSphere, { + visible: false, + }); + Overlays.editOverlay(warpLine, { + visible: false, + }); + MyAvatar.position = warpPosition; +} + +function reportAxisValue(axis, newValue, oldValue) { + if (Math.abs(oldValue) < 0.2) oldValue = 0; + if (Math.abs(newValue) < 0.2) newValue = 0; + + if (axis == AXIS_FORWARD) { + moveDirection.z = newValue; + } else if (axis == AXIS_STRAFE) { + moveDirection.x = newValue; + } else if (axis == AXIS_ROTATE) { + if (oldValue == 0 && newValue != 0) { + var rotateRadians = newValue > 0 ? -ROTATE_INCREMENT : ROTATE_INCREMENT; + var orientation = MyAvatar.orientation; + orientation = Quat.multiply(Quat.fromPitchYawRollRadians(0, rotateRadians, 0), orientation) ; + MyAvatar.orientation = orientation; + } + } +} + +function reportButtonValue(button, newValue, oldValue) { + print("The value for button " + button + " has changed from " + oldValue + " to " + newValue); + if (button == BUTTON_FLY_DOWN) { + flyDownButtonState = newValue; + } else if (button == BUTTON_FLY_UP) { + flyUpButtonState = newValue; + } else if (button == BUTTON_WARP) { + if (newValue) { + activateWarp(); + } else { + finishWarp(); + } + } else if (button == BUTTON_TURN_AROUND) { + if (newValue) { + MyAvatar.orientation = Quat.multiply( + Quat.fromPitchYawRollRadians(0, Math.PI, 0), MyAvatar.orientation); + } + } else if (newValue) { + var direction = null; + + if (button == BUTTON_WARP_FORWARD) { + direction = Quat.getFront(Camera.getOrientation()); + } else if (button == BUTTON_WARP_BACKWARD) { + direction = Quat.getFront(Camera.getOrientation()); + direction = Vec3.multiply(-1, direction); + } else if (button == BUTTON_WARP_LEFT) { + direction = Quat.getRight(Camera.getOrientation()); + direction = Vec3.multiply(-1, direction); + } else if (button == BUTTON_WARP_RIGHT) { + direction = Quat.getRight(Camera.getOrientation()); + } + + if (direction) { + direction.y = 0; + direction = Vec3.multiply(Vec3.normalize(direction), WARP_DISTANCE); + MyAvatar.position = Vec3.sum(MyAvatar.position, direction); + } + } + + if (flyUpButtonState && !flyDownButtonState) { + moveDirection.y = 1; + } else if (!flyUpButtonState && flyDownButtonState) { + moveDirection.y = -1; + } else { + moveDirection.y = 0; + } +} + +function update(dt) { + var velocity = { x: 0, y: 0, z: 0 }; + var move = copyVec3(moveDirection); + move.y = 0; + if (Vec3.length(move) > 0) { + velocity = Vec3.multiplyQbyV(Camera.getOrientation(), move); + velocity.y = 0; + velocity = Vec3.multiply(Vec3.normalize(velocity), MOVE_SPEED); + } + + if (moveDirection.y != 0) { + velocity.y = moveDirection.y * MOVE_SPEED; + } + + MyAvatar.setVelocity(velocity); + + updateWarp(); +} + +gamepad.axisValueChanged.connect(reportAxisValue); +gamepad.buttonStateChanged.connect(reportButtonValue); + +Script.update.connect(update); From d2c7bf4334a552319e6c0cabfc6b235c6d67c6c1 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 9 Oct 2014 15:58:26 -0700 Subject: [PATCH 11/22] fix for delete of object table row --- domain-server/resources/web/js/settings.js | 27 ++++++++++++---------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/domain-server/resources/web/js/settings.js b/domain-server/resources/web/js/settings.js index 923a01a8a9..38baf223b3 100644 --- a/domain-server/resources/web/js/settings.js +++ b/domain-server/resources/web/js/settings.js @@ -474,21 +474,24 @@ function deleteTableRow(delete_glyphicon) { if (!isArray) { // this is a hash row, so we empty it but leave the hidden input blank so it is cleared when we save row.empty() - row.html(""); - } else if (table.find('.' + Settings.DATA_ROW_CLASS).length > 1) { - updateDataChangedForSiblingRows(row) - - // this isn't the last row - we can just remove it - row.remove() + row.html(""); } else { - // this is the last row, we can't remove it completely since we need to post an empty array - row.empty() + if (table.find('.' + Settings.DATA_ROW_CLASS).length) { + updateDataChangedForSiblingRows(row) - row.removeClass(Settings.DATA_ROW_CLASS).removeClass(Settings.NEW_ROW_CLASS) - row.addClass('empty-array-row') + // this isn't the last row - we can just remove it + row.remove() + } else { + // this is the last row, we can't remove it completely since we need to post an empty array + row.empty() - row.html(""); + row.removeClass(Settings.DATA_ROW_CLASS).removeClass(Settings.NEW_ROW_CLASS) + row.addClass('empty-array-row') + + row.html(""); + } } // we need to fire a change event on one of the remaining inputs so that the sidebar badge is updated From a9eaf3b740537d9994b1ef11c980743ea86a1a1b Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 10 Oct 2014 09:27:07 -0700 Subject: [PATCH 12/22] Update gamepad.js to work with wired 360 controller --- examples/gamepad.js | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/examples/gamepad.js b/examples/gamepad.js index 1911e71a25..e4ca03451a 100644 --- a/examples/gamepad.js +++ b/examples/gamepad.js @@ -9,7 +9,18 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -gamepad = Joysticks.joystickWithName("Wireless 360 Controller"); +var CONTROLLER_NAMES = [ + "Wireless 360 Controller", + "Controller", // Wired 360 controller +] + +for (var i = 0; i < CONTROLLER_NAMES.length; i++) { + gamepad = Joysticks.joystickWithName(CONTROLLER_NAMES[i]); + if (gamepad) { + print("Found controller: " + CONTROLLER_NAMES[i]); + break; + } +} if (!gamepad) { print("No gamepad found."); @@ -194,7 +205,6 @@ function reportAxisValue(axis, newValue, oldValue) { } function reportButtonValue(button, newValue, oldValue) { - print("The value for button " + button + " has changed from " + oldValue + " to " + newValue); if (button == BUTTON_FLY_DOWN) { flyDownButtonState = newValue; } else if (button == BUTTON_FLY_UP) { @@ -260,7 +270,9 @@ function update(dt) { updateWarp(); } -gamepad.axisValueChanged.connect(reportAxisValue); -gamepad.buttonStateChanged.connect(reportButtonValue); +if (gamepad) { + gamepad.axisValueChanged.connect(reportAxisValue); + gamepad.buttonStateChanged.connect(reportButtonValue); -Script.update.connect(update); + Script.update.connect(update); +} From 3aca910e17a9e6694d3e4beed9bc98c3be2715f7 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 10 Oct 2014 09:27:15 -0700 Subject: [PATCH 13/22] remove some extra console logs --- domain-server/resources/web/js/settings.js | 1 - 1 file changed, 1 deletion(-) diff --git a/domain-server/resources/web/js/settings.js b/domain-server/resources/web/js/settings.js index 38baf223b3..9d586c8436 100644 --- a/domain-server/resources/web/js/settings.js +++ b/domain-server/resources/web/js/settings.js @@ -152,7 +152,6 @@ $(document).ready(function(){ }) $('#settings-form').on('change', 'select', function(){ - console.log("Changed" + $(this)) $("input[name='" + $(this).attr('data-hidden-input') + "']").val($(this).val()).change() }) From c69ad78d3b67d1ee736e04920962fb5556a6d303 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 10 Oct 2014 09:30:51 -0700 Subject: [PATCH 14/22] Add wired 360 controller on Windows support --- examples/gamepad.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/gamepad.js b/examples/gamepad.js index e4ca03451a..4ec0309511 100644 --- a/examples/gamepad.js +++ b/examples/gamepad.js @@ -9,8 +9,10 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +// TODO Update to work with any controller that is plugged in. var CONTROLLER_NAMES = [ "Wireless 360 Controller", + "Controller (XBOX 360 For Windows)", "Controller", // Wired 360 controller ] From f5ee55bef4052c0f63bf9b971a735d4d9836fcb8 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 10 Oct 2014 09:44:38 -0700 Subject: [PATCH 15/22] remove xbox.js now that we have gamepad.js --- examples/xbox.js | 19 ------------------- 1 file changed, 19 deletions(-) delete mode 100644 examples/xbox.js diff --git a/examples/xbox.js b/examples/xbox.js deleted file mode 100644 index 603e0dbf56..0000000000 --- a/examples/xbox.js +++ /dev/null @@ -1,19 +0,0 @@ -// -// xbox.js -// examples -// -// Created by Stephen Birarda on September 23, 2014 -// -// 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 -// - -gamepad = Joysticks.joystickWithName("Wireless 360 Controller"); - -function reportAxisValue(axis, newValue, oldValue) { - print("The value for axis " + axis + " has changed to " + newValue + ". It was " + oldValue); -} - -gamepad.axisValueChanged.connect(reportAxisValue); \ No newline at end of file From db881c0dc8368ac15f428d4b5646b351c205cc56 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 10 Oct 2014 10:32:18 -0700 Subject: [PATCH 16/22] add boundBox gettable property to EntityItemProperties --- .../entities/src/EntityItemProperties.cpp | 27 +++++++++++++++++++ libraries/entities/src/EntityItemProperties.h | 1 + 2 files changed, 28 insertions(+) diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 1080a866f5..2690bcd45b 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -174,6 +174,16 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine) cons sittingPoints.setProperty("length", _sittingPoints.size()); COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(sittingPoints, sittingPoints); // gettable, but not settable + AABox aaBox = getAABoxInMeters(); + QScriptValue boundingBox = engine->newObject(); + QScriptValue bottomRightNear = vec3toScriptValue(engine, aaBox.getCorner()); + QScriptValue topFarLeft = vec3toScriptValue(engine, aaBox.calcTopFarLeft()); + QScriptValue center = vec3toScriptValue(engine, aaBox.calcCenter()); + boundingBox.setProperty("brn", bottomRightNear); + boundingBox.setProperty("tfl", topFarLeft); + boundingBox.setProperty("center", center); + COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(boundingBox, boundingBox); // gettable, but not settable + return properties; } @@ -643,3 +653,20 @@ AACube EntityItemProperties::getMaximumAACubeInMeters() const { return AACube(minimumCorner, diameter); } + +// The minimum bounding box for the entity. +AABox EntityItemProperties::getAABoxInMeters() const { + + // _position represents the position of the registration point. + glm::vec3 registrationRemainder = glm::vec3(1.0f, 1.0f, 1.0f) - _registrationPoint; + + glm::vec3 unrotatedMinRelativeToEntity = glm::vec3(0.0f, 0.0f, 0.0f) - (_dimensions * _registrationPoint); + glm::vec3 unrotatedMaxRelativeToEntity = _dimensions * registrationRemainder; + Extents unrotatedExtentsRelativeToRegistrationPoint = { unrotatedMinRelativeToEntity, unrotatedMaxRelativeToEntity }; + Extents rotatedExtentsRelativeToRegistrationPoint = unrotatedExtentsRelativeToRegistrationPoint.getRotated(getRotation()); + + // shift the extents to be relative to the position/registration point + rotatedExtentsRelativeToRegistrationPoint.shiftBy(_position); + + return AABox(rotatedExtentsRelativeToRegistrationPoint); +} diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 3c77b63ab6..6e1594fb9b 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -101,6 +101,7 @@ public: AACube getMaximumAACubeInTreeUnits() const; AACube getMaximumAACubeInMeters() const; + AABox getAABoxInMeters() const; void debugDump() const; From ca66319aa219ab64b6fee51336ad51a15fd08148 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 10 Oct 2014 10:37:32 -0700 Subject: [PATCH 17/22] draw selection handles for bounding box correctly when rotated --- examples/libraries/entitySelectionTool.js | 144 +++++++++++----------- 1 file changed, 74 insertions(+), 70 deletions(-) diff --git a/examples/libraries/entitySelectionTool.js b/examples/libraries/entitySelectionTool.js index 0f68ef4442..b00876c969 100644 --- a/examples/libraries/entitySelectionTool.js +++ b/examples/libraries/entitySelectionTool.js @@ -454,22 +454,28 @@ SelectionDisplay = (function () { var rotateHandleOffset = 0.05; var grabberMoveUpOffset = 0.1; - var left = properties.position.x - halfDimensions.x; - var right = properties.position.x + halfDimensions.x; - var bottom = properties.position.y - halfDimensions.y; - var top = properties.position.y + halfDimensions.y; - var near = properties.position.z - halfDimensions.z; - var far = properties.position.z + halfDimensions.z; - var center = { x: properties.position.x, y: properties.position.y, z: properties.position.z }; + var top, far, left, bottom, near, right, boundsCenter, objectCenter, BLN, BRN, BLF, TLN, TRN, TLF, TRF; - var BLN = { x: left, y: bottom, z: near }; - var BRN = { x: right, y: bottom, z: near }; - var BLF = { x: left, y: bottom, z: far }; - var BRF = { x: right, y: bottom, z: far }; - var TLN = { x: left, y: top, z: near }; - var TRN = { x: right, y: top, z: near }; - var TLF = { x: left, y: top, z: far }; - var TRF = { x: right, y: top, z: far }; + objectCenter = { x: properties.position.x, y: properties.position.y, z: properties.position.z }; + + top = properties.boundingBox.tfl.y; + far = properties.boundingBox.tfl.z; + left = properties.boundingBox.tfl.x; + + bottom = properties.boundingBox.brn.y; + right = properties.boundingBox.brn.x; + near = properties.boundingBox.brn.z; + + boundsCenter = { x: properties.boundingBox.center.x, y: properties.boundingBox.center.y, z: properties.boundingBox.center.z }; + + BLN = { x: left, y: bottom, z: near }; + BRN = { x: right, y: bottom, z: near }; + BLF = { x: left, y: bottom, z: far }; + BRF = { x: right, y: bottom, z: far }; + TLN = { x: left, y: top, z: near }; + TRN = { x: right, y: top, z: near }; + TLF = { x: left, y: top, z: far }; + TRF = { x: right, y: top, z: far }; var yawCorner; var pitchCorner; @@ -488,9 +494,10 @@ SelectionDisplay = (function () { ------------------------------*/ - if (MyAvatar.position.x > center.x) { + if (MyAvatar.position.x > objectCenter.x) { // must be BRF or BRN - if (MyAvatar.position.z < center.z) { + if (MyAvatar.position.z < objectCenter.z) { + yawHandleRotation = Quat.fromVec3Degrees({ x: 270, y: 90, z: 0 }); pitchHandleRotation = Quat.fromVec3Degrees({ x: 0, y: 90, z: 0 }); rollHandleRotation = Quat.fromVec3Degrees({ x: 0, y: 0, z: 0 }); @@ -499,21 +506,21 @@ SelectionDisplay = (function () { pitchNormal = { x: 1, y: 0, z: 0 }; rollNormal = { x: 0, y: 0, z: 1 }; - yawCorner = { x: right + rotateHandleOffset, + yawCorner = { x: left + rotateHandleOffset, y: bottom - rotateHandleOffset, z: near - rotateHandleOffset }; - pitchCorner = { x: left - rotateHandleOffset, + pitchCorner = { x: right - rotateHandleOffset, y: top + rotateHandleOffset, z: near - rotateHandleOffset}; - rollCorner = { x: right + rotateHandleOffset, + rollCorner = { x: left + rotateHandleOffset, y: top + rotateHandleOffset, z: far + rotateHandleOffset }; - yawCenter = { x: center.x, y: bottom, z: center.z }; - pitchCenter = { x: left, y: center.y, z: center.z}; - rollCenter = { x: center.x, y: center.y, z: far }; + yawCenter = { x: boundsCenter.x, y: bottom, z: boundsCenter.z }; + pitchCenter = { x: right, y: boundsCenter.y, z: boundsCenter.z}; + rollCenter = { x: boundsCenter.x, y: boundsCenter.y, z: far }; Overlays.editOverlay(pitchHandle, { url: "https://s3-us-west-1.amazonaws.com/highfidelity-public/images/rotate-arrow-west-south.png" }); @@ -521,6 +528,7 @@ SelectionDisplay = (function () { } else { + yawHandleRotation = Quat.fromVec3Degrees({ x: 270, y: 0, z: 0 }); pitchHandleRotation = Quat.fromVec3Degrees({ x: 180, y: 270, z: 0 }); rollHandleRotation = Quat.fromVec3Degrees({ x: 0, y: 0, z: 90 }); @@ -530,29 +538,31 @@ SelectionDisplay = (function () { rollNormal = { x: 0, y: 0, z: 1 }; - yawCorner = { x: right + rotateHandleOffset, + yawCorner = { x: left + rotateHandleOffset, y: bottom - rotateHandleOffset, z: far + rotateHandleOffset }; - pitchCorner = { x: left - rotateHandleOffset, + pitchCorner = { x: right - rotateHandleOffset, y: top + rotateHandleOffset, z: far + rotateHandleOffset }; - rollCorner = { x: right + rotateHandleOffset, + rollCorner = { x: left + rotateHandleOffset, y: top + rotateHandleOffset, z: near - rotateHandleOffset}; - yawCenter = { x: center.x, y: bottom, z: center.z }; - pitchCenter = { x: left, y: center.y, z: center.z }; - rollCenter = { x: center.x, y: center.y, z: near}; + yawCenter = { x: boundsCenter.x, y: bottom, z: boundsCenter.z }; + pitchCenter = { x: right, y: boundsCenter.y, z: boundsCenter.z }; + rollCenter = { x: boundsCenter.x, y: boundsCenter.y, z: near}; Overlays.editOverlay(pitchHandle, { url: "https://s3-us-west-1.amazonaws.com/highfidelity-public/images/rotate-arrow-west-north.png" }); Overlays.editOverlay(rollHandle, { url: "https://s3-us-west-1.amazonaws.com/highfidelity-public/images/rotate-arrow-west-north.png" }); } } else { + // must be BLF or BLN - if (MyAvatar.position.z < center.z) { + if (MyAvatar.position.z < objectCenter.z) { + yawHandleRotation = Quat.fromVec3Degrees({ x: 270, y: 180, z: 0 }); pitchHandleRotation = Quat.fromVec3Degrees({ x: 90, y: 0, z: 90 }); rollHandleRotation = Quat.fromVec3Degrees({ x: 0, y: 0, z: 180 }); @@ -561,26 +571,27 @@ SelectionDisplay = (function () { pitchNormal = { x: 1, y: 0, z: 0 }; rollNormal = { x: 0, y: 0, z: 1 }; - yawCorner = { x: left - rotateHandleOffset, + yawCorner = { x: right - rotateHandleOffset, y: bottom - rotateHandleOffset, z: near - rotateHandleOffset }; - pitchCorner = { x: right + rotateHandleOffset, + pitchCorner = { x: left + rotateHandleOffset, y: top + rotateHandleOffset, z: near - rotateHandleOffset }; - rollCorner = { x: left - rotateHandleOffset, + rollCorner = { x: right - rotateHandleOffset, y: top + rotateHandleOffset, z: far + rotateHandleOffset}; - yawCenter = { x: center.x, y: bottom, z: center.z }; - pitchCenter = { x: right, y: center.y, z: center.z }; - rollCenter = { x: center.x, y: center.y, z: far}; + yawCenter = { x: boundsCenter.x, y: bottom, z: boundsCenter.z }; + pitchCenter = { x: left, y: boundsCenter.y, z: boundsCenter.z }; + rollCenter = { x: boundsCenter.x, y: boundsCenter.y, z: far}; Overlays.editOverlay(pitchHandle, { url: "https://s3-us-west-1.amazonaws.com/highfidelity-public/images/rotate-arrow-west-north.png" }); Overlays.editOverlay(rollHandle, { url: "https://s3-us-west-1.amazonaws.com/highfidelity-public/images/rotate-arrow-west-north.png" }); } else { + yawHandleRotation = Quat.fromVec3Degrees({ x: 270, y: 270, z: 0 }); rollHandleRotation = Quat.fromVec3Degrees({ x: 0, y: 0, z: 180 }); pitchHandleRotation = Quat.fromVec3Degrees({ x: 180, y: 270, z: 0 }); @@ -589,21 +600,21 @@ SelectionDisplay = (function () { rollNormal = { x: 0, y: 0, z: 1 }; pitchNormal = { x: 1, y: 0, z: 0 }; - yawCorner = { x: left - rotateHandleOffset, + yawCorner = { x: right - rotateHandleOffset, y: bottom - rotateHandleOffset, z: far + rotateHandleOffset }; - rollCorner = { x: left - rotateHandleOffset, + rollCorner = { x: right - rotateHandleOffset, y: top + rotateHandleOffset, z: near - rotateHandleOffset }; - pitchCorner = { x: right + rotateHandleOffset, + pitchCorner = { x: left + rotateHandleOffset, y: top + rotateHandleOffset, z: far + rotateHandleOffset}; - yawCenter = { x: center.x, y: bottom, z: center.z }; - rollCenter = { x: center.x, y: center.y, z: near }; - pitchCenter = { x: right, y: center.y, z: center.z}; + yawCenter = { x: boundsCenter.x, y: bottom, z: boundsCenter.z }; + rollCenter = { x: boundsCenter.x, y: boundsCenter.y, z: near }; + pitchCenter = { x: left, y: boundsCenter.y, z: boundsCenter.z}; Overlays.editOverlay(pitchHandle, { url: "https://s3-us-west-1.amazonaws.com/highfidelity-public/images/rotate-arrow-west-north.png" }); Overlays.editOverlay(rollHandle, { url: "https://s3-us-west-1.amazonaws.com/highfidelity-public/images/rotate-arrow-west-north.png" }); @@ -611,7 +622,6 @@ SelectionDisplay = (function () { } } - var rotateHandlesVisible = true; var translateHandlesVisible = true; var stretchHandlesVisible = true; @@ -632,17 +642,11 @@ SelectionDisplay = (function () { Overlays.editOverlay(highlightBox, { visible: false }); - print("selectionBoxVisible:" + selectionBoxVisible); - Overlays.editOverlay(selectionBox, - { - visible: selectionBoxVisible, - position: center, - dimensions: properties.dimensions, - rotation: properties.rotation, - }); + Overlays.editOverlay(selectionBox, { visible: selectionBoxVisible, position: objectCenter, dimensions: properties.dimensions, + rotation: properties.rotation,}); - Overlays.editOverlay(grabberMoveUp, { visible: translateHandlesVisible, position: { x: center.x, y: top + grabberMoveUpOffset, z: center.z } }); + Overlays.editOverlay(grabberMoveUp, { visible: translateHandlesVisible, position: { x: boundsCenter.x, y: top + grabberMoveUpOffset, z: boundsCenter.z } }); Overlays.editOverlay(grabberLBN, { visible: stretchHandlesVisible, position: { x: left, y: bottom, z: near } }); Overlays.editOverlay(grabberRBN, { visible: stretchHandlesVisible, position: { x: right, y: bottom, z: near } }); @@ -654,25 +658,25 @@ SelectionDisplay = (function () { Overlays.editOverlay(grabberRTF, { visible: stretchHandlesVisible, position: { x: right, y: top, z: far } }); - Overlays.editOverlay(grabberTOP, { visible: stretchHandlesVisible, position: { x: center.x, y: top, z: center.z } }); - Overlays.editOverlay(grabberBOTTOM, { visible: stretchHandlesVisible, position: { x: center.x, y: bottom, z: center.z } }); - Overlays.editOverlay(grabberLEFT, { visible: stretchHandlesVisible, position: { x: left, y: center.y, z: center.z } }); - Overlays.editOverlay(grabberRIGHT, { visible: stretchHandlesVisible, position: { x: right, y: center.y, z: center.z } }); - Overlays.editOverlay(grabberNEAR, { visible: stretchHandlesVisible, position: { x: center.x, y: center.y, z: near } }); - Overlays.editOverlay(grabberFAR, { visible: stretchHandlesVisible, position: { x: center.x, y: center.y, z: far } }); + Overlays.editOverlay(grabberTOP, { visible: stretchHandlesVisible, position: { x: boundsCenter.x, y: top, z: boundsCenter.z } }); + Overlays.editOverlay(grabberBOTTOM, { visible: stretchHandlesVisible, position: { x: boundsCenter.x, y: bottom, z: boundsCenter.z } }); + Overlays.editOverlay(grabberLEFT, { visible: stretchHandlesVisible, position: { x: left, y: boundsCenter.y, z: boundsCenter.z } }); + Overlays.editOverlay(grabberRIGHT, { visible: stretchHandlesVisible, position: { x: right, y: boundsCenter.y, z: boundsCenter.z } }); + Overlays.editOverlay(grabberNEAR, { visible: stretchHandlesVisible, position: { x: boundsCenter.x, y: boundsCenter.y, z: near } }); + Overlays.editOverlay(grabberFAR, { visible: stretchHandlesVisible, position: { x: boundsCenter.x, y: boundsCenter.y, z: far } }); - Overlays.editOverlay(grabberEdgeTR, { visible: stretchHandlesVisible, position: { x: right, y: top, z: center.z } }); - Overlays.editOverlay(grabberEdgeTL, { visible: stretchHandlesVisible, position: { x: left, y: top, z: center.z } }); - Overlays.editOverlay(grabberEdgeTF, { visible: stretchHandlesVisible, position: { x: center.x, y: top, z: far } }); - Overlays.editOverlay(grabberEdgeTN, { visible: stretchHandlesVisible, position: { x: center.x, y: top, z: near } }); - Overlays.editOverlay(grabberEdgeBR, { visible: stretchHandlesVisible, position: { x: right, y: bottom, z: center.z } }); - Overlays.editOverlay(grabberEdgeBL, { visible: stretchHandlesVisible, position: { x: left, y: bottom, z: center.z } }); - Overlays.editOverlay(grabberEdgeBF, { visible: stretchHandlesVisible, position: { x: center.x, y: bottom, z: far } }); - Overlays.editOverlay(grabberEdgeBN, { visible: stretchHandlesVisible, position: { x: center.x, y: bottom, z: near } }); - Overlays.editOverlay(grabberEdgeNR, { visible: stretchHandlesVisible, position: { x: right, y: center.y, z: near } }); - Overlays.editOverlay(grabberEdgeNL, { visible: stretchHandlesVisible, position: { x: left, y: center.y, z: near } }); - Overlays.editOverlay(grabberEdgeFR, { visible: stretchHandlesVisible, position: { x: right, y: center.y, z: far } }); - Overlays.editOverlay(grabberEdgeFL, { visible: stretchHandlesVisible, position: { x: left, y: center.y, z: far } }); + Overlays.editOverlay(grabberEdgeTR, { visible: stretchHandlesVisible, position: { x: right, y: top, z: boundsCenter.z } }); + Overlays.editOverlay(grabberEdgeTL, { visible: stretchHandlesVisible, position: { x: left, y: top, z: boundsCenter.z } }); + Overlays.editOverlay(grabberEdgeTF, { visible: stretchHandlesVisible, position: { x: boundsCenter.x, y: top, z: far } }); + Overlays.editOverlay(grabberEdgeTN, { visible: stretchHandlesVisible, position: { x: boundsCenter.x, y: top, z: near } }); + Overlays.editOverlay(grabberEdgeBR, { visible: stretchHandlesVisible, position: { x: right, y: bottom, z: boundsCenter.z } }); + Overlays.editOverlay(grabberEdgeBL, { visible: stretchHandlesVisible, position: { x: left, y: bottom, z: boundsCenter.z } }); + Overlays.editOverlay(grabberEdgeBF, { visible: stretchHandlesVisible, position: { x: boundsCenter.x, y: bottom, z: far } }); + Overlays.editOverlay(grabberEdgeBN, { visible: stretchHandlesVisible, position: { x: boundsCenter.x, y: bottom, z: near } }); + Overlays.editOverlay(grabberEdgeNR, { visible: stretchHandlesVisible, position: { x: right, y: boundsCenter.y, z: near } }); + Overlays.editOverlay(grabberEdgeNL, { visible: stretchHandlesVisible, position: { x: left, y: boundsCenter.y, z: near } }); + Overlays.editOverlay(grabberEdgeFR, { visible: stretchHandlesVisible, position: { x: right, y: boundsCenter.y, z: far } }); + Overlays.editOverlay(grabberEdgeFL, { visible: stretchHandlesVisible, position: { x: left, y: boundsCenter.y, z: far } }); Overlays.editOverlay(baseOfEntityProjectionOverlay, From 64d9a96a2ba53c8231769917bc5459bba57d825b Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 10 Oct 2014 10:42:13 -0700 Subject: [PATCH 18/22] Update SVG file location --- interface/src/devices/OculusManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/devices/OculusManager.cpp b/interface/src/devices/OculusManager.cpp index 8078c2666b..010258a56d 100644 --- a/interface/src/devices/OculusManager.cpp +++ b/interface/src/devices/OculusManager.cpp @@ -66,7 +66,7 @@ glm::vec3 OculusManager::_calibrationPosition; glm::quat OculusManager::_calibrationOrientation; quint64 OculusManager::_calibrationStartTime; int OculusManager::_calibrationMessage = 0; -QString OculusManager::CALIBRATION_BILLBOARD_URL = "http://ctrlaltstudio.com/hifi/hold-to-calibrate.svg"; // TODO: Update with final URL +QString OculusManager::CALIBRATION_BILLBOARD_URL = "http://hifi-public.s3.amazonaws.com/images/hold-to-calibrate.svg"; float OculusManager::CALIBRATION_BILLBOARD_SCALE = 2.f; #endif From aa37ba5dfdfeb0cecd17bc349dda44403f9e5c21 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 10 Oct 2014 10:57:17 -0700 Subject: [PATCH 19/22] Use const parameters --- interface/src/devices/OculusManager.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/devices/OculusManager.h b/interface/src/devices/OculusManager.h index e46f1673a0..dfe4a212b6 100644 --- a/interface/src/devices/OculusManager.h +++ b/interface/src/devices/OculusManager.h @@ -103,7 +103,7 @@ private: static Camera* _camera; static int _activeEyeIndex; - static void calibrate(glm::vec3 position, glm::quat orientation); + static void calibrate(const glm::vec3 position, const glm::quat orientation); enum CalibrationState { UNCALIBRATED, WAITING_FOR_DELTA, From 0a5fdee1f2d4e97c8ff5a8d730ea50c4eb49d9a5 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 10 Oct 2014 11:00:41 -0700 Subject: [PATCH 20/22] Use NULL rather than 0 for "no overlay" --- interface/src/devices/OculusManager.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/interface/src/devices/OculusManager.cpp b/interface/src/devices/OculusManager.cpp index 010258a56d..158ace0a37 100644 --- a/interface/src/devices/OculusManager.cpp +++ b/interface/src/devices/OculusManager.cpp @@ -65,7 +65,7 @@ OculusManager::CalibrationState OculusManager::_calibrationState; glm::vec3 OculusManager::_calibrationPosition; glm::quat OculusManager::_calibrationOrientation; quint64 OculusManager::_calibrationStartTime; -int OculusManager::_calibrationMessage = 0; +int OculusManager::_calibrationMessage = NULL; QString OculusManager::CALIBRATION_BILLBOARD_URL = "http://hifi-public.s3.amazonaws.com/images/hold-to-calibrate.svg"; float OculusManager::CALIBRATION_BILLBOARD_SCALE = 2.f; @@ -228,7 +228,7 @@ void OculusManager::calibrate(glm::vec3 position, glm::quat orientation) { _calibrationStartTime = usecTimestampNow(); _calibrationState = WAITING_FOR_ZERO_HELD; - if (_calibrationMessage == 0) { + if (!_calibrationMessage) { qDebug() << "Calibration message: Hold still to calibrate"; billboard = new BillboardOverlay(); @@ -254,7 +254,7 @@ void OculusManager::calibrate(glm::vec3 position, glm::quat orientation) { _calibrationState = CALIBRATED; qDebug() << "Delete calibration message"; Application::getInstance()->getOverlays().deleteOverlay(_calibrationMessage); - _calibrationMessage = 0; + _calibrationMessage = NULL; Application::getInstance()->resetSensors(); } else { quint64 quarterSeconds = (usecTimestampNow() - _calibrationStartTime) / 250000; @@ -293,10 +293,10 @@ void OculusManager::recalibrate() { void OculusManager::abandonCalibration() { #ifdef HAVE_LIBOVR _calibrationState = CALIBRATED; - if (_calibrationMessage > 0) { + if (_calibrationMessage) { qDebug() << "Delete calibration message"; Application::getInstance()->getOverlays().deleteOverlay(_calibrationMessage); - _calibrationMessage = 0; + _calibrationMessage = NULL; } #endif } From b0f4bc0d1ccbbb2c092dd35c721ea9740eb9f0a7 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 10 Oct 2014 11:08:15 -0700 Subject: [PATCH 21/22] Tidy up log messages --- interface/src/devices/OculusManager.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/interface/src/devices/OculusManager.cpp b/interface/src/devices/OculusManager.cpp index 158ace0a37..7ddd83458f 100644 --- a/interface/src/devices/OculusManager.cpp +++ b/interface/src/devices/OculusManager.cpp @@ -229,7 +229,7 @@ void OculusManager::calibrate(glm::vec3 position, glm::quat orientation) { _calibrationState = WAITING_FOR_ZERO_HELD; if (!_calibrationMessage) { - qDebug() << "Calibration message: Hold still to calibrate"; + qDebug() << "Hold still to calibrate HMD"; billboard = new BillboardOverlay(); billboard->setURL(CALIBRATION_BILLBOARD_URL); @@ -252,7 +252,7 @@ void OculusManager::calibrate(glm::vec3 position, glm::quat orientation) { && glm::angle(orientation * glm::inverse(_calibrationOrientation)) < CALIBRATION_ZERO_MAXIMUM_ANGLE) { if ((usecTimestampNow() - _calibrationStartTime) > CALIBRATION_ZERO_HOLD_TIME) { _calibrationState = CALIBRATED; - qDebug() << "Delete calibration message"; + qDebug() << "HMD calibrated"; Application::getInstance()->getOverlays().deleteOverlay(_calibrationMessage); _calibrationMessage = NULL; Application::getInstance()->resetSensors(); @@ -271,7 +271,7 @@ void OculusManager::calibrate(glm::vec3 position, glm::quat orientation) { } else { progressMessage += "."; } - qDebug() << progressMessage; + //qDebug() << progressMessage; // Progress message ready for 3D text overlays. } } } else { @@ -294,7 +294,7 @@ void OculusManager::abandonCalibration() { #ifdef HAVE_LIBOVR _calibrationState = CALIBRATED; if (_calibrationMessage) { - qDebug() << "Delete calibration message"; + qDebug() << "Abandoned HMD calibration"; Application::getInstance()->getOverlays().deleteOverlay(_calibrationMessage); _calibrationMessage = NULL; } From 357d49d442381cdbcf2280d3f0242529230c9a0a Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 10 Oct 2014 11:36:47 -0700 Subject: [PATCH 22/22] Fix building without Oculus library --- interface/src/devices/OculusManager.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/interface/src/devices/OculusManager.cpp b/interface/src/devices/OculusManager.cpp index 7ddd83458f..53715aabe9 100644 --- a/interface/src/devices/OculusManager.cpp +++ b/interface/src/devices/OculusManager.cpp @@ -188,6 +188,7 @@ void OculusManager::disconnect() { #endif } +#ifdef HAVE_LIBOVR void OculusManager::positionCalibrationBillboard(BillboardOverlay* billboard) { glm::quat headOrientation = Application::getInstance()->getAvatar()->getHeadOrientation(); headOrientation.x = 0; @@ -197,9 +198,10 @@ void OculusManager::positionCalibrationBillboard(BillboardOverlay* billboard) { + headOrientation * glm::vec3(0.f, 0.f, -CALIBRATION_MESSAGE_DISTANCE)); billboard->setRotation(headOrientation); } +#endif -void OculusManager::calibrate(glm::vec3 position, glm::quat orientation) { #ifdef HAVE_LIBOVR +void OculusManager::calibrate(glm::vec3 position, glm::quat orientation) { static QString progressMessage; static BillboardOverlay* billboard; @@ -281,8 +283,8 @@ void OculusManager::calibrate(glm::vec3 position, glm::quat orientation) { } break; } -#endif } +#endif void OculusManager::recalibrate() { #ifdef HAVE_LIBOVR