diff --git a/cmake/modules/FindFBX.cmake b/cmake/modules/FindFBX.cmake index 2e84d1ea19..9a1d08a010 100644 --- a/cmake/modules/FindFBX.cmake +++ b/cmake/modules/FindFBX.cmake @@ -56,19 +56,17 @@ elseif (${CMAKE_CXX_COMPILER_ID} MATCHES "GNU") endif() function(_fbx_find_library _name _lib _suffix) - if (MSVC12) + if (MSVC_VERSION EQUAL 1910) + set(VS_PREFIX vs2017) + elseif (MSVC_VERSION EQUAL 1900) + set(VS_PREFIX vs2015) + elseif (MSVC_VERSION EQUAL 1800) set(VS_PREFIX vs2013) - endif() - - if (MSVC11) + elseif (MSVC_VERSION EQUAL 1700) set(VS_PREFIX vs2012) - endif() - - if (MSVC10) + elseif (MSVC_VERSION EQUAL 1600) set(VS_PREFIX vs2010) - endif() - - if (MSVC90) + elseif (MSVC_VERSION EQUAL 1500) set(VS_PREFIX vs2008) endif() diff --git a/interface/resources/qml/hifi/tablet/CalibratingScreen.qml b/interface/resources/qml/hifi/tablet/CalibratingScreen.qml index 338a76989f..8053673e9c 100644 --- a/interface/resources/qml/hifi/tablet/CalibratingScreen.qml +++ b/interface/resources/qml/hifi/tablet/CalibratingScreen.qml @@ -25,11 +25,12 @@ Rectangle { signal canceled() signal restart() - property int count: 3 + property int count: 5 property string calibratingText: "CALIBRATING..." property string calibratingCountText: "CALIBRATION STARTING IN" property string calibrationSuccess: "CALIBRATION COMPLETED" property string calibrationFailed: "CALIBRATION FAILED" + property string instructionText: "Please stand in a T-Pose during calibration" HifiConstants { id: hifi } visible: true @@ -158,6 +159,15 @@ Rectangle { onClicked: { restart(); + statusText.color = hifi.colors.blueHighlight; + statusText.text = info.calibratingCountText; + directions.text = instructionText; + countDown.visible = true; + busyIndicator.running = true; + busyRotation.from = 0 + busyRotation.to = 360 + busyIndicator.source = blueIndicator; + closeWindow.stop(); numberAnimation.stop(); info.count = (timer.interval / 1000); numberAnimation.start(); @@ -178,6 +188,7 @@ Rectangle { } } + function start(interval, countNumber) { countDown.visible = true; statusText.color = hifi.colors.blueHighlight; @@ -201,6 +212,7 @@ Rectangle { busyIndicator.running = false; statusText.text = info.calibrationSuccess statusText.color = hifi.colors.greenHighlight + directions.text = "SUCCESS" closeWindow.start(); } diff --git a/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml b/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml index 52a935ab19..96413534c3 100644 --- a/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml +++ b/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml @@ -458,7 +458,7 @@ Rectangle { width: glyphButton.width + calibrationText.width + padding height: hifi.dimensions.controlLineHeight anchors.top: bottomSeperator.bottom - anchors.topMargin: 10 + anchors.topMargin: 15 anchors.left: parent.left anchors.leftMargin: leftMargin @@ -590,16 +590,24 @@ Rectangle { lastConfiguration = composeConfigurationSettings(); } + Component.onDestruction: { + var settings = InputConfiguration.configurationSettings(pluginName); + var data = { + "num_pucks": settings["puckCount"] + } + UserActivityLogger.logAction("mocap_ui_close_dialog", data); + } + HifiControls.SpinBox { id: timeToCalibrate width: 70 anchors.top: calibrationButton.bottom - anchors.topMargin: 40 + anchors.topMargin: 20 anchors.left: parent.left anchors.leftMargin: leftMargin - minimumValue: 3 - value: 3 + minimumValue: 5 + value: 5 colorScheme: hifi.colorSchemes.dark onEditingFinished: { @@ -641,17 +649,39 @@ Rectangle { to: 0 } + function logAction(action, status) { + console.log("calibrated from ui"); + var data = { + "num_pucks": status["puckCount"], + "puck_configuration": status["configuration"], + "head_puck": status["head_puck"], + "hand_puck": status["hand_pucks"] + } + UserActivityLogger.logAction(action, data); + } + function calibrationStatusInfo(status) { var calibrationScreen = stack.currentItem; + + if (!status["UI"]) { + calibratingScreen = screen.createObject(); + stack.push(calibratingScreen); + } + if (status["calibrated"]) { calibrationScreen.success(); + + if (status["UI"]) { + logAction("mocap_ui_success", status); + } + } else if (!status["calibrated"]) { - var uncalibrated = status["success"]; - if (!uncalibrated) { - calibrationScreen.failure(); + calibrationScreen.failure(); + + if (status["UI"]) { + logAction("mocap_ui_failed", status); } } - updateCalibrationButton(); } @@ -717,6 +747,12 @@ Rectangle { initializeButtonState(); updateCalibrationText(); + + var data = { + "num_pucks": settings["puckCount"] + }; + + UserActivityLogger.logAction("mocap_ui_open_dialog", data); } function displayTrackerConfiguration(type) { diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index 0c73f1fa70..1beee24fd5 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -40,19 +40,23 @@ Q_LOGGING_CATEGORY(trace_render_overlays, "trace.render.overlays") void Overlays::cleanupAllOverlays() { + QMap overlaysHUD; + QMap overlaysWorld; { - foreach(Overlay::Pointer overlay, _overlaysHUD) { - _overlaysToDelete.push_back(overlay); - } - foreach(Overlay::Pointer overlay, _overlaysWorld) { - _overlaysToDelete.push_back(overlay); - } - _overlaysHUD.clear(); - _overlaysWorld.clear(); -#if OVERLAY_PANELS - _panels.clear(); -#endif + QMutexLocker locker(&_mutex); + overlaysHUD.swap(_overlaysHUD); + overlaysWorld.swap(_overlaysWorld); } + + foreach(Overlay::Pointer overlay, overlaysHUD) { + _overlaysToDelete.push_back(overlay); + } + foreach(Overlay::Pointer overlay, overlaysWorld) { + _overlaysToDelete.push_back(overlay); + } +#if OVERLAY_PANELS + _panels.clear(); +#endif cleanupOverlaysToDelete(); } @@ -63,14 +67,19 @@ void Overlays::init() { } void Overlays::update(float deltatime) { - + QMap overlaysHUD; + QMap overlaysWorld; { - foreach(Overlay::Pointer thisOverlay, _overlaysHUD) { - thisOverlay->update(deltatime); - } - foreach(Overlay::Pointer thisOverlay, _overlaysWorld) { - thisOverlay->update(deltatime); - } + QMutexLocker locker(&_mutex); + overlaysHUD = _overlaysHUD; + overlaysWorld = _overlaysWorld; + } + + foreach(const auto& thisOverlay, overlaysHUD) { + thisOverlay->update(deltatime); + } + foreach(const auto& thisOverlay, overlaysWorld) { + thisOverlay->update(deltatime); } cleanupOverlaysToDelete(); @@ -110,8 +119,14 @@ void Overlays::renderHUD(RenderArgs* renderArgs) { int height = size.y; mat4 legacyProjection = glm::ortho(0, width, height, 0, -1000, 1000); + QMap overlaysHUD; + { + QMutexLocker locker(&_mutex); + overlaysHUD = _overlaysHUD; + } - foreach(Overlay::Pointer thisOverlay, _overlaysHUD) { + + foreach(Overlay::Pointer thisOverlay, overlaysHUD) { // Reset all batch pipeline settings between overlay geometryCache->useSimpleDrawPipeline(batch); @@ -132,7 +147,10 @@ void Overlays::enable() { _enabled = true; } +// Note, can't be invoked by scripts, but can be called by the InterfaceParentFinder +// class on packet processing threads Overlay::Pointer Overlays::getOverlay(OverlayID id) const { + QMutexLocker locker(&_mutex); if (_overlaysHUD.contains(id)) { return _overlaysHUD[id]; } @@ -193,13 +211,17 @@ OverlayID Overlays::addOverlay(const Overlay::Pointer& overlay) { overlay->setOverlayID(thisID); overlay->setStackOrder(_stackOrder++); if (overlay->is3D()) { - _overlaysWorld[thisID] = overlay; + { + QMutexLocker locker(&_mutex); + _overlaysWorld[thisID] = overlay; + } render::ScenePointer scene = qApp->getMain3DScene(); render::Transaction transaction; overlay->addToScene(overlay, scene, transaction); scene->enqueueTransaction(transaction); } else { + QMutexLocker locker(&_mutex); _overlaysHUD[thisID] = overlay; } @@ -231,9 +253,12 @@ OverlayID Overlays::cloneOverlay(OverlayID id) { bool Overlays::editOverlay(OverlayID id, const QVariant& properties) { if (QThread::currentThread() != thread()) { - bool result; - BLOCKING_INVOKE_METHOD(this, "editOverlay", Q_RETURN_ARG(bool, result), Q_ARG(OverlayID, id), Q_ARG(QVariant, properties)); - return result; + // NOTE editOverlay can be called very frequently in scripts and can't afford to + // block waiting on the main thread. Additionally, no script actually + // examines the return value and does something useful with it, so use a non-blocking + // invoke and just always return true + QMetaObject::invokeMethod(this, "editOverlay", Q_ARG(OverlayID, id), Q_ARG(QVariant, properties)); + return true; } Overlay::Pointer thisOverlay = getOverlay(id); @@ -246,9 +271,9 @@ bool Overlays::editOverlay(OverlayID id, const QVariant& properties) { bool Overlays::editOverlays(const QVariant& propertiesById) { if (QThread::currentThread() != thread()) { - bool result; - BLOCKING_INVOKE_METHOD(this, "editOverlays", Q_RETURN_ARG(bool, result), Q_ARG(QVariant, propertiesById)); - return result; + // NOTE see comment on editOverlay for why this is not a blocking call + QMetaObject::invokeMethod(this, "editOverlays", Q_ARG(QVariant, propertiesById)); + return true; } QVariantMap map = propertiesById.toMap(); @@ -275,6 +300,7 @@ void Overlays::deleteOverlay(OverlayID id) { Overlay::Pointer overlayToDelete; { + QMutexLocker locker(&_mutex); if (_overlaysHUD.contains(id)) { overlayToDelete = _overlaysHUD.take(id); } else if (_overlaysWorld.contains(id)) { @@ -378,7 +404,13 @@ OverlayID Overlays::getOverlayAtPoint(const glm::vec2& point) { if (!_enabled) { return UNKNOWN_OVERLAY_ID; } - QMapIterator i(_overlaysHUD); + + QMap overlaysHUD; + { + QMutexLocker locker(&_mutex); + overlaysHUD = _overlaysHUD; + } + QMapIterator i(overlaysHUD); const float LARGE_NEGATIVE_FLOAT = -9999999; glm::vec3 origin(pointCopy.x, pointCopy.y, LARGE_NEGATIVE_FLOAT); @@ -466,8 +498,14 @@ RayToOverlayIntersectionResult Overlays::findRayIntersectionInternal(const PickR float bestDistance = std::numeric_limits::max(); bool bestIsFront = false; + QMap overlaysWorld; + { + QMutexLocker locker(&_mutex); + overlaysWorld = _overlaysWorld; + } + RayToOverlayIntersectionResult result; - QMapIterator i(_overlaysWorld); + QMapIterator i(overlaysWorld); while (i.hasNext()) { i.next(); OverlayID thisID = i.key(); @@ -598,13 +636,20 @@ QSizeF Overlays::textSize(OverlayID id, const QString& text) { return result; } - Overlay::Pointer thisOverlay = _overlaysHUD[id]; + Overlay::Pointer thisOverlay; + { + QMutexLocker locker(&_mutex); + thisOverlay = _overlaysHUD[id]; + } if (thisOverlay) { if (auto textOverlay = std::dynamic_pointer_cast(thisOverlay)) { return textOverlay->textSize(text); } } else { - thisOverlay = _overlaysWorld[id]; + { + QMutexLocker locker(&_mutex); + thisOverlay = _overlaysWorld[id]; + } if (auto text3dOverlay = std::dynamic_pointer_cast(thisOverlay)) { return text3dOverlay->textSize(text); } @@ -675,6 +720,7 @@ bool Overlays::isAddedOverlay(OverlayID id) { return result; } + QMutexLocker locker(&_mutex); return _overlaysHUD.contains(id) || _overlaysWorld.contains(id); } @@ -949,8 +995,13 @@ QVector Overlays::findOverlays(const glm::vec3& center, float radius) { return result; } + QMap overlaysWorld; + { + QMutexLocker locker(&_mutex); + overlaysWorld = _overlaysWorld; + } - QMapIterator i(_overlaysWorld); + QMapIterator i(overlaysWorld); int checked = 0; while (i.hasNext()) { checked++; diff --git a/interface/src/ui/overlays/Overlays.h b/interface/src/ui/overlays/Overlays.h index d3fa70225e..bfb775b041 100644 --- a/interface/src/ui/overlays/Overlays.h +++ b/interface/src/ui/overlays/Overlays.h @@ -319,6 +319,7 @@ signals: private: void cleanupOverlaysToDelete(); + mutable QMutex _mutex; QMap _overlaysHUD; QMap _overlaysWorld; #if OVERLAY_PANELS diff --git a/plugins/openvr/src/ViveControllerManager.cpp b/plugins/openvr/src/ViveControllerManager.cpp index 648373ccc2..2f9aa4405a 100644 --- a/plugins/openvr/src/ViveControllerManager.cpp +++ b/plugins/openvr/src/ViveControllerManager.cpp @@ -249,6 +249,7 @@ ViveControllerManager::InputDevice::InputDevice(vr::IVRSystem*& system) : contro _configStringMap[Config::FeetAndHips] = QString("FeetAndHips"); _configStringMap[Config::FeetHipsAndChest] = QString("FeetHipsAndChest"); _configStringMap[Config::FeetHipsAndShoulders] = QString("FeetHipsAndShoulders"); + _configStringMap[Config::FeetHipsChestAndShoulders] = QString("FeetHipsChestAndShoulders"); } void ViveControllerManager::InputDevice::update(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) { @@ -325,6 +326,7 @@ void ViveControllerManager::InputDevice::calibrateFromUI(const controller::Input if (_calibrate) { uncalibrate(); calibrate(inputCalibrationData); + emitCalibrationStatus(); _calibrate = false; } } @@ -372,29 +374,23 @@ QJsonObject ViveControllerManager::InputDevice::configurationSettings() { Locker locker(_lock); QJsonObject configurationSettings; configurationSettings["trackerConfiguration"] = configToString(_preferedConfig); - configurationSettings["HMDHead"] = (_headConfig == HeadConfig::HMD) ? true : false; - configurationSettings["handController"] = (_handConfig == HandConfig::HandController) ? true : false; + configurationSettings["HMDHead"] = (_headConfig == HeadConfig::HMD); + configurationSettings["handController"] = (_handConfig == HandConfig::HandController); + configurationSettings["puckCount"] = (int)_validTrackedObjects.size(); return configurationSettings; } -void ViveControllerManager::InputDevice::emitCalibrationStatus(const bool success) { +void ViveControllerManager::InputDevice::emitCalibrationStatus() { auto inputConfiguration = DependencyManager::get(); QJsonObject status = QJsonObject(); - - if (_calibrated && success) { - status["calibrated"] = _calibrated; - status["configuration"] = configToString(_preferedConfig); - } else if (!_calibrated && !success) { - status["calibrated"] = _calibrated; - status["success"] = success; - } else if (!_calibrated && success) { - status["calibrated"] = _calibrated; - status["success"] = success; - status["configuration"] = configToString(_preferedConfig); - status["puckCount"] = (int)_validTrackedObjects.size(); - } + status["calibrated"] = _calibrated; + status["configuration"] = configToString(_preferedConfig); + status["head_puck"] = (_headConfig == HeadConfig::Puck); + status["hand_pucks"] = (_handConfig == HandConfig::Pucks); + status["puckCount"] = (int)_validTrackedObjects.size(); + status["UI"] = _calibrate; - emit inputConfiguration->calibrationStatus(status); //inputConfiguration->calibrated(status); + emit inputConfiguration->calibrationStatus(status); } void ViveControllerManager::InputDevice::handleTrackedObject(uint32_t deviceIndex, const controller::InputCalibrationData& inputCalibrationData) { @@ -437,12 +433,29 @@ void ViveControllerManager::InputDevice::handleTrackedObject(uint32_t deviceInde } } +void ViveControllerManager::InputDevice::sendUserActivityData(QString activity) { + QJsonObject jsonData = { + {"num_pucks", (int)_validTrackedObjects.size()}, + {"configuration", configToString(_preferedConfig)}, + {"head_puck", (_headConfig == HeadConfig::Puck) ? true : false}, + {"hand_pucks", (_handConfig == HandConfig::Pucks) ? true : false} + }; + + UserActivityLogger::getInstance().logAction(activity, jsonData); +} + void ViveControllerManager::InputDevice::calibrateOrUncalibrate(const controller::InputCalibrationData& inputCalibration) { if (!_calibrated) { calibrate(inputCalibration); + if (_calibrated) { + sendUserActivityData("mocap_button_success"); + } else { + sendUserActivityData("mocap_button_fail"); + } + emitCalibrationStatus(); } else { uncalibrate(); - emitCalibrationStatus(true); + sendUserActivityData("mocap_button_uncalibrate"); } } @@ -454,7 +467,6 @@ void ViveControllerManager::InputDevice::calibrate(const controller::InputCalibr if (puckCount == 0) { uncalibrate(); - emitCalibrationStatus(false); return; } @@ -473,10 +485,8 @@ void ViveControllerManager::InputDevice::calibrate(const controller::InputCalibr if (!headConfigured || !handsConfigured || !bodyConfigured) { uncalibrate(); - emitCalibrationStatus(false); } else { _calibrated = true; - emitCalibrationStatus(true); qDebug() << "PuckCalibration: " << configToString(_config) << " Configuration Successful"; } } @@ -566,8 +576,6 @@ bool ViveControllerManager::InputDevice::configureBody(glm::mat4& defaultToRefer return true; } qDebug() << "Puck Calibration: " << configToString(_config) << " Config Failed: Could not meet the minimal # of pucks"; - uncalibrate(); - emitCalibrationStatus(false); return false; } diff --git a/plugins/openvr/src/ViveControllerManager.h b/plugins/openvr/src/ViveControllerManager.h index 0b0406bb60..8397f8d804 100644 --- a/plugins/openvr/src/ViveControllerManager.h +++ b/plugins/openvr/src/ViveControllerManager.h @@ -73,6 +73,7 @@ private: void calibrateOrUncalibrate(const controller::InputCalibrationData& inputCalibration); void calibrate(const controller::InputCalibrationData& inputCalibration); void uncalibrate(); + void sendUserActivityData(QString activity); void configureCalibrationSettings(const QJsonObject configurationSettings); QJsonObject configurationSettings(); controller::Pose addOffsetToPuckPose(int joint) const; @@ -106,7 +107,7 @@ private: void calibrateHead(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration); void calibrateFromHandController(const controller::InputCalibrationData& inputCalibrationData); void calibrateFromUI(const controller::InputCalibrationData& inputCalibrationData); - void emitCalibrationStatus(const bool success); + void emitCalibrationStatus(); void calibrateNextFrame(); @@ -139,7 +140,7 @@ private: FeetAndHips, FeetHipsAndChest, FeetHipsAndShoulders, - FeetHipsChestAndShoulders, + FeetHipsChestAndShoulders }; enum class HeadConfig { diff --git a/tools/oven/src/Oven.cpp b/tools/oven/src/Oven.cpp index dc763cc82d..d0b8c3cd65 100644 --- a/tools/oven/src/Oven.cpp +++ b/tools/oven/src/Oven.cpp @@ -61,7 +61,9 @@ Oven::Oven(int argc, char* argv[]) : if (parser.isSet(CLI_INPUT_PARAMETER) || parser.isSet(CLI_OUTPUT_PARAMETER)) { if (parser.isSet(CLI_INPUT_PARAMETER) && parser.isSet(CLI_OUTPUT_PARAMETER)) { BakerCLI* cli = new BakerCLI(this); - cli->bakeFile(parser.value(CLI_INPUT_PARAMETER), parser.value(CLI_OUTPUT_PARAMETER)); + QUrl inputUrl(QDir::fromNativeSeparators(parser.value(CLI_INPUT_PARAMETER))); + QUrl outputUrl(QDir::fromNativeSeparators(parser.value(CLI_OUTPUT_PARAMETER))); + cli->bakeFile(inputUrl, outputUrl.toString()); } else { parser.showHelp(); QApplication::quit(); diff --git a/unpublishedScripts/marketplace/rocketHands/rockethands.js b/unpublishedScripts/marketplace/rocketHands/rockethands.js new file mode 100644 index 0000000000..672dcf2540 --- /dev/null +++ b/unpublishedScripts/marketplace/rocketHands/rockethands.js @@ -0,0 +1,59 @@ +"use strict"; + +/* + rockethands.js + unpublishedScripts/marketplace/rocketHands/rockethands.js + + Created by Cain Kilgore on 30/06/2017 + Copyright 2017 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 +*/ + +(function() { + var isRocketing = false; + + function checkRocketing() { + if (HMD.active && (Controller.Hardware.Vive || Controller.Hardware.OculusTouch) && canRocket()) { + isRocketing = true; + MyAvatar.motorReferenceFrame = "world"; + var moveVector = Vec3.multiply(Quat.getFront(Camera.getOrientation()), 10); + if (!MyAvatar.isFlying()) { + moveVector = Vec3.sum(moveVector, {x: 0, y: 1, z: 0}); + } + MyAvatar.motorVelocity = moveVector; + MyAvatar.motorTimescale = 1.0; + } else { + checkCanStopRocketing(); + } + }; + + function checkCanStopRocketing() { + if (isRocketing) { + MyAvatar.motorVelocity = 0; + isRocketing = false; + } + } + + function canRocket() { + var leftHand = Controller.getPoseValue(Controller.Standard.LeftHand); + var rightHand = Controller.getPoseValue(Controller.Standard.RightHand); + var leftWorldControllerPos = Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, leftHand.translation)); + var rightWorldControllerPos = Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, rightHand.translation)); + var hipPosition = MyAvatar.getJointPosition("Hips"); + var controllerHipThreshold = 0.1; // In Meters. Experimentally determined. Used to figure out if user's hands are "close enough" to their hips. + var controllerRotationThreshold = 0.25; // In Radians. Experimentally determined. Used to figure out if user's hands are within a rotation threshold. + + return ((leftWorldControllerPos.y > (hipPosition.y - controllerHipThreshold)) && + (leftWorldControllerPos.y < (hipPosition.y + controllerHipThreshold)) && + (rightWorldControllerPos.y > (hipPosition.y - controllerHipThreshold)) && + (rightWorldControllerPos.y < (hipPosition.y + controllerHipThreshold)) && + leftHand.rotation.y < controllerRotationThreshold && + leftHand.rotation.y > -controllerRotationThreshold && + rightHand.rotation.y < controllerRotationThreshold && + rightHand.rotation.y > -controllerRotationThreshold); + } + + Script.update.connect(checkRocketing); +}()); \ No newline at end of file