From 5e624246a8d517ba5a2a41d4dc68f0cdb43812e3 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 19 Jul 2018 13:00:57 +1200 Subject: [PATCH 01/29] Fix HMD.mountedChanged() API signal --- interface/src/Application.cpp | 5 +++++ interface/src/scripting/HMDScriptingInterface.h | 11 ----------- .../display-plugins/AbstractHMDScriptingInterface.h | 11 +++++++++++ .../src/display-plugins/hmd/HmdDisplayPlugin.h | 4 ++++ plugins/oculus/src/OculusBaseDisplayPlugin.cpp | 4 ++++ plugins/oculus/src/OculusBaseDisplayPlugin.h | 1 + plugins/openvr/src/OpenVrDisplayPlugin.cpp | 4 ++++ plugins/openvr/src/OpenVrDisplayPlugin.h | 2 ++ 8 files changed, 31 insertions(+), 11 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 311c08b858..526f0da5ba 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -143,6 +143,7 @@ #include #include #include +#include #include #include #include @@ -2717,6 +2718,10 @@ void Application::initializeDisplayPlugins() { QObject::connect(displayPlugin.get(), &DisplayPlugin::recommendedFramebufferSizeChanged, [this](const QSize& size) { resizeGL(); }); QObject::connect(displayPlugin.get(), &DisplayPlugin::resetSensorsRequested, this, &Application::requestReset); + if (displayPlugin->isHmd()) { + QObject::connect(dynamic_cast(displayPlugin.get()), &HmdDisplayPlugin::isHmdMountedChanged, + DependencyManager::get().data(), &HMDScriptingInterface::mountedChanged); + } } // The default display plugin needs to be activated first, otherwise the display plugin thread diff --git a/interface/src/scripting/HMDScriptingInterface.h b/interface/src/scripting/HMDScriptingInterface.h index d4dba2f0f5..8d367e3a35 100644 --- a/interface/src/scripting/HMDScriptingInterface.h +++ b/interface/src/scripting/HMDScriptingInterface.h @@ -345,17 +345,6 @@ signals: */ bool shouldShowHandControllersChanged(); - /**jsdoc - * Triggered when the HMD.mounted property value changes. - * @function HMD.mountedChanged - * @returns {Signal} - * @example Report when there's a change in the HMD being worn. - * HMD.mountedChanged.connect(function () { - * print("Mounted changed. HMD is mounted: " + HMD.mounted); - * }); - */ - void mountedChanged(); - public: HMDScriptingInterface(); static QScriptValue getHUDLookAtPosition2D(QScriptContext* context, QScriptEngine* engine); diff --git a/libraries/display-plugins/src/display-plugins/AbstractHMDScriptingInterface.h b/libraries/display-plugins/src/display-plugins/AbstractHMDScriptingInterface.h index 392fa7e2a2..7fe58618bc 100644 --- a/libraries/display-plugins/src/display-plugins/AbstractHMDScriptingInterface.h +++ b/libraries/display-plugins/src/display-plugins/AbstractHMDScriptingInterface.h @@ -54,6 +54,17 @@ signals: */ void displayModeChanged(bool isHMDMode); + /**jsdoc + * Triggered when the HMD.mounted property value changes. + * @function HMD.mountedChanged + * @returns {Signal} + * @example Report when there's a change in the HMD being worn. + * HMD.mountedChanged.connect(function () { + * print("Mounted changed. HMD is mounted: " + HMD.mounted); + * }); + */ + void mountedChanged(); + private: float _IPDScale{ 1.0 }; }; diff --git a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.h index 3639952524..22a12b7922 100644 --- a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.h @@ -21,6 +21,7 @@ #include "../OpenGLDisplayPlugin.h" class HmdDisplayPlugin : public OpenGLDisplayPlugin { + Q_OBJECT using Parent = OpenGLDisplayPlugin; public: ~HmdDisplayPlugin(); @@ -45,6 +46,9 @@ public: virtual bool onDisplayTextureReset() override { _clearPreviewFlag = true; return true; }; +signals: + void isHmdMountedChanged(); + protected: virtual void hmdPresent() = 0; virtual bool isHmdMounted() const = 0; diff --git a/plugins/oculus/src/OculusBaseDisplayPlugin.cpp b/plugins/oculus/src/OculusBaseDisplayPlugin.cpp index 5aa1e45943..60515314b6 100644 --- a/plugins/oculus/src/OculusBaseDisplayPlugin.cpp +++ b/plugins/oculus/src/OculusBaseDisplayPlugin.cpp @@ -36,6 +36,10 @@ bool OculusBaseDisplayPlugin::beginFrameRender(uint32_t frameIndex) { if (ovr::reorientRequested(status)) { emit resetSensorsRequested(); } + if (ovr::hmdMounted(status) != _isHmdMounted) { + _isHmdMounted = !_isHmdMounted; + emit isHmdMountedChanged(); + } _currentRenderFrameInfo = FrameInfo(); _currentRenderFrameInfo.sensorSampleTime = ovr_GetTimeInSeconds(); diff --git a/plugins/oculus/src/OculusBaseDisplayPlugin.h b/plugins/oculus/src/OculusBaseDisplayPlugin.h index d70d14dc28..aa6130c293 100644 --- a/plugins/oculus/src/OculusBaseDisplayPlugin.h +++ b/plugins/oculus/src/OculusBaseDisplayPlugin.h @@ -44,4 +44,5 @@ protected: ovrLayerEyeFov _sceneLayer; ovrViewScaleDesc _viewScaleDesc; // ovrLayerEyeFovDepth _depthLayer; + bool _isHmdMounted { false }; }; diff --git a/plugins/openvr/src/OpenVrDisplayPlugin.cpp b/plugins/openvr/src/OpenVrDisplayPlugin.cpp index 5e4079cbcf..c3fdad6e82 100644 --- a/plugins/openvr/src/OpenVrDisplayPlugin.cpp +++ b/plugins/openvr/src/OpenVrDisplayPlugin.cpp @@ -699,7 +699,11 @@ void OpenVrDisplayPlugin::postPreview() { _nextSimPoseData = nextSim; }); _nextRenderPoseData = nextRender; + } + if (isHmdMounted() != _isHmdMounted) { + _isHmdMounted = !_isHmdMounted; + emit isHmdMountedChanged(); } } diff --git a/plugins/openvr/src/OpenVrDisplayPlugin.h b/plugins/openvr/src/OpenVrDisplayPlugin.h index 15a434341d..a6ee93931d 100644 --- a/plugins/openvr/src/OpenVrDisplayPlugin.h +++ b/plugins/openvr/src/OpenVrDisplayPlugin.h @@ -90,4 +90,6 @@ private: friend class OpenVrSubmitThread; bool _asyncReprojectionActive { false }; + + bool _isHmdMounted { false }; }; From a3e677e64fc48f0e413aa4e8bfa10a93d553b453 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 20 Jul 2018 08:32:21 +1200 Subject: [PATCH 02/29] Code review --- interface/src/Application.cpp | 2 +- .../src/display-plugins/hmd/HmdDisplayPlugin.h | 2 +- plugins/oculus/src/OculusBaseDisplayPlugin.cpp | 6 +++--- plugins/oculus/src/OculusBaseDisplayPlugin.h | 2 +- plugins/openvr/src/OpenVrDisplayPlugin.cpp | 6 +++--- plugins/openvr/src/OpenVrDisplayPlugin.h | 2 +- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 526f0da5ba..6152a549c2 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2719,7 +2719,7 @@ void Application::initializeDisplayPlugins() { [this](const QSize& size) { resizeGL(); }); QObject::connect(displayPlugin.get(), &DisplayPlugin::resetSensorsRequested, this, &Application::requestReset); if (displayPlugin->isHmd()) { - QObject::connect(dynamic_cast(displayPlugin.get()), &HmdDisplayPlugin::isHmdMountedChanged, + QObject::connect(dynamic_cast(displayPlugin.get()), &HmdDisplayPlugin::hmdMountedChanged, DependencyManager::get().data(), &HMDScriptingInterface::mountedChanged); } } diff --git a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.h index 22a12b7922..fb10084b09 100644 --- a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.h @@ -47,7 +47,7 @@ public: virtual bool onDisplayTextureReset() override { _clearPreviewFlag = true; return true; }; signals: - void isHmdMountedChanged(); + void hmdMountedChanged(); protected: virtual void hmdPresent() = 0; diff --git a/plugins/oculus/src/OculusBaseDisplayPlugin.cpp b/plugins/oculus/src/OculusBaseDisplayPlugin.cpp index 60515314b6..36790d1b50 100644 --- a/plugins/oculus/src/OculusBaseDisplayPlugin.cpp +++ b/plugins/oculus/src/OculusBaseDisplayPlugin.cpp @@ -36,9 +36,9 @@ bool OculusBaseDisplayPlugin::beginFrameRender(uint32_t frameIndex) { if (ovr::reorientRequested(status)) { emit resetSensorsRequested(); } - if (ovr::hmdMounted(status) != _isHmdMounted) { - _isHmdMounted = !_isHmdMounted; - emit isHmdMountedChanged(); + if (ovr::hmdMounted(status) != _hmdMounted) { + _hmdMounted = !_hmdMounted; + emit hmdMountedChanged(); } _currentRenderFrameInfo = FrameInfo(); diff --git a/plugins/oculus/src/OculusBaseDisplayPlugin.h b/plugins/oculus/src/OculusBaseDisplayPlugin.h index aa6130c293..244c06ecf5 100644 --- a/plugins/oculus/src/OculusBaseDisplayPlugin.h +++ b/plugins/oculus/src/OculusBaseDisplayPlugin.h @@ -44,5 +44,5 @@ protected: ovrLayerEyeFov _sceneLayer; ovrViewScaleDesc _viewScaleDesc; // ovrLayerEyeFovDepth _depthLayer; - bool _isHmdMounted { false }; + bool _hmdMounted { false }; }; diff --git a/plugins/openvr/src/OpenVrDisplayPlugin.cpp b/plugins/openvr/src/OpenVrDisplayPlugin.cpp index c3fdad6e82..cd56eeff39 100644 --- a/plugins/openvr/src/OpenVrDisplayPlugin.cpp +++ b/plugins/openvr/src/OpenVrDisplayPlugin.cpp @@ -701,9 +701,9 @@ void OpenVrDisplayPlugin::postPreview() { _nextRenderPoseData = nextRender; } - if (isHmdMounted() != _isHmdMounted) { - _isHmdMounted = !_isHmdMounted; - emit isHmdMountedChanged(); + if (isHmdMounted() != _hmdMounted) { + _hmdMounted = !_hmdMounted; + emit hmdMountedChanged(); } } diff --git a/plugins/openvr/src/OpenVrDisplayPlugin.h b/plugins/openvr/src/OpenVrDisplayPlugin.h index a6ee93931d..add35d6383 100644 --- a/plugins/openvr/src/OpenVrDisplayPlugin.h +++ b/plugins/openvr/src/OpenVrDisplayPlugin.h @@ -91,5 +91,5 @@ private: bool _asyncReprojectionActive { false }; - bool _isHmdMounted { false }; + bool _hmdMounted { false }; }; From dfb20c4afccc45cac1268e6127a2d74813354c10 Mon Sep 17 00:00:00 2001 From: Alexander Ivash Date: Tue, 24 Jul 2018 23:02:06 +0300 Subject: [PATCH 03/29] FB16840 - Qml spinboxes in UI toolkit should focus the underlying field when clicked on --- interface/resources/qml/controls-uit/SpinBox.qml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/interface/resources/qml/controls-uit/SpinBox.qml b/interface/resources/qml/controls-uit/SpinBox.qml index 5a4ba70080..f3ae3c5d6e 100644 --- a/interface/resources/qml/controls-uit/SpinBox.qml +++ b/interface/resources/qml/controls-uit/SpinBox.qml @@ -124,6 +124,11 @@ SpinBox { color: spinBox.up.pressed || spinBox.up.hovered ? (isLightColorScheme ? hifi.colors.black : hifi.colors.white) : hifi.colors.gray } } + up.onPressedChanged: { + if(value) { + spinBox.forceActiveFocus(); + } + } down.indicator: Item { x: spinBox.width - implicitWidth - 5 @@ -138,6 +143,11 @@ SpinBox { color: spinBox.down.pressed || spinBox.down.hovered ? (isLightColorScheme ? hifi.colors.black : hifi.colors.white) : hifi.colors.gray } } + down.onPressedChanged: { + if(value) { + spinBox.forceActiveFocus(); + } + } HifiControls.Label { id: spinBoxLabel From c9d9f7363ab99e4e487d72b4c0dc10ca6cba21fe Mon Sep 17 00:00:00 2001 From: Alexander Ivash Date: Tue, 24 Jul 2018 23:19:11 +0300 Subject: [PATCH 04/29] use 'light' color scheme --- interface/resources/qml/hifi/avatarapp/AdjustWearables.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/resources/qml/hifi/avatarapp/AdjustWearables.qml b/interface/resources/qml/hifi/avatarapp/AdjustWearables.qml index a501185853..39344b04bc 100644 --- a/interface/resources/qml/hifi/avatarapp/AdjustWearables.qml +++ b/interface/resources/qml/hifi/avatarapp/AdjustWearables.qml @@ -326,7 +326,7 @@ Rectangle { height: 40 anchors.right: parent.right color: hifi.buttons.red; - colorScheme: hifi.colorSchemes.dark; + colorScheme: hifi.colorSchemes.light; text: "TAKE IT OFF" onClicked: wearableDeleted(root.avatarName, getCurrentWearable().id); enabled: wearablesCombobox.model.count !== 0 From 1ac68458997d5fc4107fc48da2d94c728e05e669 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 25 Jul 2018 09:16:46 +1200 Subject: [PATCH 05/29] Fix ParticleEffect entity JSDoc --- .../entities/src/EntityItemProperties.cpp | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index efd2376677..8838fedd59 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -886,28 +886,30 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { * @property {string} textures="" - The URL of a JPG or PNG image file to display for each particle. If you want transparency, * use PNG format. * @property {number} particleRadius=0.025 - The radius of each particle at the middle of its life. - * @property {number} radiusStart=NAN - The radius of each particle at the start of its life. If NAN, the + * @property {number} radiusStart=null - The radius of each particle at the start of its life. If null, the * particleRadius value is used. - * @property {number} radiusFinish=NAN - The radius of each particle at the end of its life. If NAN, the + * @property {number} radiusFinish=null - The radius of each particle at the end of its life. If null, the * particleRadius value is used. * @property {number} radiusSpread=0 - The spread in radius that each particle is given. If particleRadius == 0.5 - * and radiusSpread == 0.25, each particle will have a radius in the range 0.250.75. + * and radiusSpread == 0.25, each particle will have a radius in the range 0.25 – + * 0.75. * @property {Color} color=255,255,255 - The color of each particle at the middle of its life. - * @property {Color} colorStart=NAN,NAN,NAN - The color of each particle at the start of its life. If any of the values are NAN, the - * color value is used. - * @property {Color} colorFinish=NAN,NAN,NAN - The color of each particle at the end of its life. If any of the values are NAN, the - * color value is used. + * @property {Color} colorStart={} - The color of each particle at the start of its life. If any of the component values are + * undefined, the color value is used. + * @property {Color} colorFinish={} - The color of each particle at the end of its life. If any of the component values are + * undefined, the color value is used. * @property {Color} colorSpread=0,0,0 - The spread in color that each particle is given. If * color == {red: 100, green: 100, blue: 100} and colorSpread == - * {red: 10, green: 25, blue: 50}, each particle will have an acceleration in the range {red: 90, green: 75, blue: 50} - * – {red: 110, green: 125, blue: 150}. + * {red: 10, green: 25, blue: 50}, each particle will have a color in the range + * {red: 90, green: 75, blue: 50}{red: 110, green: 125, blue: 150}. * @property {number} alpha=1 - The alpha of each particle at the middle of its life. - * @property {number} alphaStart=NAN - The alpha of each particle at the start of its life. If NAN, the + * @property {number} alphaStart=null - The alpha of each particle at the start of its life. If null, the * alpha value is used. - * @property {number} alphaFinish=NAN - The alpha of each particle at the end of its life. If NAN, the + * @property {number} alphaFinish=null - The alpha of each particle at the end of its life. If null, the * alpha value is used. * @property {number} alphaSpread=0 - The spread in alpha that each particle is given. If alpha == 0.5 - * and alphaSpread == 0.25, each particle will have an alpha in the range 0.250.75. + * and alphaSpread == 0.25, each particle will have an alpha in the range 0.25 – + * 0.75. * * @property {ShapeType} shapeType="none" - Currently not used. Read-only. * From 16e06de9cd1f11490f1b37db83ac600af9963a5c Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 25 Jul 2018 22:10:14 +1200 Subject: [PATCH 06/29] Move scriptable caches into scripting interfaces Removed non-working getResource() API functions. --- assignment-client/src/Agent.cpp | 6 +- .../src/scripts/EntityScriptServer.cpp | 4 +- interface/src/Application.cpp | 21 ++-- interface/src/ui/overlays/Web3DOverlay.cpp | 4 +- libraries/animation/src/AnimationCache.h | 59 ---------- .../src/AnimationCacheScriptingInterface.cpp | 21 ++++ .../src/AnimationCacheScriptingInterface.h | 62 +++++++++++ libraries/audio/src/SoundCache.h | 62 +---------- .../src/SoundCacheScriptingInterface.cpp | 21 ++++ .../audio/src/SoundCacheScriptingInterface.h | 61 ++++++++++ .../src/model-networking/ModelCache.h | 52 --------- .../ModelCacheScriptingInterface.cpp | 17 +++ .../ModelCacheScriptingInterface.h | 52 +++++++++ .../src/model-networking/TextureCache.h | 64 +---------- .../TextureCacheScriptingInterface.cpp | 24 ++++ .../TextureCacheScriptingInterface.h | 68 ++++++++++++ libraries/networking/src/ResourceCache.cpp | 18 +++ libraries/networking/src/ResourceCache.h | 104 +++++++++++------- 18 files changed, 430 insertions(+), 290 deletions(-) create mode 100644 libraries/animation/src/AnimationCacheScriptingInterface.cpp create mode 100644 libraries/animation/src/AnimationCacheScriptingInterface.h create mode 100644 libraries/audio/src/SoundCacheScriptingInterface.cpp create mode 100644 libraries/audio/src/SoundCacheScriptingInterface.h create mode 100644 libraries/model-networking/src/model-networking/ModelCacheScriptingInterface.cpp create mode 100644 libraries/model-networking/src/model-networking/ModelCacheScriptingInterface.h create mode 100644 libraries/model-networking/src/model-networking/TextureCacheScriptingInterface.cpp create mode 100644 libraries/model-networking/src/model-networking/TextureCacheScriptingInterface.h diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 73444d1198..304f24d51c 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -31,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -454,8 +456,8 @@ void Agent::executeScript() { // register ourselves to the script engine _scriptEngine->registerGlobalObject("Agent", this); - _scriptEngine->registerGlobalObject("SoundCache", DependencyManager::get().data()); - _scriptEngine->registerGlobalObject("AnimationCache", DependencyManager::get().data()); + _scriptEngine->registerGlobalObject("SoundCache", new SoundCacheScriptingInterface(DependencyManager::get().data())); + _scriptEngine->registerGlobalObject("AnimationCache", new AnimationCacheScriptingInterface(DependencyManager::get().data())); QScriptValue webSocketServerConstructorValue = _scriptEngine->newFunction(WebSocketServerClass::constructor); _scriptEngine->globalObject().setProperty("WebSocketServer", webSocketServerConstructorValue); diff --git a/assignment-client/src/scripts/EntityScriptServer.cpp b/assignment-client/src/scripts/EntityScriptServer.cpp index ebe25b11bf..afb6d3588b 100644 --- a/assignment-client/src/scripts/EntityScriptServer.cpp +++ b/assignment-client/src/scripts/EntityScriptServer.cpp @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #include @@ -438,7 +438,7 @@ void EntityScriptServer::resetEntitiesScriptEngine() { auto webSocketServerConstructorValue = newEngine->newFunction(WebSocketServerClass::constructor); newEngine->globalObject().setProperty("WebSocketServer", webSocketServerConstructorValue); - newEngine->registerGlobalObject("SoundCache", DependencyManager::get().data()); + newEngine->registerGlobalObject("SoundCache", new SoundCacheScriptingInterface(DependencyManager::get().data())); // connect this script engines printedMessage signal to the global ScriptEngines these various messages auto scriptEngines = DependencyManager::get().data(); diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 6963f945aa..a613704afe 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -63,6 +63,7 @@ #include #include #include +#include #include #include #include @@ -98,6 +99,8 @@ #include #include #include +#include +#include #include #include #include @@ -127,7 +130,7 @@ #include #include #include -#include +#include #include #include #include @@ -2989,10 +2992,10 @@ void Application::onDesktopRootContextCreated(QQmlContext* surfaceContext) { surfaceContext->setContextProperty("LocationBookmarks", DependencyManager::get().data()); // Caches - surfaceContext->setContextProperty("AnimationCache", DependencyManager::get().data()); - surfaceContext->setContextProperty("TextureCache", DependencyManager::get().data()); - surfaceContext->setContextProperty("ModelCache", DependencyManager::get().data()); - surfaceContext->setContextProperty("SoundCache", DependencyManager::get().data()); + surfaceContext->setContextProperty("AnimationCache", new AnimationCacheScriptingInterface(DependencyManager::get().data())); + surfaceContext->setContextProperty("TextureCache", new TextureCacheScriptingInterface(DependencyManager::get().data())); + surfaceContext->setContextProperty("ModelCache", new ModelCacheScriptingInterface(DependencyManager::get().data())); + surfaceContext->setContextProperty("SoundCache", new SoundCacheScriptingInterface(DependencyManager::get().data())); surfaceContext->setContextProperty("InputConfiguration", DependencyManager::get().data()); surfaceContext->setContextProperty("Account", AccountServicesScriptingInterface::getInstance()); // DEPRECATED - TO BE REMOVED @@ -6612,10 +6615,10 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEnginePointe scriptEngine->registerGlobalObject("Pointers", DependencyManager::get().data()); // Caches - scriptEngine->registerGlobalObject("AnimationCache", DependencyManager::get().data()); - scriptEngine->registerGlobalObject("TextureCache", DependencyManager::get().data()); - scriptEngine->registerGlobalObject("ModelCache", DependencyManager::get().data()); - scriptEngine->registerGlobalObject("SoundCache", DependencyManager::get().data()); + scriptEngine->registerGlobalObject("AnimationCache", new AnimationCacheScriptingInterface(DependencyManager::get().data())); + scriptEngine->registerGlobalObject("TextureCache", new TextureCacheScriptingInterface(DependencyManager::get().data())); + scriptEngine->registerGlobalObject("ModelCache", new ModelCacheScriptingInterface(DependencyManager::get().data())); + scriptEngine->registerGlobalObject("SoundCache", new SoundCacheScriptingInterface(DependencyManager::get().data())); scriptEngine->registerGlobalObject("DialogsManager", _dialogsManagerScriptingInterface); diff --git a/interface/src/ui/overlays/Web3DOverlay.cpp b/interface/src/ui/overlays/Web3DOverlay.cpp index fbea492d1d..b65fb93707 100644 --- a/interface/src/ui/overlays/Web3DOverlay.cpp +++ b/interface/src/ui/overlays/Web3DOverlay.cpp @@ -55,7 +55,7 @@ #include "scripting/AccountServicesScriptingInterface.h" #include #include "ui/Snapshot.h" -#include "SoundCache.h" +#include "SoundCacheScriptingInterface.h" #include "raypick/PointerScriptingInterface.h" #include #include "AboutUtil.h" @@ -253,7 +253,7 @@ void Web3DOverlay::setupQmlSurface() { _webSurface->getSurfaceContext()->setContextProperty("AvatarList", DependencyManager::get().data()); _webSurface->getSurfaceContext()->setContextProperty("DialogsManager", DialogsManagerScriptingInterface::getInstance()); _webSurface->getSurfaceContext()->setContextProperty("InputConfiguration", DependencyManager::get().data()); - _webSurface->getSurfaceContext()->setContextProperty("SoundCache", DependencyManager::get().data()); + _webSurface->getSurfaceContext()->setContextProperty("SoundCache", new SoundCacheScriptingInterface(DependencyManager::get().data())); _webSurface->getSurfaceContext()->setContextProperty("MenuInterface", MenuScriptingInterface::getInstance()); _webSurface->getSurfaceContext()->setContextProperty("Settings", SettingsScriptingInterface::getInstance()); _webSurface->getSurfaceContext()->setContextProperty("AvatarBookmarks", DependencyManager::get().data()); diff --git a/libraries/animation/src/AnimationCache.h b/libraries/animation/src/AnimationCache.h index 4b0a8901f5..ca5ea5b072 100644 --- a/libraries/animation/src/AnimationCache.h +++ b/libraries/animation/src/AnimationCache.h @@ -24,71 +24,12 @@ class Animation; typedef QSharedPointer AnimationPointer; -/// Scriptable interface for FBX animation loading. class AnimationCache : public ResourceCache, public Dependency { Q_OBJECT SINGLETON_DEPENDENCY public: - // Properties are copied over from ResourceCache (see ResourceCache.h for reason). - - /**jsdoc - * API to manage animation cache resources. - * @namespace AnimationCache - * - * @hifi-interface - * @hifi-client-entity - * @hifi-assignment-client - * - * @property {number} numTotal - Total number of total resources. Read-only. - * @property {number} numCached - Total number of cached resource. Read-only. - * @property {number} sizeTotal - Size in bytes of all resources. Read-only. - * @property {number} sizeCached - Size in bytes of all cached resources. Read-only. - */ - - // Functions are copied over from ResourceCache (see ResourceCache.h for reason). - - /**jsdoc - * Get the list of all resource URLs. - * @function AnimationCache.getResourceList - * @returns {string[]} - */ - - /**jsdoc - * @function AnimationCache.dirty - * @returns {Signal} - */ - - /**jsdoc - * @function AnimationCache.updateTotalSize - * @param {number} deltaSize - */ - - /**jsdoc - * Prefetches a resource. - * @function AnimationCache.prefetch - * @param {string} url - URL of the resource to prefetch. - * @param {object} [extra=null] - * @returns {ResourceObject} - */ - - /**jsdoc - * Asynchronously loads a resource from the specified URL and returns it. - * @function AnimationCache.getResource - * @param {string} url - URL of the resource to load. - * @param {string} [fallback=""] - Fallback URL if load of the desired URL fails. - * @param {} [extra=null] - * @returns {object} - */ - - - /**jsdoc - * Returns animation resource for particular animation. - * @function AnimationCache.getAnimation - * @param {string} url - URL to load. - * @returns {AnimationObject} animation - */ Q_INVOKABLE AnimationPointer getAnimation(const QString& url) { return getAnimation(QUrl(url)); } Q_INVOKABLE AnimationPointer getAnimation(const QUrl& url); diff --git a/libraries/animation/src/AnimationCacheScriptingInterface.cpp b/libraries/animation/src/AnimationCacheScriptingInterface.cpp new file mode 100644 index 0000000000..a648a06228 --- /dev/null +++ b/libraries/animation/src/AnimationCacheScriptingInterface.cpp @@ -0,0 +1,21 @@ +// +// AnimationCacheScriptingInterface.cpp +// libraries/animation/src +// +// Created by David Rowe on 25 Jul 2018. +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "AnimationCacheScriptingInterface.h" + +AnimationCacheScriptingInterface::AnimationCacheScriptingInterface(AnimationCache* animationCache) : + _animationCache(animationCache), + ScriptableResourceCache::ScriptableResourceCache(animationCache) +{ } + +AnimationPointer AnimationCacheScriptingInterface::getAnimation(const QUrl& url) { + return _animationCache->getAnimation(url); +} \ No newline at end of file diff --git a/libraries/animation/src/AnimationCacheScriptingInterface.h b/libraries/animation/src/AnimationCacheScriptingInterface.h new file mode 100644 index 0000000000..ff7137040c --- /dev/null +++ b/libraries/animation/src/AnimationCacheScriptingInterface.h @@ -0,0 +1,62 @@ +// +// AnimationCacheScriptingInterface.h +// libraries/animation/src +// +// Created by David Rowe on 25 Jul 2018. +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#pragma once + +#ifndef hifi_AnimationCacheScriptingInterface_h +#define hifi_AnimationCacheScriptingInterface_h + +#include + +#include + +#include "AnimationCache.h" + +class AnimationCacheScriptingInterface : public ScriptableResourceCache { + Q_OBJECT + + // Properties are copied over from ResourceCache (see ResourceCache.h for reason). + + /**jsdoc + * API to manage animation cache resources. + * @namespace AnimationCache + * + * @hifi-interface + * @hifi-client-entity + * @hifi-assignment-client + * + * @property {number} numTotal - Total number of total resources. Read-only. + * @property {number} numCached - Total number of cached resource. Read-only. + * @property {number} sizeTotal - Size in bytes of all resources. Read-only. + * @property {number} sizeCached - Size in bytes of all cached resources. Read-only. + * + * @borrows ResourceCache.getResourceList as getResourceList + * @borrows ResourceCache.updateTotalSize as updateTotalSize + * @borrows ResourceCache.prefetch as prefetch + * @borrows ResourceCache.dirty as dirty + */ + +public: + AnimationCacheScriptingInterface(AnimationCache* animationCache); + + /**jsdoc + * Returns animation resource for particular animation. + * @function AnimationCache.getAnimation + * @param {string} url - URL to load. + * @returns {AnimationObject} animation + */ + Q_INVOKABLE AnimationPointer getAnimation(const QString& url) { return getAnimation(QUrl(url)); } + Q_INVOKABLE AnimationPointer getAnimation(const QUrl& url); + +private: + AnimationCache* _animationCache; +}; + +#endif // hifi_AnimationCacheScriptingInterface_h diff --git a/libraries/audio/src/SoundCache.h b/libraries/audio/src/SoundCache.h index 4352b1d459..64d392a41d 100644 --- a/libraries/audio/src/SoundCache.h +++ b/libraries/audio/src/SoundCache.h @@ -16,73 +16,13 @@ #include "Sound.h" -/// Scriptable interface for sound loading. class SoundCache : public ResourceCache, public Dependency { Q_OBJECT SINGLETON_DEPENDENCY public: - - // Properties are copied over from ResourceCache (see ResourceCache.h for reason). - - /**jsdoc - * API to manage sound cache resources. - * @namespace SoundCache - * - * @hifi-interface - * @hifi-client-entity - * @hifi-server-entity - * @hifi-assignment-client - * - * @property {number} numTotal - Total number of total resources. Read-only. - * @property {number} numCached - Total number of cached resource. Read-only. - * @property {number} sizeTotal - Size in bytes of all resources. Read-only. - * @property {number} sizeCached - Size in bytes of all cached resources. Read-only. - */ - - - // Functions are copied over from ResourceCache (see ResourceCache.h for reason). - - /**jsdoc - * Get the list of all resource URLs. - * @function SoundCache.getResourceList - * @returns {string[]} - */ - - /**jsdoc - * @function SoundCache.dirty - * @returns {Signal} - */ - - /**jsdoc - * @function SoundCache.updateTotalSize - * @param {number} deltaSize - */ - - /**jsdoc - * Prefetches a resource. - * @function SoundCache.prefetch - * @param {string} url - URL of the resource to prefetch. - * @param {object} [extra=null] - * @returns {ResourceObject} - */ - - /**jsdoc - * Asynchronously loads a resource from the specified URL and returns it. - * @function SoundCache.getResource - * @param {string} url - URL of the resource to load. - * @param {string} [fallback=""] - Fallback URL if load of the desired URL fails. - * @param {} [extra=null] - * @returns {object} - */ - - - /**jsdoc - * @function SoundCache.getSound - * @param {string} url - * @returns {SoundObject} - */ Q_INVOKABLE SharedSoundPointer getSound(const QUrl& url); + protected: virtual QSharedPointer createResource(const QUrl& url, const QSharedPointer& fallback, const void* extra) override; diff --git a/libraries/audio/src/SoundCacheScriptingInterface.cpp b/libraries/audio/src/SoundCacheScriptingInterface.cpp new file mode 100644 index 0000000000..d9c65ddd29 --- /dev/null +++ b/libraries/audio/src/SoundCacheScriptingInterface.cpp @@ -0,0 +1,21 @@ +// +// SoundCacheScriptingInterface.cpp +// libraries/audio/src +// +// Created by David Rowe on 25 Jul 2018. +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "SoundCacheScriptingInterface.h" + +SoundCacheScriptingInterface::SoundCacheScriptingInterface(SoundCache* soundCache) : + _soundCache(soundCache), + ScriptableResourceCache::ScriptableResourceCache(soundCache) +{ } + +SharedSoundPointer SoundCacheScriptingInterface::getSound(const QUrl& url) { + return _soundCache->getSound(url); +} diff --git a/libraries/audio/src/SoundCacheScriptingInterface.h b/libraries/audio/src/SoundCacheScriptingInterface.h new file mode 100644 index 0000000000..01b5753965 --- /dev/null +++ b/libraries/audio/src/SoundCacheScriptingInterface.h @@ -0,0 +1,61 @@ +// +// SoundCacheScriptingInterface.h +// libraries/audio/src +// +// Created by David Rowe on 25 Jul 2018. +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#pragma once + +#ifndef hifi_SoundCacheScriptingInterface_h +#define hifi_SoundCacheScriptingInterface_h + +#include + +#include + +#include "SoundCache.h" + +class SoundCacheScriptingInterface : public ScriptableResourceCache { + Q_OBJECT + + // Properties are copied over from ResourceCache (see ResourceCache.h for reason). + + /**jsdoc + * API to manage sound cache resources. + * @namespace SoundCache + * + * @hifi-interface + * @hifi-client-entity + * @hifi-server-entity + * @hifi-assignment-client + * + * @property {number} numTotal - Total number of total resources. Read-only. + * @property {number} numCached - Total number of cached resource. Read-only. + * @property {number} sizeTotal - Size in bytes of all resources. Read-only. + * @property {number} sizeCached - Size in bytes of all cached resources. Read-only. + * + * @borrows ResourceCache.getResourceList as getResourceList + * @borrows ResourceCache.updateTotalSize as updateTotalSize + * @borrows ResourceCache.prefetch as prefetch + * @borrows ResourceCache.dirty as dirty + */ + +public: + SoundCacheScriptingInterface(SoundCache* soundCache); + + /**jsdoc + * @function SoundCache.getSound + * @param {string} url + * @returns {SoundObject} + */ + Q_INVOKABLE SharedSoundPointer getSound(const QUrl& url); + +private: + SoundCache* _soundCache; +}; + +#endif // hifi_SoundCacheScriptingInterface_h diff --git a/libraries/model-networking/src/model-networking/ModelCache.h b/libraries/model-networking/src/model-networking/ModelCache.h index ee13d6666c..eea6c93786 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.h +++ b/libraries/model-networking/src/model-networking/ModelCache.h @@ -140,58 +140,6 @@ class ModelCache : public ResourceCache, public Dependency { public: - // Properties are copied over from ResourceCache (see ResourceCache.h for reason). - - /**jsdoc - * API to manage model cache resources. - * @namespace ModelCache - * - * @hifi-interface - * @hifi-client-entity - * - * @property {number} numTotal - Total number of total resources. Read-only. - * @property {number} numCached - Total number of cached resource. Read-only. - * @property {number} sizeTotal - Size in bytes of all resources. Read-only. - * @property {number} sizeCached - Size in bytes of all cached resources. Read-only. - */ - - - // Functions are copied over from ResourceCache (see ResourceCache.h for reason). - - /**jsdoc - * Get the list of all resource URLs. - * @function ModelCache.getResourceList - * @returns {string[]} - */ - - /**jsdoc - * @function ModelCache.dirty - * @returns {Signal} - */ - - /**jsdoc - * @function ModelCache.updateTotalSize - * @param {number} deltaSize - */ - - /**jsdoc - * Prefetches a resource. - * @function ModelCache.prefetch - * @param {string} url - URL of the resource to prefetch. - * @param {object} [extra=null] - * @returns {ResourceObject} - */ - - /**jsdoc - * Asynchronously loads a resource from the specified URL and returns it. - * @function ModelCache.getResource - * @param {string} url - URL of the resource to load. - * @param {string} [fallback=""] - Fallback URL if load of the desired URL fails. - * @param {} [extra=null] - * @returns {object} - */ - - GeometryResource::Pointer getGeometryResource(const QUrl& url, const QVariantHash& mapping = QVariantHash(), const QUrl& textureBaseUrl = QUrl()); diff --git a/libraries/model-networking/src/model-networking/ModelCacheScriptingInterface.cpp b/libraries/model-networking/src/model-networking/ModelCacheScriptingInterface.cpp new file mode 100644 index 0000000000..88330cf319 --- /dev/null +++ b/libraries/model-networking/src/model-networking/ModelCacheScriptingInterface.cpp @@ -0,0 +1,17 @@ +// +// ModelCacheScriptingInterface.cpp +// libraries/mmodel-networking/src/model-networking +// +// Created by David Rowe on 25 Jul 2018. +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "ModelCacheScriptingInterface.h" + +ModelCacheScriptingInterface::ModelCacheScriptingInterface(ModelCache* modelCache) : + _ModelCache(modelCache), + ScriptableResourceCache::ScriptableResourceCache(modelCache) +{ } diff --git a/libraries/model-networking/src/model-networking/ModelCacheScriptingInterface.h b/libraries/model-networking/src/model-networking/ModelCacheScriptingInterface.h new file mode 100644 index 0000000000..5ac8271e7a --- /dev/null +++ b/libraries/model-networking/src/model-networking/ModelCacheScriptingInterface.h @@ -0,0 +1,52 @@ +// +// ModelCacheScriptingInterface.h +// libraries/mmodel-networking/src/model-networking +// +// Created by David Rowe on 25 Jul 2018. +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#pragma once + +#ifndef hifi_ModelCacheScriptingInterface_h +#define hifi_ModelCacheScriptingInterface_h + +#include + +#include + +#include "ModelCache.h" + +class ModelCacheScriptingInterface : public ScriptableResourceCache { + Q_OBJECT + + // Properties are copied over from ResourceCache (see ResourceCache.h for reason). + + /**jsdoc + * API to manage model cache resources. + * @namespace ModelCache + * + * @hifi-interface + * @hifi-client-entity + * + * @property {number} numTotal - Total number of total resources. Read-only. + * @property {number} numCached - Total number of cached resource. Read-only. + * @property {number} sizeTotal - Size in bytes of all resources. Read-only. + * @property {number} sizeCached - Size in bytes of all cached resources. Read-only. + * + * @borrows ResourceCache.getResourceList as getResourceList + * @borrows ResourceCache.updateTotalSize as updateTotalSize + * @borrows ResourceCache.prefetch as prefetch + * @borrows ResourceCache.dirty as dirty + */ + +public: + ModelCacheScriptingInterface(ModelCache* modelCache); + +private: + ModelCache* _ModelCache; +}; + +#endif // hifi_ModelCacheScriptingInterface_h diff --git a/libraries/model-networking/src/model-networking/TextureCache.h b/libraries/model-networking/src/model-networking/TextureCache.h index bca64806c4..c914ad91af 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.h +++ b/libraries/model-networking/src/model-networking/TextureCache.h @@ -156,58 +156,6 @@ class TextureCache : public ResourceCache, public Dependency { public: - // Properties are copied over from ResourceCache (see ResourceCache.h for reason). - - /**jsdoc - * API to manage texture cache resources. - * @namespace TextureCache - * - * @hifi-interface - * @hifi-client-entity - * - * @property {number} numTotal - Total number of total resources. Read-only. - * @property {number} numCached - Total number of cached resource. Read-only. - * @property {number} sizeTotal - Size in bytes of all resources. Read-only. - * @property {number} sizeCached - Size in bytes of all cached resources. Read-only. - */ - - - // Functions are copied over from ResourceCache (see ResourceCache.h for reason). - - /**jsdoc - * Get the list of all resource URLs. - * @function TextureCache.getResourceList - * @returns {string[]} - */ - - /**jsdoc - * @function TextureCache.dirty - * @returns {Signal} - */ - - /**jsdoc - * @function TextureCache.updateTotalSize - * @param {number} deltaSize - */ - - /**jsdoc - * Prefetches a resource. - * @function TextureCache.prefetch - * @param {string} url - URL of the resource to prefetch. - * @param {object} [extra=null] - * @returns {ResourceObject} - */ - - /**jsdoc - * Asynchronously loads a resource from the specified URL and returns it. - * @function TextureCache.getResource - * @param {string} url - URL of the resource to load. - * @param {string} [fallback=""] - Fallback URL if load of the desired URL fails. - * @param {} [extra=null] - * @returns {object} - */ - - /// Returns the ID of the permutation/normal texture used for Perlin noise shader programs. This texture /// has two lines: the first, a set of random numbers in [0, 255] to be used as permutation offsets, and /// the second, a set of random unit vectors to be used as noise gradients. @@ -248,21 +196,10 @@ public: gpu::ContextPointer getGPUContext() const { return _gpuContext; } signals: - /**jsdoc - * @function TextureCache.spectatorCameraFramebufferReset - * @returns {Signal} - */ void spectatorCameraFramebufferReset(); protected: - /**jsdoc - * @function TextureCache.prefetch - * @param {string} url - * @param {number} type - * @param {number} [maxNumPixels=67108864] - * @returns {ResourceObject} - */ // Overload ResourceCache::prefetch to allow specifying texture type for loads Q_INVOKABLE ScriptableResource* prefetch(const QUrl& url, int type, int maxNumPixels = ABSOLUTE_MAX_TEXTURE_NUM_PIXELS); @@ -273,6 +210,7 @@ private: friend class ImageReader; friend class NetworkTexture; friend class DilatableNetworkTexture; + friend class TextureCacheScriptingInterface; TextureCache(); virtual ~TextureCache(); diff --git a/libraries/model-networking/src/model-networking/TextureCacheScriptingInterface.cpp b/libraries/model-networking/src/model-networking/TextureCacheScriptingInterface.cpp new file mode 100644 index 0000000000..10f4591053 --- /dev/null +++ b/libraries/model-networking/src/model-networking/TextureCacheScriptingInterface.cpp @@ -0,0 +1,24 @@ +// +// TextureCacheScriptingInterface.cpp +// libraries/mmodel-networking/src/model-networking +// +// Created by David Rowe on 25 Jul 2018. +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "TextureCacheScriptingInterface.h" + +TextureCacheScriptingInterface::TextureCacheScriptingInterface(TextureCache* textureCache) : + _textureCache(textureCache), + ScriptableResourceCache::ScriptableResourceCache(textureCache) +{ + connect(_textureCache, &TextureCache::spectatorCameraFramebufferReset, + this, &TextureCacheScriptingInterface::spectatorCameraFramebufferReset); +} + +ScriptableResource* TextureCacheScriptingInterface::prefetch(const QUrl& url, int type, int maxNumPixels) { + return _textureCache->prefetch(url, type, maxNumPixels); +} diff --git a/libraries/model-networking/src/model-networking/TextureCacheScriptingInterface.h b/libraries/model-networking/src/model-networking/TextureCacheScriptingInterface.h new file mode 100644 index 0000000000..7246dcf64e --- /dev/null +++ b/libraries/model-networking/src/model-networking/TextureCacheScriptingInterface.h @@ -0,0 +1,68 @@ +// +// TextureCacheScriptingInterface.h +// libraries/mmodel-networking/src/model-networking +// +// Created by David Rowe on 25 Jul 2018. +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#pragma once + +#ifndef hifi_TextureCacheScriptingInterface_h +#define hifi_TextureCacheScriptingInterface_h + +#include + +#include + +#include "TextureCache.h" + +class TextureCacheScriptingInterface : public ScriptableResourceCache { + Q_OBJECT + + // Properties are copied over from ResourceCache (see ResourceCache.h for reason). + + /**jsdoc + * API to manage texture cache resources. + * @namespace TextureCache + * + * @hifi-interface + * @hifi-client-entity + * + * @property {number} numTotal - Total number of total resources. Read-only. + * @property {number} numCached - Total number of cached resource. Read-only. + * @property {number} sizeTotal - Size in bytes of all resources. Read-only. + * @property {number} sizeCached - Size in bytes of all cached resources. Read-only. + * + * @borrows ResourceCache.getResourceList as getResourceList + * @borrows ResourceCache.updateTotalSize as updateTotalSize + * @borrows ResourceCache.prefetch as prefetch + * @borrows ResourceCache.dirty as dirty + */ + +public: + TextureCacheScriptingInterface(TextureCache* textureCache); + + /**jsdoc + * @function TextureCache.prefetch + * @param {string} url + * @param {number} type + * @param {number} [maxNumPixels=67108864] + * @returns {ResourceObject} + */ + Q_INVOKABLE ScriptableResource* prefetch(const QUrl& url, int type, int maxNumPixels = ABSOLUTE_MAX_TEXTURE_NUM_PIXELS); + +signals: + /**jsdoc + * @function TextureCache.spectatorCameraFramebufferReset + * @returns {Signal} + */ + void spectatorCameraFramebufferReset(); + +private: + TextureCache* _textureCache; +}; + +#endif // hifi_TextureCacheScriptingInterface_h diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index d07420f87e..7cc04cb3cb 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -131,6 +131,24 @@ QSharedPointer ResourceCacheSharedItems::getHighestPendingRequest() { return highestResource; } + +ScriptableResourceCache::ScriptableResourceCache(ResourceCache* resourceCache) { + _resourceCache = resourceCache; +} + +QVariantList ScriptableResourceCache::getResourceList() { + return _resourceCache->getResourceList(); +} + +void ScriptableResourceCache::updateTotalSize(const qint64& deltaSize) { + _resourceCache->updateTotalSize(deltaSize); +} + +ScriptableResource* ScriptableResourceCache::prefetch(const QUrl& url, void* extra) { + return _resourceCache->prefetch(url, extra); +} + + ScriptableResource::ScriptableResource(const QUrl& url) : QObject(nullptr), _url(url) { } diff --git a/libraries/networking/src/ResourceCache.h b/libraries/networking/src/ResourceCache.h index a4bd352563..072c5cc5c2 100644 --- a/libraries/networking/src/ResourceCache.h +++ b/libraries/networking/src/ResourceCache.h @@ -124,9 +124,9 @@ public: virtual ~ScriptableResource() = default; /**jsdoc - * Release this resource. - * @function ResourceObject#release - */ + * Release this resource. + * @function ResourceObject#release + */ Q_INVOKABLE void release(); const QUrl& getURL() const { return _url; } @@ -186,15 +186,6 @@ Q_DECLARE_METATYPE(ScriptableResource*); class ResourceCache : public QObject { Q_OBJECT - // JSDoc 3.5.5 doesn't augment namespaces with @property or @function definitions. - // The ResourceCache properties and functions are copied to the different exposed cache classes. - - /**jsdoc - * @property {number} numTotal - Total number of total resources. Read-only. - * @property {number} numCached - Total number of cached resource. Read-only. - * @property {number} sizeTotal - Size in bytes of all resources. Read-only. - * @property {number} sizeCached - Size in bytes of all cached resources. Read-only. - */ Q_PROPERTY(size_t numTotal READ getNumTotalResources NOTIFY dirty) Q_PROPERTY(size_t numCached READ getNumCachedResources NOTIFY dirty) Q_PROPERTY(size_t sizeTotal READ getSizeTotalResources NOTIFY dirty) @@ -207,11 +198,6 @@ public: size_t getNumCachedResources() const { return _numUnusedResources; } size_t getSizeCachedResources() const { return _unusedResourcesSize; } - /**jsdoc - * Get the list of all resource URLs. - * @function ResourceCache.getResourceList - * @returns {string[]} - */ Q_INVOKABLE QVariantList getResourceList(); static void setRequestLimit(int limit); @@ -237,40 +223,17 @@ public: signals: - /**jsdoc - * @function ResourceCache.dirty - * @returns {Signal} - */ void dirty(); protected slots: - /**jsdoc - * @function ResourceCache.updateTotalSize - * @param {number} deltaSize - */ void updateTotalSize(const qint64& deltaSize); - /**jsdoc - * Prefetches a resource. - * @function ResourceCache.prefetch - * @param {string} url - URL of the resource to prefetch. - * @param {object} [extra=null] - * @returns {ResourceObject} - */ // Prefetches a resource to be held by the QScriptEngine. // Left as a protected member so subclasses can overload prefetch // and delegate to it (see TextureCache::prefetch(const QUrl&, int). ScriptableResource* prefetch(const QUrl& url, void* extra); - /**jsdoc - * Asynchronously loads a resource from the specified URL and returns it. - * @function ResourceCache.getResource - * @param {string} url - URL of the resource to load. - * @param {string} [fallback=""] - Fallback URL if load of the desired URL fails. - * @param {} [extra=null] - * @returns {object} - */ // FIXME: The return type is not recognized by JavaScript. /// Loads a resource from the specified URL and returns it. /// If the caller is on a different thread than the ResourceCache, @@ -306,6 +269,7 @@ protected: private: friend class Resource; + friend class ScriptableResourceCache; void reserveUnusedResource(qint64 resourceSize); void resetResourceCounters(); @@ -335,6 +299,66 @@ private: QReadWriteLock _resourcesToBeGottenLock { QReadWriteLock::Recursive }; }; +/// Wrapper to expose resource caches to JS/QML +class ScriptableResourceCache : public QObject { + Q_OBJECT + + // JSDoc 3.5.5 doesn't augment namespaces with @property definitions so the following properties JSDoc is copied to the + // different exposed cache classes. + + /**jsdoc + * @property {number} numTotal - Total number of total resources. Read-only. + * @property {number} numCached - Total number of cached resource. Read-only. + * @property {number} sizeTotal - Size in bytes of all resources. Read-only. + * @property {number} sizeCached - Size in bytes of all cached resources. Read-only. + */ + Q_PROPERTY(size_t numTotal READ getNumTotalResources NOTIFY dirty) + Q_PROPERTY(size_t numCached READ getNumCachedResources NOTIFY dirty) + Q_PROPERTY(size_t sizeTotal READ getSizeTotalResources NOTIFY dirty) + Q_PROPERTY(size_t sizeCached READ getSizeCachedResources NOTIFY dirty) + +public: + ScriptableResourceCache(ResourceCache* resourceCache); + + /**jsdoc + * Get the list of all resource URLs. + * @function ResourceCache.getResourceList + * @returns {string[]} + */ + Q_INVOKABLE QVariantList getResourceList(); + + /**jsdoc + * @function ResourceCache.updateTotalSize + * @param {number} deltaSize + */ + Q_INVOKABLE void updateTotalSize(const qint64& deltaSize); + + /**jsdoc + * Prefetches a resource. + * @function ResourceCache.prefetch + * @param {string} url - URL of the resource to prefetch. + * @param {object} [extra=null] + * @returns {ResourceObject} + */ + Q_INVOKABLE ScriptableResource* prefetch(const QUrl& url, void* extra = nullptr); + +signals: + + /**jsdoc + * @function ResourceCache.dirty + * @returns {Signal} + */ + void dirty(); + +private: + ResourceCache * _resourceCache; + + size_t getNumTotalResources() const { return _resourceCache->getNumTotalResources(); } + size_t getSizeTotalResources() const { return _resourceCache->getSizeTotalResources(); } + size_t getNumCachedResources() const { return _resourceCache->getNumCachedResources(); } + size_t getSizeCachedResources() const { return _resourceCache->getSizeCachedResources(); } +}; + /// Base class for resources. class Resource : public QObject { Q_OBJECT From 51865294ac147a68b9385b8ddb272756a577fd63 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 26 Jul 2018 09:54:42 +1200 Subject: [PATCH 07/29] Fix radius and alpha start/finish values --- libraries/entities/src/EntityItemProperties.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 8838fedd59..75f6aaef34 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -886,9 +886,9 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { * @property {string} textures="" - The URL of a JPG or PNG image file to display for each particle. If you want transparency, * use PNG format. * @property {number} particleRadius=0.025 - The radius of each particle at the middle of its life. - * @property {number} radiusStart=null - The radius of each particle at the start of its life. If null, the + * @property {number} radiusStart=NaN - The radius of each particle at the start of its life. If NaN, the * particleRadius value is used. - * @property {number} radiusFinish=null - The radius of each particle at the end of its life. If null, the + * @property {number} radiusFinish=NaN - The radius of each particle at the end of its life. If NaN, the * particleRadius value is used. * @property {number} radiusSpread=0 - The spread in radius that each particle is given. If particleRadius == 0.5 * and radiusSpread == 0.25, each particle will have a radius in the range 0.25 – @@ -903,9 +903,9 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { * {red: 10, green: 25, blue: 50}, each particle will have a color in the range * {red: 90, green: 75, blue: 50}{red: 110, green: 125, blue: 150}. * @property {number} alpha=1 - The alpha of each particle at the middle of its life. - * @property {number} alphaStart=null - The alpha of each particle at the start of its life. If null, the + * @property {number} alphaStart=NaN - The alpha of each particle at the start of its life. If NaN, the * alpha value is used. - * @property {number} alphaFinish=null - The alpha of each particle at the end of its life. If null, the + * @property {number} alphaFinish=NaN - The alpha of each particle at the end of its life. If NaN, the * alpha value is used. * @property {number} alphaSpread=0 - The spread in alpha that each particle is given. If alpha == 0.5 * and alphaSpread == 0.25, each particle will have an alpha in the range 0.25 – From baf88ab508399e1eb0c282464a112f5faaf490af Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 26 Jul 2018 16:12:16 +1200 Subject: [PATCH 08/29] Revise scriptable resource caches' interfaces --- assignment-client/src/Agent.cpp | 8 +++--- assignment-client/src/AssignmentClient.cpp | 2 ++ .../src/scripts/EntityScriptServer.cpp | 3 ++- interface/src/Application.cpp | 27 +++++++++++++------ interface/src/ui/overlays/Web3DOverlay.cpp | 2 +- .../src/AnimationCacheScriptingInterface.cpp | 9 +++---- .../src/AnimationCacheScriptingInterface.h | 7 ++--- .../src/SoundCacheScriptingInterface.cpp | 7 +++-- .../audio/src/SoundCacheScriptingInterface.h | 7 ++--- .../ModelCacheScriptingInterface.cpp | 5 ++-- .../ModelCacheScriptingInterface.h | 7 ++--- .../TextureCacheScriptingInterface.cpp | 9 +++---- .../TextureCacheScriptingInterface.h | 7 ++--- libraries/networking/src/ResourceCache.cpp | 2 +- libraries/networking/src/ResourceCache.h | 6 ++--- 15 files changed, 54 insertions(+), 54 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 304f24d51c..15844b90cf 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -32,8 +32,8 @@ #include #include #include -#include #include +#include #include #include #include @@ -72,6 +72,7 @@ Agent::Agent(ReceivedMessage& message) : DependencyManager::set(); DependencyManager::set(); + DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); @@ -456,8 +457,8 @@ void Agent::executeScript() { // register ourselves to the script engine _scriptEngine->registerGlobalObject("Agent", this); - _scriptEngine->registerGlobalObject("SoundCache", new SoundCacheScriptingInterface(DependencyManager::get().data())); - _scriptEngine->registerGlobalObject("AnimationCache", new AnimationCacheScriptingInterface(DependencyManager::get().data())); + _scriptEngine->registerGlobalObject("AnimationCache", DependencyManager::get().data()); + _scriptEngine->registerGlobalObject("SoundCache", DependencyManager::get().data()); QScriptValue webSocketServerConstructorValue = _scriptEngine->newFunction(WebSocketServerClass::constructor); _scriptEngine->globalObject().setProperty("WebSocketServer", webSocketServerConstructorValue); @@ -846,6 +847,7 @@ void Agent::aboutToFinish() { DependencyManager::destroy(); DependencyManager::destroy(); + DependencyManager::destroy(); DependencyManager::destroy(); DependencyManager::destroy(); diff --git a/assignment-client/src/AssignmentClient.cpp b/assignment-client/src/AssignmentClient.cpp index 41e42aa0a1..d761699285 100644 --- a/assignment-client/src/AssignmentClient.cpp +++ b/assignment-client/src/AssignmentClient.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -63,6 +64,7 @@ AssignmentClient::AssignmentClient(Assignment::Type requestAssignmentType, QStri auto nodeList = DependencyManager::set(NodeType::Unassigned, listenPort); auto animationCache = DependencyManager::set(); + DependencyManager::set(); auto entityScriptingInterface = DependencyManager::set(false); DependencyManager::registerInheritance(); diff --git a/assignment-client/src/scripts/EntityScriptServer.cpp b/assignment-client/src/scripts/EntityScriptServer.cpp index afb6d3588b..0e1126cebe 100644 --- a/assignment-client/src/scripts/EntityScriptServer.cpp +++ b/assignment-client/src/scripts/EntityScriptServer.cpp @@ -66,6 +66,7 @@ EntityScriptServer::EntityScriptServer(ReceivedMessage& message) : ThreadedAssig DependencyManager::set(); DependencyManager::set(); + DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); @@ -438,7 +439,7 @@ void EntityScriptServer::resetEntitiesScriptEngine() { auto webSocketServerConstructorValue = newEngine->newFunction(WebSocketServerClass::constructor); newEngine->globalObject().setProperty("WebSocketServer", webSocketServerConstructorValue); - newEngine->registerGlobalObject("SoundCache", new SoundCacheScriptingInterface(DependencyManager::get().data())); + newEngine->registerGlobalObject("SoundCache", DependencyManager::get().data()); // connect this script engines printedMessage signal to the global ScriptEngines these various messages auto scriptEngines = DependencyManager::get().data(); diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index a613704afe..025290ce30 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -869,16 +869,20 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) { DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); + DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); + DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); + DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); + DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); @@ -2565,12 +2569,18 @@ Application::~Application() { DependencyManager::destroy(); // must be destroyed before the FramebufferCache + DependencyManager::destroy(); + DependencyManager::destroy(); + DependencyManager::destroy(); DependencyManager::destroy(); DependencyManager::destroy(); + DependencyManager::destroy(); DependencyManager::destroy(); + DependencyManager::destroy(); DependencyManager::destroy(); DependencyManager::destroy(); + DependencyManager::destroy(); DependencyManager::destroy(); DependencyManager::destroy(); DependencyManager::destroy(); @@ -2992,10 +3002,11 @@ void Application::onDesktopRootContextCreated(QQmlContext* surfaceContext) { surfaceContext->setContextProperty("LocationBookmarks", DependencyManager::get().data()); // Caches - surfaceContext->setContextProperty("AnimationCache", new AnimationCacheScriptingInterface(DependencyManager::get().data())); - surfaceContext->setContextProperty("TextureCache", new TextureCacheScriptingInterface(DependencyManager::get().data())); - surfaceContext->setContextProperty("ModelCache", new ModelCacheScriptingInterface(DependencyManager::get().data())); - surfaceContext->setContextProperty("SoundCache", new SoundCacheScriptingInterface(DependencyManager::get().data())); + surfaceContext->setContextProperty("AnimationCache", DependencyManager::get().data()); + surfaceContext->setContextProperty("TextureCache", DependencyManager::get().data()); + surfaceContext->setContextProperty("ModelCache", DependencyManager::get().data()); + surfaceContext->setContextProperty("SoundCache", DependencyManager::get().data()); + surfaceContext->setContextProperty("InputConfiguration", DependencyManager::get().data()); surfaceContext->setContextProperty("Account", AccountServicesScriptingInterface::getInstance()); // DEPRECATED - TO BE REMOVED @@ -6615,10 +6626,10 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEnginePointe scriptEngine->registerGlobalObject("Pointers", DependencyManager::get().data()); // Caches - scriptEngine->registerGlobalObject("AnimationCache", new AnimationCacheScriptingInterface(DependencyManager::get().data())); - scriptEngine->registerGlobalObject("TextureCache", new TextureCacheScriptingInterface(DependencyManager::get().data())); - scriptEngine->registerGlobalObject("ModelCache", new ModelCacheScriptingInterface(DependencyManager::get().data())); - scriptEngine->registerGlobalObject("SoundCache", new SoundCacheScriptingInterface(DependencyManager::get().data())); + scriptEngine->registerGlobalObject("AnimationCache", DependencyManager::get().data()); + scriptEngine->registerGlobalObject("TextureCache", DependencyManager::get().data()); + scriptEngine->registerGlobalObject("ModelCache", DependencyManager::get().data()); + scriptEngine->registerGlobalObject("SoundCache", DependencyManager::get().data()); scriptEngine->registerGlobalObject("DialogsManager", _dialogsManagerScriptingInterface); diff --git a/interface/src/ui/overlays/Web3DOverlay.cpp b/interface/src/ui/overlays/Web3DOverlay.cpp index b65fb93707..798b3d3cba 100644 --- a/interface/src/ui/overlays/Web3DOverlay.cpp +++ b/interface/src/ui/overlays/Web3DOverlay.cpp @@ -253,7 +253,7 @@ void Web3DOverlay::setupQmlSurface() { _webSurface->getSurfaceContext()->setContextProperty("AvatarList", DependencyManager::get().data()); _webSurface->getSurfaceContext()->setContextProperty("DialogsManager", DialogsManagerScriptingInterface::getInstance()); _webSurface->getSurfaceContext()->setContextProperty("InputConfiguration", DependencyManager::get().data()); - _webSurface->getSurfaceContext()->setContextProperty("SoundCache", new SoundCacheScriptingInterface(DependencyManager::get().data())); + _webSurface->getSurfaceContext()->setContextProperty("SoundCache", DependencyManager::get().data()); _webSurface->getSurfaceContext()->setContextProperty("MenuInterface", MenuScriptingInterface::getInstance()); _webSurface->getSurfaceContext()->setContextProperty("Settings", SettingsScriptingInterface::getInstance()); _webSurface->getSurfaceContext()->setContextProperty("AvatarBookmarks", DependencyManager::get().data()); diff --git a/libraries/animation/src/AnimationCacheScriptingInterface.cpp b/libraries/animation/src/AnimationCacheScriptingInterface.cpp index a648a06228..450187a084 100644 --- a/libraries/animation/src/AnimationCacheScriptingInterface.cpp +++ b/libraries/animation/src/AnimationCacheScriptingInterface.cpp @@ -11,11 +11,10 @@ #include "AnimationCacheScriptingInterface.h" -AnimationCacheScriptingInterface::AnimationCacheScriptingInterface(AnimationCache* animationCache) : - _animationCache(animationCache), - ScriptableResourceCache::ScriptableResourceCache(animationCache) +AnimationCacheScriptingInterface::AnimationCacheScriptingInterface() : + ScriptableResourceCache::ScriptableResourceCache(DependencyManager::get()) { } AnimationPointer AnimationCacheScriptingInterface::getAnimation(const QUrl& url) { - return _animationCache->getAnimation(url); -} \ No newline at end of file + return DependencyManager::get()->getAnimation(url); +} diff --git a/libraries/animation/src/AnimationCacheScriptingInterface.h b/libraries/animation/src/AnimationCacheScriptingInterface.h index ff7137040c..032ca169b8 100644 --- a/libraries/animation/src/AnimationCacheScriptingInterface.h +++ b/libraries/animation/src/AnimationCacheScriptingInterface.h @@ -19,7 +19,7 @@ #include "AnimationCache.h" -class AnimationCacheScriptingInterface : public ScriptableResourceCache { +class AnimationCacheScriptingInterface : public ScriptableResourceCache, public Dependency { Q_OBJECT // Properties are copied over from ResourceCache (see ResourceCache.h for reason). @@ -44,7 +44,7 @@ class AnimationCacheScriptingInterface : public ScriptableResourceCache { */ public: - AnimationCacheScriptingInterface(AnimationCache* animationCache); + AnimationCacheScriptingInterface(); /**jsdoc * Returns animation resource for particular animation. @@ -54,9 +54,6 @@ public: */ Q_INVOKABLE AnimationPointer getAnimation(const QString& url) { return getAnimation(QUrl(url)); } Q_INVOKABLE AnimationPointer getAnimation(const QUrl& url); - -private: - AnimationCache* _animationCache; }; #endif // hifi_AnimationCacheScriptingInterface_h diff --git a/libraries/audio/src/SoundCacheScriptingInterface.cpp b/libraries/audio/src/SoundCacheScriptingInterface.cpp index d9c65ddd29..94bb12be8c 100644 --- a/libraries/audio/src/SoundCacheScriptingInterface.cpp +++ b/libraries/audio/src/SoundCacheScriptingInterface.cpp @@ -11,11 +11,10 @@ #include "SoundCacheScriptingInterface.h" -SoundCacheScriptingInterface::SoundCacheScriptingInterface(SoundCache* soundCache) : - _soundCache(soundCache), - ScriptableResourceCache::ScriptableResourceCache(soundCache) +SoundCacheScriptingInterface::SoundCacheScriptingInterface() : + ScriptableResourceCache::ScriptableResourceCache(DependencyManager::get()) { } SharedSoundPointer SoundCacheScriptingInterface::getSound(const QUrl& url) { - return _soundCache->getSound(url); + return DependencyManager::get()->getSound(url); } diff --git a/libraries/audio/src/SoundCacheScriptingInterface.h b/libraries/audio/src/SoundCacheScriptingInterface.h index 01b5753965..1995cef026 100644 --- a/libraries/audio/src/SoundCacheScriptingInterface.h +++ b/libraries/audio/src/SoundCacheScriptingInterface.h @@ -19,7 +19,7 @@ #include "SoundCache.h" -class SoundCacheScriptingInterface : public ScriptableResourceCache { +class SoundCacheScriptingInterface : public ScriptableResourceCache, public Dependency { Q_OBJECT // Properties are copied over from ResourceCache (see ResourceCache.h for reason). @@ -45,7 +45,7 @@ class SoundCacheScriptingInterface : public ScriptableResourceCache { */ public: - SoundCacheScriptingInterface(SoundCache* soundCache); + SoundCacheScriptingInterface(); /**jsdoc * @function SoundCache.getSound @@ -53,9 +53,6 @@ public: * @returns {SoundObject} */ Q_INVOKABLE SharedSoundPointer getSound(const QUrl& url); - -private: - SoundCache* _soundCache; }; #endif // hifi_SoundCacheScriptingInterface_h diff --git a/libraries/model-networking/src/model-networking/ModelCacheScriptingInterface.cpp b/libraries/model-networking/src/model-networking/ModelCacheScriptingInterface.cpp index 88330cf319..cdf75be9ca 100644 --- a/libraries/model-networking/src/model-networking/ModelCacheScriptingInterface.cpp +++ b/libraries/model-networking/src/model-networking/ModelCacheScriptingInterface.cpp @@ -11,7 +11,6 @@ #include "ModelCacheScriptingInterface.h" -ModelCacheScriptingInterface::ModelCacheScriptingInterface(ModelCache* modelCache) : - _ModelCache(modelCache), - ScriptableResourceCache::ScriptableResourceCache(modelCache) +ModelCacheScriptingInterface::ModelCacheScriptingInterface() : + ScriptableResourceCache::ScriptableResourceCache(DependencyManager::get()) { } diff --git a/libraries/model-networking/src/model-networking/ModelCacheScriptingInterface.h b/libraries/model-networking/src/model-networking/ModelCacheScriptingInterface.h index 5ac8271e7a..5ac7ac1e50 100644 --- a/libraries/model-networking/src/model-networking/ModelCacheScriptingInterface.h +++ b/libraries/model-networking/src/model-networking/ModelCacheScriptingInterface.h @@ -19,7 +19,7 @@ #include "ModelCache.h" -class ModelCacheScriptingInterface : public ScriptableResourceCache { +class ModelCacheScriptingInterface : public ScriptableResourceCache, public Dependency { Q_OBJECT // Properties are copied over from ResourceCache (see ResourceCache.h for reason). @@ -43,10 +43,7 @@ class ModelCacheScriptingInterface : public ScriptableResourceCache { */ public: - ModelCacheScriptingInterface(ModelCache* modelCache); - -private: - ModelCache* _ModelCache; + ModelCacheScriptingInterface(); }; #endif // hifi_ModelCacheScriptingInterface_h diff --git a/libraries/model-networking/src/model-networking/TextureCacheScriptingInterface.cpp b/libraries/model-networking/src/model-networking/TextureCacheScriptingInterface.cpp index 10f4591053..ff5c7ca298 100644 --- a/libraries/model-networking/src/model-networking/TextureCacheScriptingInterface.cpp +++ b/libraries/model-networking/src/model-networking/TextureCacheScriptingInterface.cpp @@ -11,14 +11,13 @@ #include "TextureCacheScriptingInterface.h" -TextureCacheScriptingInterface::TextureCacheScriptingInterface(TextureCache* textureCache) : - _textureCache(textureCache), - ScriptableResourceCache::ScriptableResourceCache(textureCache) +TextureCacheScriptingInterface::TextureCacheScriptingInterface() : + ScriptableResourceCache::ScriptableResourceCache(DependencyManager::get()) { - connect(_textureCache, &TextureCache::spectatorCameraFramebufferReset, + connect(DependencyManager::get().data(), &TextureCache::spectatorCameraFramebufferReset, this, &TextureCacheScriptingInterface::spectatorCameraFramebufferReset); } ScriptableResource* TextureCacheScriptingInterface::prefetch(const QUrl& url, int type, int maxNumPixels) { - return _textureCache->prefetch(url, type, maxNumPixels); + return DependencyManager::get()->prefetch(url, type, maxNumPixels); } diff --git a/libraries/model-networking/src/model-networking/TextureCacheScriptingInterface.h b/libraries/model-networking/src/model-networking/TextureCacheScriptingInterface.h index 7246dcf64e..4120840759 100644 --- a/libraries/model-networking/src/model-networking/TextureCacheScriptingInterface.h +++ b/libraries/model-networking/src/model-networking/TextureCacheScriptingInterface.h @@ -19,7 +19,7 @@ #include "TextureCache.h" -class TextureCacheScriptingInterface : public ScriptableResourceCache { +class TextureCacheScriptingInterface : public ScriptableResourceCache, public Dependency { Q_OBJECT // Properties are copied over from ResourceCache (see ResourceCache.h for reason). @@ -43,7 +43,7 @@ class TextureCacheScriptingInterface : public ScriptableResourceCache { */ public: - TextureCacheScriptingInterface(TextureCache* textureCache); + TextureCacheScriptingInterface(); /**jsdoc * @function TextureCache.prefetch @@ -60,9 +60,6 @@ signals: * @returns {Signal} */ void spectatorCameraFramebufferReset(); - -private: - TextureCache* _textureCache; }; #endif // hifi_TextureCacheScriptingInterface_h diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index 7cc04cb3cb..aed9f3b0e5 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -132,7 +132,7 @@ QSharedPointer ResourceCacheSharedItems::getHighestPendingRequest() { } -ScriptableResourceCache::ScriptableResourceCache(ResourceCache* resourceCache) { +ScriptableResourceCache::ScriptableResourceCache(QSharedPointer resourceCache) { _resourceCache = resourceCache; } diff --git a/libraries/networking/src/ResourceCache.h b/libraries/networking/src/ResourceCache.h index 072c5cc5c2..2c0baad3f7 100644 --- a/libraries/networking/src/ResourceCache.h +++ b/libraries/networking/src/ResourceCache.h @@ -303,7 +303,7 @@ private: class ScriptableResourceCache : public QObject { Q_OBJECT - // JSDoc 3.5.5 doesn't augment namespaces with @property definitions so the following properties JSDoc is copied to the + // JSDoc 3.5.5 doesn't augment name spaces with @property definitions so the following properties JSDoc is copied to the // different exposed cache classes. /**jsdoc @@ -318,7 +318,7 @@ class ScriptableResourceCache : public QObject { Q_PROPERTY(size_t sizeCached READ getSizeCachedResources NOTIFY dirty) public: - ScriptableResourceCache(ResourceCache* resourceCache); + ScriptableResourceCache(QSharedPointer resourceCache); /**jsdoc * Get the list of all resource URLs. @@ -351,7 +351,7 @@ signals: void dirty(); private: - ResourceCache * _resourceCache; + QSharedPointer _resourceCache; size_t getNumTotalResources() const { return _resourceCache->getNumTotalResources(); } size_t getSizeTotalResources() const { return _resourceCache->getSizeTotalResources(); } From 9a9d190918108e6ee97072727cf906a01d45b433 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 26 Jul 2018 20:26:13 +1200 Subject: [PATCH 09/29] Remove unnecessary duplicate function --- libraries/animation/src/AnimationCacheScriptingInterface.cpp | 4 ++-- libraries/animation/src/AnimationCacheScriptingInterface.h | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/libraries/animation/src/AnimationCacheScriptingInterface.cpp b/libraries/animation/src/AnimationCacheScriptingInterface.cpp index 450187a084..3db1d31901 100644 --- a/libraries/animation/src/AnimationCacheScriptingInterface.cpp +++ b/libraries/animation/src/AnimationCacheScriptingInterface.cpp @@ -15,6 +15,6 @@ AnimationCacheScriptingInterface::AnimationCacheScriptingInterface() : ScriptableResourceCache::ScriptableResourceCache(DependencyManager::get()) { } -AnimationPointer AnimationCacheScriptingInterface::getAnimation(const QUrl& url) { - return DependencyManager::get()->getAnimation(url); +AnimationPointer AnimationCacheScriptingInterface::getAnimation(const QString& url) { + return DependencyManager::get()->getAnimation(QUrl(url)); } diff --git a/libraries/animation/src/AnimationCacheScriptingInterface.h b/libraries/animation/src/AnimationCacheScriptingInterface.h index 032ca169b8..1f5735dd0f 100644 --- a/libraries/animation/src/AnimationCacheScriptingInterface.h +++ b/libraries/animation/src/AnimationCacheScriptingInterface.h @@ -52,8 +52,7 @@ public: * @param {string} url - URL to load. * @returns {AnimationObject} animation */ - Q_INVOKABLE AnimationPointer getAnimation(const QString& url) { return getAnimation(QUrl(url)); } - Q_INVOKABLE AnimationPointer getAnimation(const QUrl& url); + Q_INVOKABLE AnimationPointer getAnimation(const QString& url); }; #endif // hifi_AnimationCacheScriptingInterface_h From 82e5d6ad29693b278c9f003d604c27e925ebab14 Mon Sep 17 00:00:00 2001 From: David Back Date: Thu, 26 Jul 2018 16:38:25 -0700 Subject: [PATCH 10/29] use triggerClicks from controllers for edit handles --- .../controllerModules/inEditMode.js | 11 +++++++++++ .../system/libraries/entitySelectionTool.js | 18 +++++++++++------- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/scripts/system/controllers/controllerModules/inEditMode.js b/scripts/system/controllers/controllerModules/inEditMode.js index 377167d7bf..e9b83bbcbb 100644 --- a/scripts/system/controllers/controllerModules/inEditMode.js +++ b/scripts/system/controllers/controllerModules/inEditMode.js @@ -73,6 +73,9 @@ Script.include("/~/system/libraries/utils.js"); method: "clearSelection" })); } + Messages.sendLocalMessage("entityToolUpdates", JSON.stringify({ + method: "triggerClicked" + })); } if (this.selectedTarget.type === Picks.INTERSECTED_ENTITY) { if (!this.isTabletMaterialEntity(this.selectedTarget.objectID)) { @@ -89,6 +92,14 @@ Script.include("/~/system/libraries/utils.js"); } this.triggerClicked = true; + } else { + if (this.triggerClicked) { + Messages.sendLocalMessage("entityToolUpdates", JSON.stringify({ + method: "triggerUnClicked" + })); + } + + this.triggerClicked = false; } this.sendPointingAtData(controllerData); diff --git a/scripts/system/libraries/entitySelectionTool.js b/scripts/system/libraries/entitySelectionTool.js index 091d431502..4a5eb9afca 100644 --- a/scripts/system/libraries/entitySelectionTool.js +++ b/scripts/system/libraries/entitySelectionTool.js @@ -14,13 +14,14 @@ // /* global SelectionManager, SelectionDisplay, grid, rayPlaneIntersection, rayPlaneIntersection2, pushCommandForSelections, - getMainTabletIDs, getControllerWorldLocation */ + getMainTabletIDs, getControllerWorldLocation, TRIGGER_ON_VALUE, TRIGGER_OFF_VALUE */ var SPACE_LOCAL = "local"; var SPACE_WORLD = "world"; var HIGHLIGHT_LIST_NAME = "editHandleHighlightList"; Script.include([ + "./controllerDispatcherUtils.js", "./controllers.js", "./utils.js" ]); @@ -67,6 +68,10 @@ SelectionManager = (function() { that.pointingAtDesktopWindowLeft = messageParsed.desktopWindow; that.pointingAtTabletLeft = messageParsed.tablet; } + } else if (messageParsed.method === "triggerClicked") { + that.triggerClicked = true; + } else if (messageParsed.method === "triggerUnClicked") { + that.triggerClicked = false; } } @@ -109,6 +114,8 @@ SelectionManager = (function() { that.pointingAtDesktopWindowRight = false; that.pointingAtTabletLeft = false; that.pointingAtTabletRight = false; + + that.triggerClicked = false; that.saveProperties = function() { that.savedProperties = {}; @@ -751,14 +758,11 @@ SelectionDisplay = (function() { // But we dont' get mousePressEvents. that.triggerMapping = Controller.newMapping(Script.resolvePath('') + '-click'); Script.scriptEnding.connect(that.triggerMapping.disable); - that.TRIGGER_GRAB_VALUE = 0.85; // From handControllerGrab/Pointer.js. Should refactor. - that.TRIGGER_ON_VALUE = 0.4; - that.TRIGGER_OFF_VALUE = 0.15; that.triggered = false; var activeHand = Controller.Standard.RightHand; function makeTriggerHandler(hand) { - return function (value) { - if (!that.triggered && (value > that.TRIGGER_GRAB_VALUE)) { // should we smooth? + return function () { + if (!that.triggered && SelectionManager.triggerClicked) { that.triggered = true; if (activeHand !== hand) { // No switching while the other is already triggered, so no need to release. @@ -775,7 +779,7 @@ SelectionDisplay = (function() { return; } that.mousePressEvent({}); - } else if (that.triggered && (value < that.TRIGGER_OFF_VALUE)) { + } else if (that.triggered && !SelectionManager.triggerClicked) { that.triggered = false; that.mouseReleaseEvent({}); } From dcdf734114c86aec781412317864887e7bbed0d3 Mon Sep 17 00:00:00 2001 From: David Back Date: Thu, 26 Jul 2018 16:43:07 -0700 Subject: [PATCH 11/29] remove unneeded --- scripts/system/libraries/entitySelectionTool.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/scripts/system/libraries/entitySelectionTool.js b/scripts/system/libraries/entitySelectionTool.js index 4a5eb9afca..00533b86a5 100644 --- a/scripts/system/libraries/entitySelectionTool.js +++ b/scripts/system/libraries/entitySelectionTool.js @@ -14,14 +14,13 @@ // /* global SelectionManager, SelectionDisplay, grid, rayPlaneIntersection, rayPlaneIntersection2, pushCommandForSelections, - getMainTabletIDs, getControllerWorldLocation, TRIGGER_ON_VALUE, TRIGGER_OFF_VALUE */ + getMainTabletIDs, getControllerWorldLocation */ var SPACE_LOCAL = "local"; var SPACE_WORLD = "world"; var HIGHLIGHT_LIST_NAME = "editHandleHighlightList"; Script.include([ - "./controllerDispatcherUtils.js", "./controllers.js", "./utils.js" ]); From cd842afc1c3d3463bd4104164f19256a13d4c335 Mon Sep 17 00:00:00 2001 From: David Back Date: Thu, 26 Jul 2018 17:52:25 -0700 Subject: [PATCH 12/29] prevent both hands triggering same time, allow one to trigger after other --- .../controllerModules/inEditMode.js | 8 +- .../system/libraries/entitySelectionTool.js | 90 ++++++++++++------- 2 files changed, 62 insertions(+), 36 deletions(-) diff --git a/scripts/system/controllers/controllerModules/inEditMode.js b/scripts/system/controllers/controllerModules/inEditMode.js index e9b83bbcbb..e6a5efc6a2 100644 --- a/scripts/system/controllers/controllerModules/inEditMode.js +++ b/scripts/system/controllers/controllerModules/inEditMode.js @@ -74,7 +74,9 @@ Script.include("/~/system/libraries/utils.js"); })); } Messages.sendLocalMessage("entityToolUpdates", JSON.stringify({ - method: "triggerClicked" + method: "triggerClicked", + clicked: true, + rightHand: this.hand === RIGHT_HAND })); } if (this.selectedTarget.type === Picks.INTERSECTED_ENTITY) { @@ -95,7 +97,9 @@ Script.include("/~/system/libraries/utils.js"); } else { if (this.triggerClicked) { Messages.sendLocalMessage("entityToolUpdates", JSON.stringify({ - method: "triggerUnClicked" + method: "triggerClicked", + clicked: false, + rightHand: this.hand === RIGHT_HAND })); } diff --git a/scripts/system/libraries/entitySelectionTool.js b/scripts/system/libraries/entitySelectionTool.js index 00533b86a5..8b7e892870 100644 --- a/scripts/system/libraries/entitySelectionTool.js +++ b/scripts/system/libraries/entitySelectionTool.js @@ -68,9 +68,11 @@ SelectionManager = (function() { that.pointingAtTabletLeft = messageParsed.tablet; } } else if (messageParsed.method === "triggerClicked") { - that.triggerClicked = true; - } else if (messageParsed.method === "triggerUnClicked") { - that.triggerClicked = false; + if (messageParsed.rightHand) { + that.triggerClickedRight = messageParsed.clicked; + } else { + that.triggerClickedLeft = messageParsed.clicked; + } } } @@ -114,7 +116,8 @@ SelectionManager = (function() { that.pointingAtTabletLeft = false; that.pointingAtTabletRight = false; - that.triggerClicked = false; + that.triggerClickedRight = false; + that.triggerClickedLeft = false; that.saveProperties = function() { that.savedProperties = {}; @@ -416,6 +419,8 @@ SelectionDisplay = (function() { YAW: 1, ROLL: 2 }; + + var NO_TRIGGER_HAND = -1; var spaceMode = SPACE_LOCAL; var overlayNames = []; @@ -757,30 +762,47 @@ SelectionDisplay = (function() { // But we dont' get mousePressEvents. that.triggerMapping = Controller.newMapping(Script.resolvePath('') + '-click'); Script.scriptEnding.connect(that.triggerMapping.disable); - that.triggered = false; - var activeHand = Controller.Standard.RightHand; + that.triggeredHand = NO_TRIGGER_HAND; + that.triggered = function() { + return that.triggeredHand !== NO_TRIGGER_HAND; + } + function triggerPress(hand) { + that.triggeredHand = hand; + var pointingAtDesktopWindow = (hand === Controller.Standard.RightHand && + SelectionManager.pointingAtDesktopWindowRight) || + (hand === Controller.Standard.LeftHand && + SelectionManager.pointingAtDesktopWindowLeft); + var pointingAtTablet = (hand === Controller.Standard.RightHand && SelectionManager.pointingAtTabletRight) || + (hand === Controller.Standard.LeftHand && SelectionManager.pointingAtTabletLeft); + if (pointingAtDesktopWindow || pointingAtTablet) { + return; + } + that.mousePressEvent({}); + } + function triggerRelease(hand) { + that.triggeredHand = NO_TRIGGER_HAND; + that.mouseReleaseEvent({}); + var otherTriggerClicked = hand == Controller.Standard.RightHand ? SelectionManager.triggerClickedLeft : + SelectionManager.triggerClickedRight; + // When one hand is released check if the other hand is clicked and should then trigger a press + if (otherTriggerClicked) { + var otherHand = hand == Controller.Standard.RightHand ? Controller.Standard.LeftHand : + Controller.Standard.RightHand; + triggerPress(otherHand); + } + } function makeTriggerHandler(hand) { return function () { - if (!that.triggered && SelectionManager.triggerClicked) { - that.triggered = true; - if (activeHand !== hand) { - // No switching while the other is already triggered, so no need to release. - activeHand = (activeHand === Controller.Standard.RightHand) ? - Controller.Standard.LeftHand : Controller.Standard.RightHand; - } - var pointingAtDesktopWindow = (hand === Controller.Standard.RightHand && - SelectionManager.pointingAtDesktopWindowRight) || - (hand === Controller.Standard.LeftHand && - SelectionManager.pointingAtDesktopWindowLeft); - var pointingAtTablet = (hand === Controller.Standard.RightHand && SelectionManager.pointingAtTabletRight) || - (hand === Controller.Standard.LeftHand && SelectionManager.pointingAtTabletLeft); - if (pointingAtDesktopWindow || pointingAtTablet) { - return; - } - that.mousePressEvent({}); - } else if (that.triggered && !SelectionManager.triggerClicked) { - that.triggered = false; - that.mouseReleaseEvent({}); + // Don't allow both hands to trigger at the same time + if (that.triggered() && hand !== that.triggeredHand) { + return; + } + var triggerClicked = hand == Controller.Standard.RightHand ? SelectionManager.triggerClickedRight : + SelectionManager.triggerClickedLeft; + if (!that.triggered() && triggerClicked) { + triggerPress(hand); + } else if (that.triggered() && !triggerClicked) { + triggerRelease(hand); } }; } @@ -836,7 +858,7 @@ SelectionDisplay = (function() { if (wantDebug) { print("=============== eST::MousePressEvent BEG ======================="); } - if (!event.isLeftButton && !that.triggered) { + if (!event.isLeftButton && !that.triggered()) { // EARLY EXIT-(if another mouse button than left is pressed ignore it) return false; } @@ -1082,9 +1104,9 @@ SelectionDisplay = (function() { that.checkControllerMove = function() { if (SelectionManager.hasSelection()) { - var controllerPose = getControllerWorldLocation(activeHand, true); - var hand = (activeHand === Controller.Standard.LeftHand) ? 0 : 1; - if (controllerPose.valid && lastControllerPoses[hand].valid && that.triggered) { + var controllerPose = getControllerWorldLocation(that.triggeredHand, true); + var hand = (that.triggeredHand === Controller.Standard.LeftHand) ? 0 : 1; + if (controllerPose.valid && lastControllerPoses[hand].valid && that.triggered()) { if (!Vec3.equal(controllerPose.position, lastControllerPoses[hand].position) || !Vec3.equal(controllerPose.rotation, lastControllerPoses[hand].rotation)) { that.mouseMoveEvent({}); @@ -1095,8 +1117,8 @@ SelectionDisplay = (function() { }; function controllerComputePickRay() { - var controllerPose = getControllerWorldLocation(activeHand, true); - if (controllerPose.valid && that.triggered) { + var controllerPose = getControllerWorldLocation(that.triggeredHand, true); + if (controllerPose.valid && that.triggered()) { var controllerPosition = controllerPose.translation; // This gets point direction right, but if you want general quaternion it would be more complicated: var controllerDirection = Quat.getUp(controllerPose.rotation); @@ -2246,11 +2268,11 @@ SelectionDisplay = (function() { } // Are we using handControllers or Mouse - only relevant for 3D tools - var controllerPose = getControllerWorldLocation(activeHand, true); + var controllerPose = getControllerWorldLocation(that.triggeredHand, true); var vector = null; var newPick = null; if (HMD.isHMDAvailable() && HMD.isHandControllerAvailable() && - controllerPose.valid && that.triggered && directionFor3DStretch) { + controllerPose.valid && that.triggered() && directionFor3DStretch) { localDeltaPivot = deltaPivot3D; newPick = pickRay.origin; vector = Vec3.subtract(newPick, lastPick3D); From 103f9e04fa0efb1544209520ef538de073978489 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 23 Jul 2018 12:58:50 -0700 Subject: [PATCH 13/29] Fix duplication not working as expected on grabbed entities --- .../system/libraries/entitySelectionTool.js | 107 ++++++++++++++---- 1 file changed, 85 insertions(+), 22 deletions(-) diff --git a/scripts/system/libraries/entitySelectionTool.js b/scripts/system/libraries/entitySelectionTool.js index 091d431502..feaa75971c 100644 --- a/scripts/system/libraries/entitySelectionTool.js +++ b/scripts/system/libraries/entitySelectionTool.js @@ -194,11 +194,40 @@ SelectionManager = (function() { } }; + // Return true if the given entity with `properties` is being grabbed by an avatar. + // This is mostly a heuristic - there is no perfect way to know if an entity is being + // grabbed. + function nonDynamicEntityIsBeingGrabbedByAvatar(properties) { + if (properties.dynamic || properties.parentID === null) { + return false; + } + + var avatar = AvatarList.getAvatar(properties.parentID); + if (avatar.sessionUUID === null) { + return false; + } + + var grabJointNames = [ + 'RightHand', 'LeftHand', + '_CONTROLLER_RIGHTHAND', '_CONTROLLER_LEFTHAND', + '_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND', '_CAMERA_RELATIVE_CONTROLLER_LEFTHAND']; + + for (var i = 0; i < grabJointNames.length; ++i) { + if (avatar.getJointIndex(grabJointNames[i]) === properties.parentJointIndex) { + return true; + } + } + + return false; + } + that.duplicateSelection = function() { var entitiesToDuplicate = []; var duplicatedEntityIDs = []; var duplicatedChildrenWithOldParents = []; var originalEntityToNewEntityID = []; + + SelectionManager.saveProperties(); // build list of entities to duplicate by including any unselected children of selected parent entities Object.keys(that.savedProperties).forEach(function(originalEntityID) { @@ -216,10 +245,33 @@ SelectionManager = (function() { properties = Entities.getEntityProperties(originalEntityID); } if (!properties.locked && (!properties.clientOnly || properties.owningAvatarID === MyAvatar.sessionUUID)) { + if (nonDynamicEntityIsBeingGrabbedByAvatar(properties)) { + properties.parentID = null; + properties.parentJointIndex = null; + properties.localPosition = properties.position; + properties.localRotation = properties.rotation; + } + delete properties.actionData; var newEntityID = Entities.addEntity(properties); + + // Re-apply actions from the original entity + var actionIDs = Entities.getActionIDs(properties.id); + for (var i = 0; i < actionIDs.length; ++i) { + var actionID = actionIDs[i]; + var actionArguments = Entities.getActionArguments(properties.id, actionID); + if (actionArguments) { + var type = actionArguments.type; + if (type == 'hold' || type == 'far-grab') { + continue; + } + delete actionArguments.ttl; + Entities.addAction(type, newEntityID, actionArguments); + } + } + duplicatedEntityIDs.push({ entityID: newEntityID, - properties: properties + properties: properties, }); if (properties.parentID !== Uuid.NULL) { duplicatedChildrenWithOldParents[newEntityID] = properties.parentID; @@ -255,7 +307,8 @@ SelectionManager = (function() { that.worldPosition = null; that.worldRotation = null; } else if (that.selections.length === 1) { - properties = Entities.getEntityProperties(that.selections[0]); + properties = Entities.getEntityProperties(that.selections[0], + ['dimensions', 'position', 'rotation', 'registrationPoint', 'boundingBox', 'type']); that.localDimensions = properties.dimensions; that.localPosition = properties.position; that.localRotation = properties.rotation; @@ -271,7 +324,7 @@ SelectionManager = (function() { SelectionDisplay.setSpaceMode(SPACE_LOCAL); } } else { - properties = Entities.getEntityProperties(that.selections[0]); + properties = Entities.getEntityProperties(that.selections[0], ['type', 'boundingBox']); that.entityType = properties.type; @@ -279,7 +332,7 @@ SelectionManager = (function() { var tfl = properties.boundingBox.tfl; for (var i = 1; i < that.selections.length; i++) { - properties = Entities.getEntityProperties(that.selections[i]); + properties = Entities.getEntityProperties(that.selections[i], 'boundingBox'); var bb = properties.boundingBox; brn.x = Math.min(bb.brn.x, brn.x); brn.y = Math.min(bb.brn.y, brn.y); @@ -1716,6 +1769,20 @@ SelectionDisplay = (function() { Vec3.print(" pickResult.intersection", pickResult.intersection); } + // Duplicate entities if alt is pressed. This will make a + // copy of the selected entities and move the _original_ entities, not + // the new ones. + if (event.isAlt || doClone) { + duplicatedEntityIDs = SelectionManager.duplicateSelection(); + var ids = []; + for (var i = 0; i < duplicatedEntityIDs.length; ++i) { + ids.push(duplicatedEntityIDs[i].entityID); + } + SelectionManager.setSelections(ids); + } else { + duplicatedEntityIDs = null; + } + SelectionManager.saveProperties(); that.resetPreviousHandleColor(); @@ -1745,15 +1812,6 @@ SelectionDisplay = (function() { z: 0 }); - // Duplicate entities if alt is pressed. This will make a - // copy of the selected entities and move the _original_ entities, not - // the new ones. - if (event.isAlt || doClone) { - duplicatedEntityIDs = SelectionManager.duplicateSelection(); - } else { - duplicatedEntityIDs = null; - } - isConstrained = false; if (wantDebug) { print("================== TRANSLATE_XZ(End) <- ======================="); @@ -1929,6 +1987,20 @@ SelectionDisplay = (function() { addHandleTool(overlay, { mode: mode, onBegin: function(event, pickRay, pickResult) { + // Duplicate entities if alt is pressed. This will make a + // copy of the selected entities and move the _original_ entities, not + // the new ones. + if (event.isAlt) { + duplicatedEntityIDs = SelectionManager.duplicateSelection(); + var ids = []; + for (var i = 0; i < duplicatedEntityIDs.length; ++i) { + ids.push(duplicatedEntityIDs[i].entityID); + } + SelectionManager.setSelections(ids); + } else { + duplicatedEntityIDs = null; + } + var axisVector; if (direction === TRANSLATE_DIRECTION.X) { axisVector = { x: 1, y: 0, z: 0 }; @@ -1955,15 +2027,6 @@ SelectionDisplay = (function() { that.setHandleStretchVisible(false); that.setHandleScaleCubeVisible(false); that.setHandleClonerVisible(false); - - // Duplicate entities if alt is pressed. This will make a - // copy of the selected entities and move the _original_ entities, not - // the new ones. - if (event.isAlt) { - duplicatedEntityIDs = SelectionManager.duplicateSelection(); - } else { - duplicatedEntityIDs = null; - } previousPickRay = pickRay; }, From ba8d44544422cd1a0076c4385f513d210b69303c Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Sat, 28 Jul 2018 00:25:16 +0200 Subject: [PATCH 14/29] fix require by queueing content requests --- libraries/script-engine/src/ScriptEngine.cpp | 15 ++++++++++++++- libraries/script-engine/src/ScriptEngine.h | 10 ++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 99c02ba1f6..fe77e36f0c 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -219,6 +219,19 @@ ScriptEngine::ScriptEngine(Context context, const QString& scriptContents, const } logException(output); }); + + if (_type == Type::ENTITY_CLIENT || _type == Type::ENTITY_SERVER) { + QObject::connect(this, &ScriptEngine::update, this, [this]() { + // process pending entity script content + if (_contentAvailableQueue.size()) { + auto pending = _contentAvailableQueue.values().toStdList(); + _contentAvailableQueue.clear(); + for (auto& args : pending) { + entityScriptContentAvailable(args.entityID, args.scriptOrURL, args.contents, args.isURL, args.success, args.status); + } + } + }); + } } QString ScriptEngine::getContext() const { @@ -2181,7 +2194,7 @@ void ScriptEngine::loadEntityScript(const EntityItemID& entityID, const QString& qCDebug(scriptengine) << "loadEntityScript.contentAvailable" << status << QUrl(url).fileName() << entityID.toString(); #endif if (!isStopping() && _entityScripts.contains(entityID)) { - entityScriptContentAvailable(entityID, url, contents, isURL, success, status); + _contentAvailableQueue[entityID] = { entityID, url, contents, isURL, success, status }; } else { #ifdef DEBUG_ENTITY_STATES qCDebug(scriptengine) << "loadEntityScript.contentAvailable -- aborting"; diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index c02a63ef3c..3280c2f249 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -71,6 +71,15 @@ public: //bool forceRedownload; }; +struct EntityScriptContentAvailable { + EntityItemID entityID; + QString scriptOrURL; + QString contents; + bool isURL; + bool success; + QString status; +}; + typedef QList CallbackList; typedef QHash RegisteredEventHandlers; @@ -762,6 +771,7 @@ protected: QHash _entityScripts; QHash _occupiedScriptURLs; QList _deferredEntityLoads; + QMap _contentAvailableQueue; bool _isThreaded { false }; QScriptEngineDebugger* _debugger { nullptr }; From 401995fb067e70a356834309ec3115fb2aee5907 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Mon, 30 Jul 2018 10:55:52 -0700 Subject: [PATCH 15/29] Leg IK fixes Fixes for raising legs and sometimes squatting while in HMD mode. --- .../resources/avatar/avatar-animation.json | 2265 +++++++++-------- .../avatar/old-avatar-animation.json | 1228 +++++++++ libraries/animation/src/AnimBlendLinear.cpp | 7 +- libraries/animation/src/AnimBlendLinear.h | 4 +- .../animation/src/AnimBlendLinearMove.cpp | 11 +- libraries/animation/src/AnimBlendLinearMove.h | 6 +- libraries/animation/src/AnimChain.h | 159 ++ libraries/animation/src/AnimClip.cpp | 6 +- libraries/animation/src/AnimClip.h | 2 +- libraries/animation/src/AnimDefaultPose.cpp | 5 +- libraries/animation/src/AnimDefaultPose.h | 2 +- .../animation/src/AnimInverseKinematics.cpp | 22 +- .../animation/src/AnimInverseKinematics.h | 4 +- libraries/animation/src/AnimManipulator.cpp | 6 +- libraries/animation/src/AnimManipulator.h | 4 +- libraries/animation/src/AnimNode.cpp | 16 + libraries/animation/src/AnimNode.h | 12 +- libraries/animation/src/AnimNodeLoader.cpp | 80 +- libraries/animation/src/AnimOverlay.cpp | 5 +- libraries/animation/src/AnimOverlay.h | 2 +- .../src/AnimPoleVectorConstraint.cpp | 245 ++ .../animation/src/AnimPoleVectorConstraint.h | 74 + libraries/animation/src/AnimPose.cpp | 13 + libraries/animation/src/AnimPose.h | 2 + libraries/animation/src/AnimSkeleton.cpp | 14 + libraries/animation/src/AnimSkeleton.h | 2 + libraries/animation/src/AnimStateMachine.cpp | 7 +- libraries/animation/src/AnimStateMachine.h | 2 +- libraries/animation/src/AnimTwoBoneIK.cpp | 292 +++ libraries/animation/src/AnimTwoBoneIK.h | 83 + libraries/animation/src/AnimUtil.cpp | 6 +- libraries/animation/src/AnimUtil.h | 2 +- libraries/animation/src/Rig.cpp | 132 +- libraries/animation/src/Rig.h | 9 +- 34 files changed, 3524 insertions(+), 1205 deletions(-) create mode 100644 interface/resources/avatar/old-avatar-animation.json create mode 100644 libraries/animation/src/AnimChain.h create mode 100644 libraries/animation/src/AnimPoleVectorConstraint.cpp create mode 100644 libraries/animation/src/AnimPoleVectorConstraint.h create mode 100644 libraries/animation/src/AnimTwoBoneIK.cpp create mode 100644 libraries/animation/src/AnimTwoBoneIK.h diff --git a/interface/resources/avatar/avatar-animation.json b/interface/resources/avatar/avatar-animation.json index 44d294f767..d689857071 100644 --- a/interface/resources/avatar/avatar-animation.json +++ b/interface/resources/avatar/avatar-animation.json @@ -1,5 +1,5 @@ { - "version": "1.0", + "version": "1.1", "root": { "id": "userAnimStateMachine", "type": "stateMachine", @@ -38,1156 +38,1201 @@ "children": [ { "id": "userAnimNone", - "type": "overlay", + "type": "poleVectorConstraint", "data": { - "alpha": 1.0, - "alphaVar": "ikOverlayAlpha", - "boneSet": "fullBody" + "enabled": false, + "referenceVector": [0, 0, 1], + "baseJointName": "RightUpLeg", + "midJointName": "RightLeg", + "tipJointName": "RightFoot", + "enabledVar": "rightFootPoleVectorEnabled", + "poleVectorVar": "rightFootPoleVector" }, "children": [ { - "id": "ik", - "type": "inverseKinematics", + "id": "rightFootIK", + "type": "twoBoneIK", "data": { - "solutionSource": "relaxToUnderPoses", - "solutionSourceVar": "solutionSource", - "targets": [ - { - "jointName": "Hips", - "positionVar": "hipsPosition", - "rotationVar": "hipsRotation", - "typeVar": "hipsType", - "weightVar": "hipsWeight", - "weight": 1.0, - "flexCoefficients": [1] - }, - { - "jointName": "RightHand", - "positionVar": "rightHandPosition", - "rotationVar": "rightHandRotation", - "typeVar": "rightHandType", - "weightVar": "rightHandWeight", - "weight": 1.0, - "flexCoefficients": [1, 0.5, 0.5, 0.2, 0.01, 0.005, 0.001, 0.0, 0.0], - "poleVectorEnabledVar": "rightHandPoleVectorEnabled", - "poleReferenceVectorVar": "rightHandPoleReferenceVector", - "poleVectorVar": "rightHandPoleVector" - }, - { - "jointName": "LeftHand", - "positionVar": "leftHandPosition", - "rotationVar": "leftHandRotation", - "typeVar": "leftHandType", - "weightVar": "leftHandWeight", - "weight": 1.0, - "flexCoefficients": [1, 0.5, 0.5, 0.2, 0.01, 0.005, 0.001, 0.0, 0.0], - "poleVectorEnabledVar": "leftHandPoleVectorEnabled", - "poleReferenceVectorVar": "leftHandPoleReferenceVector", - "poleVectorVar": "leftHandPoleVector" - }, - { - "jointName": "RightFoot", - "positionVar": "rightFootPosition", - "rotationVar": "rightFootRotation", - "typeVar": "rightFootType", - "weightVar": "rightFootWeight", - "weight": 1.0, - "flexCoefficients": [1, 0.45, 0.45], - "poleVectorEnabledVar": "rightFootPoleVectorEnabled", - "poleReferenceVectorVar": "rightFootPoleReferenceVector", - "poleVectorVar": "rightFootPoleVector" - }, - { - "jointName": "LeftFoot", - "positionVar": "leftFootPosition", - "rotationVar": "leftFootRotation", - "typeVar": "leftFootType", - "weightVar": "leftFootWeight", - "weight": 1.0, - "flexCoefficients": [1, 0.45, 0.45], - "poleVectorEnabledVar": "leftFootPoleVectorEnabled", - "poleReferenceVectorVar": "leftFootPoleReferenceVector", - "poleVectorVar": "leftFootPoleVector" - }, - { - "jointName": "Spine2", - "positionVar": "spine2Position", - "rotationVar": "spine2Rotation", - "typeVar": "spine2Type", - "weightVar": "spine2Weight", - "weight": 2.0, - "flexCoefficients": [1.0, 0.5, 0.25] - }, - { - "jointName": "Head", - "positionVar": "headPosition", - "rotationVar": "headRotation", - "typeVar": "headType", - "weightVar": "headWeight", - "weight": 4.0, - "flexCoefficients": [1, 0.5, 0.25, 0.2, 0.1] - } - ] - }, - "children": [] - }, - { - "id": "defaultPoseOverlay", - "type": "overlay", - "data": { - "alpha": 0.0, - "alphaVar": "defaultPoseOverlayAlpha", - "boneSet": "fullBody", - "boneSetVar": "defaultPoseOverlayBoneSet" + "alpha": 1.0, + "enabled": false, + "interpDuration": 15, + "baseJointName": "RightUpLeg", + "midJointName": "RightLeg", + "tipJointName": "RightFoot", + "midHingeAxis": [-1, 0, 0], + "alphaVar": "rightFootIKAlpha", + "enabledVar": "rightFootIKEnabled", + "endEffectorRotationVarVar": "rightFootIKRotationVar", + "endEffectorPositionVarVar": "rightFootIKPositionVar" }, "children": [ { - "id": "defaultPose", - "type": "defaultPose", + "id": "leftFootPoleVector", + "type": "poleVectorConstraint", "data": { - }, - "children": [] - }, - { - "id": "rightHandOverlay", - "type": "overlay", - "data": { - "alpha": 0.0, - "boneSet": "rightHand", - "alphaVar": "rightHandOverlayAlpha" + "enabled": false, + "referenceVector": [0, 0, 1], + "baseJointName": "LeftUpLeg", + "midJointName": "LeftLeg", + "tipJointName": "LeftFoot", + "enabledVar": "leftFootPoleVectorEnabled", + "poleVectorVar": "leftFootPoleVector" }, "children": [ { - "id": "rightHandStateMachine", - "type": "stateMachine", + "id": "leftFootIK", + "type": "twoBoneIK", "data": { - "currentState": "rightHandGrasp", - "states": [ - { - "id": "rightHandGrasp", - "interpTarget": 3, - "interpDuration": 3, - "transitions": [ - { "var": "isRightIndexPoint", "state": "rightIndexPoint" }, - { "var": "isRightThumbRaise", "state": "rightThumbRaise" }, - { "var": "isRightIndexPointAndThumbRaise", "state": "rightIndexPointAndThumbRaise" } - ] - }, - { - "id": "rightIndexPoint", - "interpTarget": 15, - "interpDuration": 3, - "transitions": [ - { "var": "isRightHandGrasp", "state": "rightHandGrasp" }, - { "var": "isRightThumbRaise", "state": "rightThumbRaise" }, - { "var": "isRightIndexPointAndThumbRaise", "state": "rightIndexPointAndThumbRaise" } - ] - }, - { - "id": "rightThumbRaise", - "interpTarget": 15, - "interpDuration": 3, - "transitions": [ - { "var": "isRightHandGrasp", "state": "rightHandGrasp" }, - { "var": "isRightIndexPoint", "state": "rightIndexPoint" }, - { "var": "isRightIndexPointAndThumbRaise", "state": "rightIndexPointAndThumbRaise" } - ] - }, - { - "id": "rightIndexPointAndThumbRaise", - "interpTarget": 15, - "interpDuration": 3, - "transitions": [ - { "var": "isRightHandGrasp", "state": "rightHandGrasp" }, - { "var": "isRightIndexPoint", "state": "rightIndexPoint" }, - { "var": "isRightThumbRaise", "state": "rightThumbRaise" } - ] - } - ] + "alpha": 1.0, + "enabled": false, + "interpDuration": 15, + "baseJointName": "LeftUpLeg", + "midJointName": "LeftLeg", + "tipJointName": "LeftFoot", + "midHingeAxis": [-1, 0, 0], + "alphaVar": "leftFootIKAlpha", + "enabledVar": "leftFootIKEnabled", + "endEffectorRotationVarVar": "leftFootIKRotationVar", + "endEffectorPositionVarVar": "leftFootIKPositionVar" }, "children": [ { - "id": "rightHandGrasp", - "type": "blendLinear", + "id": "ikOverlay", + "type": "overlay", "data": { - "alpha": 0.0, - "alphaVar": "rightHandGraspAlpha" + "alpha": 1.0, + "alphaVar": "ikOverlayAlpha", + "boneSet": "fullBody" }, "children": [ { - "id": "rightHandGraspOpen", - "type": "clip", + "id": "ik", + "type": "inverseKinematics", "data": { - "url": "animations/hydra_pose_open_right.fbx", - "startFrame": 0.0, - "endFrame": 0.0, - "timeScale": 1.0, - "loopFlag": true - }, - "children": [] - }, - { - "id": "rightHandGraspClosed", - "type": "clip", - "data": { - "url": "animations/hydra_pose_closed_right.fbx", - "startFrame": 0.0, - "endFrame": 0.0, - "timeScale": 1.0, - "loopFlag": true - }, - "children": [] - } - ] - }, - { - "id": "rightIndexPoint", - "type": "blendLinear", - "data": { - "alpha": 0.0, - "alphaVar": "rightHandGraspAlpha" - }, - "children": [ - { - "id": "rightIndexPointOpen", - "type": "clip", - "data": { - "url": "animations/touch_point_open_right.fbx", - "startFrame": 15.0, - "endFrame": 15.0, - "timeScale": 1.0, - "loopFlag": true - }, - "children": [] - }, - { - "id": "rightIndexPointClosed", - "type": "clip", - "data": { - "url": "animations/touch_point_closed_right.fbx", - "startFrame": 15.0, - "endFrame": 15.0, - "timeScale": 1.0, - "loopFlag": true - }, - "children": [] - } - ] - }, - { - "id": "rightThumbRaise", - "type": "blendLinear", - "data": { - "alpha": 0.0, - "alphaVar": "rightHandGraspAlpha" - }, - "children": [ - { - "id": "rightThumbRaiseOpen", - "type": "clip", - "data": { - "url": "animations/touch_thumb_open_right.fbx", - "startFrame": 15.0, - "endFrame": 15.0, - "timeScale": 1.0, - "loopFlag": true - }, - "children": [] - }, - { - "id": "rightThumbRaiseClosed", - "type": "clip", - "data": { - "url": "animations/touch_thumb_closed_right.fbx", - "startFrame": 15.0, - "endFrame": 15.0, - "timeScale": 1.0, - "loopFlag": true - }, - "children": [] - } - ] - }, - { - "id": "rightIndexPointAndThumbRaise", - "type": "blendLinear", - "data": { - "alpha": 0.0, - "alphaVar": "rightHandGraspAlpha" - }, - "children": [ - { - "id": "rightIndexPointAndThumbRaiseOpen", - "type": "clip", - "data": { - "url": "animations/touch_thumb_point_open_right.fbx", - "startFrame": 15.0, - "endFrame": 15.0, - "timeScale": 1.0, - "loopFlag": true - }, - "children": [] - }, - { - "id": "rightIndexPointAndThumbRaiseClosed", - "type": "clip", - "data": { - "url": "animations/touch_thumb_point_closed_right.fbx", - "startFrame": 15.0, - "endFrame": 15.0, - "timeScale": 1.0, - "loopFlag": true - }, - "children": [] - } - ] - } - ] - }, - { - "id": "leftHandOverlay", - "type": "overlay", - "data": { - "alpha": 0.0, - "boneSet": "leftHand", - "alphaVar": "leftHandOverlayAlpha" - }, - "children": [ - { - "id": "leftHandStateMachine", - "type": "stateMachine", - "data": { - "currentState": "leftHandGrasp", - "states": [ - { - "id": "leftHandGrasp", - "interpTarget": 3, - "interpDuration": 3, - "transitions": [ - { "var": "isLeftIndexPoint", "state": "leftIndexPoint" }, - { "var": "isLeftThumbRaise", "state": "leftThumbRaise" }, - { "var": "isLeftIndexPointAndThumbRaise", "state": "leftIndexPointAndThumbRaise" } - ] - }, - { - "id": "leftIndexPoint", - "interpTarget": 15, - "interpDuration": 3, - "transitions": [ - { "var": "isLeftHandGrasp", "state": "leftHandGrasp" }, - { "var": "isLeftThumbRaise", "state": "leftThumbRaise" }, - { "var": "isLeftIndexPointAndThumbRaise", "state": "leftIndexPointAndThumbRaise" } - ] - }, - { - "id": "leftThumbRaise", - "interpTarget": 15, - "interpDuration": 3, - "transitions": [ - { "var": "isLeftHandGrasp", "state": "leftHandGrasp" }, - { "var": "isLeftIndexPoint", "state": "leftIndexPoint" }, - { "var": "isLeftIndexPointAndThumbRaise", "state": "leftIndexPointAndThumbRaise" } - ] - }, - { - "id": "leftIndexPointAndThumbRaise", - "interpTarget": 15, - "interpDuration": 3, - "transitions": [ - { "var": "isLeftHandGrasp", "state": "leftHandGrasp" }, - { "var": "isLeftIndexPoint", "state": "leftIndexPoint" }, - { "var": "isLeftThumbRaise", "state": "leftThumbRaise" } - ] - } - ] - }, - "children": [ - { - "id": "leftHandGrasp", - "type": "blendLinear", - "data": { - "alpha": 0.0, - "alphaVar": "leftHandGraspAlpha" - }, - "children": [ - { - "id": "leftHandGraspOpen", - "type": "clip", - "data": { - "url": "animations/hydra_pose_open_left.fbx", - "startFrame": 0.0, - "endFrame": 0.0, - "timeScale": 1.0, - "loopFlag": true - }, - "children": [] - }, - { - "id": "leftHandGraspClosed", - "type": "clip", - "data": { - "url": "animations/hydra_pose_closed_left.fbx", - "startFrame": 10.0, - "endFrame": 10.0, - "timeScale": 1.0, - "loopFlag": true - }, - "children": [] - } - ] - }, - { - "id": "leftIndexPoint", - "type": "blendLinear", - "data": { - "alpha": 0.0, - "alphaVar": "leftHandGraspAlpha" - }, - "children": [ - { - "id": "leftIndexPointOpen", - "type": "clip", - "data": { - "url": "animations/touch_point_open_left.fbx", - "startFrame": 15.0, - "endFrame": 15.0, - "timeScale": 1.0, - "loopFlag": true - }, - "children": [] - }, - { - "id": "leftIndexPointClosed", - "type": "clip", - "data": { - "url": "animations/touch_point_closed_left.fbx", - "startFrame": 15.0, - "endFrame": 15.0, - "timeScale": 1.0, - "loopFlag": true - }, - "children": [] - } - ] - }, - { - "id": "leftThumbRaise", - "type": "blendLinear", - "data": { - "alpha": 0.0, - "alphaVar": "leftHandGraspAlpha" - }, - "children": [ - { - "id": "leftThumbRaiseOpen", - "type": "clip", - "data": { - "url": "animations/touch_thumb_open_left.fbx", - "startFrame": 15.0, - "endFrame": 15.0, - "timeScale": 1.0, - "loopFlag": true - }, - "children": [] - }, - { - "id": "leftThumbRaiseClosed", - "type": "clip", - "data": { - "url": "animations/touch_thumb_closed_left.fbx", - "startFrame": 15.0, - "endFrame": 15.0, - "timeScale": 1.0, - "loopFlag": true - }, - "children": [] - } - ] - }, - { - "id": "leftIndexPointAndThumbRaise", - "type": "blendLinear", - "data": { - "alpha": 0.0, - "alphaVar": "leftHandGraspAlpha" - }, - "children": [ - { - "id": "leftIndexPointAndThumbRaiseOpen", - "type": "clip", - "data": { - "url": "animations/touch_thumb_point_open_left.fbx", - "startFrame": 15.0, - "endFrame": 15.0, - "timeScale": 1.0, - "loopFlag": true - }, - "children": [] - }, - { - "id": "leftIndexPointAndThumbRaiseClosed", - "type": "clip", - "data": { - "url": "animations/touch_thumb_point_closed_left.fbx", - "startFrame": 15.0, - "endFrame": 15.0, - "timeScale": 1.0, - "loopFlag": true - }, - "children": [] - } - ] - } - ] - }, - { - "id": "mainStateMachine", - "type": "stateMachine", - "data": { - "currentState": "idle", - "states": [ - { - "id": "idle", - "interpTarget": 10, - "interpDuration": 10, - "transitions": [ - { "var": "isMovingForward", "state": "idleToWalkFwd" }, - { "var": "isMovingBackward", "state": "walkBwd" }, - { "var": "isMovingRight", "state": "strafeRight" }, - { "var": "isMovingLeft", "state": "strafeLeft" }, - { "var": "isTurningRight", "state": "turnRight" }, - { "var": "isTurningLeft", "state": "turnLeft" }, - { "var": "isFlying", "state": "fly" }, - { "var": "isTakeoffStand", "state": "takeoffStand" }, - { "var": "isTakeoffRun", "state": "takeoffRun" }, - { "var": "isInAirStand", "state": "inAirStand" }, - { "var": "isInAirRun", "state": "inAirRun" } - ] - }, - { - "id": "idleToWalkFwd", - "interpTarget": 10, - "interpDuration": 3, - "transitions": [ - { "var": "idleToWalkFwdOnDone", "state": "walkFwd" }, - { "var": "isNotMoving", "state": "idle" }, - { "var": "isMovingBackward", "state": "walkBwd" }, - { "var": "isMovingRight", "state": "strafeRight" }, - { "var": "isMovingLeft", "state": "strafeLeft" }, - { "var": "isTurningRight", "state": "turnRight" }, - { "var": "isTurningLeft", "state": "turnLeft" }, - { "var": "isFlying", "state": "fly" }, - { "var": "isTakeoffStand", "state": "takeoffStand" }, - { "var": "isTakeoffRun", "state": "takeoffRun" }, - { "var": "isInAirStand", "state": "inAirStand" }, - { "var": "isInAirRun", "state": "inAirRun" } - ] - }, - { - "id": "walkFwd", - "interpTarget": 16, - "interpDuration": 6, - "transitions": [ - { "var": "isNotMoving", "state": "idle" }, - { "var": "isMovingBackward", "state": "walkBwd" }, - { "var": "isMovingRight", "state": "strafeRight" }, - { "var": "isMovingLeft", "state": "strafeLeft" }, - { "var": "isTurningRight", "state": "turnRight" }, - { "var": "isTurningLeft", "state": "turnLeft" }, - { "var": "isFlying", "state": "fly" }, - { "var": "isTakeoffStand", "state": "takeoffStand" }, - { "var": "isTakeoffRun", "state": "takeoffRun" }, - { "var": "isInAirStand", "state": "inAirStand" }, - { "var": "isInAirRun", "state": "inAirRun" } - ] - }, - { - "id": "walkBwd", - "interpTarget": 8, - "interpDuration": 2, - "transitions": [ - { "var": "isNotMoving", "state": "idle" }, - { "var": "isMovingForward", "state": "walkFwd" }, - { "var": "isMovingRight", "state": "strafeRight" }, - { "var": "isMovingLeft", "state": "strafeLeft" }, - { "var": "isTurningRight", "state": "turnRight" }, - { "var": "isTurningLeft", "state": "turnLeft" }, - { "var": "isFlying", "state": "fly" }, - { "var": "isTakeoffStand", "state": "takeoffStand" }, - { "var": "isTakeoffRun", "state": "takeoffRun" }, - { "var": "isInAirStand", "state": "inAirStand" }, - { "var": "isInAirRun", "state": "inAirRun" } - ] - }, - { - "id": "strafeRight", - "interpTarget": 20, - "interpDuration": 1, - "transitions": [ - { "var": "isNotMoving", "state": "idle" }, - { "var": "isMovingForward", "state": "walkFwd" }, - { "var": "isMovingBackward", "state": "walkBwd" }, - { "var": "isMovingLeft", "state": "strafeLeft" }, - { "var": "isTurningRight", "state": "turnRight" }, - { "var": "isTurningLeft", "state": "turnLeft" }, - { "var": "isFlying", "state": "fly" }, - { "var": "isTakeoffStand", "state": "takeoffStand" }, - { "var": "isTakeoffRun", "state": "takeoffRun" }, - { "var": "isInAirStand", "state": "inAirStand" }, - { "var": "isInAirRun", "state": "inAirRun" } - ] - }, - { - "id": "strafeLeft", - "interpTarget": 20, - "interpDuration": 1, - "transitions": [ - { "var": "isNotMoving", "state": "idle" }, - { "var": "isMovingForward", "state": "walkFwd" }, - { "var": "isMovingBackward", "state": "walkBwd" }, - { "var": "isMovingRight", "state": "strafeRight" }, - { "var": "isTurningRight", "state": "turnRight" }, - { "var": "isTurningLeft", "state": "turnLeft" }, - { "var": "isFlying", "state": "fly" }, - { "var": "isTakeoffStand", "state": "takeoffStand" }, - { "var": "isTakeoffRun", "state": "takeoffRun" }, - { "var": "isInAirStand", "state": "inAirStand" }, - { "var": "isInAirRun", "state": "inAirRun" } - ] - }, - { - "id": "turnRight", - "interpTarget": 6, - "interpDuration": 6, - "transitions": [ - { "var": "isNotTurning", "state": "idle" }, - { "var": "isMovingForward", "state": "walkFwd" }, - { "var": "isMovingBackward", "state": "walkBwd" }, - { "var": "isMovingRight", "state": "strafeRight" }, - { "var": "isMovingLeft", "state": "strafeLeft" }, - { "var": "isTurningLeft", "state": "turnLeft" }, - { "var": "isFlying", "state": "fly" }, - { "var": "isTakeoffStand", "state": "takeoffStand" }, - { "var": "isTakeoffRun", "state": "takeoffRun" }, - { "var": "isInAirStand", "state": "inAirStand" }, - { "var": "isInAirRun", "state": "inAirRun" } - ] - }, - { - "id": "turnLeft", - "interpTarget": 6, - "interpDuration": 6, - "transitions": [ - { "var": "isNotTurning", "state": "idle" }, - { "var": "isMovingForward", "state": "walkFwd" }, - { "var": "isMovingBackward", "state": "walkBwd" }, - { "var": "isMovingRight", "state": "strafeRight" }, - { "var": "isMovingLeft", "state": "strafeLeft" }, - { "var": "isTurningRight", "state": "turnRight" }, - { "var": "isFlying", "state": "fly" }, - { "var": "isTakeoffStand", "state": "takeoffStand" }, - { "var": "isTakeoffRun", "state": "takeoffRun" }, - { "var": "isInAirStand", "state": "inAirStand" }, - { "var": "isInAirRun", "state": "inAirRun" } - ] - }, - { - "id": "fly", - "interpTarget": 6, - "interpDuration": 6, - "transitions": [ - { "var": "isNotFlying", "state": "idle" } - ] - }, - { - "id": "takeoffStand", - "interpTarget": 0, - "interpDuration": 6, - "transitions": [ - { "var": "isNotTakeoff", "state": "inAirStand" } - ] - }, - { - "id": "takeoffRun", - "interpTarget": 0, - "interpDuration": 6, - "transitions": [ - { "var": "isNotTakeoff", "state": "inAirRun" } - ] - }, - { - "id": "inAirStand", - "interpTarget": 0, - "interpDuration": 6, - "interpType": "snapshotPrev", - "transitions": [ - { "var": "isNotInAir", "state": "landStandImpact" } - ] - }, - { - "id": "inAirRun", - "interpTarget": 0, - "interpDuration": 6, - "interpType": "snapshotPrev", - "transitions": [ - { "var": "isNotInAir", "state": "landRun" } - ] - }, - { - "id": "landStandImpact", - "interpTarget": 6, - "interpDuration": 4, - "transitions": [ - { "var": "isFlying", "state": "fly" }, - { "var": "isTakeoffStand", "state": "takeoffStand" }, - { "var": "isTakeoffRun", "state": "takeoffRun" }, - { "var": "landStandImpactOnDone", "state": "landStand" } - ] - }, - { - "id": "landStand", - "interpTarget": 0, - "interpDuration": 1, - "transitions": [ - { "var": "isMovingForward", "state": "idleToWalkFwd" }, - { "var": "isMovingBackward", "state": "walkBwd" }, - { "var": "isMovingRight", "state": "strafeRight" }, - { "var": "isMovingLeft", "state": "strafeLeft" }, - { "var": "isTurningRight", "state": "turnRight" }, - { "var": "isTurningLeft", "state": "turnLeft" }, - { "var": "isFlying", "state": "fly" }, - { "var": "isTakeoffStand", "state": "takeoffStand" }, - { "var": "isTakeoffRun", "state": "takeoffRun" }, - { "var": "isInAirStand", "state": "inAirStand" }, - { "var": "isInAirRun", "state": "inAirRun" }, - { "var": "landStandOnDone", "state": "idle" } - ] - }, - { - "id": "landRun", - "interpTarget": 1, - "interpDuration": 7, - "transitions": [ - { "var": "isFlying", "state": "fly" }, - { "var": "isTakeoffStand", "state": "takeoffStand" }, - { "var": "isTakeoffRun", "state": "takeoffRun" }, - { "var": "landRunOnDone", "state": "walkFwd" } - ] - } - ] - }, - "children": [ - { - "id": "idle", - "type": "stateMachine", - "data": { - "currentState": "idleStand", - "states": [ + "solutionSource": "relaxToUnderPoses", + "solutionSourceVar": "solutionSource", + "targets": [ { - "id": "idleStand", - "interpTarget": 6, - "interpDuration": 6, - "transitions": [ - { "var": "isTalking", "state": "idleTalk" } - ] + "jointName": "Hips", + "positionVar": "hipsPosition", + "rotationVar": "hipsRotation", + "typeVar": "hipsType", + "weightVar": "hipsWeight", + "weight": 1.0, + "flexCoefficients": [1] }, { - "id": "idleTalk", - "interpTarget": 6, - "interpDuration": 6, - "transitions": [ - { "var": "notIsTalking", "state": "idleStand" } - ] + "jointName": "RightHand", + "positionVar": "rightHandPosition", + "rotationVar": "rightHandRotation", + "typeVar": "rightHandType", + "weightVar": "rightHandWeight", + "weight": 1.0, + "flexCoefficients": [1, 0.5, 0.5, 0.2, 0.01, 0.005, 0.001, 0.0, 0.0], + "poleVectorEnabledVar": "rightHandPoleVectorEnabled", + "poleReferenceVectorVar": "rightHandPoleReferenceVector", + "poleVectorVar": "rightHandPoleVector" + }, + { + "jointName": "LeftHand", + "positionVar": "leftHandPosition", + "rotationVar": "leftHandRotation", + "typeVar": "leftHandType", + "weightVar": "leftHandWeight", + "weight": 1.0, + "flexCoefficients": [1, 0.5, 0.5, 0.2, 0.01, 0.005, 0.001, 0.0, 0.0], + "poleVectorEnabledVar": "leftHandPoleVectorEnabled", + "poleReferenceVectorVar": "leftHandPoleReferenceVector", + "poleVectorVar": "leftHandPoleVector" + }, + { + "jointName": "Spine2", + "positionVar": "spine2Position", + "rotationVar": "spine2Rotation", + "typeVar": "spine2Type", + "weightVar": "spine2Weight", + "weight": 2.0, + "flexCoefficients": [1.0, 0.5, 0.25] + }, + { + "jointName": "Head", + "positionVar": "headPosition", + "rotationVar": "headRotation", + "typeVar": "headType", + "weightVar": "headWeight", + "weight": 4.0, + "flexCoefficients": [1, 0.5, 0.25, 0.2, 0.1] } ] }, - "children": [ - { - "id": "idleStand", - "type": "clip", - "data": { - "url": "animations/idle.fbx", - "startFrame": 0.0, - "endFrame": 300.0, - "timeScale": 1.0, - "loopFlag": true - }, - "children": [] - }, - { - "id": "idleTalk", - "type": "clip", - "data": { - "url": "animations/talk.fbx", - "startFrame": 0.0, - "endFrame": 800.0, - "timeScale": 1.0, - "loopFlag": true - }, - "children": [] - } - ] + "children": [] }, { - "id": "walkFwd", - "type": "blendLinearMove", + "id": "defaultPoseOverlay", + "type": "overlay", "data": { "alpha": 0.0, - "desiredSpeed": 1.4, - "characteristicSpeeds": [0.5, 1.4, 4.5], - "alphaVar": "moveForwardAlpha", - "desiredSpeedVar": "moveForwardSpeed" + "alphaVar": "defaultPoseOverlayAlpha", + "boneSet": "fullBody", + "boneSetVar": "defaultPoseOverlayBoneSet" }, "children": [ { - "id": "walkFwdShort", - "type": "clip", + "id": "defaultPose", + "type": "defaultPose", "data": { - "url": "animations/walk_short_fwd.fbx", - "startFrame": 0.0, - "endFrame": 39.0, - "timeScale": 1.0, - "loopFlag": true }, "children": [] }, { - "id": "walkFwdNormal", - "type": "clip", + "id": "rightHandOverlay", + "type": "overlay", "data": { - "url": "animations/walk_fwd.fbx", - "startFrame": 0.0, - "endFrame": 35.0, - "timeScale": 1.0, - "loopFlag": true + "alpha": 0.0, + "boneSet": "rightHand", + "alphaVar": "rightHandOverlayAlpha" }, - "children": [] - }, - { - "id": "walkFwdRun", - "type": "clip", - "data": { - "url": "animations/run_fwd.fbx", - "startFrame": 0.0, - "endFrame": 21.0, - "timeScale": 1.0, - "loopFlag": true - }, - "children": [] + "children": [ + { + "id": "rightHandStateMachine", + "type": "stateMachine", + "data": { + "currentState": "rightHandGrasp", + "states": [ + { + "id": "rightHandGrasp", + "interpTarget": 3, + "interpDuration": 3, + "transitions": [ + { "var": "isRightIndexPoint", "state": "rightIndexPoint" }, + { "var": "isRightThumbRaise", "state": "rightThumbRaise" }, + { "var": "isRightIndexPointAndThumbRaise", "state": "rightIndexPointAndThumbRaise" } + ] + }, + { + "id": "rightIndexPoint", + "interpTarget": 15, + "interpDuration": 3, + "transitions": [ + { "var": "isRightHandGrasp", "state": "rightHandGrasp" }, + { "var": "isRightThumbRaise", "state": "rightThumbRaise" }, + { "var": "isRightIndexPointAndThumbRaise", "state": "rightIndexPointAndThumbRaise" } + ] + }, + { + "id": "rightThumbRaise", + "interpTarget": 15, + "interpDuration": 3, + "transitions": [ + { "var": "isRightHandGrasp", "state": "rightHandGrasp" }, + { "var": "isRightIndexPoint", "state": "rightIndexPoint" }, + { "var": "isRightIndexPointAndThumbRaise", "state": "rightIndexPointAndThumbRaise" } + ] + }, + { + "id": "rightIndexPointAndThumbRaise", + "interpTarget": 15, + "interpDuration": 3, + "transitions": [ + { "var": "isRightHandGrasp", "state": "rightHandGrasp" }, + { "var": "isRightIndexPoint", "state": "rightIndexPoint" }, + { "var": "isRightThumbRaise", "state": "rightThumbRaise" } + ] + } + ] + }, + "children": [ + { + "id": "rightHandGrasp", + "type": "blendLinear", + "data": { + "alpha": 0.0, + "alphaVar": "rightHandGraspAlpha" + }, + "children": [ + { + "id": "rightHandGraspOpen", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/hydra_pose_open_right.fbx", + "startFrame": 0.0, + "endFrame": 0.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "rightHandGraspClosed", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/hydra_pose_closed_right.fbx", + "startFrame": 0.0, + "endFrame": 0.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + } + ] + }, + { + "id": "rightIndexPoint", + "type": "blendLinear", + "data": { + "alpha": 0.0, + "alphaVar": "rightHandGraspAlpha" + }, + "children": [ + { + "id": "rightIndexPointOpen", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/touch_point_open_right.fbx", + "startFrame": 15.0, + "endFrame": 15.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "rightIndexPointClosed", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/touch_point_closed_right.fbx", + "startFrame": 15.0, + "endFrame": 15.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + } + ] + }, + { + "id": "rightThumbRaise", + "type": "blendLinear", + "data": { + "alpha": 0.0, + "alphaVar": "rightHandGraspAlpha" + }, + "children": [ + { + "id": "rightThumbRaiseOpen", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/touch_thumb_open_right.fbx", + "startFrame": 15.0, + "endFrame": 15.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "rightThumbRaiseClosed", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/touch_thumb_closed_right.fbx", + "startFrame": 15.0, + "endFrame": 15.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + } + ] + }, + { + "id": "rightIndexPointAndThumbRaise", + "type": "blendLinear", + "data": { + "alpha": 0.0, + "alphaVar": "rightHandGraspAlpha" + }, + "children": [ + { + "id": "rightIndexPointAndThumbRaiseOpen", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/touch_thumb_point_open_right.fbx", + "startFrame": 15.0, + "endFrame": 15.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "rightIndexPointAndThumbRaiseClosed", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/touch_thumb_point_closed_right.fbx", + "startFrame": 15.0, + "endFrame": 15.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + } + ] + } + ] + }, + { + "id": "leftHandOverlay", + "type": "overlay", + "data": { + "alpha": 0.0, + "boneSet": "leftHand", + "alphaVar": "leftHandOverlayAlpha" + }, + "children": [ + { + "id": "leftHandStateMachine", + "type": "stateMachine", + "data": { + "currentState": "leftHandGrasp", + "states": [ + { + "id": "leftHandGrasp", + "interpTarget": 3, + "interpDuration": 3, + "transitions": [ + { "var": "isLeftIndexPoint", "state": "leftIndexPoint" }, + { "var": "isLeftThumbRaise", "state": "leftThumbRaise" }, + { "var": "isLeftIndexPointAndThumbRaise", "state": "leftIndexPointAndThumbRaise" } + ] + }, + { + "id": "leftIndexPoint", + "interpTarget": 15, + "interpDuration": 3, + "transitions": [ + { "var": "isLeftHandGrasp", "state": "leftHandGrasp" }, + { "var": "isLeftThumbRaise", "state": "leftThumbRaise" }, + { "var": "isLeftIndexPointAndThumbRaise", "state": "leftIndexPointAndThumbRaise" } + ] + }, + { + "id": "leftThumbRaise", + "interpTarget": 15, + "interpDuration": 3, + "transitions": [ + { "var": "isLeftHandGrasp", "state": "leftHandGrasp" }, + { "var": "isLeftIndexPoint", "state": "leftIndexPoint" }, + { "var": "isLeftIndexPointAndThumbRaise", "state": "leftIndexPointAndThumbRaise" } + ] + }, + { + "id": "leftIndexPointAndThumbRaise", + "interpTarget": 15, + "interpDuration": 3, + "transitions": [ + { "var": "isLeftHandGrasp", "state": "leftHandGrasp" }, + { "var": "isLeftIndexPoint", "state": "leftIndexPoint" }, + { "var": "isLeftThumbRaise", "state": "leftThumbRaise" } + ] + } + ] + }, + "children": [ + { + "id": "leftHandGrasp", + "type": "blendLinear", + "data": { + "alpha": 0.0, + "alphaVar": "leftHandGraspAlpha" + }, + "children": [ + { + "id": "leftHandGraspOpen", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/hydra_pose_open_left.fbx", + "startFrame": 0.0, + "endFrame": 0.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "leftHandGraspClosed", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/hydra_pose_closed_left.fbx", + "startFrame": 10.0, + "endFrame": 10.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + } + ] + }, + { + "id": "leftIndexPoint", + "type": "blendLinear", + "data": { + "alpha": 0.0, + "alphaVar": "leftHandGraspAlpha" + }, + "children": [ + { + "id": "leftIndexPointOpen", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/touch_point_open_left.fbx", + "startFrame": 15.0, + "endFrame": 15.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "leftIndexPointClosed", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/touch_point_closed_left.fbx", + "startFrame": 15.0, + "endFrame": 15.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + } + ] + }, + { + "id": "leftThumbRaise", + "type": "blendLinear", + "data": { + "alpha": 0.0, + "alphaVar": "leftHandGraspAlpha" + }, + "children": [ + { + "id": "leftThumbRaiseOpen", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/touch_thumb_open_left.fbx", + "startFrame": 15.0, + "endFrame": 15.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "leftThumbRaiseClosed", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/touch_thumb_closed_left.fbx", + "startFrame": 15.0, + "endFrame": 15.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + } + ] + }, + { + "id": "leftIndexPointAndThumbRaise", + "type": "blendLinear", + "data": { + "alpha": 0.0, + "alphaVar": "leftHandGraspAlpha" + }, + "children": [ + { + "id": "leftIndexPointAndThumbRaiseOpen", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/touch_thumb_point_open_left.fbx", + "startFrame": 15.0, + "endFrame": 15.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "leftIndexPointAndThumbRaiseClosed", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/touch_thumb_point_closed_left.fbx", + "startFrame": 15.0, + "endFrame": 15.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + } + ] + } + ] + }, + { + "id": "mainStateMachine", + "type": "stateMachine", + "data": { + "outputJoints": ["LeftFoot", "RightFoot"], + "currentState": "idle", + "states": [ + { + "id": "idle", + "interpTarget": 10, + "interpDuration": 10, + "transitions": [ + { "var": "isMovingForward", "state": "idleToWalkFwd" }, + { "var": "isMovingBackward", "state": "walkBwd" }, + { "var": "isMovingRight", "state": "strafeRight" }, + { "var": "isMovingLeft", "state": "strafeLeft" }, + { "var": "isTurningRight", "state": "turnRight" }, + { "var": "isTurningLeft", "state": "turnLeft" }, + { "var": "isFlying", "state": "fly" }, + { "var": "isTakeoffStand", "state": "takeoffStand" }, + { "var": "isTakeoffRun", "state": "takeoffRun" }, + { "var": "isInAirStand", "state": "inAirStand" }, + { "var": "isInAirRun", "state": "inAirRun" } + ] + }, + { + "id": "idleToWalkFwd", + "interpTarget": 3, + "interpDuration": 3, + "transitions": [ + { "var": "idleToWalkFwdOnDone", "state": "walkFwd" }, + { "var": "isNotMoving", "state": "idle" }, + { "var": "isMovingBackward", "state": "walkBwd" }, + { "var": "isMovingRight", "state": "strafeRight" }, + { "var": "isMovingLeft", "state": "strafeLeft" }, + { "var": "isTurningRight", "state": "turnRight" }, + { "var": "isTurningLeft", "state": "turnLeft" }, + { "var": "isFlying", "state": "fly" }, + { "var": "isTakeoffStand", "state": "takeoffStand" }, + { "var": "isTakeoffRun", "state": "takeoffRun" }, + { "var": "isInAirStand", "state": "inAirStand" }, + { "var": "isInAirRun", "state": "inAirRun" } + ] + }, + { + "id": "walkFwd", + "interpTarget": 16, + "interpDuration": 6, + "transitions": [ + { "var": "isNotMoving", "state": "idle" }, + { "var": "isMovingBackward", "state": "walkBwd" }, + { "var": "isMovingRight", "state": "strafeRight" }, + { "var": "isMovingLeft", "state": "strafeLeft" }, + { "var": "isTurningRight", "state": "turnRight" }, + { "var": "isTurningLeft", "state": "turnLeft" }, + { "var": "isFlying", "state": "fly" }, + { "var": "isTakeoffStand", "state": "takeoffStand" }, + { "var": "isTakeoffRun", "state": "takeoffRun" }, + { "var": "isInAirStand", "state": "inAirStand" }, + { "var": "isInAirRun", "state": "inAirRun" } + ] + }, + { + "id": "walkBwd", + "interpTarget": 6, + "interpDuration": 6, + "transitions": [ + { "var": "isNotMoving", "state": "idle" }, + { "var": "isMovingForward", "state": "walkFwd" }, + { "var": "isMovingRight", "state": "strafeRight" }, + { "var": "isMovingLeft", "state": "strafeLeft" }, + { "var": "isTurningRight", "state": "turnRight" }, + { "var": "isTurningLeft", "state": "turnLeft" }, + { "var": "isFlying", "state": "fly" }, + { "var": "isTakeoffStand", "state": "takeoffStand" }, + { "var": "isTakeoffRun", "state": "takeoffRun" }, + { "var": "isInAirStand", "state": "inAirStand" }, + { "var": "isInAirRun", "state": "inAirRun" } + ] + }, + { + "id": "strafeRight", + "interpTarget": 6, + "interpDuration": 6, + "transitions": [ + { "var": "isNotMoving", "state": "idle" }, + { "var": "isMovingForward", "state": "walkFwd" }, + { "var": "isMovingBackward", "state": "walkBwd" }, + { "var": "isMovingLeft", "state": "strafeLeft" }, + { "var": "isTurningRight", "state": "turnRight" }, + { "var": "isTurningLeft", "state": "turnLeft" }, + { "var": "isFlying", "state": "fly" }, + { "var": "isTakeoffStand", "state": "takeoffStand" }, + { "var": "isTakeoffRun", "state": "takeoffRun" }, + { "var": "isInAirStand", "state": "inAirStand" }, + { "var": "isInAirRun", "state": "inAirRun" } + ] + }, + { + "id": "strafeLeft", + "interpTarget": 6, + "interpDuration": 6, + "transitions": [ + { "var": "isNotMoving", "state": "idle" }, + { "var": "isMovingForward", "state": "walkFwd" }, + { "var": "isMovingBackward", "state": "walkBwd" }, + { "var": "isMovingRight", "state": "strafeRight" }, + { "var": "isTurningRight", "state": "turnRight" }, + { "var": "isTurningLeft", "state": "turnLeft" }, + { "var": "isFlying", "state": "fly" }, + { "var": "isTakeoffStand", "state": "takeoffStand" }, + { "var": "isTakeoffRun", "state": "takeoffRun" }, + { "var": "isInAirStand", "state": "inAirStand" }, + { "var": "isInAirRun", "state": "inAirRun" } + ] + }, + { + "id": "turnRight", + "interpTarget": 6, + "interpDuration": 6, + "transitions": [ + { "var": "isNotTurning", "state": "idle" }, + { "var": "isMovingForward", "state": "walkFwd" }, + { "var": "isMovingBackward", "state": "walkBwd" }, + { "var": "isMovingRight", "state": "strafeRight" }, + { "var": "isMovingLeft", "state": "strafeLeft" }, + { "var": "isTurningLeft", "state": "turnLeft" }, + { "var": "isFlying", "state": "fly" }, + { "var": "isTakeoffStand", "state": "takeoffStand" }, + { "var": "isTakeoffRun", "state": "takeoffRun" }, + { "var": "isInAirStand", "state": "inAirStand" }, + { "var": "isInAirRun", "state": "inAirRun" } + ] + }, + { + "id": "turnLeft", + "interpTarget": 6, + "interpDuration": 6, + "transitions": [ + { "var": "isNotTurning", "state": "idle" }, + { "var": "isMovingForward", "state": "walkFwd" }, + { "var": "isMovingBackward", "state": "walkBwd" }, + { "var": "isMovingRight", "state": "strafeRight" }, + { "var": "isMovingLeft", "state": "strafeLeft" }, + { "var": "isTurningRight", "state": "turnRight" }, + { "var": "isFlying", "state": "fly" }, + { "var": "isTakeoffStand", "state": "takeoffStand" }, + { "var": "isTakeoffRun", "state": "takeoffRun" }, + { "var": "isInAirStand", "state": "inAirStand" }, + { "var": "isInAirRun", "state": "inAirRun" } + ] + }, + { + "id": "fly", + "interpTarget": 6, + "interpDuration": 6, + "transitions": [ + { "var": "isNotFlying", "state": "idle" } + ] + }, + { + "id": "takeoffStand", + "interpTarget": 0, + "interpDuration": 6, + "transitions": [ + { "var": "isNotTakeoff", "state": "inAirStand" } + ] + }, + { + "id": "takeoffRun", + "interpTarget": 0, + "interpDuration": 6, + "transitions": [ + { "var": "isNotTakeoff", "state": "inAirRun" } + ] + }, + { + "id": "inAirStand", + "interpTarget": 0, + "interpDuration": 6, + "interpType": "snapshotPrev", + "transitions": [ + { "var": "isNotInAir", "state": "landStandImpact" } + ] + }, + { + "id": "inAirRun", + "interpTarget": 0, + "interpDuration": 6, + "interpType": "snapshotPrev", + "transitions": [ + { "var": "isNotInAir", "state": "landRun" } + ] + }, + { + "id": "landStandImpact", + "interpTarget": 6, + "interpDuration": 4, + "transitions": [ + { "var": "isFlying", "state": "fly" }, + { "var": "isTakeoffStand", "state": "takeoffStand" }, + { "var": "isTakeoffRun", "state": "takeoffRun" }, + { "var": "landStandImpactOnDone", "state": "landStand" } + ] + }, + { + "id": "landStand", + "interpTarget": 0, + "interpDuration": 1, + "transitions": [ + { "var": "isMovingForward", "state": "idleToWalkFwd" }, + { "var": "isMovingBackward", "state": "walkBwd" }, + { "var": "isMovingRight", "state": "strafeRight" }, + { "var": "isMovingLeft", "state": "strafeLeft" }, + { "var": "isTurningRight", "state": "turnRight" }, + { "var": "isTurningLeft", "state": "turnLeft" }, + { "var": "isFlying", "state": "fly" }, + { "var": "isTakeoffStand", "state": "takeoffStand" }, + { "var": "isTakeoffRun", "state": "takeoffRun" }, + { "var": "isInAirStand", "state": "inAirStand" }, + { "var": "isInAirRun", "state": "inAirRun" }, + { "var": "landStandOnDone", "state": "idle" } + ] + }, + { + "id": "landRun", + "interpTarget": 1, + "interpDuration": 7, + "transitions": [ + { "var": "isFlying", "state": "fly" }, + { "var": "isTakeoffStand", "state": "takeoffStand" }, + { "var": "isTakeoffRun", "state": "takeoffRun" }, + { "var": "landRunOnDone", "state": "walkFwd" } + ] + } + ] + }, + "children": [ + { + "id": "idle", + "type": "stateMachine", + "data": { + "currentState": "idleStand", + "states": [ + { + "id": "idleStand", + "interpTarget": 6, + "interpDuration": 6, + "transitions": [ + { "var": "isTalking", "state": "idleTalk" } + ] + }, + { + "id": "idleTalk", + "interpTarget": 6, + "interpDuration": 6, + "transitions": [ + { "var": "notIsTalking", "state": "idleStand" } + ] + } + ] + }, + "children": [ + { + "id": "idleStand", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/idle.fbx", + "startFrame": 0.0, + "endFrame": 300.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "idleTalk", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/talk.fbx", + "startFrame": 0.0, + "endFrame": 800.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + } + ] + }, + { + "id": "walkFwd", + "type": "blendLinearMove", + "data": { + "alpha": 0.0, + "desiredSpeed": 1.4, + "characteristicSpeeds": [0.5, 1.4, 4.5], + "alphaVar": "moveForwardAlpha", + "desiredSpeedVar": "moveForwardSpeed" + }, + "children": [ + { + "id": "walkFwdShort", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/walk_short_fwd.fbx", + "startFrame": 0.0, + "endFrame": 39.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "walkFwdNormal", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/walk_fwd.fbx", + "startFrame": 0.0, + "endFrame": 35.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "walkFwdRun", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/run_fwd.fbx", + "startFrame": 0.0, + "endFrame": 21.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + } + ] + }, + { + "id": "idleToWalkFwd", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/idle_to_walk.fbx", + "startFrame": 1.0, + "endFrame": 13.0, + "timeScale": 1.0, + "loopFlag": false + }, + "children": [] + }, + { + "id": "walkBwd", + "type": "blendLinearMove", + "data": { + "alpha": 0.0, + "desiredSpeed": 1.4, + "characteristicSpeeds": [0.6, 1.45], + "alphaVar": "moveBackwardAlpha", + "desiredSpeedVar": "moveBackwardSpeed" + }, + "children": [ + { + "id": "walkBwdShort", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/walk_short_bwd.fbx", + "startFrame": 0.0, + "endFrame": 38.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "walkBwdNormal", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/walk_bwd.fbx", + "startFrame": 0.0, + "endFrame": 36.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + } + ] + }, + { + "id": "turnLeft", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/turn_left.fbx", + "startFrame": 0.0, + "endFrame": 28.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "turnRight", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/turn_left.fbx", + "startFrame": 0.0, + "endFrame": 30.0, + "timeScale": 1.0, + "loopFlag": true, + "mirrorFlag": true + }, + "children": [] + }, + { + "id": "strafeLeft", + "type": "blendLinearMove", + "data": { + "alpha": 0.0, + "desiredSpeed": 1.4, + "characteristicSpeeds": [0.2, 0.65], + "alphaVar": "moveLateralAlpha", + "desiredSpeedVar": "moveLateralSpeed" + }, + "children": [ + { + "id": "strafeLeftShort", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/side_step_short_left.fbx", + "startFrame": 0.0, + "endFrame": 28.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "strafeLeftNormal", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/side_step_left.fbx", + "startFrame": 0.0, + "endFrame": 30.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + } + ] + }, + { + "id": "strafeRight", + "type": "blendLinearMove", + "data": { + "alpha": 0.0, + "desiredSpeed": 1.4, + "characteristicSpeeds": [0.2, 0.65], + "alphaVar": "moveLateralAlpha", + "desiredSpeedVar": "moveLateralSpeed" + }, + "children": [ + { + "id": "strafeRightShort", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/side_step_short_right.fbx", + "startFrame": 0.0, + "endFrame": 28.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "strafeRightNormal", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/side_step_right.fbx", + "startFrame": 0.0, + "endFrame": 30.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + } + ] + }, + { + "id": "fly", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/fly.fbx", + "startFrame": 1.0, + "endFrame": 80.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "takeoffStand", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/jump_standing_takeoff.fbx", + "startFrame": 17.0, + "endFrame": 25.0, + "timeScale": 1.0, + "loopFlag": false + }, + "children": [] + }, + { + "id": "takeoffRun", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/jump_takeoff.fbx", + "startFrame": 1.0, + "endFrame": 2.5, + "timeScale": 0.01, + "loopFlag": false + }, + "children": [] + }, + { + "id": "inAirStand", + "type": "blendLinear", + "data": { + "alpha": 0.0, + "alphaVar": "inAirAlpha" + }, + "children": [ + { + "id": "inAirStandPreApex", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/jump_standing_apex.fbx", + "startFrame": 0.0, + "endFrame": 0.0, + "timeScale": 0.0, + "loopFlag": false + }, + "children": [] + }, + { + "id": "inAirStandApex", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/jump_standing_apex.fbx", + "startFrame": 1.0, + "endFrame": 1.0, + "timeScale": 1.0, + "loopFlag": false + }, + "children": [] + }, + { + "id": "inAirStandPostApex", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/jump_standing_apex.fbx", + "startFrame": 2.0, + "endFrame": 2.0, + "timeScale": 1.0, + "loopFlag": false + }, + "children": [] + } + ] + }, + { + "id": "inAirRun", + "type": "blendLinear", + "data": { + "alpha": 0.0, + "alphaVar": "inAirAlpha" + }, + "children": [ + { + "id": "inAirRunPreApex", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/jump_in_air.fbx", + "startFrame": 0.0, + "endFrame": 0.0, + "timeScale": 0.0, + "loopFlag": false + }, + "children": [] + }, + { + "id": "inAirRunApex", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/jump_in_air.fbx", + "startFrame": 6.0, + "endFrame": 6.0, + "timeScale": 1.0, + "loopFlag": false + }, + "children": [] + }, + { + "id": "inAirRunPostApex", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/jump_in_air.fbx", + "startFrame": 11.0, + "endFrame": 11.0, + "timeScale": 1.0, + "loopFlag": false + }, + "children": [] + } + ] + }, + { + "id": "landStandImpact", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/jump_standing_land.fbx", + "startFrame": 1.0, + "endFrame": 6.0, + "timeScale": 1.0, + "loopFlag": false + }, + "children": [] + }, + { + "id": "landStand", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/jump_standing_land.fbx", + "startFrame": 6.0, + "endFrame": 28.0, + "timeScale": 1.0, + "loopFlag": false + }, + "children": [] + }, + { + "id": "landRun", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/jump_land.fbx", + "startFrame": 1.0, + "endFrame": 6.0, + "timeScale": 0.65, + "loopFlag": false + }, + "children": [] + } + ] + } + ] + } + ] } ] - }, - { - "id": "idleToWalkFwd", - "type": "clip", - "data": { - "url": "animations/idle_to_walk.fbx", - "startFrame": 1.0, - "endFrame": 13.0, - "timeScale": 1.0, - "loopFlag": false - }, - "children": [] - }, - { - "id": "walkBwd", - "type": "blendLinearMove", - "data": { - "alpha": 0.0, - "desiredSpeed": 1.4, - "characteristicSpeeds": [0.6, 1.45], - "alphaVar": "moveBackwardAlpha", - "desiredSpeedVar": "moveBackwardSpeed" - }, - "children": [ - { - "id": "walkBwdShort", - "type": "clip", - "data": { - "url": "animations/walk_short_bwd.fbx", - "startFrame": 0.0, - "endFrame": 38.0, - "timeScale": 1.0, - "loopFlag": true - }, - "children": [] - }, - { - "id": "walkBwdNormal", - "type": "clip", - "data": { - "url": "animations/walk_bwd.fbx", - "startFrame": 0.0, - "endFrame": 36.0, - "timeScale": 1.0, - "loopFlag": true - }, - "children": [] - } - ] - }, - { - "id": "turnLeft", - "type": "clip", - "data": { - "url": "animations/turn_left.fbx", - "startFrame": 0.0, - "endFrame": 28.0, - "timeScale": 1.0, - "loopFlag": true - }, - "children": [] - }, - { - "id": "turnRight", - "type": "clip", - "data": { - "url": "animations/turn_left.fbx", - "startFrame": 0.0, - "endFrame": 30.0, - "timeScale": 1.0, - "loopFlag": true, - "mirrorFlag": true - }, - "children": [] - }, - { - "id": "strafeLeft", - "type": "blendLinearMove", - "data": { - "alpha": 0.0, - "desiredSpeed": 1.4, - "characteristicSpeeds": [0.2, 0.65], - "alphaVar": "moveLateralAlpha", - "desiredSpeedVar": "moveLateralSpeed" - }, - "children": [ - { - "id": "strafeLeftShort", - "type": "clip", - "data": { - "url": "animations/side_step_short_left.fbx", - "startFrame": 0.0, - "endFrame": 28.0, - "timeScale": 1.0, - "loopFlag": true - }, - "children": [] - }, - { - "id": "strafeLeftNormal", - "type": "clip", - "data": { - "url": "animations/side_step_left.fbx", - "startFrame": 0.0, - "endFrame": 30.0, - "timeScale": 1.0, - "loopFlag": true - }, - "children": [] - } - ] - }, - { - "id": "strafeRight", - "type": "blendLinearMove", - "data": { - "alpha": 0.0, - "desiredSpeed": 1.4, - "characteristicSpeeds": [0.2, 0.65], - "alphaVar": "moveLateralAlpha", - "desiredSpeedVar": "moveLateralSpeed" - }, - "children": [ - { - "id": "strafeRightShort", - "type": "clip", - "data": { - "url": "animations/side_step_short_right.fbx", - "startFrame": 0.0, - "endFrame": 28.0, - "timeScale": 1.0, - "loopFlag": true - }, - "children": [] - }, - { - "id": "strafeRightNormal", - "type": "clip", - "data": { - "url": "animations/side_step_right.fbx", - "startFrame": 0.0, - "endFrame": 30.0, - "timeScale": 1.0, - "loopFlag": true - }, - "children": [] - } - ] - }, - { - "id": "fly", - "type": "clip", - "data": { - "url": "animations/fly.fbx", - "startFrame": 1.0, - "endFrame": 80.0, - "timeScale": 1.0, - "loopFlag": true - }, - "children": [] - }, - { - "id": "takeoffStand", - "type": "clip", - "data": { - "url": "animations/jump_standing_takeoff.fbx", - "startFrame": 17.0, - "endFrame": 25.0, - "timeScale": 1.0, - "loopFlag": false - }, - "children": [] - }, - { - "id": "takeoffRun", - "type": "clip", - "data": { - "url": "animations/jump_takeoff.fbx", - "startFrame": 1.0, - "endFrame": 2.5, - "timeScale": 0.01, - "loopFlag": false - }, - "children": [] - }, - { - "id": "inAirStand", - "type": "blendLinear", - "data": { - "alpha": 0.0, - "alphaVar": "inAirAlpha" - }, - "children": [ - { - "id": "inAirStandPreApex", - "type": "clip", - "data": { - "url": "animations/jump_standing_apex.fbx", - "startFrame": 0.0, - "endFrame": 0.0, - "timeScale": 0.0, - "loopFlag": false - }, - "children": [] - }, - { - "id": "inAirStandApex", - "type": "clip", - "data": { - "url": "animations/jump_standing_apex.fbx", - "startFrame": 1.0, - "endFrame": 1.0, - "timeScale": 1.0, - "loopFlag": false - }, - "children": [] - }, - { - "id": "inAirStandPostApex", - "type": "clip", - "data": { - "url": "animations/jump_standing_apex.fbx", - "startFrame": 2.0, - "endFrame": 2.0, - "timeScale": 1.0, - "loopFlag": false - }, - "children": [] - } - ] - }, - { - "id": "inAirRun", - "type": "blendLinear", - "data": { - "alpha": 0.0, - "alphaVar": "inAirAlpha" - }, - "children": [ - { - "id": "inAirRunPreApex", - "type": "clip", - "data": { - "url": "animations/jump_in_air.fbx", - "startFrame": 0.0, - "endFrame": 0.0, - "timeScale": 0.0, - "loopFlag": false - }, - "children": [] - }, - { - "id": "inAirRunApex", - "type": "clip", - "data": { - "url": "animations/jump_in_air.fbx", - "startFrame": 6.0, - "endFrame": 6.0, - "timeScale": 1.0, - "loopFlag": false - }, - "children": [] - }, - { - "id": "inAirRunPostApex", - "type": "clip", - "data": { - "url": "animations/jump_in_air.fbx", - "startFrame": 11.0, - "endFrame": 11.0, - "timeScale": 1.0, - "loopFlag": false - }, - "children": [] - } - ] - }, - { - "id": "landStandImpact", - "type": "clip", - "data": { - "url": "animations/jump_standing_land.fbx", - "startFrame": 1.0, - "endFrame": 6.0, - "timeScale": 1.0, - "loopFlag": false - }, - "children": [] - }, - { - "id": "landStand", - "type": "clip", - "data": { - "url": "animations/jump_standing_land.fbx", - "startFrame": 6.0, - "endFrame": 28.0, - "timeScale": 1.0, - "loopFlag": false - }, - "children": [] - }, - { - "id": "landRun", - "type": "clip", - "data": { - "url": "animations/jump_land.fbx", - "startFrame": 1.0, - "endFrame": 6.0, - "timeScale": 0.65, - "loopFlag": false - }, - "children": [] } ] } @@ -1203,7 +1248,7 @@ "id": "userAnimA", "type": "clip", "data": { - "url": "animations/idle.fbx", + "url": "qrc:///avatar/animations/idle.fbx", "startFrame": 0.0, "endFrame": 90.0, "timeScale": 1.0, @@ -1215,7 +1260,7 @@ "id": "userAnimB", "type": "clip", "data": { - "url": "animations/idle.fbx", + "url": "qrc:///avatar/animations/idle.fbx", "startFrame": 0.0, "endFrame": 90.0, "timeScale": 1.0, diff --git a/interface/resources/avatar/old-avatar-animation.json b/interface/resources/avatar/old-avatar-animation.json new file mode 100644 index 0000000000..44d294f767 --- /dev/null +++ b/interface/resources/avatar/old-avatar-animation.json @@ -0,0 +1,1228 @@ +{ + "version": "1.0", + "root": { + "id": "userAnimStateMachine", + "type": "stateMachine", + "data": { + "currentState": "userAnimNone", + "states": [ + { + "id": "userAnimNone", + "interpTarget": 6, + "interpDuration": 6, + "transitions": [ + { "var": "userAnimA", "state": "userAnimA" }, + { "var": "userAnimB", "state": "userAnimB" } + ] + }, + { + "id": "userAnimA", + "interpTarget": 6, + "interpDuration": 6, + "transitions": [ + { "var": "userAnimNone", "state": "userAnimNone" }, + { "var": "userAnimB", "state": "userAnimB" } + ] + }, + { + "id": "userAnimB", + "interpTarget": 6, + "interpDuration": 6, + "transitions": [ + { "var": "userAnimNone", "state": "userAnimNone" }, + { "var": "userAnimA", "state": "userAnimA" } + ] + } + ] + }, + "children": [ + { + "id": "userAnimNone", + "type": "overlay", + "data": { + "alpha": 1.0, + "alphaVar": "ikOverlayAlpha", + "boneSet": "fullBody" + }, + "children": [ + { + "id": "ik", + "type": "inverseKinematics", + "data": { + "solutionSource": "relaxToUnderPoses", + "solutionSourceVar": "solutionSource", + "targets": [ + { + "jointName": "Hips", + "positionVar": "hipsPosition", + "rotationVar": "hipsRotation", + "typeVar": "hipsType", + "weightVar": "hipsWeight", + "weight": 1.0, + "flexCoefficients": [1] + }, + { + "jointName": "RightHand", + "positionVar": "rightHandPosition", + "rotationVar": "rightHandRotation", + "typeVar": "rightHandType", + "weightVar": "rightHandWeight", + "weight": 1.0, + "flexCoefficients": [1, 0.5, 0.5, 0.2, 0.01, 0.005, 0.001, 0.0, 0.0], + "poleVectorEnabledVar": "rightHandPoleVectorEnabled", + "poleReferenceVectorVar": "rightHandPoleReferenceVector", + "poleVectorVar": "rightHandPoleVector" + }, + { + "jointName": "LeftHand", + "positionVar": "leftHandPosition", + "rotationVar": "leftHandRotation", + "typeVar": "leftHandType", + "weightVar": "leftHandWeight", + "weight": 1.0, + "flexCoefficients": [1, 0.5, 0.5, 0.2, 0.01, 0.005, 0.001, 0.0, 0.0], + "poleVectorEnabledVar": "leftHandPoleVectorEnabled", + "poleReferenceVectorVar": "leftHandPoleReferenceVector", + "poleVectorVar": "leftHandPoleVector" + }, + { + "jointName": "RightFoot", + "positionVar": "rightFootPosition", + "rotationVar": "rightFootRotation", + "typeVar": "rightFootType", + "weightVar": "rightFootWeight", + "weight": 1.0, + "flexCoefficients": [1, 0.45, 0.45], + "poleVectorEnabledVar": "rightFootPoleVectorEnabled", + "poleReferenceVectorVar": "rightFootPoleReferenceVector", + "poleVectorVar": "rightFootPoleVector" + }, + { + "jointName": "LeftFoot", + "positionVar": "leftFootPosition", + "rotationVar": "leftFootRotation", + "typeVar": "leftFootType", + "weightVar": "leftFootWeight", + "weight": 1.0, + "flexCoefficients": [1, 0.45, 0.45], + "poleVectorEnabledVar": "leftFootPoleVectorEnabled", + "poleReferenceVectorVar": "leftFootPoleReferenceVector", + "poleVectorVar": "leftFootPoleVector" + }, + { + "jointName": "Spine2", + "positionVar": "spine2Position", + "rotationVar": "spine2Rotation", + "typeVar": "spine2Type", + "weightVar": "spine2Weight", + "weight": 2.0, + "flexCoefficients": [1.0, 0.5, 0.25] + }, + { + "jointName": "Head", + "positionVar": "headPosition", + "rotationVar": "headRotation", + "typeVar": "headType", + "weightVar": "headWeight", + "weight": 4.0, + "flexCoefficients": [1, 0.5, 0.25, 0.2, 0.1] + } + ] + }, + "children": [] + }, + { + "id": "defaultPoseOverlay", + "type": "overlay", + "data": { + "alpha": 0.0, + "alphaVar": "defaultPoseOverlayAlpha", + "boneSet": "fullBody", + "boneSetVar": "defaultPoseOverlayBoneSet" + }, + "children": [ + { + "id": "defaultPose", + "type": "defaultPose", + "data": { + }, + "children": [] + }, + { + "id": "rightHandOverlay", + "type": "overlay", + "data": { + "alpha": 0.0, + "boneSet": "rightHand", + "alphaVar": "rightHandOverlayAlpha" + }, + "children": [ + { + "id": "rightHandStateMachine", + "type": "stateMachine", + "data": { + "currentState": "rightHandGrasp", + "states": [ + { + "id": "rightHandGrasp", + "interpTarget": 3, + "interpDuration": 3, + "transitions": [ + { "var": "isRightIndexPoint", "state": "rightIndexPoint" }, + { "var": "isRightThumbRaise", "state": "rightThumbRaise" }, + { "var": "isRightIndexPointAndThumbRaise", "state": "rightIndexPointAndThumbRaise" } + ] + }, + { + "id": "rightIndexPoint", + "interpTarget": 15, + "interpDuration": 3, + "transitions": [ + { "var": "isRightHandGrasp", "state": "rightHandGrasp" }, + { "var": "isRightThumbRaise", "state": "rightThumbRaise" }, + { "var": "isRightIndexPointAndThumbRaise", "state": "rightIndexPointAndThumbRaise" } + ] + }, + { + "id": "rightThumbRaise", + "interpTarget": 15, + "interpDuration": 3, + "transitions": [ + { "var": "isRightHandGrasp", "state": "rightHandGrasp" }, + { "var": "isRightIndexPoint", "state": "rightIndexPoint" }, + { "var": "isRightIndexPointAndThumbRaise", "state": "rightIndexPointAndThumbRaise" } + ] + }, + { + "id": "rightIndexPointAndThumbRaise", + "interpTarget": 15, + "interpDuration": 3, + "transitions": [ + { "var": "isRightHandGrasp", "state": "rightHandGrasp" }, + { "var": "isRightIndexPoint", "state": "rightIndexPoint" }, + { "var": "isRightThumbRaise", "state": "rightThumbRaise" } + ] + } + ] + }, + "children": [ + { + "id": "rightHandGrasp", + "type": "blendLinear", + "data": { + "alpha": 0.0, + "alphaVar": "rightHandGraspAlpha" + }, + "children": [ + { + "id": "rightHandGraspOpen", + "type": "clip", + "data": { + "url": "animations/hydra_pose_open_right.fbx", + "startFrame": 0.0, + "endFrame": 0.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "rightHandGraspClosed", + "type": "clip", + "data": { + "url": "animations/hydra_pose_closed_right.fbx", + "startFrame": 0.0, + "endFrame": 0.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + } + ] + }, + { + "id": "rightIndexPoint", + "type": "blendLinear", + "data": { + "alpha": 0.0, + "alphaVar": "rightHandGraspAlpha" + }, + "children": [ + { + "id": "rightIndexPointOpen", + "type": "clip", + "data": { + "url": "animations/touch_point_open_right.fbx", + "startFrame": 15.0, + "endFrame": 15.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "rightIndexPointClosed", + "type": "clip", + "data": { + "url": "animations/touch_point_closed_right.fbx", + "startFrame": 15.0, + "endFrame": 15.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + } + ] + }, + { + "id": "rightThumbRaise", + "type": "blendLinear", + "data": { + "alpha": 0.0, + "alphaVar": "rightHandGraspAlpha" + }, + "children": [ + { + "id": "rightThumbRaiseOpen", + "type": "clip", + "data": { + "url": "animations/touch_thumb_open_right.fbx", + "startFrame": 15.0, + "endFrame": 15.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "rightThumbRaiseClosed", + "type": "clip", + "data": { + "url": "animations/touch_thumb_closed_right.fbx", + "startFrame": 15.0, + "endFrame": 15.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + } + ] + }, + { + "id": "rightIndexPointAndThumbRaise", + "type": "blendLinear", + "data": { + "alpha": 0.0, + "alphaVar": "rightHandGraspAlpha" + }, + "children": [ + { + "id": "rightIndexPointAndThumbRaiseOpen", + "type": "clip", + "data": { + "url": "animations/touch_thumb_point_open_right.fbx", + "startFrame": 15.0, + "endFrame": 15.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "rightIndexPointAndThumbRaiseClosed", + "type": "clip", + "data": { + "url": "animations/touch_thumb_point_closed_right.fbx", + "startFrame": 15.0, + "endFrame": 15.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + } + ] + } + ] + }, + { + "id": "leftHandOverlay", + "type": "overlay", + "data": { + "alpha": 0.0, + "boneSet": "leftHand", + "alphaVar": "leftHandOverlayAlpha" + }, + "children": [ + { + "id": "leftHandStateMachine", + "type": "stateMachine", + "data": { + "currentState": "leftHandGrasp", + "states": [ + { + "id": "leftHandGrasp", + "interpTarget": 3, + "interpDuration": 3, + "transitions": [ + { "var": "isLeftIndexPoint", "state": "leftIndexPoint" }, + { "var": "isLeftThumbRaise", "state": "leftThumbRaise" }, + { "var": "isLeftIndexPointAndThumbRaise", "state": "leftIndexPointAndThumbRaise" } + ] + }, + { + "id": "leftIndexPoint", + "interpTarget": 15, + "interpDuration": 3, + "transitions": [ + { "var": "isLeftHandGrasp", "state": "leftHandGrasp" }, + { "var": "isLeftThumbRaise", "state": "leftThumbRaise" }, + { "var": "isLeftIndexPointAndThumbRaise", "state": "leftIndexPointAndThumbRaise" } + ] + }, + { + "id": "leftThumbRaise", + "interpTarget": 15, + "interpDuration": 3, + "transitions": [ + { "var": "isLeftHandGrasp", "state": "leftHandGrasp" }, + { "var": "isLeftIndexPoint", "state": "leftIndexPoint" }, + { "var": "isLeftIndexPointAndThumbRaise", "state": "leftIndexPointAndThumbRaise" } + ] + }, + { + "id": "leftIndexPointAndThumbRaise", + "interpTarget": 15, + "interpDuration": 3, + "transitions": [ + { "var": "isLeftHandGrasp", "state": "leftHandGrasp" }, + { "var": "isLeftIndexPoint", "state": "leftIndexPoint" }, + { "var": "isLeftThumbRaise", "state": "leftThumbRaise" } + ] + } + ] + }, + "children": [ + { + "id": "leftHandGrasp", + "type": "blendLinear", + "data": { + "alpha": 0.0, + "alphaVar": "leftHandGraspAlpha" + }, + "children": [ + { + "id": "leftHandGraspOpen", + "type": "clip", + "data": { + "url": "animations/hydra_pose_open_left.fbx", + "startFrame": 0.0, + "endFrame": 0.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "leftHandGraspClosed", + "type": "clip", + "data": { + "url": "animations/hydra_pose_closed_left.fbx", + "startFrame": 10.0, + "endFrame": 10.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + } + ] + }, + { + "id": "leftIndexPoint", + "type": "blendLinear", + "data": { + "alpha": 0.0, + "alphaVar": "leftHandGraspAlpha" + }, + "children": [ + { + "id": "leftIndexPointOpen", + "type": "clip", + "data": { + "url": "animations/touch_point_open_left.fbx", + "startFrame": 15.0, + "endFrame": 15.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "leftIndexPointClosed", + "type": "clip", + "data": { + "url": "animations/touch_point_closed_left.fbx", + "startFrame": 15.0, + "endFrame": 15.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + } + ] + }, + { + "id": "leftThumbRaise", + "type": "blendLinear", + "data": { + "alpha": 0.0, + "alphaVar": "leftHandGraspAlpha" + }, + "children": [ + { + "id": "leftThumbRaiseOpen", + "type": "clip", + "data": { + "url": "animations/touch_thumb_open_left.fbx", + "startFrame": 15.0, + "endFrame": 15.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "leftThumbRaiseClosed", + "type": "clip", + "data": { + "url": "animations/touch_thumb_closed_left.fbx", + "startFrame": 15.0, + "endFrame": 15.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + } + ] + }, + { + "id": "leftIndexPointAndThumbRaise", + "type": "blendLinear", + "data": { + "alpha": 0.0, + "alphaVar": "leftHandGraspAlpha" + }, + "children": [ + { + "id": "leftIndexPointAndThumbRaiseOpen", + "type": "clip", + "data": { + "url": "animations/touch_thumb_point_open_left.fbx", + "startFrame": 15.0, + "endFrame": 15.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "leftIndexPointAndThumbRaiseClosed", + "type": "clip", + "data": { + "url": "animations/touch_thumb_point_closed_left.fbx", + "startFrame": 15.0, + "endFrame": 15.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + } + ] + } + ] + }, + { + "id": "mainStateMachine", + "type": "stateMachine", + "data": { + "currentState": "idle", + "states": [ + { + "id": "idle", + "interpTarget": 10, + "interpDuration": 10, + "transitions": [ + { "var": "isMovingForward", "state": "idleToWalkFwd" }, + { "var": "isMovingBackward", "state": "walkBwd" }, + { "var": "isMovingRight", "state": "strafeRight" }, + { "var": "isMovingLeft", "state": "strafeLeft" }, + { "var": "isTurningRight", "state": "turnRight" }, + { "var": "isTurningLeft", "state": "turnLeft" }, + { "var": "isFlying", "state": "fly" }, + { "var": "isTakeoffStand", "state": "takeoffStand" }, + { "var": "isTakeoffRun", "state": "takeoffRun" }, + { "var": "isInAirStand", "state": "inAirStand" }, + { "var": "isInAirRun", "state": "inAirRun" } + ] + }, + { + "id": "idleToWalkFwd", + "interpTarget": 10, + "interpDuration": 3, + "transitions": [ + { "var": "idleToWalkFwdOnDone", "state": "walkFwd" }, + { "var": "isNotMoving", "state": "idle" }, + { "var": "isMovingBackward", "state": "walkBwd" }, + { "var": "isMovingRight", "state": "strafeRight" }, + { "var": "isMovingLeft", "state": "strafeLeft" }, + { "var": "isTurningRight", "state": "turnRight" }, + { "var": "isTurningLeft", "state": "turnLeft" }, + { "var": "isFlying", "state": "fly" }, + { "var": "isTakeoffStand", "state": "takeoffStand" }, + { "var": "isTakeoffRun", "state": "takeoffRun" }, + { "var": "isInAirStand", "state": "inAirStand" }, + { "var": "isInAirRun", "state": "inAirRun" } + ] + }, + { + "id": "walkFwd", + "interpTarget": 16, + "interpDuration": 6, + "transitions": [ + { "var": "isNotMoving", "state": "idle" }, + { "var": "isMovingBackward", "state": "walkBwd" }, + { "var": "isMovingRight", "state": "strafeRight" }, + { "var": "isMovingLeft", "state": "strafeLeft" }, + { "var": "isTurningRight", "state": "turnRight" }, + { "var": "isTurningLeft", "state": "turnLeft" }, + { "var": "isFlying", "state": "fly" }, + { "var": "isTakeoffStand", "state": "takeoffStand" }, + { "var": "isTakeoffRun", "state": "takeoffRun" }, + { "var": "isInAirStand", "state": "inAirStand" }, + { "var": "isInAirRun", "state": "inAirRun" } + ] + }, + { + "id": "walkBwd", + "interpTarget": 8, + "interpDuration": 2, + "transitions": [ + { "var": "isNotMoving", "state": "idle" }, + { "var": "isMovingForward", "state": "walkFwd" }, + { "var": "isMovingRight", "state": "strafeRight" }, + { "var": "isMovingLeft", "state": "strafeLeft" }, + { "var": "isTurningRight", "state": "turnRight" }, + { "var": "isTurningLeft", "state": "turnLeft" }, + { "var": "isFlying", "state": "fly" }, + { "var": "isTakeoffStand", "state": "takeoffStand" }, + { "var": "isTakeoffRun", "state": "takeoffRun" }, + { "var": "isInAirStand", "state": "inAirStand" }, + { "var": "isInAirRun", "state": "inAirRun" } + ] + }, + { + "id": "strafeRight", + "interpTarget": 20, + "interpDuration": 1, + "transitions": [ + { "var": "isNotMoving", "state": "idle" }, + { "var": "isMovingForward", "state": "walkFwd" }, + { "var": "isMovingBackward", "state": "walkBwd" }, + { "var": "isMovingLeft", "state": "strafeLeft" }, + { "var": "isTurningRight", "state": "turnRight" }, + { "var": "isTurningLeft", "state": "turnLeft" }, + { "var": "isFlying", "state": "fly" }, + { "var": "isTakeoffStand", "state": "takeoffStand" }, + { "var": "isTakeoffRun", "state": "takeoffRun" }, + { "var": "isInAirStand", "state": "inAirStand" }, + { "var": "isInAirRun", "state": "inAirRun" } + ] + }, + { + "id": "strafeLeft", + "interpTarget": 20, + "interpDuration": 1, + "transitions": [ + { "var": "isNotMoving", "state": "idle" }, + { "var": "isMovingForward", "state": "walkFwd" }, + { "var": "isMovingBackward", "state": "walkBwd" }, + { "var": "isMovingRight", "state": "strafeRight" }, + { "var": "isTurningRight", "state": "turnRight" }, + { "var": "isTurningLeft", "state": "turnLeft" }, + { "var": "isFlying", "state": "fly" }, + { "var": "isTakeoffStand", "state": "takeoffStand" }, + { "var": "isTakeoffRun", "state": "takeoffRun" }, + { "var": "isInAirStand", "state": "inAirStand" }, + { "var": "isInAirRun", "state": "inAirRun" } + ] + }, + { + "id": "turnRight", + "interpTarget": 6, + "interpDuration": 6, + "transitions": [ + { "var": "isNotTurning", "state": "idle" }, + { "var": "isMovingForward", "state": "walkFwd" }, + { "var": "isMovingBackward", "state": "walkBwd" }, + { "var": "isMovingRight", "state": "strafeRight" }, + { "var": "isMovingLeft", "state": "strafeLeft" }, + { "var": "isTurningLeft", "state": "turnLeft" }, + { "var": "isFlying", "state": "fly" }, + { "var": "isTakeoffStand", "state": "takeoffStand" }, + { "var": "isTakeoffRun", "state": "takeoffRun" }, + { "var": "isInAirStand", "state": "inAirStand" }, + { "var": "isInAirRun", "state": "inAirRun" } + ] + }, + { + "id": "turnLeft", + "interpTarget": 6, + "interpDuration": 6, + "transitions": [ + { "var": "isNotTurning", "state": "idle" }, + { "var": "isMovingForward", "state": "walkFwd" }, + { "var": "isMovingBackward", "state": "walkBwd" }, + { "var": "isMovingRight", "state": "strafeRight" }, + { "var": "isMovingLeft", "state": "strafeLeft" }, + { "var": "isTurningRight", "state": "turnRight" }, + { "var": "isFlying", "state": "fly" }, + { "var": "isTakeoffStand", "state": "takeoffStand" }, + { "var": "isTakeoffRun", "state": "takeoffRun" }, + { "var": "isInAirStand", "state": "inAirStand" }, + { "var": "isInAirRun", "state": "inAirRun" } + ] + }, + { + "id": "fly", + "interpTarget": 6, + "interpDuration": 6, + "transitions": [ + { "var": "isNotFlying", "state": "idle" } + ] + }, + { + "id": "takeoffStand", + "interpTarget": 0, + "interpDuration": 6, + "transitions": [ + { "var": "isNotTakeoff", "state": "inAirStand" } + ] + }, + { + "id": "takeoffRun", + "interpTarget": 0, + "interpDuration": 6, + "transitions": [ + { "var": "isNotTakeoff", "state": "inAirRun" } + ] + }, + { + "id": "inAirStand", + "interpTarget": 0, + "interpDuration": 6, + "interpType": "snapshotPrev", + "transitions": [ + { "var": "isNotInAir", "state": "landStandImpact" } + ] + }, + { + "id": "inAirRun", + "interpTarget": 0, + "interpDuration": 6, + "interpType": "snapshotPrev", + "transitions": [ + { "var": "isNotInAir", "state": "landRun" } + ] + }, + { + "id": "landStandImpact", + "interpTarget": 6, + "interpDuration": 4, + "transitions": [ + { "var": "isFlying", "state": "fly" }, + { "var": "isTakeoffStand", "state": "takeoffStand" }, + { "var": "isTakeoffRun", "state": "takeoffRun" }, + { "var": "landStandImpactOnDone", "state": "landStand" } + ] + }, + { + "id": "landStand", + "interpTarget": 0, + "interpDuration": 1, + "transitions": [ + { "var": "isMovingForward", "state": "idleToWalkFwd" }, + { "var": "isMovingBackward", "state": "walkBwd" }, + { "var": "isMovingRight", "state": "strafeRight" }, + { "var": "isMovingLeft", "state": "strafeLeft" }, + { "var": "isTurningRight", "state": "turnRight" }, + { "var": "isTurningLeft", "state": "turnLeft" }, + { "var": "isFlying", "state": "fly" }, + { "var": "isTakeoffStand", "state": "takeoffStand" }, + { "var": "isTakeoffRun", "state": "takeoffRun" }, + { "var": "isInAirStand", "state": "inAirStand" }, + { "var": "isInAirRun", "state": "inAirRun" }, + { "var": "landStandOnDone", "state": "idle" } + ] + }, + { + "id": "landRun", + "interpTarget": 1, + "interpDuration": 7, + "transitions": [ + { "var": "isFlying", "state": "fly" }, + { "var": "isTakeoffStand", "state": "takeoffStand" }, + { "var": "isTakeoffRun", "state": "takeoffRun" }, + { "var": "landRunOnDone", "state": "walkFwd" } + ] + } + ] + }, + "children": [ + { + "id": "idle", + "type": "stateMachine", + "data": { + "currentState": "idleStand", + "states": [ + { + "id": "idleStand", + "interpTarget": 6, + "interpDuration": 6, + "transitions": [ + { "var": "isTalking", "state": "idleTalk" } + ] + }, + { + "id": "idleTalk", + "interpTarget": 6, + "interpDuration": 6, + "transitions": [ + { "var": "notIsTalking", "state": "idleStand" } + ] + } + ] + }, + "children": [ + { + "id": "idleStand", + "type": "clip", + "data": { + "url": "animations/idle.fbx", + "startFrame": 0.0, + "endFrame": 300.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "idleTalk", + "type": "clip", + "data": { + "url": "animations/talk.fbx", + "startFrame": 0.0, + "endFrame": 800.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + } + ] + }, + { + "id": "walkFwd", + "type": "blendLinearMove", + "data": { + "alpha": 0.0, + "desiredSpeed": 1.4, + "characteristicSpeeds": [0.5, 1.4, 4.5], + "alphaVar": "moveForwardAlpha", + "desiredSpeedVar": "moveForwardSpeed" + }, + "children": [ + { + "id": "walkFwdShort", + "type": "clip", + "data": { + "url": "animations/walk_short_fwd.fbx", + "startFrame": 0.0, + "endFrame": 39.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "walkFwdNormal", + "type": "clip", + "data": { + "url": "animations/walk_fwd.fbx", + "startFrame": 0.0, + "endFrame": 35.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "walkFwdRun", + "type": "clip", + "data": { + "url": "animations/run_fwd.fbx", + "startFrame": 0.0, + "endFrame": 21.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + } + ] + }, + { + "id": "idleToWalkFwd", + "type": "clip", + "data": { + "url": "animations/idle_to_walk.fbx", + "startFrame": 1.0, + "endFrame": 13.0, + "timeScale": 1.0, + "loopFlag": false + }, + "children": [] + }, + { + "id": "walkBwd", + "type": "blendLinearMove", + "data": { + "alpha": 0.0, + "desiredSpeed": 1.4, + "characteristicSpeeds": [0.6, 1.45], + "alphaVar": "moveBackwardAlpha", + "desiredSpeedVar": "moveBackwardSpeed" + }, + "children": [ + { + "id": "walkBwdShort", + "type": "clip", + "data": { + "url": "animations/walk_short_bwd.fbx", + "startFrame": 0.0, + "endFrame": 38.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "walkBwdNormal", + "type": "clip", + "data": { + "url": "animations/walk_bwd.fbx", + "startFrame": 0.0, + "endFrame": 36.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + } + ] + }, + { + "id": "turnLeft", + "type": "clip", + "data": { + "url": "animations/turn_left.fbx", + "startFrame": 0.0, + "endFrame": 28.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "turnRight", + "type": "clip", + "data": { + "url": "animations/turn_left.fbx", + "startFrame": 0.0, + "endFrame": 30.0, + "timeScale": 1.0, + "loopFlag": true, + "mirrorFlag": true + }, + "children": [] + }, + { + "id": "strafeLeft", + "type": "blendLinearMove", + "data": { + "alpha": 0.0, + "desiredSpeed": 1.4, + "characteristicSpeeds": [0.2, 0.65], + "alphaVar": "moveLateralAlpha", + "desiredSpeedVar": "moveLateralSpeed" + }, + "children": [ + { + "id": "strafeLeftShort", + "type": "clip", + "data": { + "url": "animations/side_step_short_left.fbx", + "startFrame": 0.0, + "endFrame": 28.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "strafeLeftNormal", + "type": "clip", + "data": { + "url": "animations/side_step_left.fbx", + "startFrame": 0.0, + "endFrame": 30.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + } + ] + }, + { + "id": "strafeRight", + "type": "blendLinearMove", + "data": { + "alpha": 0.0, + "desiredSpeed": 1.4, + "characteristicSpeeds": [0.2, 0.65], + "alphaVar": "moveLateralAlpha", + "desiredSpeedVar": "moveLateralSpeed" + }, + "children": [ + { + "id": "strafeRightShort", + "type": "clip", + "data": { + "url": "animations/side_step_short_right.fbx", + "startFrame": 0.0, + "endFrame": 28.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "strafeRightNormal", + "type": "clip", + "data": { + "url": "animations/side_step_right.fbx", + "startFrame": 0.0, + "endFrame": 30.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + } + ] + }, + { + "id": "fly", + "type": "clip", + "data": { + "url": "animations/fly.fbx", + "startFrame": 1.0, + "endFrame": 80.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "takeoffStand", + "type": "clip", + "data": { + "url": "animations/jump_standing_takeoff.fbx", + "startFrame": 17.0, + "endFrame": 25.0, + "timeScale": 1.0, + "loopFlag": false + }, + "children": [] + }, + { + "id": "takeoffRun", + "type": "clip", + "data": { + "url": "animations/jump_takeoff.fbx", + "startFrame": 1.0, + "endFrame": 2.5, + "timeScale": 0.01, + "loopFlag": false + }, + "children": [] + }, + { + "id": "inAirStand", + "type": "blendLinear", + "data": { + "alpha": 0.0, + "alphaVar": "inAirAlpha" + }, + "children": [ + { + "id": "inAirStandPreApex", + "type": "clip", + "data": { + "url": "animations/jump_standing_apex.fbx", + "startFrame": 0.0, + "endFrame": 0.0, + "timeScale": 0.0, + "loopFlag": false + }, + "children": [] + }, + { + "id": "inAirStandApex", + "type": "clip", + "data": { + "url": "animations/jump_standing_apex.fbx", + "startFrame": 1.0, + "endFrame": 1.0, + "timeScale": 1.0, + "loopFlag": false + }, + "children": [] + }, + { + "id": "inAirStandPostApex", + "type": "clip", + "data": { + "url": "animations/jump_standing_apex.fbx", + "startFrame": 2.0, + "endFrame": 2.0, + "timeScale": 1.0, + "loopFlag": false + }, + "children": [] + } + ] + }, + { + "id": "inAirRun", + "type": "blendLinear", + "data": { + "alpha": 0.0, + "alphaVar": "inAirAlpha" + }, + "children": [ + { + "id": "inAirRunPreApex", + "type": "clip", + "data": { + "url": "animations/jump_in_air.fbx", + "startFrame": 0.0, + "endFrame": 0.0, + "timeScale": 0.0, + "loopFlag": false + }, + "children": [] + }, + { + "id": "inAirRunApex", + "type": "clip", + "data": { + "url": "animations/jump_in_air.fbx", + "startFrame": 6.0, + "endFrame": 6.0, + "timeScale": 1.0, + "loopFlag": false + }, + "children": [] + }, + { + "id": "inAirRunPostApex", + "type": "clip", + "data": { + "url": "animations/jump_in_air.fbx", + "startFrame": 11.0, + "endFrame": 11.0, + "timeScale": 1.0, + "loopFlag": false + }, + "children": [] + } + ] + }, + { + "id": "landStandImpact", + "type": "clip", + "data": { + "url": "animations/jump_standing_land.fbx", + "startFrame": 1.0, + "endFrame": 6.0, + "timeScale": 1.0, + "loopFlag": false + }, + "children": [] + }, + { + "id": "landStand", + "type": "clip", + "data": { + "url": "animations/jump_standing_land.fbx", + "startFrame": 6.0, + "endFrame": 28.0, + "timeScale": 1.0, + "loopFlag": false + }, + "children": [] + }, + { + "id": "landRun", + "type": "clip", + "data": { + "url": "animations/jump_land.fbx", + "startFrame": 1.0, + "endFrame": 6.0, + "timeScale": 0.65, + "loopFlag": false + }, + "children": [] + } + ] + } + ] + } + ] + } + ] + } + ] + }, + { + "id": "userAnimA", + "type": "clip", + "data": { + "url": "animations/idle.fbx", + "startFrame": 0.0, + "endFrame": 90.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "userAnimB", + "type": "clip", + "data": { + "url": "animations/idle.fbx", + "startFrame": 0.0, + "endFrame": 90.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + } + ] + } +} diff --git a/libraries/animation/src/AnimBlendLinear.cpp b/libraries/animation/src/AnimBlendLinear.cpp index 936126bf52..54a92acbd0 100644 --- a/libraries/animation/src/AnimBlendLinear.cpp +++ b/libraries/animation/src/AnimBlendLinear.cpp @@ -24,7 +24,7 @@ AnimBlendLinear::~AnimBlendLinear() { } -const AnimPoseVec& AnimBlendLinear::evaluate(const AnimVariantMap& animVars, const AnimContext& context, float dt, Triggers& triggersOut) { +const AnimPoseVec& AnimBlendLinear::evaluate(const AnimVariantMap& animVars, const AnimContext& context, float dt, AnimVariantMap& triggersOut) { _alpha = animVars.lookup(_alphaVar, _alpha); @@ -43,6 +43,9 @@ const AnimPoseVec& AnimBlendLinear::evaluate(const AnimVariantMap& animVars, con evaluateAndBlendChildren(animVars, context, triggersOut, alpha, prevPoseIndex, nextPoseIndex, dt); } + + processOutputJoints(triggersOut); + return _poses; } @@ -51,7 +54,7 @@ const AnimPoseVec& AnimBlendLinear::getPosesInternal() const { return _poses; } -void AnimBlendLinear::evaluateAndBlendChildren(const AnimVariantMap& animVars, const AnimContext& context, Triggers& triggersOut, float alpha, +void AnimBlendLinear::evaluateAndBlendChildren(const AnimVariantMap& animVars, const AnimContext& context, AnimVariantMap& triggersOut, float alpha, size_t prevPoseIndex, size_t nextPoseIndex, float dt) { if (prevPoseIndex == nextPoseIndex) { // this can happen if alpha is on an integer boundary diff --git a/libraries/animation/src/AnimBlendLinear.h b/libraries/animation/src/AnimBlendLinear.h index 0dae6aabdb..d0fe2a8503 100644 --- a/libraries/animation/src/AnimBlendLinear.h +++ b/libraries/animation/src/AnimBlendLinear.h @@ -30,7 +30,7 @@ public: AnimBlendLinear(const QString& id, float alpha); virtual ~AnimBlendLinear() override; - virtual const AnimPoseVec& evaluate(const AnimVariantMap& animVars, const AnimContext& context, float dt, Triggers& triggersOut) override; + virtual const AnimPoseVec& evaluate(const AnimVariantMap& animVars, const AnimContext& context, float dt, AnimVariantMap& triggersOut) override; void setAlphaVar(const QString& alphaVar) { _alphaVar = alphaVar; } @@ -38,7 +38,7 @@ protected: // for AnimDebugDraw rendering virtual const AnimPoseVec& getPosesInternal() const override; - void evaluateAndBlendChildren(const AnimVariantMap& animVars, const AnimContext& context, Triggers& triggersOut, float alpha, + void evaluateAndBlendChildren(const AnimVariantMap& animVars, const AnimContext& context, AnimVariantMap& triggersOut, float alpha, size_t prevPoseIndex, size_t nextPoseIndex, float dt); AnimPoseVec _poses; diff --git a/libraries/animation/src/AnimBlendLinearMove.cpp b/libraries/animation/src/AnimBlendLinearMove.cpp index 40fbb5a6f7..68af5c6acc 100644 --- a/libraries/animation/src/AnimBlendLinearMove.cpp +++ b/libraries/animation/src/AnimBlendLinearMove.cpp @@ -26,7 +26,7 @@ AnimBlendLinearMove::~AnimBlendLinearMove() { } -const AnimPoseVec& AnimBlendLinearMove::evaluate(const AnimVariantMap& animVars, const AnimContext& context, float dt, Triggers& triggersOut) { +const AnimPoseVec& AnimBlendLinearMove::evaluate(const AnimVariantMap& animVars, const AnimContext& context, float dt, AnimVariantMap& triggersOut) { assert(_children.size() == _characteristicSpeeds.size()); @@ -54,6 +54,9 @@ const AnimPoseVec& AnimBlendLinearMove::evaluate(const AnimVariantMap& animVars, setFrameAndPhase(dt, alpha, prevPoseIndex, nextPoseIndex, &prevDeltaTime, &nextDeltaTime, triggersOut); evaluateAndBlendChildren(animVars, context, triggersOut, alpha, prevPoseIndex, nextPoseIndex, prevDeltaTime, nextDeltaTime); } + + processOutputJoints(triggersOut); + return _poses; } @@ -62,7 +65,7 @@ const AnimPoseVec& AnimBlendLinearMove::getPosesInternal() const { return _poses; } -void AnimBlendLinearMove::evaluateAndBlendChildren(const AnimVariantMap& animVars, const AnimContext& context, Triggers& triggersOut, float alpha, +void AnimBlendLinearMove::evaluateAndBlendChildren(const AnimVariantMap& animVars, const AnimContext& context, AnimVariantMap& triggersOut, float alpha, size_t prevPoseIndex, size_t nextPoseIndex, float prevDeltaTime, float nextDeltaTime) { if (prevPoseIndex == nextPoseIndex) { @@ -82,7 +85,7 @@ void AnimBlendLinearMove::evaluateAndBlendChildren(const AnimVariantMap& animVar } void AnimBlendLinearMove::setFrameAndPhase(float dt, float alpha, int prevPoseIndex, int nextPoseIndex, - float* prevDeltaTimeOut, float* nextDeltaTimeOut, Triggers& triggersOut) { + float* prevDeltaTimeOut, float* nextDeltaTimeOut, AnimVariantMap& triggersOut) { const float FRAMES_PER_SECOND = 30.0f; auto prevClipNode = std::dynamic_pointer_cast(_children[prevPoseIndex]); @@ -109,7 +112,7 @@ void AnimBlendLinearMove::setFrameAndPhase(float dt, float alpha, int prevPoseIn // detect loop trigger events if (_phase >= 1.0f) { - triggersOut.push_back(_id + "Loop"); + triggersOut.setTrigger(_id + "Loop"); _phase = glm::fract(_phase); } diff --git a/libraries/animation/src/AnimBlendLinearMove.h b/libraries/animation/src/AnimBlendLinearMove.h index 083858f873..ff2f2d7763 100644 --- a/libraries/animation/src/AnimBlendLinearMove.h +++ b/libraries/animation/src/AnimBlendLinearMove.h @@ -39,7 +39,7 @@ public: AnimBlendLinearMove(const QString& id, float alpha, float desiredSpeed, const std::vector& characteristicSpeeds); virtual ~AnimBlendLinearMove() override; - virtual const AnimPoseVec& evaluate(const AnimVariantMap& animVars, const AnimContext& context, float dt, Triggers& triggersOut) override; + virtual const AnimPoseVec& evaluate(const AnimVariantMap& animVars, const AnimContext& context, float dt, AnimVariantMap& triggersOut) override; void setAlphaVar(const QString& alphaVar) { _alphaVar = alphaVar; } void setDesiredSpeedVar(const QString& desiredSpeedVar) { _desiredSpeedVar = desiredSpeedVar; } @@ -48,12 +48,12 @@ protected: // for AnimDebugDraw rendering virtual const AnimPoseVec& getPosesInternal() const override; - void evaluateAndBlendChildren(const AnimVariantMap& animVars, const AnimContext& context, Triggers& triggersOut, float alpha, + void evaluateAndBlendChildren(const AnimVariantMap& animVars, const AnimContext& context, AnimVariantMap& triggersOut, float alpha, size_t prevPoseIndex, size_t nextPoseIndex, float prevDeltaTime, float nextDeltaTime); void setFrameAndPhase(float dt, float alpha, int prevPoseIndex, int nextPoseIndex, - float* prevDeltaTimeOut, float* nextDeltaTimeOut, Triggers& triggersOut); + float* prevDeltaTimeOut, float* nextDeltaTimeOut, AnimVariantMap& triggersOut); virtual void setCurrentFrameInternal(float frame) override; diff --git a/libraries/animation/src/AnimChain.h b/libraries/animation/src/AnimChain.h new file mode 100644 index 0000000000..ed88000e75 --- /dev/null +++ b/libraries/animation/src/AnimChain.h @@ -0,0 +1,159 @@ +// +// AnimChain.h +// +// Created by Anthony J. Thibault on 7/16/2018. +// Copyright (c) 2018 High Fidelity, Inc. All rights reserved. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_AnimChain +#define hifi_AnimChain + +#include +#include +#include + +#include + +template +class AnimChainT { + +public: + AnimChainT() {} + + AnimChainT(const AnimChainT& orig) { + _top = orig._top; + for (int i = 0; i < _top; i++) { + _chain[i] = orig._chain[i]; + } + } + + AnimChainT& operator=(const AnimChainT& orig) { + _top = orig._top; + for (int i = 0; i < _top; i++) { + _chain[i] = orig._chain[i]; + } + return *this; + } + + bool buildFromRelativePoses(const AnimSkeleton::ConstPointer& skeleton, const AnimPoseVec& relativePoses, int tipIndex) { + _top = 0; + // iterate through the skeleton parents, from the tip to the base, copying over relativePoses into the chain. + for (int jointIndex = tipIndex; jointIndex != -1; jointIndex = skeleton->getParentIndex(jointIndex)) { + if (_top >= N) { + assert(chainTop < N); + // stack overflow + return false; + } + _chain[_top].relativePose = relativePoses[jointIndex]; + _chain[_top].jointIndex = jointIndex; + _chain[_top].dirty = true; + _top++; + } + + buildDirtyAbsolutePoses(); + + return true; + } + + const AnimPose& getAbsolutePoseFromJointIndex(int jointIndex) const { + for (int i = 0; i < _top; i++) { + if (_chain[i].jointIndex == jointIndex) { + return _chain[i].absolutePose; + } + } + return AnimPose::identity; + } + + bool setRelativePoseAtJointIndex(int jointIndex, const AnimPose& relativePose) { + bool foundIndex = false; + for (int i = _top - 1; i >= 0; i--) { + if (_chain[i].jointIndex == jointIndex) { + _chain[i].relativePose = relativePose; + foundIndex = true; + } + // all child absolute poses are now dirty + if (foundIndex) { + _chain[i].dirty = true; + } + } + return foundIndex; + } + + void buildDirtyAbsolutePoses() { + // the relative and absolute pose is the same for the base of the chain. + _chain[_top - 1].absolutePose = _chain[_top - 1].relativePose; + _chain[_top - 1].dirty = false; + + // iterate chain from base to tip, concatinating the relative poses to build the absolute poses. + for (int i = _top - 1; i > 0; i--) { + AnimChainElem& parent = _chain[i]; + AnimChainElem& child = _chain[i - 1]; + + if (child.dirty) { + child.absolutePose = parent.absolutePose * child.relativePose; + child.dirty = false; + } + } + } + + void blend(const AnimChainT& srcChain, float alpha) { + // make sure chains have same lengths + assert(srcChain._top == _top); + if (srcChain._top != _top) { + return; + } + + // only blend the relative poses + for (int i = 0; i < _top; i++) { + _chain[i].relativePose.blend(srcChain._chain[i].relativePose, alpha); + _chain[i].dirty = true; + } + } + + int size() const { + return _top; + } + + void outputRelativePoses(AnimPoseVec& relativePoses) { + for (int i = 0; i < _top; i++) { + relativePoses[_chain[i].jointIndex] = _chain[i].relativePose; + } + } + + void debugDraw(const glm::mat4& geomToWorldMat, const glm::vec4& color) const { + for (int i = 1; i < _top; i++) { + glm::vec3 start = transformPoint(geomToWorldMat, _chain[i - 1].absolutePose.trans()); + glm::vec3 end = transformPoint(geomToWorldMat, _chain[i].absolutePose.trans()); + DebugDraw::getInstance().drawRay(start, end, color); + } + } + + void dump() const { + for (int i = 0; i < _top; i++) { + qWarning() << "AJT: AnimPoseElem[" << i << "]"; + qWarning() << "AJT: relPose =" << _chain[i].relativePose; + qWarning() << "AJT: absPose =" << _chain[i].absolutePose; + qWarning() << "AJT: jointIndex =" << _chain[i].jointIndex; + qWarning() << "AJT: dirty =" << _chain[i].dirty; + } + } + +protected: + + struct AnimChainElem { + AnimPose relativePose; + AnimPose absolutePose; + int jointIndex { -1 }; + bool dirty { true }; + }; + + AnimChainElem _chain[N]; + int _top { 0 }; +}; + +using AnimChain = AnimChainT<10>; + +#endif diff --git a/libraries/animation/src/AnimClip.cpp b/libraries/animation/src/AnimClip.cpp index 7d358e85cc..f9195a608b 100644 --- a/libraries/animation/src/AnimClip.cpp +++ b/libraries/animation/src/AnimClip.cpp @@ -30,7 +30,7 @@ AnimClip::~AnimClip() { } -const AnimPoseVec& AnimClip::evaluate(const AnimVariantMap& animVars, const AnimContext& context, float dt, Triggers& triggersOut) { +const AnimPoseVec& AnimClip::evaluate(const AnimVariantMap& animVars, const AnimContext& context, float dt, AnimVariantMap& triggersOut) { // lookup parameters from animVars, using current instance variables as defaults. _startFrame = animVars.lookup(_startFrameVar, _startFrame); @@ -77,6 +77,8 @@ const AnimPoseVec& AnimClip::evaluate(const AnimVariantMap& animVars, const Anim ::blend(_poses.size(), &prevFrame[0], &nextFrame[0], alpha, &_poses[0]); } + processOutputJoints(triggersOut); + return _poses; } @@ -89,7 +91,7 @@ void AnimClip::loadURL(const QString& url) { void AnimClip::setCurrentFrameInternal(float frame) { // because dt is 0, we should not encounter any triggers const float dt = 0.0f; - Triggers triggers; + AnimVariantMap triggers; _frame = ::accumulateTime(_startFrame, _endFrame, _timeScale, frame + _startFrame, dt, _loopFlag, _id, triggers); } diff --git a/libraries/animation/src/AnimClip.h b/libraries/animation/src/AnimClip.h index 717972ca26..eba361fd4c 100644 --- a/libraries/animation/src/AnimClip.h +++ b/libraries/animation/src/AnimClip.h @@ -28,7 +28,7 @@ public: AnimClip(const QString& id, const QString& url, float startFrame, float endFrame, float timeScale, bool loopFlag, bool mirrorFlag); virtual ~AnimClip() override; - virtual const AnimPoseVec& evaluate(const AnimVariantMap& animVars, const AnimContext& context, float dt, Triggers& triggersOut) override; + virtual const AnimPoseVec& evaluate(const AnimVariantMap& animVars, const AnimContext& context, float dt, AnimVariantMap& triggersOut) override; void setStartFrameVar(const QString& startFrameVar) { _startFrameVar = startFrameVar; } void setEndFrameVar(const QString& endFrameVar) { _endFrameVar = endFrameVar; } diff --git a/libraries/animation/src/AnimDefaultPose.cpp b/libraries/animation/src/AnimDefaultPose.cpp index 70bcbe7c21..3ed2ff6cca 100644 --- a/libraries/animation/src/AnimDefaultPose.cpp +++ b/libraries/animation/src/AnimDefaultPose.cpp @@ -20,12 +20,15 @@ AnimDefaultPose::~AnimDefaultPose() { } -const AnimPoseVec& AnimDefaultPose::evaluate(const AnimVariantMap& animVars, const AnimContext& context, float dt, Triggers& triggersOut) { +const AnimPoseVec& AnimDefaultPose::evaluate(const AnimVariantMap& animVars, const AnimContext& context, float dt, AnimVariantMap& triggersOut) { if (_skeleton) { _poses = _skeleton->getRelativeDefaultPoses(); } else { _poses.clear(); } + + processOutputJoints(triggersOut); + return _poses; } diff --git a/libraries/animation/src/AnimDefaultPose.h b/libraries/animation/src/AnimDefaultPose.h index eefefac7af..13143f8d92 100644 --- a/libraries/animation/src/AnimDefaultPose.h +++ b/libraries/animation/src/AnimDefaultPose.h @@ -21,7 +21,7 @@ public: AnimDefaultPose(const QString& id); virtual ~AnimDefaultPose() override; - virtual const AnimPoseVec& evaluate(const AnimVariantMap& animVars, const AnimContext& context, float dt, Triggers& triggersOut) override; + virtual const AnimPoseVec& evaluate(const AnimVariantMap& animVars, const AnimContext& context, float dt, AnimVariantMap& triggersOut) override; protected: // for AnimDebugDraw rendering virtual const AnimPoseVec& getPosesInternal() const override; diff --git a/libraries/animation/src/AnimInverseKinematics.cpp b/libraries/animation/src/AnimInverseKinematics.cpp index dc004fe60d..c8d36db58f 100644 --- a/libraries/animation/src/AnimInverseKinematics.cpp +++ b/libraries/animation/src/AnimInverseKinematics.cpp @@ -259,14 +259,6 @@ void AnimInverseKinematics::solve(const AnimContext& context, const std::vector< jointChainInfoVec[i].jointInfoVec[j].rot = safeMix(_prevJointChainInfoVec[i].jointInfoVec[j].rot, jointChainInfoVec[i].jointInfoVec[j].rot, alpha); jointChainInfoVec[i].jointInfoVec[j].trans = lerp(_prevJointChainInfoVec[i].jointInfoVec[j].trans, jointChainInfoVec[i].jointInfoVec[j].trans, alpha); } - - // if joint chain was just disabled, ramp the weight toward zero. - if (_prevJointChainInfoVec[i].target.getType() != IKTarget::Type::Unknown && - jointChainInfoVec[i].target.getType() == IKTarget::Type::Unknown) { - IKTarget newTarget = _prevJointChainInfoVec[i].target; - newTarget.setWeight((1.0f - alpha) * _prevJointChainInfoVec[i].target.getWeight()); - jointChainInfoVec[i].target = newTarget; - } } } } @@ -874,14 +866,14 @@ void AnimInverseKinematics::solveTargetWithSpline(const AnimContext& context, co } //virtual -const AnimPoseVec& AnimInverseKinematics::evaluate(const AnimVariantMap& animVars, const AnimContext& context, float dt, AnimNode::Triggers& triggersOut) { +const AnimPoseVec& AnimInverseKinematics::evaluate(const AnimVariantMap& animVars, const AnimContext& context, float dt, AnimVariantMap& triggersOut) { // don't call this function, call overlay() instead assert(false); return _relativePoses; } //virtual -const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars, const AnimContext& context, float dt, Triggers& triggersOut, const AnimPoseVec& underPoses) { +const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars, const AnimContext& context, float dt, AnimVariantMap& triggersOut, const AnimPoseVec& underPoses) { #ifdef Q_OS_ANDROID // disable IK on android return underPoses; @@ -961,6 +953,7 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars PROFILE_RANGE_EX(simulation_animation, "ik/shiftHips", 0xffff00ff, 0); if (_hipsTargetIndex >= 0) { + assert(_hipsTargetIndex < (int)targets.size()); // slam the hips to match the _hipsTarget @@ -1045,6 +1038,7 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars PROFILE_RANGE_EX(simulation_animation, "ik/ccd", 0xffff00ff, 0); setSecondaryTargets(context); + preconditionRelativePosesToAvoidLimbLock(context, targets); solve(context, targets, dt, jointChainInfoVec); @@ -1056,6 +1050,8 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars } } + processOutputJoints(triggersOut); + return _relativePoses; } @@ -1750,7 +1746,7 @@ void AnimInverseKinematics::preconditionRelativePosesToAvoidLimbLock(const AnimC const float MIN_AXIS_LENGTH = 1.0e-4f; for (auto& target : targets) { - if (target.getIndex() != -1) { + if (target.getIndex() != -1 && target.getType() == IKTarget::Type::RotationAndPosition) { for (int i = 0; i < NUM_LIMBS; i++) { if (limbs[i].first == target.getIndex()) { int tipIndex = limbs[i].first; @@ -1843,6 +1839,10 @@ void AnimInverseKinematics::initRelativePosesFromSolutionSource(SolutionSource s default: case SolutionSource::RelaxToUnderPoses: blendToPoses(underPoses, underPoses, RELAX_BLEND_FACTOR); + // special case for hips: don't dampen hip motion from underposes + if (_hipsIndex >= 0 && _hipsIndex < (int)_relativePoses.size()) { + _relativePoses[_hipsIndex] = underPoses[_hipsIndex]; + } break; case SolutionSource::RelaxToLimitCenterPoses: blendToPoses(_limitCenterPoses, underPoses, RELAX_BLEND_FACTOR); diff --git a/libraries/animation/src/AnimInverseKinematics.h b/libraries/animation/src/AnimInverseKinematics.h index ee1f9f43ad..0136b7d125 100644 --- a/libraries/animation/src/AnimInverseKinematics.h +++ b/libraries/animation/src/AnimInverseKinematics.h @@ -52,8 +52,8 @@ public: const QString& typeVar, const QString& weightVar, float weight, const std::vector& flexCoefficients, const QString& poleVectorEnabledVar, const QString& poleReferenceVectorVar, const QString& poleVectorVar); - virtual const AnimPoseVec& evaluate(const AnimVariantMap& animVars, const AnimContext& context, float dt, AnimNode::Triggers& triggersOut) override; - virtual const AnimPoseVec& overlay(const AnimVariantMap& animVars, const AnimContext& context, float dt, Triggers& triggersOut, const AnimPoseVec& underPoses) override; + virtual const AnimPoseVec& evaluate(const AnimVariantMap& animVars, const AnimContext& context, float dt, AnimVariantMap& triggersOut) override; + virtual const AnimPoseVec& overlay(const AnimVariantMap& animVars, const AnimContext& context, float dt, AnimVariantMap& triggersOut, const AnimPoseVec& underPoses) override; void clearIKJointLimitHistory(); diff --git a/libraries/animation/src/AnimManipulator.cpp b/libraries/animation/src/AnimManipulator.cpp index 46b3cf1c28..1146cbb19a 100644 --- a/libraries/animation/src/AnimManipulator.cpp +++ b/libraries/animation/src/AnimManipulator.cpp @@ -32,11 +32,11 @@ AnimManipulator::~AnimManipulator() { } -const AnimPoseVec& AnimManipulator::evaluate(const AnimVariantMap& animVars, const AnimContext& context, float dt, Triggers& triggersOut) { +const AnimPoseVec& AnimManipulator::evaluate(const AnimVariantMap& animVars, const AnimContext& context, float dt, AnimVariantMap& triggersOut) { return overlay(animVars, context, dt, triggersOut, _skeleton->getRelativeDefaultPoses()); } -const AnimPoseVec& AnimManipulator::overlay(const AnimVariantMap& animVars, const AnimContext& context, float dt, Triggers& triggersOut, const AnimPoseVec& underPoses) { +const AnimPoseVec& AnimManipulator::overlay(const AnimVariantMap& animVars, const AnimContext& context, float dt, AnimVariantMap& triggersOut, const AnimPoseVec& underPoses) { _alpha = animVars.lookup(_alphaVar, _alpha); _poses = underPoses; @@ -74,6 +74,8 @@ const AnimPoseVec& AnimManipulator::overlay(const AnimVariantMap& animVars, cons } } + processOutputJoints(triggersOut); + return _poses; } diff --git a/libraries/animation/src/AnimManipulator.h b/libraries/animation/src/AnimManipulator.h index 1134f75da9..96af08a50a 100644 --- a/libraries/animation/src/AnimManipulator.h +++ b/libraries/animation/src/AnimManipulator.h @@ -22,8 +22,8 @@ public: AnimManipulator(const QString& id, float alpha); virtual ~AnimManipulator() override; - virtual const AnimPoseVec& evaluate(const AnimVariantMap& animVars, const AnimContext& context, float dt, Triggers& triggersOut) override; - virtual const AnimPoseVec& overlay(const AnimVariantMap& animVars, const AnimContext& context, float dt, Triggers& triggersOut, const AnimPoseVec& underPoses) override; + virtual const AnimPoseVec& evaluate(const AnimVariantMap& animVars, const AnimContext& context, float dt, AnimVariantMap& triggersOut) override; + virtual const AnimPoseVec& overlay(const AnimVariantMap& animVars, const AnimContext& context, float dt, AnimVariantMap& triggersOut, const AnimPoseVec& underPoses) override; void setAlphaVar(const QString& alphaVar) { _alphaVar = alphaVar; } diff --git a/libraries/animation/src/AnimNode.cpp b/libraries/animation/src/AnimNode.cpp index ba8e095109..f055e6b473 100644 --- a/libraries/animation/src/AnimNode.cpp +++ b/libraries/animation/src/AnimNode.cpp @@ -59,3 +59,19 @@ void AnimNode::setCurrentFrame(float frame) { child->setCurrentFrameInternal(frame); } } + +void AnimNode::processOutputJoints(AnimVariantMap& triggersOut) const { + if (!_skeleton) { + return; + } + + for (auto&& jointName : _outputJointNames) { + // TODO: cache the jointIndices + int jointIndex = _skeleton->nameToJointIndex(jointName); + if (jointIndex >= 0) { + AnimPose pose = _skeleton->getAbsolutePose(jointIndex, getPosesInternal()); + triggersOut.set(_id + jointName + "Rotation", pose.rot()); + triggersOut.set(_id + jointName + "Position", pose.trans()); + } + } +} diff --git a/libraries/animation/src/AnimNode.h b/libraries/animation/src/AnimNode.h index 6d9d35b19b..d2ab61219a 100644 --- a/libraries/animation/src/AnimNode.h +++ b/libraries/animation/src/AnimNode.h @@ -45,11 +45,12 @@ public: Manipulator, InverseKinematics, DefaultPose, + TwoBoneIK, + PoleVectorConstraint, NumTypes }; using Pointer = std::shared_ptr; using ConstPointer = std::shared_ptr; - using Triggers = std::vector; friend class AnimDebugDraw; friend void buildChildMap(std::map& map, Pointer node); @@ -61,6 +62,8 @@ public: const QString& getID() const { return _id; } Type getType() const { return _type; } + void addOutputJoint(const QString& outputJointName) { _outputJointNames.push_back(outputJointName); } + // hierarchy accessors Pointer getParent(); void addChild(Pointer child); @@ -74,8 +77,8 @@ public: AnimSkeleton::ConstPointer getSkeleton() const { return _skeleton; } - virtual const AnimPoseVec& evaluate(const AnimVariantMap& animVars, const AnimContext& context, float dt, Triggers& triggersOut) = 0; - virtual const AnimPoseVec& overlay(const AnimVariantMap& animVars, const AnimContext& context, float dt, Triggers& triggersOut, + virtual const AnimPoseVec& evaluate(const AnimVariantMap& animVars, const AnimContext& context, float dt, AnimVariantMap& triggersOut) = 0; + virtual const AnimPoseVec& overlay(const AnimVariantMap& animVars, const AnimContext& context, float dt, AnimVariantMap& triggersOut, const AnimPoseVec& underPoses) { return evaluate(animVars, context, dt, triggersOut); } @@ -114,11 +117,14 @@ protected: // for AnimDebugDraw rendering virtual const AnimPoseVec& getPosesInternal() const = 0; + void processOutputJoints(AnimVariantMap& triggersOut) const; + Type _type; QString _id; std::vector _children; AnimSkeleton::ConstPointer _skeleton; std::weak_ptr _parent; + std::vector _outputJointNames; // no copies AnimNode(const AnimNode&) = delete; diff --git a/libraries/animation/src/AnimNodeLoader.cpp b/libraries/animation/src/AnimNodeLoader.cpp index 4169ff61a7..543eec9a3b 100644 --- a/libraries/animation/src/AnimNodeLoader.cpp +++ b/libraries/animation/src/AnimNodeLoader.cpp @@ -25,6 +25,8 @@ #include "AnimManipulator.h" #include "AnimInverseKinematics.h" #include "AnimDefaultPose.h" +#include "AnimTwoBoneIK.h" +#include "AnimPoleVectorConstraint.h" using NodeLoaderFunc = AnimNode::Pointer (*)(const QJsonObject& jsonObj, const QString& id, const QUrl& jsonUrl); using NodeProcessFunc = bool (*)(AnimNode::Pointer node, const QJsonObject& jsonObj, const QString& id, const QUrl& jsonUrl); @@ -38,6 +40,8 @@ static AnimNode::Pointer loadStateMachineNode(const QJsonObject& jsonObj, const static AnimNode::Pointer loadManipulatorNode(const QJsonObject& jsonObj, const QString& id, const QUrl& jsonUrl); static AnimNode::Pointer loadInverseKinematicsNode(const QJsonObject& jsonObj, const QString& id, const QUrl& jsonUrl); static AnimNode::Pointer loadDefaultPoseNode(const QJsonObject& jsonObj, const QString& id, const QUrl& jsonUrl); +static AnimNode::Pointer loadTwoBoneIKNode(const QJsonObject& jsonObj, const QString& id, const QUrl& jsonUrl); +static AnimNode::Pointer loadPoleVectorConstraintNode(const QJsonObject& jsonObj, const QString& id, const QUrl& jsonUrl); static const float ANIM_GRAPH_LOAD_PRIORITY = 10.0f; @@ -56,6 +60,8 @@ static const char* animNodeTypeToString(AnimNode::Type type) { case AnimNode::Type::Manipulator: return "manipulator"; case AnimNode::Type::InverseKinematics: return "inverseKinematics"; case AnimNode::Type::DefaultPose: return "defaultPose"; + case AnimNode::Type::TwoBoneIK: return "twoBoneIK"; + case AnimNode::Type::PoleVectorConstraint: return "poleVectorConstraint"; case AnimNode::Type::NumTypes: return nullptr; }; return nullptr; @@ -116,6 +122,8 @@ static NodeLoaderFunc animNodeTypeToLoaderFunc(AnimNode::Type type) { case AnimNode::Type::Manipulator: return loadManipulatorNode; case AnimNode::Type::InverseKinematics: return loadInverseKinematicsNode; case AnimNode::Type::DefaultPose: return loadDefaultPoseNode; + case AnimNode::Type::TwoBoneIK: return loadTwoBoneIKNode; + case AnimNode::Type::PoleVectorConstraint: return loadPoleVectorConstraintNode; case AnimNode::Type::NumTypes: return nullptr; }; return nullptr; @@ -131,6 +139,8 @@ static NodeProcessFunc animNodeTypeToProcessFunc(AnimNode::Type type) { case AnimNode::Type::Manipulator: return processDoNothing; case AnimNode::Type::InverseKinematics: return processDoNothing; case AnimNode::Type::DefaultPose: return processDoNothing; + case AnimNode::Type::TwoBoneIK: return processDoNothing; + case AnimNode::Type::PoleVectorConstraint: return processDoNothing; case AnimNode::Type::NumTypes: return nullptr; }; return nullptr; @@ -189,6 +199,25 @@ static NodeProcessFunc animNodeTypeToProcessFunc(AnimNode::Type type) { } \ do {} while (0) +#define READ_VEC3(NAME, JSON_OBJ, ID, URL, ERROR_RETURN) \ + auto NAME##_VAL = JSON_OBJ.value(#NAME); \ + if (!NAME##_VAL.isArray()) { \ + qCCritical(animation) << "AnimNodeLoader, error reading vector" \ + << #NAME << "id =" << ID \ + << ", url =" << URL.toDisplayString(); \ + return ERROR_RETURN; \ + } \ + QJsonArray NAME##_ARRAY = NAME##_VAL.toArray(); \ + if (NAME##_ARRAY.size() != 3) { \ + qCCritical(animation) << "AnimNodeLoader, vector size != 3" \ + << #NAME << "id =" << ID \ + << ", url =" << URL.toDisplayString(); \ + return ERROR_RETURN; \ + } \ + glm::vec3 NAME((float)NAME##_ARRAY.at(0).toDouble(), \ + (float)NAME##_ARRAY.at(1).toDouble(), \ + (float)NAME##_ARRAY.at(2).toDouble()) + static AnimNode::Pointer loadNode(const QJsonObject& jsonObj, const QUrl& jsonUrl) { auto idVal = jsonObj.value("id"); if (!idVal.isString()) { @@ -216,6 +245,16 @@ static AnimNode::Pointer loadNode(const QJsonObject& jsonObj, const QUrl& jsonUr } auto dataObj = dataValue.toObject(); + std::vector outputJoints; + + auto outputJoints_VAL = dataObj.value("outputJoints"); + if (outputJoints_VAL.isArray()) { + QJsonArray outputJoints_ARRAY = outputJoints_VAL.toArray(); + for (int i = 0; i < outputJoints_ARRAY.size(); i++) { + outputJoints.push_back(outputJoints_ARRAY.at(i).toString()); + } + } + assert((int)type >= 0 && type < AnimNode::Type::NumTypes); auto node = (animNodeTypeToLoaderFunc(type))(dataObj, id, jsonUrl); if (!node) { @@ -242,6 +281,9 @@ static AnimNode::Pointer loadNode(const QJsonObject& jsonObj, const QUrl& jsonUr } if ((animNodeTypeToProcessFunc(type))(node, dataObj, id, jsonUrl)) { + for (auto&& outputJoint : outputJoints) { + node->addOutputJoint(outputJoint); + } return node; } else { return nullptr; @@ -531,6 +573,41 @@ static AnimNode::Pointer loadDefaultPoseNode(const QJsonObject& jsonObj, const Q return node; } +static AnimNode::Pointer loadTwoBoneIKNode(const QJsonObject& jsonObj, const QString& id, const QUrl& jsonUrl) { + READ_FLOAT(alpha, jsonObj, id, jsonUrl, nullptr); + READ_BOOL(enabled, jsonObj, id, jsonUrl, nullptr); + READ_FLOAT(interpDuration, jsonObj, id, jsonUrl, nullptr); + READ_STRING(baseJointName, jsonObj, id, jsonUrl, nullptr); + READ_STRING(midJointName, jsonObj, id, jsonUrl, nullptr); + READ_STRING(tipJointName, jsonObj, id, jsonUrl, nullptr); + READ_VEC3(midHingeAxis, jsonObj, id, jsonUrl, nullptr); + READ_STRING(alphaVar, jsonObj, id, jsonUrl, nullptr); + READ_STRING(enabledVar, jsonObj, id, jsonUrl, nullptr); + READ_STRING(endEffectorRotationVarVar, jsonObj, id, jsonUrl, nullptr); + READ_STRING(endEffectorPositionVarVar, jsonObj, id, jsonUrl, nullptr); + + auto node = std::make_shared(id, alpha, enabled, interpDuration, + baseJointName, midJointName, tipJointName, midHingeAxis, + alphaVar, enabledVar, + endEffectorRotationVarVar, endEffectorPositionVarVar); + return node; +} + +static AnimNode::Pointer loadPoleVectorConstraintNode(const QJsonObject& jsonObj, const QString& id, const QUrl& jsonUrl) { + READ_VEC3(referenceVector, jsonObj, id, jsonUrl, nullptr); + READ_BOOL(enabled, jsonObj, id, jsonUrl, nullptr); + READ_STRING(baseJointName, jsonObj, id, jsonUrl, nullptr); + READ_STRING(midJointName, jsonObj, id, jsonUrl, nullptr); + READ_STRING(tipJointName, jsonObj, id, jsonUrl, nullptr); + READ_STRING(enabledVar, jsonObj, id, jsonUrl, nullptr); + READ_STRING(poleVectorVar, jsonObj, id, jsonUrl, nullptr); + + auto node = std::make_shared(id, enabled, referenceVector, + baseJointName, midJointName, tipJointName, + enabledVar, poleVectorVar); + return node; +} + void buildChildMap(std::map& map, AnimNode::Pointer node) { for (int i = 0; i < (int)node->getChildCount(); ++i) { map.insert(std::pair(node->getChild(i)->getID(), i)); @@ -682,7 +759,8 @@ AnimNode::Pointer AnimNodeLoader::load(const QByteArray& contents, const QUrl& j QString version = versionVal.toString(); // check version - if (version != "1.0") { + // AJT: TODO version check + if (version != "1.0" && version != "1.1") { qCCritical(animation) << "AnimNodeLoader, bad version number" << version << "expected \"1.0\", url =" << jsonUrl.toDisplayString(); return nullptr; } diff --git a/libraries/animation/src/AnimOverlay.cpp b/libraries/animation/src/AnimOverlay.cpp index 10594af20a..910f9b37c0 100644 --- a/libraries/animation/src/AnimOverlay.cpp +++ b/libraries/animation/src/AnimOverlay.cpp @@ -41,7 +41,7 @@ void AnimOverlay::buildBoneSet(BoneSet boneSet) { } } -const AnimPoseVec& AnimOverlay::evaluate(const AnimVariantMap& animVars, const AnimContext& context, float dt, Triggers& triggersOut) { +const AnimPoseVec& AnimOverlay::evaluate(const AnimVariantMap& animVars, const AnimContext& context, float dt, AnimVariantMap& triggersOut) { // lookup parameters from animVars, using current instance variables as defaults. // NOTE: switching bonesets can be an expensive operation, let's try to avoid it. @@ -66,6 +66,9 @@ const AnimPoseVec& AnimOverlay::evaluate(const AnimVariantMap& animVars, const A } } } + + processOutputJoints(triggersOut); + return _poses; } diff --git a/libraries/animation/src/AnimOverlay.h b/libraries/animation/src/AnimOverlay.h index 8b6e1529fc..70929bd4e4 100644 --- a/libraries/animation/src/AnimOverlay.h +++ b/libraries/animation/src/AnimOverlay.h @@ -45,7 +45,7 @@ public: AnimOverlay(const QString& id, BoneSet boneSet, float alpha); virtual ~AnimOverlay() override; - virtual const AnimPoseVec& evaluate(const AnimVariantMap& animVars, const AnimContext& context, float dt, Triggers& triggersOut) override; + virtual const AnimPoseVec& evaluate(const AnimVariantMap& animVars, const AnimContext& context, float dt, AnimVariantMap& triggersOut) override; void setBoneSetVar(const QString& boneSetVar) { _boneSetVar = boneSetVar; } void setAlphaVar(const QString& alphaVar) { _alphaVar = alphaVar; } diff --git a/libraries/animation/src/AnimPoleVectorConstraint.cpp b/libraries/animation/src/AnimPoleVectorConstraint.cpp new file mode 100644 index 0000000000..49fe05c7cf --- /dev/null +++ b/libraries/animation/src/AnimPoleVectorConstraint.cpp @@ -0,0 +1,245 @@ +// +// AnimPoleVectorConstraint.cpp +// +// Created by Anthony J. Thibault on 5/12/18. +// Copyright (c) 2018 High Fidelity, Inc. All rights reserved. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "AnimPoleVectorConstraint.h" +#include "AnimationLogging.h" +#include "AnimUtil.h" +#include "GLMHelpers.h" + +const float FRAMES_PER_SECOND = 30.0f; +const float INTERP_DURATION = 6.0f; + +AnimPoleVectorConstraint::AnimPoleVectorConstraint(const QString& id, bool enabled, glm::vec3 referenceVector, + const QString& baseJointName, const QString& midJointName, const QString& tipJointName, + const QString& enabledVar, const QString& poleVectorVar) : + AnimNode(AnimNode::Type::PoleVectorConstraint, id), + _enabled(enabled), + _referenceVector(referenceVector), + _baseJointName(baseJointName), + _midJointName(midJointName), + _tipJointName(tipJointName), + _enabledVar(enabledVar), + _poleVectorVar(poleVectorVar) { + +} + +AnimPoleVectorConstraint::~AnimPoleVectorConstraint() { + +} + +const AnimPoseVec& AnimPoleVectorConstraint::evaluate(const AnimVariantMap& animVars, const AnimContext& context, float dt, AnimVariantMap& triggersOut) { + + assert(_children.size() == 1); + if (_children.size() != 1) { + return _poses; + } + + // evalute underPoses + AnimPoseVec underPoses = _children[0]->evaluate(animVars, context, dt, triggersOut); + + // if we don't have a skeleton, or jointName lookup failed. + if (!_skeleton || _baseJointIndex == -1 || _midJointIndex == -1 || _tipJointIndex == -1 || underPoses.size() == 0) { + // pass underPoses through unmodified. + _poses = underPoses; + return _poses; + } + + // guard against size changes + if (underPoses.size() != _poses.size()) { + _poses = underPoses; + } + + // Look up poleVector from animVars, make sure to convert into geom space. + glm::vec3 poleVector = animVars.lookupRigToGeometryVector(_poleVectorVar, Vectors::UNIT_Z); + float poleVectorLength = glm::length(poleVector); + + // determine if we should interpolate + bool enabled = animVars.lookup(_enabledVar, _enabled); + + const float MIN_LENGTH = 1.0e-4f; + if (glm::length(poleVector) < MIN_LENGTH) { + enabled = false; + } + + if (enabled != _enabled) { + AnimChain poseChain; + poseChain.buildFromRelativePoses(_skeleton, _poses, _tipJointIndex); + if (enabled) { + beginInterp(InterpType::SnapshotToSolve, poseChain); + } else { + beginInterp(InterpType::SnapshotToUnderPoses, poseChain); + } + } + _enabled = enabled; + + // don't build chains or do IK if we are disbled & not interping. + if (_interpType == InterpType::None && !enabled) { + _poses = underPoses; + return _poses; + } + + // compute chain + AnimChain underChain; + underChain.buildFromRelativePoses(_skeleton, underPoses, _tipJointIndex); + AnimChain ikChain = underChain; + + AnimPose baseParentPose = ikChain.getAbsolutePoseFromJointIndex(_baseParentJointIndex); + AnimPose basePose = ikChain.getAbsolutePoseFromJointIndex(_baseJointIndex); + AnimPose midPose = ikChain.getAbsolutePoseFromJointIndex(_midJointIndex); + AnimPose tipPose = ikChain.getAbsolutePoseFromJointIndex(_tipJointIndex); + + // Look up refVector from animVars, make sure to convert into geom space. + glm::vec3 refVector = midPose.xformVectorFast(_referenceVector); + float refVectorLength = glm::length(refVector); + + glm::vec3 axis = basePose.trans() - tipPose.trans(); + float axisLength = glm::length(axis); + glm::vec3 unitAxis = axis / axisLength; + + glm::vec3 sideVector = glm::cross(unitAxis, refVector); + float sideVectorLength = glm::length(sideVector); + + // project refVector onto axis plane + glm::vec3 refVectorProj = refVector - glm::dot(refVector, unitAxis) * unitAxis; + float refVectorProjLength = glm::length(refVectorProj); + + // project poleVector on plane formed by axis. + glm::vec3 poleVectorProj = poleVector - glm::dot(poleVector, unitAxis) * unitAxis; + float poleVectorProjLength = glm::length(poleVectorProj); + + // double check for zero length vectors or vectors parallel to rotaiton axis. + if (axisLength > MIN_LENGTH && refVectorLength > MIN_LENGTH && sideVectorLength > MIN_LENGTH && + refVectorProjLength > MIN_LENGTH && poleVectorProjLength > MIN_LENGTH) { + + float dot = glm::clamp(glm::dot(refVectorProj / refVectorProjLength, poleVectorProj / poleVectorProjLength), 0.0f, 1.0f); + float sideDot = glm::dot(poleVector, sideVector); + float theta = copysignf(1.0f, sideDot) * acosf(dot); + + glm::quat deltaRot = glm::angleAxis(theta, unitAxis); + + // transform result back into parent relative frame. + glm::quat relBaseRot = glm::inverse(baseParentPose.rot()) * deltaRot * basePose.rot(); + ikChain.setRelativePoseAtJointIndex(_baseJointIndex, AnimPose(relBaseRot, underPoses[_baseJointIndex].trans())); + + glm::quat relTipRot = glm::inverse(midPose.rot()) * glm::inverse(deltaRot) * tipPose.rot(); + ikChain.setRelativePoseAtJointIndex(_tipJointIndex, AnimPose(relTipRot, underPoses[_tipJointIndex].trans())); + } + + // start off by initializing output poses with the underPoses + _poses = underPoses; + + // apply smooth interpolation + if (_interpType != InterpType::None) { + _interpAlpha += _interpAlphaVel * dt; + + if (_interpAlpha < 1.0f) { + AnimChain interpChain; + if (_interpType == InterpType::SnapshotToUnderPoses) { + interpChain = underChain; + interpChain.blend(_snapshotChain, _interpAlpha); + } else if (_interpType == InterpType::SnapshotToSolve) { + interpChain = ikChain; + interpChain.blend(_snapshotChain, _interpAlpha); + } + // copy interpChain into _poses + interpChain.outputRelativePoses(_poses); + } else { + // interpolation complete + _interpType = InterpType::None; + } + } + + if (_interpType == InterpType::None) { + if (enabled) { + // copy chain into _poses + ikChain.outputRelativePoses(_poses); + } else { + // copy under chain into _poses + underChain.outputRelativePoses(_poses); + } + } + + if (context.getEnableDebugDrawIKChains()) { + if (_interpType == InterpType::None && enabled) { + const vec4 BLUE(0.0f, 0.0f, 1.0f, 1.0f); + ikChain.debugDraw(context.getRigToWorldMatrix() * context.getGeometryToRigMatrix(), BLUE); + } + } + + if (context.getEnableDebugDrawIKChains()) { + if (enabled) { + const glm::vec4 RED(1.0f, 0.0f, 0.0f, 1.0f); + const glm::vec4 GREEN(0.0f, 1.0f, 0.0f, 1.0f); + const glm::vec4 CYAN(0.0f, 1.0f, 1.0f, 1.0f); + const glm::vec4 YELLOW(1.0f, 0.0f, 1.0f, 1.0f); + const float VECTOR_LENGTH = 0.5f; + + glm::mat4 geomToWorld = context.getRigToWorldMatrix() * context.getGeometryToRigMatrix(); + + // draw the pole + glm::vec3 start = transformPoint(geomToWorld, basePose.trans()); + glm::vec3 end = transformPoint(geomToWorld, tipPose.trans()); + DebugDraw::getInstance().drawRay(start, end, CYAN); + + // draw the poleVector + glm::vec3 midPoint = 0.5f * (start + end); + glm::vec3 poleVectorEnd = midPoint + VECTOR_LENGTH * glm::normalize(transformVectorFast(geomToWorld, poleVector)); + DebugDraw::getInstance().drawRay(midPoint, poleVectorEnd, GREEN); + + // draw the refVector + glm::vec3 refVectorEnd = midPoint + VECTOR_LENGTH * glm::normalize(transformVectorFast(geomToWorld, refVector)); + DebugDraw::getInstance().drawRay(midPoint, refVectorEnd, RED); + + // draw the sideVector + glm::vec3 sideVector = glm::cross(poleVector, refVector); + glm::vec3 sideVectorEnd = midPoint + VECTOR_LENGTH * glm::normalize(transformVectorFast(geomToWorld, sideVector)); + DebugDraw::getInstance().drawRay(midPoint, sideVectorEnd, YELLOW); + } + } + + processOutputJoints(triggersOut); + + return _poses; +} + +// for AnimDebugDraw rendering +const AnimPoseVec& AnimPoleVectorConstraint::getPosesInternal() const { + return _poses; +} + +void AnimPoleVectorConstraint::setSkeletonInternal(AnimSkeleton::ConstPointer skeleton) { + AnimNode::setSkeletonInternal(skeleton); + lookUpIndices(); +} + +void AnimPoleVectorConstraint::lookUpIndices() { + assert(_skeleton); + + // look up bone indices by name + std::vector indices = _skeleton->lookUpJointIndices({_baseJointName, _midJointName, _tipJointName}); + + // cache the results + _baseJointIndex = indices[0]; + _midJointIndex = indices[1]; + _tipJointIndex = indices[2]; + + if (_baseJointIndex != -1) { + _baseParentJointIndex = _skeleton->getParentIndex(_baseJointIndex); + } +} + +void AnimPoleVectorConstraint::beginInterp(InterpType interpType, const AnimChain& chain) { + // capture the current poses in a snapshot. + _snapshotChain = chain; + + _interpType = interpType; + _interpAlphaVel = FRAMES_PER_SECOND / INTERP_DURATION; + _interpAlpha = 0.0f; +} diff --git a/libraries/animation/src/AnimPoleVectorConstraint.h b/libraries/animation/src/AnimPoleVectorConstraint.h new file mode 100644 index 0000000000..44e22671c1 --- /dev/null +++ b/libraries/animation/src/AnimPoleVectorConstraint.h @@ -0,0 +1,74 @@ +// +// AnimPoleVectorConstraint.h +// +// Created by Anthony J. Thibault on 5/25/18. +// Copyright (c) 2018 High Fidelity, Inc. All rights reserved. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_AnimPoleVectorConstraint_h +#define hifi_AnimPoleVectorConstraint_h + +#include "AnimNode.h" +#include "AnimChain.h" + +// Three bone IK chain + +class AnimPoleVectorConstraint : public AnimNode { +public: + friend class AnimTests; + + AnimPoleVectorConstraint(const QString& id, bool enabled, glm::vec3 referenceVector, + const QString& baseJointName, const QString& midJointName, const QString& tipJointName, + const QString& enabledVar, const QString& poleVectorVar); + virtual ~AnimPoleVectorConstraint() override; + + virtual const AnimPoseVec& evaluate(const AnimVariantMap& animVars, const AnimContext& context, float dt, AnimVariantMap& triggersOut) override; + +protected: + + enum class InterpType { + None = 0, + SnapshotToUnderPoses, + SnapshotToSolve, + NumTypes + }; + + // for AnimDebugDraw rendering + virtual const AnimPoseVec& getPosesInternal() const override; + virtual void setSkeletonInternal(AnimSkeleton::ConstPointer skeleton) override; + + void lookUpIndices(); + void beginInterp(InterpType interpType, const AnimChain& chain); + + AnimPoseVec _poses; + + bool _enabled; + glm::vec3 _referenceVector; + + QString _baseJointName; + QString _midJointName; + QString _tipJointName; + + QString _enabledVar; + QString _poleVectorVar; + + int _baseParentJointIndex { -1 }; + int _baseJointIndex { -1 }; + int _midJointIndex { -1 }; + int _tipJointIndex { -1 }; + + InterpType _interpType { InterpType::None }; + float _interpAlphaVel { 0.0f }; + float _interpAlpha { 0.0f }; + + AnimChain _snapshotChain; + + // no copies + AnimPoleVectorConstraint(const AnimPoleVectorConstraint&) = delete; + AnimPoleVectorConstraint& operator=(const AnimPoleVectorConstraint&) = delete; +}; + +#endif // hifi_AnimPoleVectorConstraint_h diff --git a/libraries/animation/src/AnimPose.cpp b/libraries/animation/src/AnimPose.cpp index a0b8fba1da..5d1fbdd8b2 100644 --- a/libraries/animation/src/AnimPose.cpp +++ b/libraries/animation/src/AnimPose.cpp @@ -12,6 +12,7 @@ #include #include #include +#include "AnimUtil.h" const AnimPose AnimPose::identity = AnimPose(glm::vec3(1.0f), glm::quat(), @@ -77,4 +78,16 @@ AnimPose::operator glm::mat4() const { glm::vec4(zAxis, 0.0f), glm::vec4(_trans, 1.0f)); } +void AnimPose::blend(const AnimPose& srcPose, float alpha) { + // adjust signs if necessary + const glm::quat& q1 = srcPose._rot; + glm::quat q2 = _rot; + float dot = glm::dot(q1, q2); + if (dot < 0.0f) { + q2 = -q2; + } + _scale = lerp(srcPose._scale, _scale, alpha); + _rot = safeLerp(srcPose._rot, _rot, alpha); + _trans = lerp(srcPose._trans, _trans, alpha); +} diff --git a/libraries/animation/src/AnimPose.h b/libraries/animation/src/AnimPose.h index 2df3d1f2e4..1558a6b881 100644 --- a/libraries/animation/src/AnimPose.h +++ b/libraries/animation/src/AnimPose.h @@ -46,6 +46,8 @@ public: const glm::vec3& trans() const { return _trans; } glm::vec3& trans() { return _trans; } + void blend(const AnimPose& srcPose, float alpha); + private: friend QDebug operator<<(QDebug debug, const AnimPose& pose); glm::vec3 _scale { 1.0f }; diff --git a/libraries/animation/src/AnimSkeleton.cpp b/libraries/animation/src/AnimSkeleton.cpp index e00cad9bc7..bed9c590be 100644 --- a/libraries/animation/src/AnimSkeleton.cpp +++ b/libraries/animation/src/AnimSkeleton.cpp @@ -282,3 +282,17 @@ void AnimSkeleton::dump(const AnimPoseVec& poses) const { qCDebug(animation) << "]"; } +std::vector AnimSkeleton::lookUpJointIndices(const std::vector& jointNames) const { + std::vector result; + result.reserve(jointNames.size()); + for (auto& name : jointNames) { + int index = nameToJointIndex(name); + if (index == -1) { + qWarning(animation) << "AnimSkeleton::lookUpJointIndices(): could not find bone with named " << name; + } + result.push_back(index); + } + return result; +} + + diff --git a/libraries/animation/src/AnimSkeleton.h b/libraries/animation/src/AnimSkeleton.h index 27dbf5ea92..2ebf3f4f5d 100644 --- a/libraries/animation/src/AnimSkeleton.h +++ b/libraries/animation/src/AnimSkeleton.h @@ -61,6 +61,8 @@ public: void dump(bool verbose) const; void dump(const AnimPoseVec& poses) const; + std::vector lookUpJointIndices(const std::vector& jointNames) const; + protected: void buildSkeletonFromJoints(const std::vector& joints); diff --git a/libraries/animation/src/AnimStateMachine.cpp b/libraries/animation/src/AnimStateMachine.cpp index 4e86b92c0b..ca2bad88ea 100644 --- a/libraries/animation/src/AnimStateMachine.cpp +++ b/libraries/animation/src/AnimStateMachine.cpp @@ -21,7 +21,7 @@ AnimStateMachine::~AnimStateMachine() { } -const AnimPoseVec& AnimStateMachine::evaluate(const AnimVariantMap& animVars, const AnimContext& context, float dt, Triggers& triggersOut) { +const AnimPoseVec& AnimStateMachine::evaluate(const AnimVariantMap& animVars, const AnimContext& context, float dt, AnimVariantMap& triggersOut) { QString desiredStateID = animVars.lookup(_currentStateVar, _currentState->getID()); if (_currentState->getID() != desiredStateID) { @@ -81,6 +81,9 @@ const AnimPoseVec& AnimStateMachine::evaluate(const AnimVariantMap& animVars, co if (!_duringInterp) { _poses = currentStateNode->evaluate(animVars, context, dt, triggersOut); } + + processOutputJoints(triggersOut); + return _poses; } @@ -107,7 +110,7 @@ void AnimStateMachine::switchState(const AnimVariantMap& animVars, const AnimCon // because dt is 0, we should not encounter any triggers const float dt = 0.0f; - Triggers triggers; + AnimVariantMap triggers; if (_interpType == InterpType::SnapshotBoth) { // snapshot previous pose. diff --git a/libraries/animation/src/AnimStateMachine.h b/libraries/animation/src/AnimStateMachine.h index 711326a9ae..7a4a28a0ef 100644 --- a/libraries/animation/src/AnimStateMachine.h +++ b/libraries/animation/src/AnimStateMachine.h @@ -113,7 +113,7 @@ public: explicit AnimStateMachine(const QString& id); virtual ~AnimStateMachine() override; - virtual const AnimPoseVec& evaluate(const AnimVariantMap& animVars, const AnimContext& context, float dt, Triggers& triggersOut) override; + virtual const AnimPoseVec& evaluate(const AnimVariantMap& animVars, const AnimContext& context, float dt, AnimVariantMap& triggersOut) override; void setCurrentStateVar(QString& currentStateVar) { _currentStateVar = currentStateVar; } diff --git a/libraries/animation/src/AnimTwoBoneIK.cpp b/libraries/animation/src/AnimTwoBoneIK.cpp new file mode 100644 index 0000000000..bab37bf728 --- /dev/null +++ b/libraries/animation/src/AnimTwoBoneIK.cpp @@ -0,0 +1,292 @@ +// +// AnimTwoBoneIK.cpp +// +// Created by Anthony J. Thibault on 5/12/18. +// Copyright (c) 2018 High Fidelity, Inc. All rights reserved. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "AnimTwoBoneIK.h" + +#include + +#include "AnimationLogging.h" +#include "AnimUtil.h" + +const float FRAMES_PER_SECOND = 30.0f; + +AnimTwoBoneIK::AnimTwoBoneIK(const QString& id, float alpha, bool enabled, float interpDuration, + const QString& baseJointName, const QString& midJointName, + const QString& tipJointName, const glm::vec3& midHingeAxis, + const QString& alphaVar, const QString& enabledVar, + const QString& endEffectorRotationVarVar, const QString& endEffectorPositionVarVar) : + AnimNode(AnimNode::Type::TwoBoneIK, id), + _alpha(alpha), + _enabled(enabled), + _interpDuration(interpDuration), + _baseJointName(baseJointName), + _midJointName(midJointName), + _tipJointName(tipJointName), + _midHingeAxis(glm::normalize(midHingeAxis)), + _alphaVar(alphaVar), + _enabledVar(enabledVar), + _endEffectorRotationVarVar(endEffectorRotationVarVar), + _endEffectorPositionVarVar(endEffectorPositionVarVar), + _prevEndEffectorRotationVar(), + _prevEndEffectorPositionVar() +{ + +} + +AnimTwoBoneIK::~AnimTwoBoneIK() { + +} + +const AnimPoseVec& AnimTwoBoneIK::evaluate(const AnimVariantMap& animVars, const AnimContext& context, float dt, AnimVariantMap& triggersOut) { + + assert(_children.size() == 1); + if (_children.size() != 1) { + return _poses; + } + + // evalute underPoses + AnimPoseVec underPoses = _children[0]->evaluate(animVars, context, dt, triggersOut); + + // if we don't have a skeleton, or jointName lookup failed. + if (!_skeleton || _baseJointIndex == -1 || _midJointIndex == -1 || _tipJointIndex == -1 || underPoses.size() == 0) { + // pass underPoses through unmodified. + _poses = underPoses; + return _poses; + } + + // guard against size changes + if (underPoses.size() != _poses.size()) { + _poses = underPoses; + } + + const float MIN_ALPHA = 0.0f; + const float MAX_ALPHA = 1.0f; + float alpha = glm::clamp(animVars.lookup(_alphaVar, _alpha), MIN_ALPHA, MAX_ALPHA); + + // don't perform IK if we have bad indices, or alpha is zero + if (_tipJointIndex == -1 || _midJointIndex == -1 || _baseJointIndex == -1 || alpha == 0.0f) { + _poses = underPoses; + return _poses; + } + + // determine if we should interpolate + bool enabled = animVars.lookup(_enabledVar, _enabled); + if (enabled != _enabled) { + AnimChain poseChain; + poseChain.buildFromRelativePoses(_skeleton, _poses, _tipJointIndex); + if (enabled) { + beginInterp(InterpType::SnapshotToSolve, poseChain); + } else { + beginInterp(InterpType::SnapshotToUnderPoses, poseChain); + } + } + _enabled = enabled; + + // don't build chains or do IK if we are disbled & not interping. + if (_interpType == InterpType::None && !enabled) { + _poses = underPoses; + return _poses; + } + + // compute chain + AnimChain underChain; + underChain.buildFromRelativePoses(_skeleton, underPoses, _tipJointIndex); + AnimChain ikChain = underChain; + + AnimPose baseParentPose = ikChain.getAbsolutePoseFromJointIndex(_baseParentJointIndex); + AnimPose basePose = ikChain.getAbsolutePoseFromJointIndex(_baseJointIndex); + AnimPose midPose = ikChain.getAbsolutePoseFromJointIndex(_midJointIndex); + AnimPose tipPose = ikChain.getAbsolutePoseFromJointIndex(_tipJointIndex); + + QString endEffectorRotationVar = animVars.lookup(_endEffectorRotationVarVar, QString("")); + QString endEffectorPositionVar = animVars.lookup(_endEffectorPositionVarVar, QString("")); + + // if either of the endEffectorVars have changed + if ((!_prevEndEffectorRotationVar.isEmpty() && (_prevEndEffectorRotationVar != endEffectorRotationVar)) || + (!_prevEndEffectorPositionVar.isEmpty() && (_prevEndEffectorPositionVar != endEffectorPositionVar))) { + // begin interp to smooth out transition between prev and new end effector. + AnimChain poseChain; + poseChain.buildFromRelativePoses(_skeleton, _poses, _tipJointIndex); + beginInterp(InterpType::SnapshotToSolve, poseChain); + } + + // Look up end effector from animVars, make sure to convert into geom space. + // First look in the triggers then look in the animVars, so we can follow output joints underneath us in the anim graph + AnimPose targetPose(tipPose); + if (triggersOut.hasKey(endEffectorRotationVar)) { + targetPose.rot() = triggersOut.lookupRigToGeometry(endEffectorRotationVar, tipPose.rot()); + } else if (animVars.hasKey(endEffectorRotationVar)) { + targetPose.rot() = animVars.lookupRigToGeometry(endEffectorRotationVar, tipPose.rot()); + } + + if (triggersOut.hasKey(endEffectorPositionVar)) { + targetPose.trans() = triggersOut.lookupRigToGeometry(endEffectorPositionVar, tipPose.trans()); + } else if (animVars.hasKey(endEffectorRotationVar)) { + targetPose.trans() = animVars.lookupRigToGeometry(endEffectorPositionVar, tipPose.trans()); + } + + _prevEndEffectorRotationVar = endEffectorRotationVar; + _prevEndEffectorPositionVar = endEffectorPositionVar; + + glm::vec3 bicepVector = midPose.trans() - basePose.trans(); + float r0 = glm::length(bicepVector); + bicepVector = bicepVector / r0; + + glm::vec3 forearmVector = tipPose.trans() - midPose.trans(); + float r1 = glm::length(forearmVector); + forearmVector = forearmVector / r1; + + float d = glm::length(targetPose.trans() - basePose.trans()); + + float midAngle = 0.0f; + if (d < r0 + r1) { + float y = sqrtf((-d + r1 - r0) * (-d - r1 + r0) * (-d + r1 + r0) * (d + r1 + r0)) / (2.0f * d); + midAngle = PI - (acosf(y / r0) + acosf(y / r1)); + } + + // compute midJoint rotation + glm::quat relMidRot = glm::angleAxis(midAngle, _midHingeAxis); + + // insert new relative pose into the chain and rebuild it. + ikChain.setRelativePoseAtJointIndex(_midJointIndex, AnimPose(relMidRot, underPoses[_midJointIndex].trans())); + ikChain.buildDirtyAbsolutePoses(); + + // recompute tip pose after mid joint has been rotated + AnimPose newTipPose = ikChain.getAbsolutePoseFromJointIndex(_tipJointIndex); + + glm::vec3 leverArm = newTipPose.trans() - basePose.trans(); + glm::vec3 targetLine = targetPose.trans() - basePose.trans(); + + // compute delta rotation that brings leverArm parallel to targetLine + glm::vec3 axis = glm::cross(leverArm, targetLine); + float axisLength = glm::length(axis); + const float MIN_AXIS_LENGTH = 1.0e-4f; + if (axisLength > MIN_AXIS_LENGTH) { + axis /= axisLength; + float cosAngle = glm::clamp(glm::dot(leverArm, targetLine) / (glm::length(leverArm) * glm::length(targetLine)), -1.0f, 1.0f); + float angle = acosf(cosAngle); + glm::quat deltaRot = glm::angleAxis(angle, axis); + + // combine deltaRot with basePose. + glm::quat absRot = deltaRot * basePose.rot(); + + // transform result back into parent relative frame. + glm::quat relBaseRot = glm::inverse(baseParentPose.rot()) * absRot; + ikChain.setRelativePoseAtJointIndex(_baseJointIndex, AnimPose(relBaseRot, underPoses[_baseJointIndex].trans())); + } + + // recompute midJoint pose after base has been rotated. + ikChain.buildDirtyAbsolutePoses(); + AnimPose midJointPose = ikChain.getAbsolutePoseFromJointIndex(_midJointIndex); + + // transform target rotation in to parent relative frame. + glm::quat relTipRot = glm::inverse(midJointPose.rot()) * targetPose.rot(); + ikChain.setRelativePoseAtJointIndex(_tipJointIndex, AnimPose(relTipRot, underPoses[_tipJointIndex].trans())); + + // blend with the underChain + ikChain.blend(underChain, alpha); + + // start off by initializing output poses with the underPoses + _poses = underPoses; + + // apply smooth interpolation + if (_interpType != InterpType::None) { + _interpAlpha += _interpAlphaVel * dt; + + if (_interpAlpha < 1.0f) { + AnimChain interpChain; + if (_interpType == InterpType::SnapshotToUnderPoses) { + interpChain = underChain; + interpChain.blend(_snapshotChain, _interpAlpha); + } else if (_interpType == InterpType::SnapshotToSolve) { + interpChain = ikChain; + interpChain.blend(_snapshotChain, _interpAlpha); + } + // copy interpChain into _poses + interpChain.outputRelativePoses(_poses); + } else { + // interpolation complete + _interpType = InterpType::None; + } + } + + if (_interpType == InterpType::None) { + if (enabled) { + // copy chain into _poses + ikChain.outputRelativePoses(_poses); + } else { + // copy under chain into _poses + underChain.outputRelativePoses(_poses); + } + } + + if (context.getEnableDebugDrawIKTargets()) { + const vec4 RED(1.0f, 0.0f, 0.0f, 1.0f); + const vec4 GREEN(0.0f, 1.0f, 0.0f, 1.0f); + glm::mat4 rigToAvatarMat = createMatFromQuatAndPos(Quaternions::Y_180, glm::vec3()); + + glm::mat4 geomTargetMat = createMatFromQuatAndPos(targetPose.rot(), targetPose.trans()); + glm::mat4 avatarTargetMat = rigToAvatarMat * context.getGeometryToRigMatrix() * geomTargetMat; + + QString name = QString("%1_target").arg(_id); + DebugDraw::getInstance().addMyAvatarMarker(name, glmExtractRotation(avatarTargetMat), + extractTranslation(avatarTargetMat), _enabled ? GREEN : RED); + } else if (_lastEnableDebugDrawIKTargets) { + QString name = QString("%1_target").arg(_id); + DebugDraw::getInstance().removeMyAvatarMarker(name); + } + _lastEnableDebugDrawIKTargets = context.getEnableDebugDrawIKTargets(); + + if (context.getEnableDebugDrawIKChains()) { + if (_interpType == InterpType::None && enabled) { + const vec4 CYAN(0.0f, 1.0f, 1.0f, 1.0f); + ikChain.debugDraw(context.getRigToWorldMatrix() * context.getGeometryToRigMatrix(), CYAN); + } + } + + processOutputJoints(triggersOut); + + return _poses; +} + +// for AnimDebugDraw rendering +const AnimPoseVec& AnimTwoBoneIK::getPosesInternal() const { + return _poses; +} + +void AnimTwoBoneIK::setSkeletonInternal(AnimSkeleton::ConstPointer skeleton) { + AnimNode::setSkeletonInternal(skeleton); + lookUpIndices(); +} + +void AnimTwoBoneIK::lookUpIndices() { + assert(_skeleton); + + // look up bone indices by name + std::vector indices = _skeleton->lookUpJointIndices({_baseJointName, _midJointName, _tipJointName}); + + // cache the results + _baseJointIndex = indices[0]; + _midJointIndex = indices[1]; + _tipJointIndex = indices[2]; + + if (_baseJointIndex != -1) { + _baseParentJointIndex = _skeleton->getParentIndex(_baseJointIndex); + } +} + +void AnimTwoBoneIK::beginInterp(InterpType interpType, const AnimChain& chain) { + // capture the current poses in a snapshot. + _snapshotChain = chain; + + _interpType = interpType; + _interpAlphaVel = FRAMES_PER_SECOND / _interpDuration; + _interpAlpha = 0.0f; +} diff --git a/libraries/animation/src/AnimTwoBoneIK.h b/libraries/animation/src/AnimTwoBoneIK.h new file mode 100644 index 0000000000..23bc02a662 --- /dev/null +++ b/libraries/animation/src/AnimTwoBoneIK.h @@ -0,0 +1,83 @@ +// +// AnimTwoBoneIK.h +// +// Created by Anthony J. Thibault on 5/12/18. +// Copyright (c) 2018 High Fidelity, Inc. All rights reserved. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_AnimTwoBoneIK_h +#define hifi_AnimTwoBoneIK_h + +#include "AnimNode.h" +#include "AnimChain.h" + +// Simple two bone IK chain +class AnimTwoBoneIK : public AnimNode { +public: + friend class AnimTests; + + AnimTwoBoneIK(const QString& id, float alpha, bool enabled, float interpDuration, + const QString& baseJointName, const QString& midJointName, + const QString& tipJointName, const glm::vec3& midHingeAxis, + const QString& alphaVar, const QString& enabledVar, + const QString& endEffectorRotationVarVar, const QString& endEffectorPositionVarVar); + virtual ~AnimTwoBoneIK() override; + + virtual const AnimPoseVec& evaluate(const AnimVariantMap& animVars, const AnimContext& context, float dt, AnimVariantMap& triggersOut) override; + +protected: + + enum class InterpType { + None = 0, + SnapshotToUnderPoses, + SnapshotToSolve, + NumTypes + }; + + // for AnimDebugDraw rendering + virtual const AnimPoseVec& getPosesInternal() const override; + virtual void setSkeletonInternal(AnimSkeleton::ConstPointer skeleton) override; + + void lookUpIndices(); + void beginInterp(InterpType interpType, const AnimChain& chain); + + AnimPoseVec _poses; + + float _alpha; + bool _enabled; + float _interpDuration; // in frames (1/30 sec) + QString _baseJointName; + QString _midJointName; + QString _tipJointName; + glm::vec3 _midHingeAxis; // in baseJoint relative frame, should be normalized + + int _baseParentJointIndex { -1 }; + int _baseJointIndex { -1 }; + int _midJointIndex { -1 }; + int _tipJointIndex { -1 }; + + QString _alphaVar; // float - (0, 1) 0 means underPoses only, 1 means IK only. + QString _enabledVar; // bool + QString _endEffectorRotationVarVar; // string + QString _endEffectorPositionVarVar; // string + + QString _prevEndEffectorRotationVar; + QString _prevEndEffectorPositionVar; + + InterpType _interpType { InterpType::None }; + float _interpAlphaVel { 0.0f }; + float _interpAlpha { 0.0f }; + + AnimChain _snapshotChain; + + bool _lastEnableDebugDrawIKTargets { false }; + + // no copies + AnimTwoBoneIK(const AnimTwoBoneIK&) = delete; + AnimTwoBoneIK& operator=(const AnimTwoBoneIK&) = delete; +}; + +#endif // hifi_AnimTwoBoneIK_h diff --git a/libraries/animation/src/AnimUtil.cpp b/libraries/animation/src/AnimUtil.cpp index acb90126fc..00c1f32c5a 100644 --- a/libraries/animation/src/AnimUtil.cpp +++ b/libraries/animation/src/AnimUtil.cpp @@ -53,7 +53,7 @@ glm::quat averageQuats(size_t numQuats, const glm::quat* quats) { } float accumulateTime(float startFrame, float endFrame, float timeScale, float currentFrame, float dt, bool loopFlag, - const QString& id, AnimNode::Triggers& triggersOut) { + const QString& id, AnimVariantMap& triggersOut) { const float EPSILON = 0.0001f; float frame = currentFrame; @@ -79,12 +79,12 @@ float accumulateTime(float startFrame, float endFrame, float timeScale, float cu if (framesRemaining >= framesTillEnd) { if (loopFlag) { // anim loop - triggersOut.push_back(id + "OnLoop"); + triggersOut.setTrigger(id + "OnLoop"); framesRemaining -= framesTillEnd; frame = clampedStartFrame; } else { // anim end - triggersOut.push_back(id + "OnDone"); + triggersOut.setTrigger(id + "OnDone"); frame = endFrame; framesRemaining = 0.0f; } diff --git a/libraries/animation/src/AnimUtil.h b/libraries/animation/src/AnimUtil.h index 3cd7f4b6fb..9300f1a7a0 100644 --- a/libraries/animation/src/AnimUtil.h +++ b/libraries/animation/src/AnimUtil.h @@ -19,7 +19,7 @@ void blend(size_t numPoses, const AnimPose* a, const AnimPose* b, float alpha, A glm::quat averageQuats(size_t numQuats, const glm::quat* quats); float accumulateTime(float startFrame, float endFrame, float timeScale, float currentFrame, float dt, bool loopFlag, - const QString& id, AnimNode::Triggers& triggersOut); + const QString& id, AnimVariantMap& triggersOut); inline glm::quat safeLerp(const glm::quat& a, const glm::quat& b, float alpha) { // adjust signs if necessary diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index 87e33ed95d..b2f5c0148b 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -59,6 +59,21 @@ const glm::vec3 DEFAULT_RIGHT_EYE_POS(-0.3f, 0.9f, 0.0f); const glm::vec3 DEFAULT_LEFT_EYE_POS(0.3f, 0.9f, 0.0f); const glm::vec3 DEFAULT_HEAD_POS(0.0f, 0.75f, 0.0f); +static const QString LEFT_FOOT_POSITION("leftFootPosition"); +static const QString LEFT_FOOT_ROTATION("leftFootRotation"); +static const QString LEFT_FOOT_IK_POSITION_VAR("leftFootIKPositionVar"); +static const QString LEFT_FOOT_IK_ROTATION_VAR("leftFootIKRotationVar"); +static const QString MAIN_STATE_MACHINE_LEFT_FOOT_ROTATION("mainStateMachineLeftFootRotation"); +static const QString MAIN_STATE_MACHINE_LEFT_FOOT_POSITION("mainStateMachineLeftFootPosition"); + +static const QString RIGHT_FOOT_POSITION("rightFootPosition"); +static const QString RIGHT_FOOT_ROTATION("rightFootRotation"); +static const QString RIGHT_FOOT_IK_POSITION_VAR("rightFootIKPositionVar"); +static const QString RIGHT_FOOT_IK_ROTATION_VAR("rightFootIKRotationVar"); +static const QString MAIN_STATE_MACHINE_RIGHT_FOOT_ROTATION("mainStateMachineRightFootRotation"); +static const QString MAIN_STATE_MACHINE_RIGHT_FOOT_POSITION("mainStateMachineRightFootPosition"); + + Rig::Rig() { // Ensure thread-safe access to the rigRegistry. std::lock_guard guard(rigRegistryMutex); @@ -1049,7 +1064,7 @@ void Rig::updateAnimations(float deltaTime, const glm::mat4& rootTransform, cons getGeometryToRigTransform(), rigToWorldTransform); // evaluate the animation - AnimNode::Triggers triggersOut; + AnimVariantMap triggersOut; _internalPoseSet._relativePoses = _animNode->evaluate(_animVars, context, deltaTime, triggersOut); if ((int)_internalPoseSet._relativePoses.size() != _animSkeleton->getNumJoints()) { @@ -1057,9 +1072,7 @@ void Rig::updateAnimations(float deltaTime, const glm::mat4& rootTransform, cons _internalPoseSet._relativePoses = _animSkeleton->getRelativeDefaultPoses(); } _animVars.clearTriggers(); - for (auto& trigger : triggersOut) { - _animVars.setTrigger(trigger); - } + _animVars = triggersOut; } applyOverridePoses(); buildAbsoluteRigPoses(_internalPoseSet._relativePoses, _internalPoseSet._absolutePoses); @@ -1241,7 +1254,7 @@ glm::vec3 Rig::deflectHandFromTorso(const glm::vec3& handPosition, const FBXJoin } void Rig::updateHands(bool leftHandEnabled, bool rightHandEnabled, bool hipsEnabled, bool hipsEstimated, - bool leftArmEnabled, bool rightArmEnabled, float dt, + bool leftArmEnabled, bool rightArmEnabled, bool headEnabled, float dt, const AnimPose& leftHandPose, const AnimPose& rightHandPose, const FBXJointShapeInfo& hipsShapeInfo, const FBXJointShapeInfo& spineShapeInfo, const FBXJointShapeInfo& spine1ShapeInfo, const FBXJointShapeInfo& spine2ShapeInfo, @@ -1305,7 +1318,13 @@ void Rig::updateHands(bool leftHandEnabled, bool rightHandEnabled, bool hipsEnab _animVars.unset("leftHandPosition"); _animVars.unset("leftHandRotation"); - _animVars.set("leftHandType", (int)IKTarget::Type::HipsRelativeRotationAndPosition); + + if (headEnabled) { + _animVars.set("leftHandType", (int)IKTarget::Type::HipsRelativeRotationAndPosition); + } else { + // disable hand IK for desktop mode + _animVars.set("leftHandType", (int)IKTarget::Type::Unknown); + } } if (rightHandEnabled) { @@ -1364,21 +1383,41 @@ void Rig::updateHands(bool leftHandEnabled, bool rightHandEnabled, bool hipsEnab _animVars.unset("rightHandPosition"); _animVars.unset("rightHandRotation"); - _animVars.set("rightHandType", (int)IKTarget::Type::HipsRelativeRotationAndPosition); + + if (headEnabled) { + _animVars.set("rightHandType", (int)IKTarget::Type::HipsRelativeRotationAndPosition); + } else { + // disable hand IK for desktop mode + _animVars.set("rightHandType", (int)IKTarget::Type::Unknown); + } } } -void Rig::updateFeet(bool leftFootEnabled, bool rightFootEnabled, const AnimPose& leftFootPose, const AnimPose& rightFootPose, +void Rig::updateFeet(bool leftFootEnabled, bool rightFootEnabled, bool headEnabled, + const AnimPose& leftFootPose, const AnimPose& rightFootPose, const glm::mat4& rigToSensorMatrix, const glm::mat4& sensorToRigMatrix) { - const float KNEE_POLE_VECTOR_BLEND_FACTOR = 0.95f; - int hipsIndex = indexOfJoint("Hips"); + const float KNEE_POLE_VECTOR_BLEND_FACTOR = 0.85f; + + if (headEnabled) { + // always do IK if head is enabled + _animVars.set("leftFootIKEnabled", true); + _animVars.set("rightFootIKEnabled", true); + } else { + // only do IK if we have a valid foot. + _animVars.set("leftFootIKEnabled", leftFootEnabled); + _animVars.set("rightFootIKEnabled", rightFootEnabled); + } if (leftFootEnabled) { - _animVars.set("leftFootPosition", leftFootPose.trans()); - _animVars.set("leftFootRotation", leftFootPose.rot()); - _animVars.set("leftFootType", (int)IKTarget::Type::RotationAndPosition); + + _animVars.set(LEFT_FOOT_POSITION, leftFootPose.trans()); + _animVars.set(LEFT_FOOT_ROTATION, leftFootPose.rot()); + + // We want to drive the IK directly from the trackers. + _animVars.set(LEFT_FOOT_IK_POSITION_VAR, LEFT_FOOT_POSITION); + _animVars.set(LEFT_FOOT_IK_ROTATION_VAR, LEFT_FOOT_ROTATION); int footJointIndex = _animSkeleton->nameToJointIndex("LeftFoot"); int kneeJointIndex = _animSkeleton->nameToJointIndex("LeftLeg"); @@ -1396,20 +1435,25 @@ void Rig::updateFeet(bool leftFootEnabled, bool rightFootEnabled, const AnimPose _prevLeftFootPoleVector = smoothDeltaRot * _prevLeftFootPoleVector; _animVars.set("leftFootPoleVectorEnabled", true); - _animVars.set("leftFootPoleReferenceVector", Vectors::UNIT_Z); _animVars.set("leftFootPoleVector", transformVectorFast(sensorToRigMatrix, _prevLeftFootPoleVector)); } else { - _animVars.unset("leftFootPosition"); - _animVars.unset("leftFootRotation"); - _animVars.set("leftFootType", (int)IKTarget::Type::RotationAndPosition); + // We want to drive the IK from the underlying animation. + // This gives us the ability to squat while in the HMD, without the feet from dipping under the floor. + _animVars.set(LEFT_FOOT_IK_POSITION_VAR, MAIN_STATE_MACHINE_LEFT_FOOT_POSITION); + _animVars.set(LEFT_FOOT_IK_ROTATION_VAR, MAIN_STATE_MACHINE_LEFT_FOOT_ROTATION); + + // We want to match the animated knee pose as close as possible, so don't use poleVectors _animVars.set("leftFootPoleVectorEnabled", false); _prevLeftFootPoleVectorValid = false; } if (rightFootEnabled) { - _animVars.set("rightFootPosition", rightFootPose.trans()); - _animVars.set("rightFootRotation", rightFootPose.rot()); - _animVars.set("rightFootType", (int)IKTarget::Type::RotationAndPosition); + _animVars.set(RIGHT_FOOT_POSITION, rightFootPose.trans()); + _animVars.set(RIGHT_FOOT_ROTATION, rightFootPose.rot()); + + // We want to drive the IK directly from the trackers. + _animVars.set(RIGHT_FOOT_IK_POSITION_VAR, RIGHT_FOOT_POSITION); + _animVars.set(RIGHT_FOOT_IK_ROTATION_VAR, RIGHT_FOOT_ROTATION); int footJointIndex = _animSkeleton->nameToJointIndex("RightFoot"); int kneeJointIndex = _animSkeleton->nameToJointIndex("RightLeg"); @@ -1427,13 +1471,16 @@ void Rig::updateFeet(bool leftFootEnabled, bool rightFootEnabled, const AnimPose _prevRightFootPoleVector = smoothDeltaRot * _prevRightFootPoleVector; _animVars.set("rightFootPoleVectorEnabled", true); - _animVars.set("rightFootPoleReferenceVector", Vectors::UNIT_Z); _animVars.set("rightFootPoleVector", transformVectorFast(sensorToRigMatrix, _prevRightFootPoleVector)); } else { - _animVars.unset("rightFootPosition"); - _animVars.unset("rightFootRotation"); + // We want to drive the IK from the underlying animation. + // This gives us the ability to squat while in the HMD, without the feet from dipping under the floor. + _animVars.set(RIGHT_FOOT_IK_POSITION_VAR, MAIN_STATE_MACHINE_RIGHT_FOOT_POSITION); + _animVars.set(RIGHT_FOOT_IK_ROTATION_VAR, MAIN_STATE_MACHINE_RIGHT_FOOT_ROTATION); + + // We want to match the animated knee pose as close as possible, so don't use poleVectors _animVars.set("rightFootPoleVectorEnabled", false); - _animVars.set("rightFootType", (int)IKTarget::Type::RotationAndPosition); + _prevRightFootPoleVectorValid = false; } } @@ -1467,6 +1514,10 @@ void Rig::updateEyeJoint(int index, const glm::vec3& modelTranslation, const glm deltaQuat = glm::angleAxis(glm::clamp(glm::angle(deltaQuat), -MAX_ANGLE, MAX_ANGLE), glm::axis(deltaQuat)); } + + + + // directly set absolutePose rotation _internalPoseSet._absolutePoses[index].rot() = deltaQuat * headQuat; @@ -1561,31 +1612,18 @@ bool Rig::calculateElbowPoleVector(int handIndex, int elbowIndex, int armIndex, return true; } +// returns a poleVector for the knees that is a blend of the foot and the hips. +// targetFootPose is in rig space +// result poleVector is also in rig space. glm::vec3 Rig::calculateKneePoleVector(int footJointIndex, int kneeIndex, int upLegIndex, int hipsIndex, const AnimPose& targetFootPose) const { + const float FOOT_THETA = 0.8969f; // 51.39 degrees + const glm::vec3 localFootForward(0.0f, cosf(FOOT_THETA), sinf(FOOT_THETA)); + glm::vec3 footForward = targetFootPose.rot() * localFootForward; AnimPose hipsPose = _externalPoseSet._absolutePoses[hipsIndex]; - AnimPose footPose = targetFootPose; - AnimPose kneePose = _externalPoseSet._absolutePoses[kneeIndex]; - AnimPose upLegPose = _externalPoseSet._absolutePoses[upLegIndex]; + glm::vec3 hipsForward = hipsPose.rot() * Vectors::UNIT_Z; - // ray from foot to upLeg - glm::vec3 d = glm::normalize(footPose.trans() - upLegPose.trans()); - - // form a plane normal to the hips x-axis - glm::vec3 n = hipsPose.rot() * Vectors::UNIT_X; - - // project d onto this plane - glm::vec3 dProj = d - glm::dot(d, n) * n; - - // rotate dProj by 90 degrees to get the poleVector. - glm::vec3 poleVector = glm::angleAxis(-PI / 2.0f, n) * dProj; - - // blend the foot oreintation into the pole vector - glm::quat kneeToFootDelta = footPose.rot() * glm::inverse(kneePose.rot()); - const float WRIST_POLE_ADJUST_FACTOR = 0.5f; - glm::quat poleAdjust = quatLerp(Quaternions::IDENTITY, kneeToFootDelta, WRIST_POLE_ADJUST_FACTOR); - - return glm::normalize(poleAdjust * poleVector); + return glm::normalize(lerp(hipsForward, footForward, 0.75f)); } void Rig::updateFromControllerParameters(const ControllerParameters& params, float dt) { @@ -1610,12 +1648,12 @@ void Rig::updateFromControllerParameters(const ControllerParameters& params, flo updateHead(headEnabled, hipsEnabled, params.primaryControllerPoses[PrimaryControllerType_Head]); - updateHands(leftHandEnabled, rightHandEnabled, hipsEnabled, hipsEstimated, leftArmEnabled, rightArmEnabled, dt, + updateHands(leftHandEnabled, rightHandEnabled, hipsEnabled, hipsEstimated, leftArmEnabled, rightArmEnabled, headEnabled, dt, params.primaryControllerPoses[PrimaryControllerType_LeftHand], params.primaryControllerPoses[PrimaryControllerType_RightHand], params.hipsShapeInfo, params.spineShapeInfo, params.spine1ShapeInfo, params.spine2ShapeInfo, params.rigToSensorMatrix, sensorToRigMatrix); - updateFeet(leftFootEnabled, rightFootEnabled, + updateFeet(leftFootEnabled, rightFootEnabled, headEnabled, params.primaryControllerPoses[PrimaryControllerType_LeftFoot], params.primaryControllerPoses[PrimaryControllerType_RightFoot], params.rigToSensorMatrix, sensorToRigMatrix); diff --git a/libraries/animation/src/Rig.h b/libraries/animation/src/Rig.h index 1a1337fa84..b128403a4b 100644 --- a/libraries/animation/src/Rig.h +++ b/libraries/animation/src/Rig.h @@ -75,6 +75,10 @@ public: }; struct ControllerParameters { + ControllerParameters() { + memset(primaryControllerFlags, 0, NumPrimaryControllerTypes); + memset(secondaryControllerFlags, 0, NumPrimaryControllerTypes); + } glm::mat4 rigToSensorMatrix; AnimPose primaryControllerPoses[NumPrimaryControllerTypes]; // rig space uint8_t primaryControllerFlags[NumPrimaryControllerTypes]; @@ -229,12 +233,13 @@ protected: void updateHead(bool headEnabled, bool hipsEnabled, const AnimPose& headMatrix); void updateHands(bool leftHandEnabled, bool rightHandEnabled, bool hipsEnabled, bool hipsEstimated, - bool leftArmEnabled, bool rightArmEnabled, float dt, + bool leftArmEnabled, bool rightArmEnabled, bool headEnabled, float dt, const AnimPose& leftHandPose, const AnimPose& rightHandPose, const FBXJointShapeInfo& hipsShapeInfo, const FBXJointShapeInfo& spineShapeInfo, const FBXJointShapeInfo& spine1ShapeInfo, const FBXJointShapeInfo& spine2ShapeInfo, const glm::mat4& rigToSensorMatrix, const glm::mat4& sensorToRigMatrix); - void updateFeet(bool leftFootEnabled, bool rightFootEnabled, const AnimPose& leftFootPose, const AnimPose& rightFootPose, + void updateFeet(bool leftFootEnabled, bool rightFootEnabled, bool headEnabled, + const AnimPose& leftFootPose, const AnimPose& rightFootPose, const glm::mat4& rigToSensorMatrix, const glm::mat4& sensorToRigMatrix); void updateEyeJoint(int index, const glm::vec3& modelTranslation, const glm::quat& modelRotation, const glm::vec3& lookAt, const glm::vec3& saccade); From 6a6ece89105b4cc82dadaec0656b7852e3684012 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Mon, 30 Jul 2018 11:49:44 -0700 Subject: [PATCH 16/29] Warning fixes and whitespace cleanup --- .../src/AnimPoleVectorConstraint.cpp | 1 - libraries/animation/src/Rig.cpp | 25 ++++--------------- 2 files changed, 5 insertions(+), 21 deletions(-) diff --git a/libraries/animation/src/AnimPoleVectorConstraint.cpp b/libraries/animation/src/AnimPoleVectorConstraint.cpp index 49fe05c7cf..f017fe2348 100644 --- a/libraries/animation/src/AnimPoleVectorConstraint.cpp +++ b/libraries/animation/src/AnimPoleVectorConstraint.cpp @@ -58,7 +58,6 @@ const AnimPoseVec& AnimPoleVectorConstraint::evaluate(const AnimVariantMap& anim // Look up poleVector from animVars, make sure to convert into geom space. glm::vec3 poleVector = animVars.lookupRigToGeometryVector(_poleVectorVar, Vectors::UNIT_Z); - float poleVectorLength = glm::length(poleVector); // determine if we should interpolate bool enabled = animVars.lookup(_enabledVar, _enabled); diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index b2f5c0148b..8c73da61b5 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -1514,10 +1514,6 @@ void Rig::updateEyeJoint(int index, const glm::vec3& modelTranslation, const glm deltaQuat = glm::angleAxis(glm::clamp(glm::angle(deltaQuat), -MAX_ANGLE, MAX_ANGLE), glm::axis(deltaQuat)); } - - - - // directly set absolutePose rotation _internalPoseSet._absolutePoses[index].rot() = deltaQuat * headQuat; @@ -1526,23 +1522,12 @@ void Rig::updateEyeJoint(int index, const glm::vec3& modelTranslation, const glm for (int i = 0; i < (int)children.size(); i++) { int jointIndex = children[i]; int parentIndex = _animSkeleton->getParentIndex(jointIndex); - _internalPoseSet._absolutePoses[jointIndex] = + _internalPoseSet._absolutePoses[jointIndex] = _internalPoseSet._absolutePoses[parentIndex] * _internalPoseSet._relativePoses[jointIndex]; } } } -static glm::quat quatLerp(const glm::quat& q1, const glm::quat& q2, float alpha) { - float dot = glm::dot(q1, q2); - glm::quat temp; - if (dot < 0.0f) { - temp = -q2; - } else { - temp = q2; - } - return glm::normalize(glm::lerp(q1, temp, alpha)); -} - bool Rig::calculateElbowPoleVector(int handIndex, int elbowIndex, int armIndex, int oppositeArmIndex, glm::vec3& poleVector) const { // The resulting Pole Vector is calculated as the sum of a three vectors. // The first is the vector with direction shoulder-hand. The module of this vector is inversely proportional to the strength of the resulting Pole Vector. @@ -1561,7 +1546,7 @@ bool Rig::calculateElbowPoleVector(int handIndex, int elbowIndex, int armIndex, glm::vec3 backVector = oppositeArmPose.trans() - armPose.trans(); glm::vec3 backCenter = armPose.trans() + 0.5f * backVector; - + const float OVER_BACK_HEAD_PERCENTAGE = 0.2f; glm::vec3 headCenter = backCenter + glm::vec3(0, OVER_BACK_HEAD_PERCENTAGE * backVector.length(), 0); @@ -1573,7 +1558,7 @@ bool Rig::calculateElbowPoleVector(int handIndex, int elbowIndex, int armIndex, glm::vec3 headForward = headCenter + horizontalModule * frontVector; glm::vec3 armToHead = headForward - armPose.trans(); - + float armToHandDistance = glm::length(armToHand); float armToElbowDistance = glm::length(armToElbow); float elbowToHandDistance = glm::length(elbowToHand); @@ -1584,7 +1569,7 @@ bool Rig::calculateElbowPoleVector(int handIndex, int elbowIndex, int armIndex, // How much the hand is reaching for the opposite side float oppositeProjection = glm::dot(armToHandDir, glm::normalize(backVector)); - + // Don't use pole vector when the hands are behind if (glm::dot(frontVector, armToHand) < 0 && oppositeProjection < 0.5f * armTotalDistance) { return false; @@ -1603,7 +1588,7 @@ bool Rig::calculateElbowPoleVector(int handIndex, int elbowIndex, int armIndex, const float FORWARD_CORRECTOR_WEIGHT = 3.0f; float elbowForwardTrigger = FORWARD_TRIGGER_PERCENTAGE * armToHandDistance; - + if (oppositeProjection > -elbowForwardTrigger) { float forwardAmount = FORWARD_CORRECTOR_WEIGHT * (elbowForwardTrigger + oppositeProjection); correctionVector = forwardAmount * frontVector; From 58f95bd07b39c4b62e7b3586071ee371cdbc118c Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Mon, 30 Jul 2018 13:14:32 -0700 Subject: [PATCH 17/29] assert fix --- libraries/animation/src/AnimChain.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/animation/src/AnimChain.h b/libraries/animation/src/AnimChain.h index ed88000e75..2385e0c16a 100644 --- a/libraries/animation/src/AnimChain.h +++ b/libraries/animation/src/AnimChain.h @@ -43,7 +43,7 @@ public: // iterate through the skeleton parents, from the tip to the base, copying over relativePoses into the chain. for (int jointIndex = tipIndex; jointIndex != -1; jointIndex = skeleton->getParentIndex(jointIndex)) { if (_top >= N) { - assert(chainTop < N); + assert(_top < N); // stack overflow return false; } From b420ef8cf2a1b86d6d2af3310ee6e99a1d71cd18 Mon Sep 17 00:00:00 2001 From: David Back Date: Mon, 30 Jul 2018 13:21:09 -0700 Subject: [PATCH 18/29] fix trigger clicks on vive --- .../system/libraries/entitySelectionTool.js | 39 ++++++++++++------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/scripts/system/libraries/entitySelectionTool.js b/scripts/system/libraries/entitySelectionTool.js index 8b7e892870..96dc9d676b 100644 --- a/scripts/system/libraries/entitySelectionTool.js +++ b/scripts/system/libraries/entitySelectionTool.js @@ -761,13 +761,13 @@ SelectionDisplay = (function() { // We get mouseMoveEvents from the handControllers, via handControllerPointer. // But we dont' get mousePressEvents. that.triggerMapping = Controller.newMapping(Script.resolvePath('') + '-click'); + that.triggerPressMapping = Controller.newMapping(Script.resolvePath('') + '-press'); Script.scriptEnding.connect(that.triggerMapping.disable); that.triggeredHand = NO_TRIGGER_HAND; that.triggered = function() { return that.triggeredHand !== NO_TRIGGER_HAND; } function triggerPress(hand) { - that.triggeredHand = hand; var pointingAtDesktopWindow = (hand === Controller.Standard.RightHand && SelectionManager.pointingAtDesktopWindowRight) || (hand === Controller.Standard.LeftHand && @@ -777,6 +777,7 @@ SelectionDisplay = (function() { if (pointingAtDesktopWindow || pointingAtTablet) { return; } + that.triggeredHand = hand; that.mousePressEvent({}); } function triggerRelease(hand) { @@ -791,23 +792,33 @@ SelectionDisplay = (function() { triggerPress(otherHand); } } - function makeTriggerHandler(hand) { - return function () { - // Don't allow both hands to trigger at the same time - if (that.triggered() && hand !== that.triggeredHand) { - return; - } + function handleTriggerPress(hand, triggerClicked) { + // Don't allow both hands to trigger at the same time + if (that.triggered() && hand !== that.triggeredHand) { + return; + } + if (!that.triggered() && triggerClicked) { + triggerPress(hand); + } else if (that.triggered() && !triggerClicked) { + triggerRelease(hand); + } + } + function makePressHandler(hand) { + return function (value) { var triggerClicked = hand == Controller.Standard.RightHand ? SelectionManager.triggerClickedRight : SelectionManager.triggerClickedLeft; - if (!that.triggered() && triggerClicked) { - triggerPress(hand); - } else if (that.triggered() && !triggerClicked) { - triggerRelease(hand); - } + handleTriggerPress(hand, triggerClicked); }; } - that.triggerMapping.from(Controller.Standard.RT).peek().to(makeTriggerHandler(Controller.Standard.RightHand)); - that.triggerMapping.from(Controller.Standard.LT).peek().to(makeTriggerHandler(Controller.Standard.LeftHand)); + function makeClickHandler(hand) { + return function (clicked) { + handleTriggerPress(hand, clicked); + }; + } + that.triggerPressMapping.from(Controller.Standard.RT).peek().to(makePressHandler(Controller.Standard.RightHand)); + that.triggerPressMapping.from(Controller.Standard.LT).peek().to(makePressHandler(Controller.Standard.LeftHand)); + that.triggerMapping.from(Controller.Standard.RTClick).peek().to(makeClickHandler(Controller.Standard.RightHand)); + that.triggerMapping.from(Controller.Standard.LTClick).peek().to(makeClickHandler(Controller.Standard.LeftHand)); // FUNCTION DEF(s): Intersection Check Helpers function testRayIntersect(queryRay, overlayIncludes, overlayExcludes) { From 9ec14c1f0dcfbfef3aff165da6d49c64a20673c1 Mon Sep 17 00:00:00 2001 From: Liv Erickson Date: Mon, 30 Jul 2018 18:03:26 -0700 Subject: [PATCH 19/29] update bubble context for RC 71 --- cmake/externals/serverless-content/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/externals/serverless-content/CMakeLists.txt b/cmake/externals/serverless-content/CMakeLists.txt index 8505e0bab8..21f1a2b737 100644 --- a/cmake/externals/serverless-content/CMakeLists.txt +++ b/cmake/externals/serverless-content/CMakeLists.txt @@ -4,8 +4,8 @@ set(EXTERNAL_NAME serverless-content) ExternalProject_Add( ${EXTERNAL_NAME} - URL http://cdn.highfidelity.com/content-sets/serverless-tutorial-RC69.zip - URL_MD5 e2467b08de069da7e22ec8e032435592 + URL http://cdn.highfidelity.com/content-sets/serverless-tutorial-RC70.zip + URL_MD5 84a2eedf568272a8098930427fc35f26 CONFIGURE_COMMAND "" BUILD_COMMAND "" INSTALL_COMMAND "" From 4a722a62f7a106c7603a1cb8d4e6f5ad739729f8 Mon Sep 17 00:00:00 2001 From: David Back Date: Tue, 31 Jul 2018 11:51:16 -0700 Subject: [PATCH 20/29] use click handler only, remove triggerClicked --- .../controllerModules/inEditMode.js | 25 ++--- .../system/libraries/entitySelectionTool.js | 91 ++++++------------- 2 files changed, 37 insertions(+), 79 deletions(-) diff --git a/scripts/system/controllers/controllerModules/inEditMode.js b/scripts/system/controllers/controllerModules/inEditMode.js index e6a5efc6a2..3e53d5af12 100644 --- a/scripts/system/controllers/controllerModules/inEditMode.js +++ b/scripts/system/controllers/controllerModules/inEditMode.js @@ -66,44 +66,33 @@ Script.include("/~/system/libraries/utils.js"); this.sendPickData = function(controllerData) { if (controllerData.triggerClicks[this.hand]) { + var hand = this.hand === RIGHT_HAND ? Controller.Standard.RightHand : Controller.Standard.LeftHand; if (!this.triggerClicked) { this.selectedTarget = controllerData.rayPicks[this.hand]; if (!this.selectedTarget.intersects) { Messages.sendLocalMessage("entityToolUpdates", JSON.stringify({ - method: "clearSelection" + method: "clearSelection", + hand: hand })); } - Messages.sendLocalMessage("entityToolUpdates", JSON.stringify({ - method: "triggerClicked", - clicked: true, - rightHand: this.hand === RIGHT_HAND - })); } if (this.selectedTarget.type === Picks.INTERSECTED_ENTITY) { if (!this.isTabletMaterialEntity(this.selectedTarget.objectID)) { Messages.sendLocalMessage("entityToolUpdates", JSON.stringify({ method: "selectEntity", - entityID: this.selectedTarget.objectID + entityID: this.selectedTarget.objectID, + hand: hand })); } } else if (this.selectedTarget.type === Picks.INTERSECTED_OVERLAY) { Messages.sendLocalMessage("entityToolUpdates", JSON.stringify({ method: "selectOverlay", - overlayID: this.selectedTarget.objectID + overlayID: this.selectedTarget.objectID, + hand: hand })); } this.triggerClicked = true; - } else { - if (this.triggerClicked) { - Messages.sendLocalMessage("entityToolUpdates", JSON.stringify({ - method: "triggerClicked", - clicked: false, - rightHand: this.hand === RIGHT_HAND - })); - } - - this.triggerClicked = false; } this.sendPointingAtData(controllerData); diff --git a/scripts/system/libraries/entitySelectionTool.js b/scripts/system/libraries/entitySelectionTool.js index 96dc9d676b..dedc1c4811 100644 --- a/scripts/system/libraries/entitySelectionTool.js +++ b/scripts/system/libraries/entitySelectionTool.js @@ -53,26 +53,24 @@ SelectionManager = (function() { } if (messageParsed.method === "selectEntity") { - if (wantDebug) { - print("setting selection to " + messageParsed.entityID); + if (!SelectionDisplay.triggered() || SelectionDisplay.triggeredHand === messageParsed.hand) { + if (wantDebug) { + print("setting selection to " + messageParsed.entityID); + } + that.setSelections([messageParsed.entityID]); } - that.setSelections([messageParsed.entityID]); } else if (messageParsed.method === "clearSelection") { - that.clearSelections(); + if (!SelectionDisplay.triggered() || SelectionDisplay.triggeredHand === messageParsed.hand) { + that.clearSelections(); + } } else if (messageParsed.method === "pointingAt") { - if (messageParsed.rightHand) { + if (messageParsed.hand === Controller.Standard.RightHand) { that.pointingAtDesktopWindowRight = messageParsed.desktopWindow; that.pointingAtTabletRight = messageParsed.tablet; } else { that.pointingAtDesktopWindowLeft = messageParsed.desktopWindow; that.pointingAtTabletLeft = messageParsed.tablet; } - } else if (messageParsed.method === "triggerClicked") { - if (messageParsed.rightHand) { - that.triggerClickedRight = messageParsed.clicked; - } else { - that.triggerClickedLeft = messageParsed.clicked; - } } } @@ -115,9 +113,6 @@ SelectionManager = (function() { that.pointingAtDesktopWindowRight = false; that.pointingAtTabletLeft = false; that.pointingAtTabletRight = false; - - that.triggerClickedRight = false; - that.triggerClickedLeft = false; that.saveProperties = function() { that.savedProperties = {}; @@ -761,62 +756,36 @@ SelectionDisplay = (function() { // We get mouseMoveEvents from the handControllers, via handControllerPointer. // But we dont' get mousePressEvents. that.triggerMapping = Controller.newMapping(Script.resolvePath('') + '-click'); - that.triggerPressMapping = Controller.newMapping(Script.resolvePath('') + '-press'); Script.scriptEnding.connect(that.triggerMapping.disable); that.triggeredHand = NO_TRIGGER_HAND; that.triggered = function() { return that.triggeredHand !== NO_TRIGGER_HAND; } - function triggerPress(hand) { - var pointingAtDesktopWindow = (hand === Controller.Standard.RightHand && - SelectionManager.pointingAtDesktopWindowRight) || - (hand === Controller.Standard.LeftHand && - SelectionManager.pointingAtDesktopWindowLeft); - var pointingAtTablet = (hand === Controller.Standard.RightHand && SelectionManager.pointingAtTabletRight) || - (hand === Controller.Standard.LeftHand && SelectionManager.pointingAtTabletLeft); - if (pointingAtDesktopWindow || pointingAtTablet) { - return; - } - that.triggeredHand = hand; - that.mousePressEvent({}); - } - function triggerRelease(hand) { - that.triggeredHand = NO_TRIGGER_HAND; - that.mouseReleaseEvent({}); - var otherTriggerClicked = hand == Controller.Standard.RightHand ? SelectionManager.triggerClickedLeft : - SelectionManager.triggerClickedRight; - // When one hand is released check if the other hand is clicked and should then trigger a press - if (otherTriggerClicked) { - var otherHand = hand == Controller.Standard.RightHand ? Controller.Standard.LeftHand : - Controller.Standard.RightHand; - triggerPress(otherHand); - } - } - function handleTriggerPress(hand, triggerClicked) { - // Don't allow both hands to trigger at the same time - if (that.triggered() && hand !== that.triggeredHand) { - return; - } - if (!that.triggered() && triggerClicked) { - triggerPress(hand); - } else if (that.triggered() && !triggerClicked) { - triggerRelease(hand); - } - } - function makePressHandler(hand) { - return function (value) { - var triggerClicked = hand == Controller.Standard.RightHand ? SelectionManager.triggerClickedRight : - SelectionManager.triggerClickedLeft; - handleTriggerPress(hand, triggerClicked); - }; - } function makeClickHandler(hand) { return function (clicked) { - handleTriggerPress(hand, clicked); + print("DBACK TEST makeClickHandler " + hand + " " + clicked); + // Don't allow both hands to trigger at the same time + if (that.triggered() && hand !== that.triggeredHand) { + return; + } + if (!that.triggered() && clicked) { + var pointingAtDesktopWindow = (hand === Controller.Standard.RightHand && + SelectionManager.pointingAtDesktopWindowRight) || + (hand === Controller.Standard.LeftHand && + SelectionManager.pointingAtDesktopWindowLeft); + var pointingAtTablet = (hand === Controller.Standard.RightHand && SelectionManager.pointingAtTabletRight) || + (hand === Controller.Standard.LeftHand && SelectionManager.pointingAtTabletLeft); + if (pointingAtDesktopWindow || pointingAtTablet) { + return; + } + that.triggeredHand = hand; + that.mousePressEvent({}); + } else if (that.triggered() && !clicked) { + that.triggeredHand = NO_TRIGGER_HAND; + that.mouseReleaseEvent({}); + } }; } - that.triggerPressMapping.from(Controller.Standard.RT).peek().to(makePressHandler(Controller.Standard.RightHand)); - that.triggerPressMapping.from(Controller.Standard.LT).peek().to(makePressHandler(Controller.Standard.LeftHand)); that.triggerMapping.from(Controller.Standard.RTClick).peek().to(makeClickHandler(Controller.Standard.RightHand)); that.triggerMapping.from(Controller.Standard.LTClick).peek().to(makeClickHandler(Controller.Standard.LeftHand)); From ad9ec267817865dfd3ece04344cea406d5636f9c Mon Sep 17 00:00:00 2001 From: David Back Date: Tue, 31 Jul 2018 11:53:17 -0700 Subject: [PATCH 21/29] print --- scripts/system/libraries/entitySelectionTool.js | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/system/libraries/entitySelectionTool.js b/scripts/system/libraries/entitySelectionTool.js index dedc1c4811..297ee7bb36 100644 --- a/scripts/system/libraries/entitySelectionTool.js +++ b/scripts/system/libraries/entitySelectionTool.js @@ -763,7 +763,6 @@ SelectionDisplay = (function() { } function makeClickHandler(hand) { return function (clicked) { - print("DBACK TEST makeClickHandler " + hand + " " + clicked); // Don't allow both hands to trigger at the same time if (that.triggered() && hand !== that.triggeredHand) { return; From 6e6eae2160e104731abeead52f358571107f46ea Mon Sep 17 00:00:00 2001 From: Alexander Ivash Date: Mon, 23 Jul 2018 22:17:05 +0300 Subject: [PATCH 22/29] Avatarapp: base 'SquareLabel' on button from Uit --- .../resources/qml/controls-uit/Button.qml | 3 +- interface/resources/qml/hifi/AvatarApp.qml | 26 +++++---------- .../qml/hifi/avatarapp/SquareLabel.qml | 33 ++++++++++++++----- 3 files changed, 36 insertions(+), 26 deletions(-) diff --git a/interface/resources/qml/controls-uit/Button.qml b/interface/resources/qml/controls-uit/Button.qml index caf9c9ec82..f1a6e4bb4a 100644 --- a/interface/resources/qml/controls-uit/Button.qml +++ b/interface/resources/qml/controls-uit/Button.qml @@ -20,6 +20,7 @@ Original.Button { property int color: 0 property int colorScheme: hifi.colorSchemes.light property int fontSize: hifi.fontSizes.buttonLabel + property int radius: hifi.buttons.radius property alias implicitTextWidth: buttonText.implicitWidth property string buttonGlyph: ""; property int fontCapitalization: Font.AllUppercase @@ -46,7 +47,7 @@ Original.Button { } background: Rectangle { - radius: hifi.buttons.radius + radius: control.radius border.width: (control.color === hifi.buttons.none || (control.color === hifi.buttons.noneBorderless && control.hovered) || diff --git a/interface/resources/qml/hifi/AvatarApp.qml b/interface/resources/qml/hifi/AvatarApp.qml index c74ff73c8a..b7e1adda70 100644 --- a/interface/resources/qml/hifi/AvatarApp.qml +++ b/interface/resources/qml/hifi/AvatarApp.qml @@ -476,17 +476,13 @@ Rectangle { anchors.verticalCenter: avatarNameLabel.verticalCenter glyphText: "." glyphSize: 22 - - MouseArea { - anchors.fill: parent - onClicked: { - popup.showSpecifyAvatarUrl(currentAvatar.avatarUrl, function() { - var url = popup.inputText.text; - emitSendToScript({'method' : 'applyExternalAvatar', 'avatarURL' : url}) - }, function(link) { - Qt.openUrlExternally(link); - }); - } + onClicked: { + popup.showSpecifyAvatarUrl(currentAvatar.avatarUrl, function() { + var url = popup.inputText.text; + emitSendToScript({'method' : 'applyExternalAvatar', 'avatarURL' : url}) + }, function(link) { + Qt.openUrlExternally(link); + }); } } @@ -496,12 +492,8 @@ Rectangle { glyphText: "\ue02e" visible: avatarWearablesCount !== 0 - - MouseArea { - anchors.fill: parent - onClicked: { - adjustWearables.open(currentAvatar); - } + onClicked: { + adjustWearables.open(currentAvatar); } } diff --git a/interface/resources/qml/hifi/avatarapp/SquareLabel.qml b/interface/resources/qml/hifi/avatarapp/SquareLabel.qml index 3c5463e1dd..e2c456ec04 100644 --- a/interface/resources/qml/hifi/avatarapp/SquareLabel.qml +++ b/interface/resources/qml/hifi/avatarapp/SquareLabel.qml @@ -1,25 +1,42 @@ import "../../styles-uit" +import "../../controls-uit" as HifiControlsUit import QtQuick 2.9 import QtGraphicalEffects 1.0 -ShadowRectangle { +Item { + id: root width: 44 height: 28 - AvatarAppStyle { - id: style + signal clicked(); + + HifiControlsUit.Button { + id: button + + HifiConstants { + id: hifi + } + + anchors.fill: parent + color: hifi.buttons.blue; + colorScheme: hifi.colorSchemes.light; + radius: 3 + onClicked: root.clicked(); } - gradient: Gradient { - GradientStop { position: 0.0; color: style.colors.blueHighlight } - GradientStop { position: 1.0; color: style.colors.blueAccent } + DropShadow { + id: shadow + anchors.fill: button + radius: 6 + horizontalOffset: 0 + verticalOffset: 3 + color: Qt.rgba(0, 0, 0, 0.25) + source: button } property alias glyphText: glyph.text property alias glyphRotation: glyph.rotation property alias glyphSize: glyph.size - radius: 3 - HiFiGlyphs { id: glyph color: 'white' From 74343c71d85ef37adf831e00e55ec9556170b809 Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Tue, 31 Jul 2018 22:29:53 +0200 Subject: [PATCH 23/29] CR fixes --- libraries/entities-renderer/src/EntityTreeRenderer.h | 3 --- libraries/entities/src/EntityItemID.h | 3 +++ libraries/script-engine/src/ScriptEngine.cpp | 9 +++++---- libraries/script-engine/src/ScriptEngine.h | 5 ++++- 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.h b/libraries/entities-renderer/src/EntityTreeRenderer.h index f810aa64b6..4ba1a0060b 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.h +++ b/libraries/entities-renderer/src/EntityTreeRenderer.h @@ -40,9 +40,6 @@ namespace render { namespace entities { } } -// Allow the use of std::unordered_map with QUuid keys -namespace std { template<> struct hash { size_t operator()(const EntityItemID& id) const; }; } - using EntityRenderer = render::entities::EntityRenderer; using EntityRendererPointer = render::entities::EntityRendererPointer; using EntityRendererWeakPointer = render::entities::EntityRendererWeakPointer; diff --git a/libraries/entities/src/EntityItemID.h b/libraries/entities/src/EntityItemID.h index 41a11147f8..c9ffa13941 100644 --- a/libraries/entities/src/EntityItemID.h +++ b/libraries/entities/src/EntityItemID.h @@ -45,4 +45,7 @@ QScriptValue EntityItemIDtoScriptValue(QScriptEngine* engine, const EntityItemID void EntityItemIDfromScriptValue(const QScriptValue &object, EntityItemID& properties); QVector qVectorEntityItemIDFromScriptValue(const QScriptValue& array); +// Allow the use of std::unordered_map with QUuid keys +namespace std { template<> struct hash { size_t operator()(const EntityItemID& id) const; }; } + #endif // hifi_EntityItemID_h diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index fe77e36f0c..11f61cd368 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -223,10 +223,11 @@ ScriptEngine::ScriptEngine(Context context, const QString& scriptContents, const if (_type == Type::ENTITY_CLIENT || _type == Type::ENTITY_SERVER) { QObject::connect(this, &ScriptEngine::update, this, [this]() { // process pending entity script content - if (_contentAvailableQueue.size()) { - auto pending = _contentAvailableQueue.values().toStdList(); - _contentAvailableQueue.clear(); - for (auto& args : pending) { + if (!_contentAvailableQueue.empty()) { + EntityScriptContentAvailableMap pending; + std::swap(_contentAvailableQueue, pending); + for (auto& pair : pending) { + auto& args = pair.second; entityScriptContentAvailable(args.entityID, args.scriptOrURL, args.contents, args.isURL, args.success, args.status); } } diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index 3280c2f249..1791360a45 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -12,6 +12,7 @@ #ifndef hifi_ScriptEngine_h #define hifi_ScriptEngine_h +#include #include #include @@ -80,6 +81,8 @@ struct EntityScriptContentAvailable { QString status; }; +typedef std::unordered_map EntityScriptContentAvailableMap; + typedef QList CallbackList; typedef QHash RegisteredEventHandlers; @@ -771,7 +774,7 @@ protected: QHash _entityScripts; QHash _occupiedScriptURLs; QList _deferredEntityLoads; - QMap _contentAvailableQueue; + EntityScriptContentAvailableMap _contentAvailableQueue; bool _isThreaded { false }; QScriptEngineDebugger* _debugger { nullptr }; From bbdc7ba38025fa7dfe5b0eb233bdd1e5f4c789df Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 31 Jul 2018 10:19:12 -0700 Subject: [PATCH 24/29] Fix Uuid null comparison and dangling comma in Create tool --- scripts/system/libraries/entitySelectionTool.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/system/libraries/entitySelectionTool.js b/scripts/system/libraries/entitySelectionTool.js index feaa75971c..5ce807d37c 100644 --- a/scripts/system/libraries/entitySelectionTool.js +++ b/scripts/system/libraries/entitySelectionTool.js @@ -198,12 +198,12 @@ SelectionManager = (function() { // This is mostly a heuristic - there is no perfect way to know if an entity is being // grabbed. function nonDynamicEntityIsBeingGrabbedByAvatar(properties) { - if (properties.dynamic || properties.parentID === null) { + if (properties.dynamic || Uuid.isNull(properties.parentID)) { return false; } var avatar = AvatarList.getAvatar(properties.parentID); - if (avatar.sessionUUID === null) { + if (Uuid.isNull(avatar.sessionUUID)) { return false; } @@ -271,7 +271,7 @@ SelectionManager = (function() { duplicatedEntityIDs.push({ entityID: newEntityID, - properties: properties, + properties: properties }); if (properties.parentID !== Uuid.NULL) { duplicatedChildrenWithOldParents[newEntityID] = properties.parentID; From 003e826d6072118d9fc29984d5ab72adde45244e Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Wed, 1 Aug 2018 00:23:34 +0200 Subject: [PATCH 25/29] move over definition so it could be linked in the assignment-client too --- libraries/entities-renderer/src/EntityTreeRenderer.cpp | 1 - libraries/entities/src/EntityItemID.cpp | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 129391e43a..e330427350 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -40,7 +40,6 @@ #include -size_t std::hash::operator()(const EntityItemID& id) const { return qHash(id); } std::function EntityTreeRenderer::_entitiesShouldFadeFunction; QString resolveScriptURL(const QString& scriptUrl) { diff --git a/libraries/entities/src/EntityItemID.cpp b/libraries/entities/src/EntityItemID.cpp index 3b4ca1cea0..28b8e109ca 100644 --- a/libraries/entities/src/EntityItemID.cpp +++ b/libraries/entities/src/EntityItemID.cpp @@ -69,3 +69,4 @@ QVector qVectorEntityItemIDFromScriptValue(const QScriptValue& arr return newVector; } +size_t std::hash::operator()(const EntityItemID& id) const { return qHash(id); } From acf1afea01fd90911bbf9647eaa84c9f1531c382 Mon Sep 17 00:00:00 2001 From: Liv Erickson Date: Tue, 31 Jul 2018 15:41:59 -0700 Subject: [PATCH 26/29] fix audio files playing swapped input, trying to amplify audio playback --- cmake/externals/serverless-content/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/externals/serverless-content/CMakeLists.txt b/cmake/externals/serverless-content/CMakeLists.txt index 21f1a2b737..782e50dc27 100644 --- a/cmake/externals/serverless-content/CMakeLists.txt +++ b/cmake/externals/serverless-content/CMakeLists.txt @@ -4,8 +4,8 @@ set(EXTERNAL_NAME serverless-content) ExternalProject_Add( ${EXTERNAL_NAME} - URL http://cdn.highfidelity.com/content-sets/serverless-tutorial-RC70.zip - URL_MD5 84a2eedf568272a8098930427fc35f26 + URL http://cdn.highfidelity.com/content-sets/serverless-tutorial-RC70v2.zip + URL_MD5 35fcc8e635e71d0b00a08455a2582448 CONFIGURE_COMMAND "" BUILD_COMMAND "" INSTALL_COMMAND "" From e8068fea0a2f495318ea781b0492a983af9509bd Mon Sep 17 00:00:00 2001 From: David Back Date: Tue, 31 Jul 2018 17:18:35 -0700 Subject: [PATCH 27/29] block selecting overlays with other hand --- scripts/system/edit.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/scripts/system/edit.js b/scripts/system/edit.js index 4b8abff84b..52af3e3a7e 100644 --- a/scripts/system/edit.js +++ b/scripts/system/edit.js @@ -963,13 +963,15 @@ function handleOverlaySelectionToolUpdates(channel, message, sender) { var data = JSON.parse(message); if (data.method === "selectOverlay") { - if (wantDebug) { - print("setting selection to overlay " + data.overlayID); - } - var entity = entityIconOverlayManager.findEntity(data.overlayID); + if (!selectionDisplay.triggered() || selectionDisplay.triggeredHand === data.hand) { + if (wantDebug) { + print("setting selection to overlay " + data.overlayID); + } + var entity = entityIconOverlayManager.findEntity(data.overlayID); - if (entity !== null) { - selectionManager.setSelections([entity]); + if (entity !== null) { + selectionManager.setSelections([entity]); + } } } } From fd780845bbf2e2da9260f8abfadbe8372992f581 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Tue, 31 Jul 2018 18:25:04 -0700 Subject: [PATCH 28/29] Code review feedback --- libraries/animation/src/AnimPose.cpp | 8 -------- libraries/animation/src/AnimTwoBoneIK.cpp | 1 + libraries/animation/src/AnimUtil.cpp | 8 -------- libraries/animation/src/Rig.cpp | 2 +- 4 files changed, 2 insertions(+), 17 deletions(-) diff --git a/libraries/animation/src/AnimPose.cpp b/libraries/animation/src/AnimPose.cpp index 5d1fbdd8b2..d77514e691 100644 --- a/libraries/animation/src/AnimPose.cpp +++ b/libraries/animation/src/AnimPose.cpp @@ -79,14 +79,6 @@ AnimPose::operator glm::mat4() const { } void AnimPose::blend(const AnimPose& srcPose, float alpha) { - // adjust signs if necessary - const glm::quat& q1 = srcPose._rot; - glm::quat q2 = _rot; - float dot = glm::dot(q1, q2); - if (dot < 0.0f) { - q2 = -q2; - } - _scale = lerp(srcPose._scale, _scale, alpha); _rot = safeLerp(srcPose._rot, _rot, alpha); _trans = lerp(srcPose._trans, _trans, alpha); diff --git a/libraries/animation/src/AnimTwoBoneIK.cpp b/libraries/animation/src/AnimTwoBoneIK.cpp index bab37bf728..d68240d176 100644 --- a/libraries/animation/src/AnimTwoBoneIK.cpp +++ b/libraries/animation/src/AnimTwoBoneIK.cpp @@ -145,6 +145,7 @@ const AnimPoseVec& AnimTwoBoneIK::evaluate(const AnimVariantMap& animVars, const float d = glm::length(targetPose.trans() - basePose.trans()); + // http://mathworld.wolfram.com/Circle-CircleIntersection.html float midAngle = 0.0f; if (d < r0 + r1) { float y = sqrtf((-d + r1 - r0) * (-d - r1 + r0) * (-d + r1 + r0) * (d + r1 + r0)) / (2.0f * d); diff --git a/libraries/animation/src/AnimUtil.cpp b/libraries/animation/src/AnimUtil.cpp index 00c1f32c5a..c23e228556 100644 --- a/libraries/animation/src/AnimUtil.cpp +++ b/libraries/animation/src/AnimUtil.cpp @@ -21,14 +21,6 @@ void blend(size_t numPoses, const AnimPose* a, const AnimPose* b, float alpha, A const AnimPose& aPose = a[i]; const AnimPose& bPose = b[i]; - // adjust signs if necessary - const glm::quat& q1 = aPose.rot(); - glm::quat q2 = bPose.rot(); - float dot = glm::dot(q1, q2); - if (dot < 0.0f) { - q2 = -q2; - } - result[i].scale() = lerp(aPose.scale(), bPose.scale(), alpha); result[i].rot() = safeLerp(aPose.rot(), bPose.rot(), alpha); result[i].trans() = lerp(aPose.trans(), bPose.trans(), alpha); diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index 8c73da61b5..33f14e121e 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -63,8 +63,8 @@ static const QString LEFT_FOOT_POSITION("leftFootPosition"); static const QString LEFT_FOOT_ROTATION("leftFootRotation"); static const QString LEFT_FOOT_IK_POSITION_VAR("leftFootIKPositionVar"); static const QString LEFT_FOOT_IK_ROTATION_VAR("leftFootIKRotationVar"); -static const QString MAIN_STATE_MACHINE_LEFT_FOOT_ROTATION("mainStateMachineLeftFootRotation"); static const QString MAIN_STATE_MACHINE_LEFT_FOOT_POSITION("mainStateMachineLeftFootPosition"); +static const QString MAIN_STATE_MACHINE_LEFT_FOOT_ROTATION("mainStateMachineLeftFootRotation"); static const QString RIGHT_FOOT_POSITION("rightFootPosition"); static const QString RIGHT_FOOT_ROTATION("rightFootRotation"); From 6369cee0d1aa69cd48defc0eeaf218f0b95ac4c0 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 24 Jul 2018 16:17:03 -0700 Subject: [PATCH 29/29] Fix added entities not being undoable in Create --- scripts/system/edit.js | 65 ++++++++++++++++++++++++++++-------------- 1 file changed, 43 insertions(+), 22 deletions(-) diff --git a/scripts/system/edit.js b/scripts/system/edit.js index 1c0b7c2dcb..81cafd3ec1 100644 --- a/scripts/system/edit.js +++ b/scripts/system/edit.js @@ -316,10 +316,10 @@ var toolBar = (function () { direction = Vec3.multiplyQbyV(direction, Vec3.UNIT_Z); // Align entity with Avatar orientation. properties.rotation = MyAvatar.orientation; - + var PRE_ADJUST_ENTITY_TYPES = ["Box", "Sphere", "Shape", "Text", "Web", "Material"]; if (PRE_ADJUST_ENTITY_TYPES.indexOf(properties.type) !== -1) { - + // Adjust position of entity per bounding box prior to creating it. var registration = properties.registration; if (registration === undefined) { @@ -352,7 +352,12 @@ var toolBar = (function () { properties.userData = JSON.stringify({ grabbableKey: { grabbable: false } }); } + SelectionManager.saveProperties(); entityID = Entities.addEntity(properties); + pushCommandForSelections([{ + entityID: entityID, + properties: properties + }], [], true); if (properties.type === "ParticleEffect") { selectParticleEntity(entityID); @@ -1588,7 +1593,7 @@ function deleteSelectedEntities() { Entities.deleteEntity(entityID); } } - + if (savedProperties.length > 0) { SelectionManager.clearSelections(); pushCommandForSelections([], savedProperties); @@ -1878,12 +1883,14 @@ Controller.keyReleaseEvent.connect(keyReleaseEvent); Controller.keyPressEvent.connect(keyPressEvent); function recursiveAdd(newParentID, parentData) { - var children = parentData.children; - for (var i = 0; i < children.length; i++) { - var childProperties = children[i].properties; - childProperties.parentID = newParentID; - var newChildID = Entities.addEntity(childProperties); - recursiveAdd(newChildID, children[i]); + if (parentData.children !== undefined) { + var children = parentData.children; + for (var i = 0; i < children.length; i++) { + var childProperties = children[i].properties; + childProperties.parentID = newParentID; + var newChildID = Entities.addEntity(childProperties); + recursiveAdd(newChildID, children[i]); + } } } @@ -1893,16 +1900,22 @@ function recursiveAdd(newParentID, parentData) { var DELETED_ENTITY_MAP = {}; function applyEntityProperties(data) { - var properties = data.setProperties; + var editEntities = data.editEntities; var selectedEntityIDs = []; + var selectEdits = data.createEntities.length == 0 || !data.selectCreated; var i, entityID; - for (i = 0; i < properties.length; i++) { - entityID = properties[i].entityID; + for (i = 0; i < editEntities.length; i++) { + var entityID = editEntities[i].entityID; if (DELETED_ENTITY_MAP[entityID] !== undefined) { entityID = DELETED_ENTITY_MAP[entityID]; } - Entities.editEntity(entityID, properties[i].properties); - selectedEntityIDs.push(entityID); + var entityProperties = editEntities[i].properties; + if (entityProperties !== null) { + Entities.editEntity(entityID, entityProperties); + } + if (selectEdits) { + selectedEntityIDs.push(entityID); + } } for (i = 0; i < data.createEntities.length; i++) { entityID = data.createEntities[i].entityID; @@ -1931,31 +1944,39 @@ function applyEntityProperties(data) { // For currently selected entities, push a command to the UndoStack that uses the current entity properties for the // redo command, and the saved properties for the undo command. Also, include create and delete entity data. -function pushCommandForSelections(createdEntityData, deletedEntityData) { +function pushCommandForSelections(createdEntityData, deletedEntityData, doNotSaveEditProperties) { + doNotSaveEditProperties = false; var undoData = { - setProperties: [], + editEntities: [], createEntities: deletedEntityData || [], deleteEntities: createdEntityData || [], selectCreated: true }; var redoData = { - setProperties: [], + editEntities: [], createEntities: createdEntityData || [], deleteEntities: deletedEntityData || [], - selectCreated: false + selectCreated: true }; for (var i = 0; i < SelectionManager.selections.length; i++) { var entityID = SelectionManager.selections[i]; var initialProperties = SelectionManager.savedProperties[entityID]; - var currentProperties = Entities.getEntityProperties(entityID); + var currentProperties = null; if (!initialProperties) { continue; } - undoData.setProperties.push({ + + if (doNotSaveEditProperties) { + initialProperties = null; + } else { + currentProperties = Entities.getEntityProperties(entityID); + } + + undoData.editEntities.push({ entityID: entityID, properties: initialProperties }); - redoData.setProperties.push({ + redoData.editEntities.push({ entityID: entityID, properties: currentProperties }); @@ -2227,7 +2248,7 @@ var PropertiesTool = function (opts) { updateSelections(true); } }; - + createToolsWindow.webEventReceived.addListener(this, onWebEventReceived); webView.webEventReceived.connect(onWebEventReceived);