From e88207a73e2b714e4efe36e2b7c00dfdba83b12f Mon Sep 17 00:00:00 2001 From: Simon Walton Date: Fri, 29 Jun 2018 11:34:22 -0700 Subject: [PATCH 01/75] Move script-engine creation to run thread ScriptsModel should be created and destroyed on same thread, or else crash on Windows occurs. See https://github.com/highfidelity/hifi/pull/13492 --- assignment-client/src/Agent.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 42924a8487..956b1d88de 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -76,12 +76,6 @@ Agent::Agent(ReceivedMessage& message) : DependencyManager::set(); DependencyManager::set(); - DependencyManager::set(); - DependencyManager::set(ScriptEngine::AGENT_SCRIPT); - - DependencyManager::set(); - DependencyManager::set(); - // Needed to ensure the creation of the DebugDraw instance on the main thread DebugDraw::getInstance(); @@ -157,6 +151,11 @@ void Agent::handleAudioPacket(QSharedPointer message) { static const QString AGENT_LOGGING_NAME = "agent"; void Agent::run() { + DependencyManager::set(); + DependencyManager::set(ScriptEngine::AGENT_SCRIPT); + + DependencyManager::set(); + DependencyManager::set(); // make sure we request our script once the agent connects to the domain auto nodeList = DependencyManager::get(); From 2b997ec159c622c45a19f66bc54c5914948d9026 Mon Sep 17 00:00:00 2001 From: Simon Walton Date: Thu, 5 Jul 2018 14:43:34 -0700 Subject: [PATCH 02/75] Don't reference Agent members after scriptEngine returns The Agent calls the script engine execute loop, which calls the Qt event processor, which may delete the Agent via deleteLater(). Take out unnecessary call to setFinished() to avoid crash. Probably this was a latent bug exposed by the eralier PR changes. --- assignment-client/src/Agent.cpp | 3 +-- libraries/script-engine/src/ScriptEngine.cpp | 3 ++- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 956b1d88de..9a5d69f64b 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -494,8 +494,6 @@ void Agent::executeScript() { Frame::clearFrameHandler(AVATAR_FRAME_TYPE); DependencyManager::destroy(); - - setFinished(true); } QUuid Agent::getSessionUUID() const { @@ -829,6 +827,7 @@ void Agent::aboutToFinish() { // our entity tree is going to go away so tell that to the EntityScriptingInterface DependencyManager::get()->setEntityTree(nullptr); + DependencyManager::get()->setPacketSender(nullptr); DependencyManager::get()->cleanup(); diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 99c02ba1f6..97364a6119 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -1199,7 +1199,8 @@ void ScriptEngine::run() { stopAllTimers(); // make sure all our timers are stopped if the script is ending emit scriptEnding(); - if (entityScriptingInterface->getEntityPacketSender()->serversExist()) { + if (entityScriptingInterface->getEntityPacketSender() && + entityScriptingInterface->getEntityPacketSender()->serversExist()) { // release the queue of edit entity messages. entityScriptingInterface->getEntityPacketSender()->releaseQueuedMessages(); From 363f27cb032728b0cbb4d452b924485ecacc5c3f Mon Sep 17 00:00:00 2001 From: Simon Walton Date: Fri, 6 Jul 2018 10:27:20 -0700 Subject: [PATCH 03/75] Run Agent script on its own thread Uses ScriptEngine::runInThread() so that on takedown the Agent is not deleted under its own executeScript() method. --- assignment-client/src/Agent.cpp | 13 +++++++------ libraries/script-engine/src/ScriptEngine.cpp | 3 +-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 9a5d69f64b..7398e70634 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -488,12 +488,13 @@ void Agent::executeScript() { avatarDataTimer->setTimerType(Qt::PreciseTimer); avatarDataTimer->start(); - _scriptEngine->run(); + connect(_scriptEngine.data(), &ScriptEngine::doneRunning, this, [=]() { + Frame::clearFrameHandler(AUDIO_FRAME_TYPE); + Frame::clearFrameHandler(AVATAR_FRAME_TYPE); + DependencyManager::destroy(); + setFinished(true); }); - Frame::clearFrameHandler(AUDIO_FRAME_TYPE); - Frame::clearFrameHandler(AVATAR_FRAME_TYPE); - - DependencyManager::destroy(); + _scriptEngine->runInThread(); } QUuid Agent::getSessionUUID() const { @@ -823,11 +824,11 @@ void Agent::aboutToFinish() { if (_scriptEngine) { _scriptEngine->stop(); + _scriptEngine->waitTillDoneRunning(); } // our entity tree is going to go away so tell that to the EntityScriptingInterface DependencyManager::get()->setEntityTree(nullptr); - DependencyManager::get()->setPacketSender(nullptr); DependencyManager::get()->cleanup(); diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 97364a6119..99c02ba1f6 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -1199,8 +1199,7 @@ void ScriptEngine::run() { stopAllTimers(); // make sure all our timers are stopped if the script is ending emit scriptEnding(); - if (entityScriptingInterface->getEntityPacketSender() && - entityScriptingInterface->getEntityPacketSender()->serversExist()) { + if (entityScriptingInterface->getEntityPacketSender()->serversExist()) { // release the queue of edit entity messages. entityScriptingInterface->getEntityPacketSender()->releaseQueuedMessages(); From 000423673e8ccec268e652c356d6771595225ea9 Mon Sep 17 00:00:00 2001 From: Simon Walton Date: Mon, 9 Jul 2018 13:30:44 -0700 Subject: [PATCH 04/75] Don't explicitly destroy script engine; emit finished when actually finished --- assignment-client/src/Agent.cpp | 2 +- libraries/networking/src/ThreadedAssignment.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 42924a8487..caa087e120 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -497,6 +497,7 @@ void Agent::executeScript() { DependencyManager::destroy(); setFinished(true); + emit finished(); } QUuid Agent::getSessionUUID() const { @@ -838,7 +839,6 @@ void Agent::aboutToFinish() { // destroy all other created dependencies DependencyManager::destroy(); - DependencyManager::destroy(); DependencyManager::destroy(); DependencyManager::destroy(); diff --git a/libraries/networking/src/ThreadedAssignment.cpp b/libraries/networking/src/ThreadedAssignment.cpp index 9a69d9b3d8..ad1fc83c65 100644 --- a/libraries/networking/src/ThreadedAssignment.cpp +++ b/libraries/networking/src/ThreadedAssignment.cpp @@ -67,7 +67,7 @@ void ThreadedAssignment::setFinished(bool isFinished) { // call our virtual aboutToFinish method - this gives the ThreadedAssignment subclass a chance to cleanup aboutToFinish(); - emit finished(); + //emit finished(); } } } From 9505f5c6feeec338ecbf9bd61dc09be08b90c386 Mon Sep 17 00:00:00 2001 From: Simon Walton Date: Mon, 9 Jul 2018 13:38:17 -0700 Subject: [PATCH 05/75] Revert current approach --- assignment-client/src/Agent.cpp | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 7398e70634..42924a8487 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -76,6 +76,12 @@ Agent::Agent(ReceivedMessage& message) : DependencyManager::set(); DependencyManager::set(); + DependencyManager::set(); + DependencyManager::set(ScriptEngine::AGENT_SCRIPT); + + DependencyManager::set(); + DependencyManager::set(); + // Needed to ensure the creation of the DebugDraw instance on the main thread DebugDraw::getInstance(); @@ -151,11 +157,6 @@ void Agent::handleAudioPacket(QSharedPointer message) { static const QString AGENT_LOGGING_NAME = "agent"; void Agent::run() { - DependencyManager::set(); - DependencyManager::set(ScriptEngine::AGENT_SCRIPT); - - DependencyManager::set(); - DependencyManager::set(); // make sure we request our script once the agent connects to the domain auto nodeList = DependencyManager::get(); @@ -488,13 +489,14 @@ void Agent::executeScript() { avatarDataTimer->setTimerType(Qt::PreciseTimer); avatarDataTimer->start(); - connect(_scriptEngine.data(), &ScriptEngine::doneRunning, this, [=]() { - Frame::clearFrameHandler(AUDIO_FRAME_TYPE); - Frame::clearFrameHandler(AVATAR_FRAME_TYPE); - DependencyManager::destroy(); - setFinished(true); }); + _scriptEngine->run(); - _scriptEngine->runInThread(); + Frame::clearFrameHandler(AUDIO_FRAME_TYPE); + Frame::clearFrameHandler(AVATAR_FRAME_TYPE); + + DependencyManager::destroy(); + + setFinished(true); } QUuid Agent::getSessionUUID() const { @@ -824,7 +826,6 @@ void Agent::aboutToFinish() { if (_scriptEngine) { _scriptEngine->stop(); - _scriptEngine->waitTillDoneRunning(); } // our entity tree is going to go away so tell that to the EntityScriptingInterface From 1c23fc75a476879c9c5f5967f54109eeea544420 Mon Sep 17 00:00:00 2001 From: Simon Walton Date: Mon, 9 Jul 2018 16:56:54 -0700 Subject: [PATCH 06/75] Emit finished signal from AC derived classes To avoid Agent destruction-in-use move emit finished from setFinished to Agent methods. For other ACs emit from aboutToFinish(). --- assignment-client/src/Agent.cpp | 2 ++ assignment-client/src/assets/AssetServer.cpp | 1 + assignment-client/src/entities/EntityServer.cpp | 2 ++ assignment-client/src/scripts/EntityScriptServer.cpp | 2 ++ libraries/networking/src/ThreadedAssignment.cpp | 2 -- libraries/networking/src/ThreadedAssignment.h | 2 +- 6 files changed, 8 insertions(+), 3 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index caa087e120..1b36cd7207 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -335,6 +335,7 @@ void Agent::scriptRequestFinished() { } setFinished(true); + emit finished(); } request->deleteLater(); @@ -839,6 +840,7 @@ void Agent::aboutToFinish() { // destroy all other created dependencies DependencyManager::destroy(); + DependencyManager::destroy(); DependencyManager::destroy(); DependencyManager::destroy(); diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index e0c35b7148..7999d55fae 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -342,6 +342,7 @@ void AssetServer::aboutToFinish() { while (_pendingBakes.size() > 0) { QCoreApplication::processEvents(); } + emit finished(); } void AssetServer::run() { diff --git a/assignment-client/src/entities/EntityServer.cpp b/assignment-client/src/entities/EntityServer.cpp index 8b86ba5eb2..4162a4f156 100644 --- a/assignment-client/src/entities/EntityServer.cpp +++ b/assignment-client/src/entities/EntityServer.cpp @@ -72,6 +72,8 @@ void EntityServer::aboutToFinish() { DependencyManager::get()->cleanup(); OctreeServer::aboutToFinish(); + + emit finished(); } void EntityServer::handleEntityPacket(QSharedPointer message, SharedNodePointer senderNode) { diff --git a/assignment-client/src/scripts/EntityScriptServer.cpp b/assignment-client/src/scripts/EntityScriptServer.cpp index eea8e8b470..6198b03fbe 100644 --- a/assignment-client/src/scripts/EntityScriptServer.cpp +++ b/assignment-client/src/scripts/EntityScriptServer.cpp @@ -582,4 +582,6 @@ void EntityScriptServer::aboutToFinish() { _codec->releaseEncoder(_encoder); _encoder = nullptr; } + + emit finished(); } diff --git a/libraries/networking/src/ThreadedAssignment.cpp b/libraries/networking/src/ThreadedAssignment.cpp index ad1fc83c65..d6c09d2a6c 100644 --- a/libraries/networking/src/ThreadedAssignment.cpp +++ b/libraries/networking/src/ThreadedAssignment.cpp @@ -66,8 +66,6 @@ void ThreadedAssignment::setFinished(bool isFinished) { // call our virtual aboutToFinish method - this gives the ThreadedAssignment subclass a chance to cleanup aboutToFinish(); - - //emit finished(); } } } diff --git a/libraries/networking/src/ThreadedAssignment.h b/libraries/networking/src/ThreadedAssignment.h index 9372cfa667..f245ec917f 100644 --- a/libraries/networking/src/ThreadedAssignment.h +++ b/libraries/networking/src/ThreadedAssignment.h @@ -25,7 +25,7 @@ public: ~ThreadedAssignment() { stop(); } void setFinished(bool isFinished); - virtual void aboutToFinish() { }; + virtual void aboutToFinish() { emit finished(); }; void addPacketStatsAndSendStatsPacket(QJsonObject statsObject); public slots: From 2c629e2ec8fefde1e48ade09e4efe44a93666d82 Mon Sep 17 00:00:00 2001 From: Simon Walton Date: Mon, 9 Jul 2018 17:38:39 -0700 Subject: [PATCH 07/75] Don't destroy ScriptEngines in aboutToFinish() --- assignment-client/src/Agent.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 1b36cd7207..6a637223fe 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -840,7 +840,6 @@ void Agent::aboutToFinish() { // destroy all other created dependencies DependencyManager::destroy(); - DependencyManager::destroy(); DependencyManager::destroy(); DependencyManager::destroy(); From a305a6a534ba514d40a2bba85496f022f2df8139 Mon Sep 17 00:00:00 2001 From: Simon Walton Date: Thu, 12 Jul 2018 16:48:41 -0700 Subject: [PATCH 08/75] Emit finished in Agent::aboutToFinish() if script execution hasn't started yet --- assignment-client/src/Agent.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 6a637223fe..1cbe1f66ed 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -828,6 +828,8 @@ void Agent::aboutToFinish() { if (_scriptEngine) { _scriptEngine->stop(); + } else { + emit finished(); } // our entity tree is going to go away so tell that to the EntityScriptingInterface From ab4faca2fd4ad609bed961c4876050b11022f6bf Mon Sep 17 00:00:00 2001 From: Simon Walton Date: Fri, 13 Jul 2018 11:18:28 -0700 Subject: [PATCH 09/75] Emit finished() in new AudioMixer::aboutToFinish(). --- assignment-client/src/audio/AudioMixer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index d56b22466e..2db5a296f7 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -109,6 +109,7 @@ AudioMixer::AudioMixer(ReceivedMessage& message) : void AudioMixer::aboutToFinish() { DependencyManager::destroy(); + emit finished(); } void AudioMixer::queueAudioPacket(QSharedPointer message, SharedNodePointer node) { From b60ea1f6a28f5a67b60928872f12185a53d1f9b3 Mon Sep 17 00:00:00 2001 From: Simon Walton Date: Mon, 16 Jul 2018 18:25:46 -0700 Subject: [PATCH 10/75] Fixes from reviewer Call base version from aboutToFinish(); add comment for script-engine logic. --- assignment-client/src/Agent.cpp | 8 +++++--- assignment-client/src/assets/AssetServer.cpp | 2 +- assignment-client/src/audio/AudioMixer.cpp | 2 +- assignment-client/src/entities/EntityServer.cpp | 3 +-- assignment-client/src/scripts/EntityScriptServer.cpp | 2 +- 5 files changed, 9 insertions(+), 8 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index ca2cf30d68..0be691662d 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -336,7 +336,7 @@ void Agent::scriptRequestFinished() { } setFinished(true); - emit finished(); + ThreadedAssignment::aboutToFinish(); } request->deleteLater(); @@ -499,7 +499,7 @@ void Agent::executeScript() { DependencyManager::destroy(); setFinished(true); - emit finished(); + ThreadedAssignment::aboutToFinish(); } QUuid Agent::getSessionUUID() const { @@ -827,10 +827,12 @@ void Agent::processAgentAvatarAudio() { void Agent::aboutToFinish() { setIsAvatar(false);// will stop timers for sending identity packets + // If script engine not started yet then finish up, else will be done when + // script engine exits. if (_scriptEngine) { _scriptEngine->stop(); } else { - emit finished(); + ThreadedAssignment::aboutToFinish(); } // our entity tree is going to go away so tell that to the EntityScriptingInterface diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 7999d55fae..4ff4078255 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -342,7 +342,7 @@ void AssetServer::aboutToFinish() { while (_pendingBakes.size() > 0) { QCoreApplication::processEvents(); } - emit finished(); + ThreadedAssignment::aboutToFinish(); } void AssetServer::run() { diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 2db5a296f7..ec9f26b53c 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -109,7 +109,7 @@ AudioMixer::AudioMixer(ReceivedMessage& message) : void AudioMixer::aboutToFinish() { DependencyManager::destroy(); - emit finished(); + ThreadedAssignment::aboutToFinish(); } void AudioMixer::queueAudioPacket(QSharedPointer message, SharedNodePointer node) { diff --git a/assignment-client/src/entities/EntityServer.cpp b/assignment-client/src/entities/EntityServer.cpp index 4162a4f156..6303cafde8 100644 --- a/assignment-client/src/entities/EntityServer.cpp +++ b/assignment-client/src/entities/EntityServer.cpp @@ -72,8 +72,7 @@ void EntityServer::aboutToFinish() { DependencyManager::get()->cleanup(); OctreeServer::aboutToFinish(); - - emit finished(); + ThreadedAssignment::aboutToFinish(); } void EntityServer::handleEntityPacket(QSharedPointer message, SharedNodePointer senderNode) { diff --git a/assignment-client/src/scripts/EntityScriptServer.cpp b/assignment-client/src/scripts/EntityScriptServer.cpp index a1258fe8db..b40ffbcfb3 100644 --- a/assignment-client/src/scripts/EntityScriptServer.cpp +++ b/assignment-client/src/scripts/EntityScriptServer.cpp @@ -588,5 +588,5 @@ void EntityScriptServer::aboutToFinish() { _encoder = nullptr; } - emit finished(); + ThreadedAssignment::aboutToFinish(); } From 5e624246a8d517ba5a2a41d4dc68f0cdb43812e3 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 19 Jul 2018 13:00:57 +1200 Subject: [PATCH 11/75] 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 12/75] 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 13/75] 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 14/75] 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 15/75] 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 47e99cdeacbc2023fd0762669e22bb644ee3df18 Mon Sep 17 00:00:00 2001 From: Simon Walton Date: Tue, 24 Jul 2018 16:50:37 -0700 Subject: [PATCH 16/75] Initial code for AC side of Enabling Physics plan When interface sets query flag send only entities close to main frustrum origin, until no more available, then send unreliabe sequence # reliably. --- .../src/entities/EntityTreeSendThread.cpp | 9 ++++ .../src/entities/EntityTreeSendThread.h | 2 + .../src/octree/OctreeSendThread.cpp | 30 +++++++---- .../src/octree/OctreeSendThread.h | 1 + interface/src/Application.cpp | 1 + .../networking/src/udt/PacketHeaders.cpp | 2 +- libraries/networking/src/udt/PacketHeaders.h | 1 + libraries/octree/src/OctreeQuery.cpp | 19 ++++++- libraries/octree/src/OctreeQuery.h | 8 +++ .../shared/src/shared/ConicalViewFrustum.cpp | 5 ++ .../shared/src/shared/ConicalViewFrustum.h | 3 ++ tools/dissectors/1-hfudt.lua | 51 +++++++++++++++++-- 12 files changed, 116 insertions(+), 16 deletions(-) diff --git a/assignment-client/src/entities/EntityTreeSendThread.cpp b/assignment-client/src/entities/EntityTreeSendThread.cpp index f008ef9925..af0c09aec7 100644 --- a/assignment-client/src/entities/EntityTreeSendThread.cpp +++ b/assignment-client/src/entities/EntityTreeSendThread.cpp @@ -17,6 +17,8 @@ #include "EntityServer.h" +// Initially just send all items within this distance. +const float EntityTreeSendThread::INITIAL_RADIUS = 50.0f; EntityTreeSendThread::EntityTreeSendThread(OctreeServer* myServer, const SharedNodePointer& node) : OctreeSendThread(myServer, node) @@ -112,6 +114,13 @@ void EntityTreeSendThread::traverseTreeAndSendContents(SharedNodePointer node, O int32_t lodLevelOffset = nodeData->getBoundaryLevelAdjust() + (viewFrustumChanged ? LOW_RES_MOVING_ADJUST : NO_BOUNDARY_ADJUST); newView.lodScaleFactor = powf(2.0f, lodLevelOffset); + if (nodeData->wantReportInitialResult() && !newView.viewFrustums.empty()) { + auto& mainView = newView.viewFrustums[0]; + // Force acceptance within INITIAL_RADIUS. + mainView.setSimpleRadius(INITIAL_RADIUS); + newView.lodScaleFactor = 0.0f; + } + startNewTraversal(newView, root); // When the viewFrustum changed the sort order may be incorrect, so we re-sort diff --git a/assignment-client/src/entities/EntityTreeSendThread.h b/assignment-client/src/entities/EntityTreeSendThread.h index 1305d7bfc7..8c66f47aea 100644 --- a/assignment-client/src/entities/EntityTreeSendThread.h +++ b/assignment-client/src/entities/EntityTreeSendThread.h @@ -58,6 +58,8 @@ private: int32_t _numEntitiesOffset { 0 }; uint16_t _numEntities { 0 }; + const static float INITIAL_RADIUS; + private slots: void editingEntityPointer(const EntityItemPointer& entity); void deletingEntityPointer(EntityItem* entity); diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index e9aa44b970..98b06d6344 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -195,6 +195,7 @@ int OctreeSendThread::handlePacketSend(SharedNodePointer node, OctreeQueryNode* // actually send it OctreeServer::didCallWriteDatagram(this); DependencyManager::get()->sendUnreliablePacket(statsPacket, *node); + _lastSequenceNumber = (decltype(_lastSequenceNumber)) statsPacket.getSequenceNumber(); } else { // not enough room in the packet, send two packets @@ -211,10 +212,9 @@ int OctreeSendThread::handlePacketSend(SharedNodePointer node, OctreeQueryNode* //_totalWastedBytes += 0; _trueBytesSent += numBytes; numPackets++; + NLPacket& sentPacket = nodeData->getPacket(); if (debug) { - NLPacket& sentPacket = nodeData->getPacket(); - sentPacket.seek(sizeof(OCTREE_PACKET_FLAGS)); OCTREE_PACKET_SEQUENCE sequence; @@ -231,9 +231,10 @@ int OctreeSendThread::handlePacketSend(SharedNodePointer node, OctreeQueryNode* // second packet OctreeServer::didCallWriteDatagram(this); - DependencyManager::get()->sendUnreliablePacket(nodeData->getPacket(), *node); + DependencyManager::get()->sendUnreliablePacket(sentPacket, *node); + _lastSequenceNumber = (decltype(_lastSequenceNumber)) sentPacket.getSequenceNumber(); - numBytes = nodeData->getPacket().getDataSize(); + numBytes = sentPacket.getDataSize(); _totalBytes += numBytes; _totalPackets++; // we count wasted bytes here because we were unable to fit the stats packet @@ -243,8 +244,6 @@ int OctreeSendThread::handlePacketSend(SharedNodePointer node, OctreeQueryNode* numPackets++; if (debug) { - NLPacket& sentPacket = nodeData->getPacket(); - sentPacket.seek(sizeof(OCTREE_PACKET_FLAGS)); OCTREE_PACKET_SEQUENCE sequence; @@ -265,9 +264,11 @@ int OctreeSendThread::handlePacketSend(SharedNodePointer node, OctreeQueryNode* if (nodeData->isPacketWaiting() && !nodeData->isShuttingDown()) { // just send the octree packet OctreeServer::didCallWriteDatagram(this); - DependencyManager::get()->sendUnreliablePacket(nodeData->getPacket(), *node); + NLPacket& sentPacket = nodeData->getPacket(); + DependencyManager::get()->sendUnreliablePacket(sentPacket, *node); + _lastSequenceNumber = (decltype(_lastSequenceNumber)) sentPacket.getSequenceNumber(); - int numBytes = nodeData->getPacket().getDataSize(); + int numBytes = sentPacket.getDataSize(); _totalBytes += numBytes; _totalPackets++; int thisWastedBytes = udt::MAX_PACKET_SIZE - numBytes; @@ -276,8 +277,6 @@ int OctreeSendThread::handlePacketSend(SharedNodePointer node, OctreeQueryNode* _trueBytesSent += numBytes; if (debug) { - NLPacket& sentPacket = nodeData->getPacket(); - sentPacket.seek(sizeof(OCTREE_PACKET_FLAGS)); OCTREE_PACKET_SEQUENCE sequence; @@ -512,6 +511,17 @@ void OctreeSendThread::traverseTreeAndSendContents(SharedNodePointer node, Octre OctreeServer::trackInsideTime((float)(usecTimestampNow() - startInside)); } + if (params.stopReason == EncodeBitstreamParams::FINISHED && nodeData->wantReportInitialResult()) { + // Dealt with nearby entities. + nodeData->setReportInitialResult(false); + + // send EntityQueryInitialResultsComplete reliable packet ... + auto initialCompletion = NLPacket::create(PacketType::EntityQueryInitialResultsComplete, -1, true); + QDataStream initialCompletionStream(initialCompletion.get()); + initialCompletionStream << _lastSequenceNumber; + DependencyManager::get()->sendPacket(std::move(initialCompletion), *node.data()); + } + if (somethingToSend && _myServer->wantsVerboseDebug()) { qCDebug(octree) << "Hit PPS Limit, packetsSentThisInterval =" << _packetsSentThisInterval << " maxPacketsPerInterval = " << maxPacketsPerInterval diff --git a/assignment-client/src/octree/OctreeSendThread.h b/assignment-client/src/octree/OctreeSendThread.h index 91c0ec7adc..58d2e3a160 100644 --- a/assignment-client/src/octree/OctreeSendThread.h +++ b/assignment-client/src/octree/OctreeSendThread.h @@ -60,6 +60,7 @@ protected: QWeakPointer _node; OctreeServer* _myServer { nullptr }; QUuid _nodeUuid; + udt::SequenceNumber::Type _lastSequenceNumber { 0 }; private: /// Called before a packetDistributor pass to allow for pre-distribution processing diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 311c08b858..55e634275d 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -6134,6 +6134,7 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType) { auto lodManager = DependencyManager::get(); _octreeQuery.setOctreeSizeScale(lodManager->getOctreeSizeScale()); _octreeQuery.setBoundaryLevelAdjust(lodManager->getBoundaryLevelAdjust()); + _octreeQuery.setReportInitialResult(true); auto nodeList = DependencyManager::get(); diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index 13ffcb5120..bb9666ee37 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -95,7 +95,7 @@ PacketVersion versionForPacketType(PacketType packetType) { case PacketType::AvatarIdentityRequest: return 22; default: - return 21; + return 22; } } diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 6e1aca83e5..7cba3baaf0 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -126,6 +126,7 @@ public: EntityScriptCallMethod, ChallengeOwnershipRequest, ChallengeOwnershipReply, + EntityQueryInitialResultsComplete, OctreeDataFileRequest, OctreeDataFileReply, diff --git a/libraries/octree/src/OctreeQuery.cpp b/libraries/octree/src/OctreeQuery.cpp index 0d56dbb88f..5fb886df10 100644 --- a/libraries/octree/src/OctreeQuery.cpp +++ b/libraries/octree/src/OctreeQuery.cpp @@ -27,6 +27,10 @@ OctreeQuery::OctreeQuery(bool randomizeConnectionID) { } } +const OctreeQuery::OctreeQueryFlags operator|=(OctreeQuery::OctreeQueryFlags& lhs, int rhs) { + return lhs = OctreeQuery::OctreeQueryFlags(lhs | rhs); +} + int OctreeQuery::getBroadcastData(unsigned char* destinationBuffer) { unsigned char* bufferStart = destinationBuffer; @@ -76,7 +80,12 @@ int OctreeQuery::getBroadcastData(unsigned char* destinationBuffer) { memcpy(destinationBuffer, binaryParametersDocument.data(), binaryParametersBytes); destinationBuffer += binaryParametersBytes; } - + + OctreeQueryFlags queryFlags { NoFlags }; + queryFlags |= (_reportInitialResult ? OctreeQuery::WantInitialResult : 0); + memcpy(destinationBuffer, &queryFlags, sizeof(queryFlags)); + destinationBuffer += sizeof(queryFlags); + return destinationBuffer - bufferStart; } @@ -150,6 +159,12 @@ int OctreeQuery::parseData(ReceivedMessage& message) { QWriteLocker jsonParameterLocker { &_jsonParametersLock }; _jsonParameters = newJsonDocument.object(); } - + + OctreeQueryFlags queryFlags; + memcpy(&queryFlags, sourceBuffer, sizeof(queryFlags)); + sourceBuffer += sizeof(queryFlags); + + _reportInitialResult = bool(queryFlags & OctreeQueryFlags::WantInitialResult); + return sourceBuffer - startPosition; } diff --git a/libraries/octree/src/OctreeQuery.h b/libraries/octree/src/OctreeQuery.h index 0ca75bdeb0..711a22e9b5 100644 --- a/libraries/octree/src/OctreeQuery.h +++ b/libraries/octree/src/OctreeQuery.h @@ -52,6 +52,10 @@ public: bool hasReceivedFirstQuery() const { return _hasReceivedFirstQuery; } + // Want a report when the initial query is complete. + bool wantReportInitialResult() const { return _reportInitialResult; } + void setReportInitialResult(bool reportInitialResult) { _reportInitialResult = reportInitialResult; } + signals: void incomingConnectionIDChanged(); @@ -73,8 +77,12 @@ protected: QJsonObject _jsonParameters; QReadWriteLock _jsonParametersLock; + + enum OctreeQueryFlags : uint16_t { NoFlags = 0x0, WantInitialResult = 0x1 }; + friend const OctreeQuery::OctreeQueryFlags operator|=(OctreeQuery::OctreeQueryFlags& lhs, const int rhs); bool _hasReceivedFirstQuery { false }; + bool _reportInitialResult { false }; }; #endif // hifi_OctreeQuery_h diff --git a/libraries/shared/src/shared/ConicalViewFrustum.cpp b/libraries/shared/src/shared/ConicalViewFrustum.cpp index 2ef096e3a8..3d56683c82 100644 --- a/libraries/shared/src/shared/ConicalViewFrustum.cpp +++ b/libraries/shared/src/shared/ConicalViewFrustum.cpp @@ -144,3 +144,8 @@ int ConicalViewFrustum::deserialize(const unsigned char* sourceBuffer) { return sourceBuffer - startPosition; } + +void ConicalViewFrustum::setSimpleRadius(float radius) { + _radius = radius; + _farClip = radius / 2.0f; +} diff --git a/libraries/shared/src/shared/ConicalViewFrustum.h b/libraries/shared/src/shared/ConicalViewFrustum.h index dc372d560e..2180516441 100644 --- a/libraries/shared/src/shared/ConicalViewFrustum.h +++ b/libraries/shared/src/shared/ConicalViewFrustum.h @@ -54,6 +54,9 @@ public: int serialize(unsigned char* destinationBuffer) const; int deserialize(const unsigned char* sourceBuffer); + // Just test for within radius. + void setSimpleRadius(float radius); + private: glm::vec3 _position { 0.0f, 0.0f, 0.0f }; glm::vec3 _direction { 0.0f, 0.0f, 1.0f }; diff --git a/tools/dissectors/1-hfudt.lua b/tools/dissectors/1-hfudt.lua index 137bee659b..9bed892885 100644 --- a/tools/dissectors/1-hfudt.lua +++ b/tools/dissectors/1-hfudt.lua @@ -86,12 +86,12 @@ local packet_types = { [22] = "ICEServerPeerInformation", [23] = "ICEServerQuery", [24] = "OctreeStats", - [25] = "Jurisdiction", + [25] = "UNUSED_PACKET_TYPE_1", [26] = "AvatarIdentityRequest", [27] = "AssignmentClientStatus", [28] = "NoisyMute", [29] = "AvatarIdentity", - [30] = "AvatarBillboard", + [30] = "NodeIgnoreRequest", [31] = "DomainConnectRequest", [32] = "DomainServerRequireDTLS", [33] = "NodeJsonStats", @@ -115,7 +115,52 @@ local packet_types = { [51] = "AssetUpload", [52] = "AssetUploadReply", [53] = "AssetGetInfo", - [54] = "AssetGetInfoReply" + [54] = "AssetGetInfoReply", + [55] = "DomainDisconnectRequest", + [56] = "DomainServerRemovedNode", + [57] = "MessagesData", + [58] = "MessagesSubscribe", + [59] = "MessagesUnsubscribe", + [60] = "ICEServerHeartbeatDenied", + [61] = "AssetMappingOperation", + [62] = "AssetMappingOperationReply", + [63] = "ICEServerHeartbeatACK", + [64] = "NegotiateAudioFormat", + [65] = "SelectedAudioFormat", + [66] = "MoreEntityShapes", + [67] = "NodeKickRequest", + [68] = "NodeMuteRequest", + [69] = "RadiusIgnoreRequest", + [70] = "UsernameFromIDRequest", + [71] = "UsernameFromIDReply", + [72] = "AvatarQuery", + [73] = "RequestsDomainListData", + [74] = "PerAvatarGainSet", + [75] = "EntityScriptGetStatus", + [76] = "EntityScriptGetStatusReply", + [77] = "ReloadEntityServerScript", + [78] = "EntityPhysics", + [79] = "EntityServerScriptLog", + [80] = "AdjustAvatarSorting", + [81] = "OctreeFileReplacement", + [82] = "CollisionEventChanges", + [83] = "ReplicatedMicrophoneAudioNoEcho", + [84] = "ReplicatedMicrophoneAudioWithEcho", + [85] = "ReplicatedInjectAudio", + [86] = "ReplicatedSilentAudioFrame", + [87] = "ReplicatedAvatarIdentity", + [88] = "ReplicatedKillAvatar", + [89] = "ReplicatedBulkAvatarData", + [90] = "DomainContentReplacementFromUrl", + [91] = "ChallengeOwnership", + [92] = "EntityScriptCallMethod", + [93] = "ChallengeOwnershipRequest", + [94] = "ChallengeOwnershipReply", + [95] = "EntityQueryInitialResultsComplete", + [96] = "OctreeDataFileRequest", + [97] = "OctreeDataFileReply", + [98] = "OctreeDataPersist", + [99] = "EntityClone" } local unsourced_packet_types = { From 0cc96f2be14163f7bee0650781e5ce4df1b977a5 Mon Sep 17 00:00:00 2001 From: Simon Walton Date: Tue, 17 Jul 2018 11:04:25 -0700 Subject: [PATCH 17/75] Raise posix descriptor limit if necessary --- .../src/AssignmentClientMonitor.cpp | 24 +++++++++++++++++++ .../src/AssignmentClientMonitor.h | 2 ++ 2 files changed, 26 insertions(+) diff --git a/assignment-client/src/AssignmentClientMonitor.cpp b/assignment-client/src/AssignmentClientMonitor.cpp index 2847d4ebf1..163e5229bd 100644 --- a/assignment-client/src/AssignmentClientMonitor.cpp +++ b/assignment-client/src/AssignmentClientMonitor.cpp @@ -25,6 +25,9 @@ #include "AssignmentClientChildData.h" #include "SharedUtil.h" #include +#ifdef POSIX_SOURCE +#include +#endif const QString ASSIGNMENT_CLIENT_MONITOR_TARGET_NAME = "assignment-client-monitor"; const int WAIT_FOR_CHILD_MSECS = 1000; @@ -71,6 +74,7 @@ AssignmentClientMonitor::AssignmentClientMonitor(const unsigned int numAssignmen auto& packetReceiver = DependencyManager::get()->getPacketReceiver(); packetReceiver.registerListener(PacketType::AssignmentClientStatus, this, "handleChildStatusPacket"); + adjustOsResources(_numAssignmentClientForks); // use QProcess to fork off a process for each of the child assignment clients for (unsigned int i = 0; i < _numAssignmentClientForks; i++) { spawnChildClient(); @@ -372,3 +376,23 @@ bool AssignmentClientMonitor::handleHTTPRequest(HTTPConnection* connection, cons return true; } + +void AssignmentClientMonitor::adjustOsResources(unsigned int numForks) const +{ +#ifdef _POSIX_SOURCE + // QProcess on Unix uses six descriptors, some temporarily, for each child proc. + unsigned requiredDescriptors = 30 + 6 * numForks; + struct rlimit descLimits; + if (getrlimit(RLIMIT_NOFILE, &descLimits) == 0) { + if (descLimits.rlim_cur < requiredDescriptors) { + descLimits.rlim_cur = requiredDescriptors; + if (setrlimit(RLIMIT_NOFILE, &descLimits) == 0) { + qDebug() << "Resetting descriptor limit to" << requiredDescriptors; + } else { + const char *const errorString = strerror(errno); + qDebug() << "Failed to reset descriptor limit to" << requiredDescriptors << ":" << errorString; + } + } + } +#endif +} diff --git a/assignment-client/src/AssignmentClientMonitor.h b/assignment-client/src/AssignmentClientMonitor.h index 8848d503ae..331eed4599 100644 --- a/assignment-client/src/AssignmentClientMonitor.h +++ b/assignment-client/src/AssignmentClientMonitor.h @@ -23,6 +23,7 @@ #include "AssignmentClientChildData.h" #include #include +#include extern const char* NUM_FORKS_PARAMETER; @@ -55,6 +56,7 @@ public slots: private: void spawnChildClient(); void simultaneousWaitOnChildren(int waitMsecs); + void adjustOsResources(unsigned int numForks) const; QTimer _checkSparesTimer; // every few seconds see if it need fewer or more spare children From 6098c53d32641b73dc4d2f50c6d908857c5afa36 Mon Sep 17 00:00:00 2001 From: Simon Walton Date: Tue, 17 Jul 2018 11:29:31 -0700 Subject: [PATCH 18/75] Remove #include from header --- assignment-client/src/AssignmentClientMonitor.h | 1 - 1 file changed, 1 deletion(-) diff --git a/assignment-client/src/AssignmentClientMonitor.h b/assignment-client/src/AssignmentClientMonitor.h index 331eed4599..659ff4b001 100644 --- a/assignment-client/src/AssignmentClientMonitor.h +++ b/assignment-client/src/AssignmentClientMonitor.h @@ -23,7 +23,6 @@ #include "AssignmentClientChildData.h" #include #include -#include extern const char* NUM_FORKS_PARAMETER; From 7181c3ad487fd39f8760e5333e3d097798db33e5 Mon Sep 17 00:00:00 2001 From: Simon Walton Date: Tue, 17 Jul 2018 12:11:22 -0700 Subject: [PATCH 19/75] Fix typo in preprocessor symbol --- assignment-client/src/AssignmentClientMonitor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assignment-client/src/AssignmentClientMonitor.cpp b/assignment-client/src/AssignmentClientMonitor.cpp index 163e5229bd..9809c1b7d6 100644 --- a/assignment-client/src/AssignmentClientMonitor.cpp +++ b/assignment-client/src/AssignmentClientMonitor.cpp @@ -25,7 +25,7 @@ #include "AssignmentClientChildData.h" #include "SharedUtil.h" #include -#ifdef POSIX_SOURCE +#ifdef _POSIX_SOURCE #include #endif From 06d1602c0dd42495acd671fe0105c5cefc719c4c Mon Sep 17 00:00:00 2001 From: Simon Walton Date: Tue, 17 Jul 2018 14:39:21 -0700 Subject: [PATCH 20/75] Use max of --max & --n for resources; other clean-up --- assignment-client/src/AssignmentClientMonitor.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/assignment-client/src/AssignmentClientMonitor.cpp b/assignment-client/src/AssignmentClientMonitor.cpp index 9809c1b7d6..eb764a128c 100644 --- a/assignment-client/src/AssignmentClientMonitor.cpp +++ b/assignment-client/src/AssignmentClientMonitor.cpp @@ -74,7 +74,7 @@ AssignmentClientMonitor::AssignmentClientMonitor(const unsigned int numAssignmen auto& packetReceiver = DependencyManager::get()->getPacketReceiver(); packetReceiver.registerListener(PacketType::AssignmentClientStatus, this, "handleChildStatusPacket"); - adjustOsResources(_numAssignmentClientForks); + adjustOsResources(std::max(_numAssignmentClientForks, _maxAssignmentClientForks)); // use QProcess to fork off a process for each of the child assignment clients for (unsigned int i = 0; i < _numAssignmentClientForks; i++) { spawnChildClient(); @@ -380,7 +380,8 @@ bool AssignmentClientMonitor::handleHTTPRequest(HTTPConnection* connection, cons void AssignmentClientMonitor::adjustOsResources(unsigned int numForks) const { #ifdef _POSIX_SOURCE - // QProcess on Unix uses six descriptors, some temporarily, for each child proc. + // QProcess on Unix uses six (I think) descriptors, some temporarily, for each child proc. + // Formula based on tests with a Ubuntu 16.04 VM. unsigned requiredDescriptors = 30 + 6 * numForks; struct rlimit descLimits; if (getrlimit(RLIMIT_NOFILE, &descLimits) == 0) { @@ -393,6 +394,9 @@ void AssignmentClientMonitor::adjustOsResources(unsigned int numForks) const qDebug() << "Failed to reset descriptor limit to" << requiredDescriptors << ":" << errorString; } } + } else { + const char *const errorString = strerror(errno); + qDebug() << "Failed to read descriptor limit:" << errorString; } #endif } From 187259c838cfc950192a86ab8488501294c0caf6 Mon Sep 17 00:00:00 2001 From: Simon Walton Date: Tue, 17 Jul 2018 11:04:25 -0700 Subject: [PATCH 21/75] Raise posix descriptor limit if necessary --- assignment-client/src/AssignmentClientMonitor.h | 1 + 1 file changed, 1 insertion(+) diff --git a/assignment-client/src/AssignmentClientMonitor.h b/assignment-client/src/AssignmentClientMonitor.h index 659ff4b001..331eed4599 100644 --- a/assignment-client/src/AssignmentClientMonitor.h +++ b/assignment-client/src/AssignmentClientMonitor.h @@ -23,6 +23,7 @@ #include "AssignmentClientChildData.h" #include #include +#include extern const char* NUM_FORKS_PARAMETER; From 2d653db0640832bc0875fcf01f4fc4afc7e214ea Mon Sep 17 00:00:00 2001 From: Simon Walton Date: Tue, 17 Jul 2018 11:29:31 -0700 Subject: [PATCH 22/75] Remove #include from header --- assignment-client/src/AssignmentClientMonitor.h | 1 - 1 file changed, 1 deletion(-) diff --git a/assignment-client/src/AssignmentClientMonitor.h b/assignment-client/src/AssignmentClientMonitor.h index 331eed4599..659ff4b001 100644 --- a/assignment-client/src/AssignmentClientMonitor.h +++ b/assignment-client/src/AssignmentClientMonitor.h @@ -23,7 +23,6 @@ #include "AssignmentClientChildData.h" #include #include -#include extern const char* NUM_FORKS_PARAMETER; From 16e06de9cd1f11490f1b37db83ac600af9963a5c Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 25 Jul 2018 22:10:14 +1200 Subject: [PATCH 23/75] 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 7cb917f7355bdfea0dfb3d4fd0cb8441a3c1a2eb Mon Sep 17 00:00:00 2001 From: Simon Walton Date: Wed, 25 Jul 2018 14:45:26 -0700 Subject: [PATCH 24/75] Angles aren't boolean! --- libraries/shared/src/shared/ConicalViewFrustum.cpp | 6 +++--- libraries/shared/src/shared/ConicalViewFrustum.h | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/libraries/shared/src/shared/ConicalViewFrustum.cpp b/libraries/shared/src/shared/ConicalViewFrustum.cpp index 3d56683c82..78f4f7d1bc 100644 --- a/libraries/shared/src/shared/ConicalViewFrustum.cpp +++ b/libraries/shared/src/shared/ConicalViewFrustum.cpp @@ -69,7 +69,7 @@ bool ConicalViewFrustum::intersects(const AABox& box) const { return intersects(position, distance, radius); } -bool ConicalViewFrustum::getAngularSize(const AACube& cube) const { +float ConicalViewFrustum::getAngularSize(const AACube& cube) const { auto radius = 0.5f * SQRT_THREE * cube.getScale(); // radius of bounding sphere auto position = cube.calcCenter() - _position; // position of bounding sphere in view-frame float distance = glm::length(position); @@ -77,7 +77,7 @@ bool ConicalViewFrustum::getAngularSize(const AACube& cube) const { return getAngularSize(distance, radius); } -bool ConicalViewFrustum::getAngularSize(const AABox& box) const { +float ConicalViewFrustum::getAngularSize(const AABox& box) const { auto radius = 0.5f * glm::length(box.getScale()); // radius of bounding sphere auto position = box.calcCenter() - _position; // position of bounding sphere in view-frame float distance = glm::length(position); @@ -107,7 +107,7 @@ bool ConicalViewFrustum::intersects(const glm::vec3& relativePosition, float dis sqrtf(distance * distance - radius * radius) * _cosAngle - radius * _sinAngle; } -bool ConicalViewFrustum::getAngularSize(float distance, float radius) const { +float ConicalViewFrustum::getAngularSize(float distance, float radius) const { const float AVOID_DIVIDE_BY_ZERO = 0.001f; float angularSize = radius / (distance + AVOID_DIVIDE_BY_ZERO); return angularSize; diff --git a/libraries/shared/src/shared/ConicalViewFrustum.h b/libraries/shared/src/shared/ConicalViewFrustum.h index 2180516441..6a2cc53f03 100644 --- a/libraries/shared/src/shared/ConicalViewFrustum.h +++ b/libraries/shared/src/shared/ConicalViewFrustum.h @@ -45,11 +45,11 @@ public: bool intersects(const AACube& cube) const; bool intersects(const AABox& box) const; - bool getAngularSize(const AACube& cube) const; - bool getAngularSize(const AABox& box) const; + float getAngularSize(const AACube& cube) const; + float getAngularSize(const AABox& box) const; bool intersects(const glm::vec3& relativePosition, float distance, float radius) const; - bool getAngularSize(float distance, float radius) const; + float getAngularSize(float distance, float radius) const; int serialize(unsigned char* destinationBuffer) const; int deserialize(const unsigned char* sourceBuffer); From 8f0283444719a88fe853f327e35cc3e74cb30dfa Mon Sep 17 00:00:00 2001 From: Simon Walton Date: Wed, 25 Jul 2018 14:46:47 -0700 Subject: [PATCH 25/75] Set params.stopReason in another place --- assignment-client/src/entities/EntityTreeSendThread.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/assignment-client/src/entities/EntityTreeSendThread.cpp b/assignment-client/src/entities/EntityTreeSendThread.cpp index af0c09aec7..5ca4c3588e 100644 --- a/assignment-client/src/entities/EntityTreeSendThread.cpp +++ b/assignment-client/src/entities/EntityTreeSendThread.cpp @@ -310,6 +310,7 @@ void EntityTreeSendThread::startNewTraversal(const DiffTraversal::View& view, En bool EntityTreeSendThread::traverseTreeAndBuildNextPacketPayload(EncodeBitstreamParams& params, const QJsonObject& jsonFilters) { if (_sendQueue.empty()) { + params.stopReason = EncodeBitstreamParams::FINISHED; OctreeServer::trackEncodeTime(OctreeServer::SKIP_TIME); return false; } From 51865294ac147a68b9385b8ddb272756a577fd63 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 26 Jul 2018 09:54:42 +1200 Subject: [PATCH 26/75] 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 2c06487df086d9bab9682152939ecbb7324f6bd3 Mon Sep 17 00:00:00 2001 From: Simon Walton Date: Wed, 25 Jul 2018 17:05:05 -0700 Subject: [PATCH 27/75] Move sending of completion packet up to EntityTreeSendThread I hadn't appreciated the continuous nature of the scene traversal. Looks good now. Also changed some identifier names. --- .../src/entities/EntityTreeSendThread.cpp | 21 +++++++++++++++---- .../src/entities/EntityTreeSendThread.h | 2 +- .../src/octree/OctreeSendThread.cpp | 15 +++---------- .../src/octree/OctreeSendThread.h | 2 +- libraries/octree/src/OctreeQuery.cpp | 4 ++-- libraries/octree/src/OctreeQuery.h | 8 +++---- 6 files changed, 28 insertions(+), 24 deletions(-) diff --git a/assignment-client/src/entities/EntityTreeSendThread.cpp b/assignment-client/src/entities/EntityTreeSendThread.cpp index 5ca4c3588e..19dc92686a 100644 --- a/assignment-client/src/entities/EntityTreeSendThread.cpp +++ b/assignment-client/src/entities/EntityTreeSendThread.cpp @@ -18,7 +18,7 @@ #include "EntityServer.h" // Initially just send all items within this distance. -const float EntityTreeSendThread::INITIAL_RADIUS = 50.0f; +const float EntityTreeSendThread::INITIAL_RADIUS = 10.0f; EntityTreeSendThread::EntityTreeSendThread(OctreeServer* myServer, const SharedNodePointer& node) : OctreeSendThread(myServer, node) @@ -102,7 +102,7 @@ void EntityTreeSendThread::preDistributionProcessing() { } } -void EntityTreeSendThread::traverseTreeAndSendContents(SharedNodePointer node, OctreeQueryNode* nodeData, +bool EntityTreeSendThread::traverseTreeAndSendContents(SharedNodePointer node, OctreeQueryNode* nodeData, bool viewFrustumChanged, bool isFullScene) { if (viewFrustumChanged || _traversal.finished()) { EntityTreeElementPointer root = std::dynamic_pointer_cast(_myServer->getOctree()->getRoot()); @@ -114,7 +114,7 @@ void EntityTreeSendThread::traverseTreeAndSendContents(SharedNodePointer node, O int32_t lodLevelOffset = nodeData->getBoundaryLevelAdjust() + (viewFrustumChanged ? LOW_RES_MOVING_ADJUST : NO_BOUNDARY_ADJUST); newView.lodScaleFactor = powf(2.0f, lodLevelOffset); - if (nodeData->wantReportInitialResult() && !newView.viewFrustums.empty()) { + if (nodeData->wantReportInitialCompletion() && !newView.viewFrustums.empty()) { auto& mainView = newView.viewFrustums[0]; // Force acceptance within INITIAL_RADIUS. mainView.setSimpleRadius(INITIAL_RADIUS); @@ -165,7 +165,20 @@ void EntityTreeSendThread::traverseTreeAndSendContents(SharedNodePointer node, O OctreeServer::trackTreeTraverseTime((float)(usecTimestampNow() - startTime)); } - OctreeSendThread::traverseTreeAndSendContents(node, nodeData, viewFrustumChanged, isFullScene); + bool sendComplete = OctreeSendThread::traverseTreeAndSendContents(node, nodeData, viewFrustumChanged, isFullScene); + + if (sendComplete && nodeData->wantReportInitialCompletion() && _traversal.finished()) { + // Dealt with all nearby entities. + nodeData->setReportInitialCompletion(false); + + // Send EntityQueryInitialResultsComplete reliable packet ... + auto initialCompletion = NLPacket::create(PacketType::EntityQueryInitialResultsComplete, -1, true); + QDataStream initialCompletionStream(initialCompletion.get()); + initialCompletionStream << _lastSequenceNumber; + DependencyManager::get()->sendPacket(std::move(initialCompletion), *node.data()); + } + + return sendComplete; } bool EntityTreeSendThread::addAncestorsToExtraFlaggedEntities(const QUuid& filteredEntityID, diff --git a/assignment-client/src/entities/EntityTreeSendThread.h b/assignment-client/src/entities/EntityTreeSendThread.h index 8c66f47aea..c9f4d06164 100644 --- a/assignment-client/src/entities/EntityTreeSendThread.h +++ b/assignment-client/src/entities/EntityTreeSendThread.h @@ -31,7 +31,7 @@ public: EntityTreeSendThread(OctreeServer* myServer, const SharedNodePointer& node); protected: - void traverseTreeAndSendContents(SharedNodePointer node, OctreeQueryNode* nodeData, + bool traverseTreeAndSendContents(SharedNodePointer node, OctreeQueryNode* nodeData, bool viewFrustumChanged, bool isFullScene) override; private slots: diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index 98b06d6344..54a7bbfa2d 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -433,7 +433,7 @@ int OctreeSendThread::packetDistributor(SharedNodePointer node, OctreeQueryNode* return _truePacketsSent; } -void OctreeSendThread::traverseTreeAndSendContents(SharedNodePointer node, OctreeQueryNode* nodeData, bool viewFrustumChanged, bool isFullScene) { +bool OctreeSendThread::traverseTreeAndSendContents(SharedNodePointer node, OctreeQueryNode* nodeData, bool viewFrustumChanged, bool isFullScene) { // calculate max number of packets that can be sent during this interval int clientMaxPacketsPerInterval = std::max(1, (nodeData->getMaxQueryPacketsPerSecond() / INTERVALS_PER_SECOND)); int maxPacketsPerInterval = std::min(clientMaxPacketsPerInterval, _myServer->getPacketsPerClientPerInterval()); @@ -511,20 +511,11 @@ void OctreeSendThread::traverseTreeAndSendContents(SharedNodePointer node, Octre OctreeServer::trackInsideTime((float)(usecTimestampNow() - startInside)); } - if (params.stopReason == EncodeBitstreamParams::FINISHED && nodeData->wantReportInitialResult()) { - // Dealt with nearby entities. - nodeData->setReportInitialResult(false); - - // send EntityQueryInitialResultsComplete reliable packet ... - auto initialCompletion = NLPacket::create(PacketType::EntityQueryInitialResultsComplete, -1, true); - QDataStream initialCompletionStream(initialCompletion.get()); - initialCompletionStream << _lastSequenceNumber; - DependencyManager::get()->sendPacket(std::move(initialCompletion), *node.data()); - } - if (somethingToSend && _myServer->wantsVerboseDebug()) { qCDebug(octree) << "Hit PPS Limit, packetsSentThisInterval =" << _packetsSentThisInterval << " maxPacketsPerInterval = " << maxPacketsPerInterval << " clientMaxPacketsPerInterval = " << clientMaxPacketsPerInterval; } + + return params.stopReason == EncodeBitstreamParams::FINISHED; } diff --git a/assignment-client/src/octree/OctreeSendThread.h b/assignment-client/src/octree/OctreeSendThread.h index 58d2e3a160..fc529c3e3a 100644 --- a/assignment-client/src/octree/OctreeSendThread.h +++ b/assignment-client/src/octree/OctreeSendThread.h @@ -52,7 +52,7 @@ protected: /// Implements generic processing behavior for this thread. virtual bool process() override; - virtual void traverseTreeAndSendContents(SharedNodePointer node, OctreeQueryNode* nodeData, + virtual bool traverseTreeAndSendContents(SharedNodePointer node, OctreeQueryNode* nodeData, bool viewFrustumChanged, bool isFullScene); virtual bool traverseTreeAndBuildNextPacketPayload(EncodeBitstreamParams& params, const QJsonObject& jsonFilters) = 0; diff --git a/libraries/octree/src/OctreeQuery.cpp b/libraries/octree/src/OctreeQuery.cpp index 5fb886df10..77977bf01e 100644 --- a/libraries/octree/src/OctreeQuery.cpp +++ b/libraries/octree/src/OctreeQuery.cpp @@ -82,7 +82,7 @@ int OctreeQuery::getBroadcastData(unsigned char* destinationBuffer) { } OctreeQueryFlags queryFlags { NoFlags }; - queryFlags |= (_reportInitialResult ? OctreeQuery::WantInitialResult : 0); + queryFlags |= (_reportInitialCompletion ? OctreeQuery::WantInitialCompletion : 0); memcpy(destinationBuffer, &queryFlags, sizeof(queryFlags)); destinationBuffer += sizeof(queryFlags); @@ -164,7 +164,7 @@ int OctreeQuery::parseData(ReceivedMessage& message) { memcpy(&queryFlags, sourceBuffer, sizeof(queryFlags)); sourceBuffer += sizeof(queryFlags); - _reportInitialResult = bool(queryFlags & OctreeQueryFlags::WantInitialResult); + _reportInitialCompletion = bool(queryFlags & OctreeQueryFlags::WantInitialCompletion); return sourceBuffer - startPosition; } diff --git a/libraries/octree/src/OctreeQuery.h b/libraries/octree/src/OctreeQuery.h index 711a22e9b5..04d6793158 100644 --- a/libraries/octree/src/OctreeQuery.h +++ b/libraries/octree/src/OctreeQuery.h @@ -53,8 +53,8 @@ public: bool hasReceivedFirstQuery() const { return _hasReceivedFirstQuery; } // Want a report when the initial query is complete. - bool wantReportInitialResult() const { return _reportInitialResult; } - void setReportInitialResult(bool reportInitialResult) { _reportInitialResult = reportInitialResult; } + bool wantReportInitialCompletion() const { return _reportInitialCompletion; } + void setReportInitialCompletion(bool reportInitialCompletion) { _reportInitialCompletion = reportInitialCompletion; } signals: void incomingConnectionIDChanged(); @@ -78,11 +78,11 @@ protected: QJsonObject _jsonParameters; QReadWriteLock _jsonParametersLock; - enum OctreeQueryFlags : uint16_t { NoFlags = 0x0, WantInitialResult = 0x1 }; + enum OctreeQueryFlags : uint16_t { NoFlags = 0x0, WantInitialCompletion = 0x1 }; friend const OctreeQuery::OctreeQueryFlags operator|=(OctreeQuery::OctreeQueryFlags& lhs, const int rhs); bool _hasReceivedFirstQuery { false }; - bool _reportInitialResult { false }; + bool _reportInitialCompletion { false }; }; #endif // hifi_OctreeQuery_h From a15e78a0f4420b5e51a73b487ba3f126a87f96ee Mon Sep 17 00:00:00 2001 From: Simon Walton Date: Wed, 25 Jul 2018 17:36:53 -0700 Subject: [PATCH 28/75] Missed an identifier change --- interface/src/Application.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 55e634275d..94f89a66ad 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -6134,7 +6134,7 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType) { auto lodManager = DependencyManager::get(); _octreeQuery.setOctreeSizeScale(lodManager->getOctreeSizeScale()); _octreeQuery.setBoundaryLevelAdjust(lodManager->getBoundaryLevelAdjust()); - _octreeQuery.setReportInitialResult(true); + _octreeQuery.setReportInitialCompletion(true); auto nodeList = DependencyManager::get(); From baf88ab508399e1eb0c282464a112f5faaf490af Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 26 Jul 2018 16:12:16 +1200 Subject: [PATCH 29/75] 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 30/75] 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 6e23caca0dd15b01d6aa63ad69e4f2272a9c4132 Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Thu, 26 Jul 2018 20:25:42 +0200 Subject: [PATCH 31/75] handle both wantsTrigger and triggerable in CreateApp --- scripts/system/html/entityProperties.html | 4 +-- scripts/system/html/js/entityProperties.js | 31 ++++++++++++++-------- 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/scripts/system/html/entityProperties.html b/scripts/system/html/entityProperties.html index 8d63261f4c..9614f8b8fe 100644 --- a/scripts/system/html/entityProperties.html +++ b/scripts/system/html/entityProperties.html @@ -126,8 +126,8 @@
- - + +
diff --git a/scripts/system/html/js/entityProperties.js b/scripts/system/html/js/entityProperties.js index a6a781b35f..59186bf38f 100644 --- a/scripts/system/html/js/entityProperties.js +++ b/scripts/system/html/js/entityProperties.js @@ -308,9 +308,10 @@ function setUserDataFromEditor(noUpdate) { } } -function multiDataUpdater(groupName, updateKeyPair, userDataElement, defaults) { +function multiDataUpdater(groupName, updateKeyPair, userDataElement, defaults, removeKeys) { var properties = {}; var parsedData = {}; + var keysToBeRemoved = removeKeys ? removeKeys : []; try { if ($('#userdata-editor').css('height') !== "0px") { // if there is an expanded, we want to use its json. @@ -342,6 +343,12 @@ function multiDataUpdater(groupName, updateKeyPair, userDataElement, defaults) { parsedData[groupName][key] = defaults[key]; } }); + keysToBeRemoved.forEach(function(key) { + if (parsedData[groupName].hasOwnProperty(key)) { + delete parsedData[groupName][key]; + } + }); + if (Object.keys(parsedData[groupName]).length === 0) { delete parsedData[groupName]; } @@ -355,11 +362,11 @@ function multiDataUpdater(groupName, updateKeyPair, userDataElement, defaults) { updateProperties(properties); } -function userDataChanger(groupName, keyName, values, userDataElement, defaultValue) { +function userDataChanger(groupName, keyName, values, userDataElement, defaultValue, removeKeys) { var val = {}, def = {}; val[keyName] = values; def[keyName] = defaultValue; - multiDataUpdater(groupName, val, userDataElement, def); + multiDataUpdater(groupName, val, userDataElement, def, removeKeys); } function setMaterialDataFromEditor(noUpdate) { @@ -711,7 +718,7 @@ function loaded() { var elCloneableLifetime = document.getElementById("property-cloneable-lifetime"); var elCloneableLimit = document.getElementById("property-cloneable-limit"); - var elWantsTrigger = document.getElementById("property-wants-trigger"); + var elTriggerable = document.getElementById("property-triggerable"); var elIgnoreIK = document.getElementById("property-ignore-ik"); var elLifetime = document.getElementById("property-lifetime"); @@ -1037,7 +1044,7 @@ function loaded() { elGrabbable.checked = properties.dynamic; - elWantsTrigger.checked = false; + elTriggerable.checked = false; elIgnoreIK.checked = true; elCloneable.checked = properties.cloneable; @@ -1060,10 +1067,12 @@ function loaded() { } else { elGrabbable.checked = true; } - if ("wantsTrigger" in grabbableData) { - elWantsTrigger.checked = grabbableData.wantsTrigger; + if ("triggerable" in grabbableData) { + elTriggerable.checked = grabbableData.triggerable; + } else if ("wantsTrigger" in grabbableData) { + elTriggerable.checked = grabbableData.wantsTrigger; } else { - elWantsTrigger.checked = false; + elTriggerable.checked = false; } if ("ignoreIK" in grabbableData) { elIgnoreIK.checked = grabbableData.ignoreIK; @@ -1076,7 +1085,7 @@ function loaded() { } if (!grabbablesSet) { elGrabbable.checked = true; - elWantsTrigger.checked = false; + elTriggerable.checked = false; elIgnoreIK.checked = true; elCloneable.checked = false; } @@ -1447,8 +1456,8 @@ function loaded() { elCloneableLifetime.addEventListener('change', createEmitNumberPropertyUpdateFunction('cloneLifetime')); elCloneableLimit.addEventListener('change', createEmitNumberPropertyUpdateFunction('cloneLimit')); - elWantsTrigger.addEventListener('change', function() { - userDataChanger("grabbableKey", "wantsTrigger", elWantsTrigger, elUserData, false); + elTriggerable.addEventListener('change', function() { + userDataChanger("grabbableKey", "triggerable", elTriggerable, elUserData, false, ['wantsTrigger']); }); elIgnoreIK.addEventListener('change', function() { userDataChanger("grabbableKey", "ignoreIK", elIgnoreIK, elUserData, true); From 82e5d6ad29693b278c9f003d604c27e925ebab14 Mon Sep 17 00:00:00 2001 From: David Back Date: Thu, 26 Jul 2018 16:38:25 -0700 Subject: [PATCH 32/75] 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 33/75] 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 34/75] 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 0cec9a72d629b3888273e8ef7c169f0e5e7314c2 Mon Sep 17 00:00:00 2001 From: Simon Walton Date: Thu, 26 Jul 2018 18:10:38 -0700 Subject: [PATCH 35/75] Implement client-side enable physics once indicated EntityData has arrived Also now use Entity Server Protocol sequence numbers. --- .../src/entities/EntityTreeSendThread.cpp | 2 +- .../src/octree/OctreeSendThread.cpp | 3 -- .../src/octree/OctreeSendThread.h | 1 - interface/src/Application.cpp | 8 +++-- .../src/octree/OctreePacketProcessor.cpp | 34 +++++++++++++++++-- interface/src/octree/OctreePacketProcessor.h | 10 ++++++ libraries/octree/src/OctreeProcessor.cpp | 2 ++ libraries/octree/src/OctreeProcessor.h | 3 ++ 8 files changed, 52 insertions(+), 11 deletions(-) diff --git a/assignment-client/src/entities/EntityTreeSendThread.cpp b/assignment-client/src/entities/EntityTreeSendThread.cpp index 19dc92686a..154d22f253 100644 --- a/assignment-client/src/entities/EntityTreeSendThread.cpp +++ b/assignment-client/src/entities/EntityTreeSendThread.cpp @@ -174,7 +174,7 @@ bool EntityTreeSendThread::traverseTreeAndSendContents(SharedNodePointer node, O // Send EntityQueryInitialResultsComplete reliable packet ... auto initialCompletion = NLPacket::create(PacketType::EntityQueryInitialResultsComplete, -1, true); QDataStream initialCompletionStream(initialCompletion.get()); - initialCompletionStream << _lastSequenceNumber; + initialCompletionStream << OCTREE_PACKET_SEQUENCE(nodeData->getSequenceNumber() - 1U); DependencyManager::get()->sendPacket(std::move(initialCompletion), *node.data()); } diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index 54a7bbfa2d..ab357f4146 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -195,7 +195,6 @@ int OctreeSendThread::handlePacketSend(SharedNodePointer node, OctreeQueryNode* // actually send it OctreeServer::didCallWriteDatagram(this); DependencyManager::get()->sendUnreliablePacket(statsPacket, *node); - _lastSequenceNumber = (decltype(_lastSequenceNumber)) statsPacket.getSequenceNumber(); } else { // not enough room in the packet, send two packets @@ -232,7 +231,6 @@ int OctreeSendThread::handlePacketSend(SharedNodePointer node, OctreeQueryNode* // second packet OctreeServer::didCallWriteDatagram(this); DependencyManager::get()->sendUnreliablePacket(sentPacket, *node); - _lastSequenceNumber = (decltype(_lastSequenceNumber)) sentPacket.getSequenceNumber(); numBytes = sentPacket.getDataSize(); _totalBytes += numBytes; @@ -266,7 +264,6 @@ int OctreeSendThread::handlePacketSend(SharedNodePointer node, OctreeQueryNode* OctreeServer::didCallWriteDatagram(this); NLPacket& sentPacket = nodeData->getPacket(); DependencyManager::get()->sendUnreliablePacket(sentPacket, *node); - _lastSequenceNumber = (decltype(_lastSequenceNumber)) sentPacket.getSequenceNumber(); int numBytes = sentPacket.getDataSize(); _totalBytes += numBytes; diff --git a/assignment-client/src/octree/OctreeSendThread.h b/assignment-client/src/octree/OctreeSendThread.h index fc529c3e3a..bdf0f03364 100644 --- a/assignment-client/src/octree/OctreeSendThread.h +++ b/assignment-client/src/octree/OctreeSendThread.h @@ -60,7 +60,6 @@ protected: QWeakPointer _node; OctreeServer* _myServer { nullptr }; QUuid _nodeUuid; - udt::SequenceNumber::Type _lastSequenceNumber { 0 }; private: /// Called before a packetDistributor pass to allow for pre-distribution processing diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 94f89a66ad..ed67b7464c 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -5476,8 +5476,9 @@ void Application::update(float deltaTime) { // for nearby entities before starting bullet up. quint64 now = usecTimestampNow(); const int PHYSICS_CHECK_TIMEOUT = 2 * USECS_PER_SECOND; - - if (now - _lastPhysicsCheckTime > PHYSICS_CHECK_TIMEOUT || _fullSceneReceivedCounter > _fullSceneCounterAtLastPhysicsCheck) { + auto entityTreeRenderer = getEntities(); + if (entityTreeRenderer && _octreeProcessor.octreeSequenceIsComplete(entityTreeRenderer->getLastOctreeMessageSequence()) ) { + /*if (now - _lastPhysicsCheckTime > PHYSICS_CHECK_TIMEOUT || _fullSceneReceivedCounter > _fullSceneCounterAtLastPhysicsCheck) {*/ // we've received a new full-scene octree stats packet, or it's been long enough to try again anyway _lastPhysicsCheckTime = now; _fullSceneCounterAtLastPhysicsCheck = _fullSceneReceivedCounter; @@ -6134,7 +6135,7 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType) { auto lodManager = DependencyManager::get(); _octreeQuery.setOctreeSizeScale(lodManager->getOctreeSizeScale()); _octreeQuery.setBoundaryLevelAdjust(lodManager->getBoundaryLevelAdjust()); - _octreeQuery.setReportInitialCompletion(true); + _octreeQuery.setReportInitialCompletion(!_physicsEnabled); auto nodeList = DependencyManager::get(); @@ -6279,6 +6280,7 @@ void Application::clearDomainOctreeDetails() { _octreeServerSceneStats.clear(); }); + _octreeProcessor.resetCompletionSequenceNumber(); // reset the model renderer getEntities()->clear(); diff --git a/interface/src/octree/OctreePacketProcessor.cpp b/interface/src/octree/OctreePacketProcessor.cpp index 7d38e29710..5ab2218f67 100644 --- a/interface/src/octree/OctreePacketProcessor.cpp +++ b/interface/src/octree/OctreePacketProcessor.cpp @@ -21,9 +21,9 @@ OctreePacketProcessor::OctreePacketProcessor() { setObjectName("Octree Packet Processor"); auto& packetReceiver = DependencyManager::get()->getPacketReceiver(); - - packetReceiver.registerDirectListenerForTypes({ PacketType::OctreeStats, PacketType::EntityData, PacketType::EntityErase }, - this, "handleOctreePacket"); + const PacketReceiver::PacketTypeList octreePackets = + { PacketType::OctreeStats, PacketType::EntityData, PacketType::EntityErase, PacketType::EntityQueryInitialResultsComplete }; + packetReceiver.registerDirectListenerForTypes(octreePackets, this, "handleOctreePacket"); } void OctreePacketProcessor::handleOctreePacket(QSharedPointer message, SharedNodePointer senderNode) { @@ -111,8 +111,36 @@ void OctreePacketProcessor::processPacket(QSharedPointer messag } } break; + case PacketType::EntityQueryInitialResultsComplete: { + // Read sequence # + OCTREE_PACKET_SEQUENCE completionNumber; + message->readPrimitive(&completionNumber); + _completionSequenceNumber = completionNumber; + _completionSequenceNumberValid = true; + } break; + default: { // nothing to do } break; } } + +void OctreePacketProcessor::resetCompletionSequenceNumber() { + _completionSequenceNumber = false; +} + +namespace { + template constexpr bool lessThanWraparound(int a, int b) { + static const int MAX_T_VALUE = std::numeric_limits::max(); + if (b < a) { + b += MAX_T_VALUE; + } + return (b - a) < (MAX_T_VALUE / 2); + } +} + +bool OctreePacketProcessor::octreeSequenceIsComplete(int sequenceNumber) const { + const int completionSequenceNumber = _completionSequenceNumber; + return _completionSequenceNumberValid && + !lessThanWraparound(completionSequenceNumber, sequenceNumber); +} diff --git a/interface/src/octree/OctreePacketProcessor.h b/interface/src/octree/OctreePacketProcessor.h index d04cab3584..f7e001fbde 100644 --- a/interface/src/octree/OctreePacketProcessor.h +++ b/interface/src/octree/OctreePacketProcessor.h @@ -22,13 +22,23 @@ class OctreePacketProcessor : public ReceivedPacketProcessor { public: OctreePacketProcessor(); + bool octreeSequenceIsComplete(int sequenceNumber) const; + signals: void packetVersionMismatch(); +public slots: + void resetCompletionSequenceNumber(); + protected: virtual void processPacket(QSharedPointer message, SharedNodePointer sendingNode) override; private slots: void handleOctreePacket(QSharedPointer message, SharedNodePointer senderNode); + +private: + bool _completionSequenceNumberValid { false }; + std::atomic _completionSequenceNumber { 0 }; + }; #endif // hifi_OctreePacketProcessor_h diff --git a/libraries/octree/src/OctreeProcessor.cpp b/libraries/octree/src/OctreeProcessor.cpp index beaac1198c..206ff399d9 100644 --- a/libraries/octree/src/OctreeProcessor.cpp +++ b/libraries/octree/src/OctreeProcessor.cpp @@ -192,6 +192,8 @@ void OctreeProcessor::processDatagram(ReceivedMessage& message, SharedNodePointe _elementsInLastWindow = 0; _entitiesInLastWindow = 0; } + + _lastOctreeMessageSequence = sequence; } } diff --git a/libraries/octree/src/OctreeProcessor.h b/libraries/octree/src/OctreeProcessor.h index 325b33cd15..8085682fa5 100644 --- a/libraries/octree/src/OctreeProcessor.h +++ b/libraries/octree/src/OctreeProcessor.h @@ -56,6 +56,8 @@ public: float getAverageUncompressPerPacket() const { return _uncompressPerPacket.getAverage(); } float getAverageReadBitstreamPerPacket() const { return _readBitstreamPerPacket.getAverage(); } + OCTREE_PACKET_SEQUENCE getLastOctreeMessageSequence() const { return _lastOctreeMessageSequence; } + protected: virtual OctreePointer createTree() = 0; @@ -77,6 +79,7 @@ protected: int _packetsInLastWindow = 0; int _elementsInLastWindow = 0; int _entitiesInLastWindow = 0; + std::atomic _lastOctreeMessageSequence = 0; }; From 4d559bbaeeb59063515fc7c4c8ab60528d1acbfc Mon Sep 17 00:00:00 2001 From: Simon Walton Date: Fri, 27 Jul 2018 10:05:34 -0700 Subject: [PATCH 36/75] Don't initialize an atomic; squelch gcc warning --- libraries/octree/src/OctreeProcessor.h | 2 +- libraries/octree/src/OctreeQuery.cpp | 2 +- libraries/octree/src/OctreeQuery.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/octree/src/OctreeProcessor.h b/libraries/octree/src/OctreeProcessor.h index 8085682fa5..1bc3bd10f9 100644 --- a/libraries/octree/src/OctreeProcessor.h +++ b/libraries/octree/src/OctreeProcessor.h @@ -79,7 +79,7 @@ protected: int _packetsInLastWindow = 0; int _elementsInLastWindow = 0; int _entitiesInLastWindow = 0; - std::atomic _lastOctreeMessageSequence = 0; + std::atomic _lastOctreeMessageSequence; }; diff --git a/libraries/octree/src/OctreeQuery.cpp b/libraries/octree/src/OctreeQuery.cpp index 77977bf01e..8c3685dc69 100644 --- a/libraries/octree/src/OctreeQuery.cpp +++ b/libraries/octree/src/OctreeQuery.cpp @@ -27,7 +27,7 @@ OctreeQuery::OctreeQuery(bool randomizeConnectionID) { } } -const OctreeQuery::OctreeQueryFlags operator|=(OctreeQuery::OctreeQueryFlags& lhs, int rhs) { +OctreeQuery::OctreeQueryFlags operator|=(OctreeQuery::OctreeQueryFlags& lhs, int rhs) { return lhs = OctreeQuery::OctreeQueryFlags(lhs | rhs); } diff --git a/libraries/octree/src/OctreeQuery.h b/libraries/octree/src/OctreeQuery.h index 04d6793158..2c3c00ef05 100644 --- a/libraries/octree/src/OctreeQuery.h +++ b/libraries/octree/src/OctreeQuery.h @@ -79,7 +79,7 @@ protected: QReadWriteLock _jsonParametersLock; enum OctreeQueryFlags : uint16_t { NoFlags = 0x0, WantInitialCompletion = 0x1 }; - friend const OctreeQuery::OctreeQueryFlags operator|=(OctreeQuery::OctreeQueryFlags& lhs, const int rhs); + friend OctreeQuery::OctreeQueryFlags operator|=(OctreeQuery::OctreeQueryFlags& lhs, const int rhs); bool _hasReceivedFirstQuery { false }; bool _reportInitialCompletion { false }; From 3d390203e20fa88f73d4a2a35132177e0fae6b48 Mon Sep 17 00:00:00 2001 From: Simon Walton Date: Fri, 27 Jul 2018 11:34:08 -0700 Subject: [PATCH 37/75] More fixes for clang & gcc C++14 issues, I think. --- interface/src/Application.cpp | 2 +- interface/src/octree/OctreePacketProcessor.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index ed67b7464c..1c4de2165a 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -5475,7 +5475,7 @@ void Application::update(float deltaTime) { // we haven't yet enabled physics. we wait until we think we have all the collision information // for nearby entities before starting bullet up. quint64 now = usecTimestampNow(); - const int PHYSICS_CHECK_TIMEOUT = 2 * USECS_PER_SECOND; + //const int PHYSICS_CHECK_TIMEOUT = 2 * USECS_PER_SECOND; auto entityTreeRenderer = getEntities(); if (entityTreeRenderer && _octreeProcessor.octreeSequenceIsComplete(entityTreeRenderer->getLastOctreeMessageSequence()) ) { /*if (now - _lastPhysicsCheckTime > PHYSICS_CHECK_TIMEOUT || _fullSceneReceivedCounter > _fullSceneCounterAtLastPhysicsCheck) {*/ diff --git a/interface/src/octree/OctreePacketProcessor.cpp b/interface/src/octree/OctreePacketProcessor.cpp index 5ab2218f67..696fa4ffd4 100644 --- a/interface/src/octree/OctreePacketProcessor.cpp +++ b/interface/src/octree/OctreePacketProcessor.cpp @@ -130,8 +130,8 @@ void OctreePacketProcessor::resetCompletionSequenceNumber() { } namespace { - template constexpr bool lessThanWraparound(int a, int b) { - static const int MAX_T_VALUE = std::numeric_limits::max(); + template bool lessThanWraparound(int a, int b) { + constexpr int MAX_T_VALUE = std::numeric_limits::max(); if (b < a) { b += MAX_T_VALUE; } From 103f9e04fa0efb1544209520ef538de073978489 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 23 Jul 2018 12:58:50 -0700 Subject: [PATCH 38/75] 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 5315b020ec2ec2087c7484b882a77a3610c9ff55 Mon Sep 17 00:00:00 2001 From: Simon Walton Date: Fri, 27 Jul 2018 14:51:24 -0700 Subject: [PATCH 39/75] Use locking for the OctreePacketProcessor additions --- interface/src/octree/OctreePacketProcessor.cpp | 8 ++++++-- interface/src/octree/OctreePacketProcessor.h | 4 +++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/interface/src/octree/OctreePacketProcessor.cpp b/interface/src/octree/OctreePacketProcessor.cpp index 696fa4ffd4..62dcd056e9 100644 --- a/interface/src/octree/OctreePacketProcessor.cpp +++ b/interface/src/octree/OctreePacketProcessor.cpp @@ -115,6 +115,8 @@ void OctreePacketProcessor::processPacket(QSharedPointer messag // Read sequence # OCTREE_PACKET_SEQUENCE completionNumber; message->readPrimitive(&completionNumber); + + Locker lock(_completionMutex); _completionSequenceNumber = completionNumber; _completionSequenceNumberValid = true; } break; @@ -126,6 +128,7 @@ void OctreePacketProcessor::processPacket(QSharedPointer messag } void OctreePacketProcessor::resetCompletionSequenceNumber() { + Locker lock(_completionMutex); _completionSequenceNumber = false; } @@ -140,7 +143,8 @@ namespace { } bool OctreePacketProcessor::octreeSequenceIsComplete(int sequenceNumber) const { - const int completionSequenceNumber = _completionSequenceNumber; + Locker lock(_completionMutex); + // If we've received the flagged seq # and the current one is >= it. return _completionSequenceNumberValid && - !lessThanWraparound(completionSequenceNumber, sequenceNumber); + !lessThanWraparound(_completionSequenceNumber, sequenceNumber); } diff --git a/interface/src/octree/OctreePacketProcessor.h b/interface/src/octree/OctreePacketProcessor.h index f7e001fbde..ad1ab6c36c 100644 --- a/interface/src/octree/OctreePacketProcessor.h +++ b/interface/src/octree/OctreePacketProcessor.h @@ -37,8 +37,10 @@ private slots: void handleOctreePacket(QSharedPointer message, SharedNodePointer senderNode); private: + mutable std::mutex _completionMutex; + using Locker = std::lock_guard; bool _completionSequenceNumberValid { false }; - std::atomic _completionSequenceNumber { 0 }; + int _completionSequenceNumber { 0 }; }; #endif // hifi_OctreePacketProcessor_h From ba8d44544422cd1a0076c4385f513d210b69303c Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Sat, 28 Jul 2018 00:25:16 +0200 Subject: [PATCH 40/75] 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 2ac6ca3291015d0b5ebdcc676ada0bf9413f31bc Mon Sep 17 00:00:00 2001 From: Simon Walton Date: Fri, 27 Jul 2018 17:32:35 -0700 Subject: [PATCH 41/75] Remove old physics-enabling code --- interface/src/Application.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 1c4de2165a..6c5efee807 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -5475,10 +5475,9 @@ void Application::update(float deltaTime) { // we haven't yet enabled physics. we wait until we think we have all the collision information // for nearby entities before starting bullet up. quint64 now = usecTimestampNow(); - //const int PHYSICS_CHECK_TIMEOUT = 2 * USECS_PER_SECOND; + // Check for flagged EntityData having arrived. auto entityTreeRenderer = getEntities(); if (entityTreeRenderer && _octreeProcessor.octreeSequenceIsComplete(entityTreeRenderer->getLastOctreeMessageSequence()) ) { - /*if (now - _lastPhysicsCheckTime > PHYSICS_CHECK_TIMEOUT || _fullSceneReceivedCounter > _fullSceneCounterAtLastPhysicsCheck) {*/ // we've received a new full-scene octree stats packet, or it's been long enough to try again anyway _lastPhysicsCheckTime = now; _fullSceneCounterAtLastPhysicsCheck = _fullSceneReceivedCounter; From 3d1fe7da9f09e86118e844c6c33d0b38c5e4506e Mon Sep 17 00:00:00 2001 From: Simon Walton Date: Fri, 27 Jul 2018 18:22:36 -0700 Subject: [PATCH 42/75] Reset known entity-state when leaving initial send state --- assignment-client/src/entities/EntityTreeSendThread.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/assignment-client/src/entities/EntityTreeSendThread.cpp b/assignment-client/src/entities/EntityTreeSendThread.cpp index 154d22f253..6079f03c26 100644 --- a/assignment-client/src/entities/EntityTreeSendThread.cpp +++ b/assignment-client/src/entities/EntityTreeSendThread.cpp @@ -170,6 +170,7 @@ bool EntityTreeSendThread::traverseTreeAndSendContents(SharedNodePointer node, O if (sendComplete && nodeData->wantReportInitialCompletion() && _traversal.finished()) { // Dealt with all nearby entities. nodeData->setReportInitialCompletion(false); + resetState(); // Send EntityQueryInitialResultsComplete reliable packet ... auto initialCompletion = NLPacket::create(PacketType::EntityQueryInitialResultsComplete, -1, true); From be1bbc07c26de990ea3040a0a77269c5f7afec4b Mon Sep 17 00:00:00 2001 From: Simon Walton Date: Mon, 30 Jul 2018 10:20:55 -0700 Subject: [PATCH 43/75] Don't wait for (nonexistant) ES when in serverless mode --- interface/src/Application.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 6c5efee807..0037c9500f 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -5477,7 +5477,8 @@ void Application::update(float deltaTime) { quint64 now = usecTimestampNow(); // Check for flagged EntityData having arrived. auto entityTreeRenderer = getEntities(); - if (entityTreeRenderer && _octreeProcessor.octreeSequenceIsComplete(entityTreeRenderer->getLastOctreeMessageSequence()) ) { + if (isServerlessMode() || + (entityTreeRenderer && _octreeProcessor.octreeSequenceIsComplete(entityTreeRenderer->getLastOctreeMessageSequence()) )) { // we've received a new full-scene octree stats packet, or it's been long enough to try again anyway _lastPhysicsCheckTime = now; _fullSceneCounterAtLastPhysicsCheck = _fullSceneReceivedCounter; From 401995fb067e70a356834309ec3115fb2aee5907 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Mon, 30 Jul 2018 10:55:52 -0700 Subject: [PATCH 44/75] 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 45/75] 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 46/75] 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 47/75] 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 48/75] 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 8c512ec19bd8c13443faa388f48e0ec5e9781d23 Mon Sep 17 00:00:00 2001 From: Simon Walton Date: Mon, 30 Jul 2018 18:03:45 -0700 Subject: [PATCH 49/75] Send spherical view from Interface rather than creating in ES --- .../src/entities/EntityTreeSendThread.cpp | 12 +--------- .../src/entities/EntityTreeSendThread.h | 2 -- interface/src/Application.cpp | 22 ++++++++++++++----- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/assignment-client/src/entities/EntityTreeSendThread.cpp b/assignment-client/src/entities/EntityTreeSendThread.cpp index 6079f03c26..2e777ae0f1 100644 --- a/assignment-client/src/entities/EntityTreeSendThread.cpp +++ b/assignment-client/src/entities/EntityTreeSendThread.cpp @@ -17,9 +17,6 @@ #include "EntityServer.h" -// Initially just send all items within this distance. -const float EntityTreeSendThread::INITIAL_RADIUS = 10.0f; - EntityTreeSendThread::EntityTreeSendThread(OctreeServer* myServer, const SharedNodePointer& node) : OctreeSendThread(myServer, node) { @@ -113,14 +110,7 @@ bool EntityTreeSendThread::traverseTreeAndSendContents(SharedNodePointer node, O int32_t lodLevelOffset = nodeData->getBoundaryLevelAdjust() + (viewFrustumChanged ? LOW_RES_MOVING_ADJUST : NO_BOUNDARY_ADJUST); newView.lodScaleFactor = powf(2.0f, lodLevelOffset); - - if (nodeData->wantReportInitialCompletion() && !newView.viewFrustums.empty()) { - auto& mainView = newView.viewFrustums[0]; - // Force acceptance within INITIAL_RADIUS. - mainView.setSimpleRadius(INITIAL_RADIUS); - newView.lodScaleFactor = 0.0f; - } - + startNewTraversal(newView, root); // When the viewFrustum changed the sort order may be incorrect, so we re-sort diff --git a/assignment-client/src/entities/EntityTreeSendThread.h b/assignment-client/src/entities/EntityTreeSendThread.h index c9f4d06164..199769ca09 100644 --- a/assignment-client/src/entities/EntityTreeSendThread.h +++ b/assignment-client/src/entities/EntityTreeSendThread.h @@ -58,8 +58,6 @@ private: int32_t _numEntitiesOffset { 0 }; uint16_t _numEntities { 0 }; - const static float INITIAL_RADIUS; - private slots: void editingEntityPointer(const EntityItemPointer& entity); void deletingEntityPointer(EntityItem* entity); diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 0037c9500f..bbb8dc8161 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -374,6 +374,7 @@ static const int THROTTLED_SIM_FRAME_PERIOD_MS = MSECS_PER_SECOND / THROTTLED_SI static const uint32_t INVALID_FRAME = UINT32_MAX; static const float PHYSICS_READY_RANGE = 3.0f; // how far from avatar to check for entities that aren't ready for simulation +static const float INITIAL_QUERY_RADIUS = 10.0f; // priority radius for entities before physics enabled static const QString DESKTOP_LOCATION = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation); @@ -6130,12 +6131,23 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType) { return; // bail early if settings are not loaded } - _octreeQuery.setConicalViews(_conicalViews); + const bool isModifiedQuery = !_physicsEnabled; + if (isModifiedQuery) { + // Create modified view that is a simple sphere. + ConicalViewFrustum sphericalView; + sphericalView.setSimpleRadius(INITIAL_QUERY_RADIUS); + _octreeQuery.setConicalViews({ sphericalView }); + _octreeQuery.setOctreeSizeScale(DEFAULT_OCTREE_SIZE_SCALE); + static constexpr float MIN_LOD_ADJUST = -20.0f; + _octreeQuery.setBoundaryLevelAdjust(MIN_LOD_ADJUST); + } else { + _octreeQuery.setConicalViews(_conicalViews); + auto lodManager = DependencyManager::get(); + _octreeQuery.setOctreeSizeScale(lodManager->getOctreeSizeScale()); + _octreeQuery.setBoundaryLevelAdjust(lodManager->getBoundaryLevelAdjust()); + } + _octreeQuery.setReportInitialCompletion(isModifiedQuery); - auto lodManager = DependencyManager::get(); - _octreeQuery.setOctreeSizeScale(lodManager->getOctreeSizeScale()); - _octreeQuery.setBoundaryLevelAdjust(lodManager->getBoundaryLevelAdjust()); - _octreeQuery.setReportInitialCompletion(!_physicsEnabled); auto nodeList = DependencyManager::get(); From 4a722a62f7a106c7603a1cb8d4e6f5ad739729f8 Mon Sep 17 00:00:00 2001 From: David Back Date: Tue, 31 Jul 2018 11:51:16 -0700 Subject: [PATCH 50/75] 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 51/75] 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 52/75] 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 53/75] 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 a320308eaf7a8b1a9f94a962c2200e7a2e65c859 Mon Sep 17 00:00:00 2001 From: Simon Walton Date: Tue, 31 Jul 2018 13:54:22 -0700 Subject: [PATCH 54/75] Fix sequence number encoding issue Don't mix QDataStream and readPrimitive. Also fix logic issues in completion check; move new packet type; don't reset known sent entities upon initial completion; other reviewer recommendations. --- .../src/entities/EntityTreeSendThread.cpp | 7 +++---- interface/src/Application.cpp | 1 + interface/src/octree/OctreePacketProcessor.cpp | 4 ++-- libraries/networking/src/udt/PacketHeaders.cpp | 2 +- libraries/networking/src/udt/PacketHeaders.h | 2 +- tools/dissectors/1-hfudt.lua | 10 +++++----- 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/assignment-client/src/entities/EntityTreeSendThread.cpp b/assignment-client/src/entities/EntityTreeSendThread.cpp index 2e777ae0f1..7e4ccc88cd 100644 --- a/assignment-client/src/entities/EntityTreeSendThread.cpp +++ b/assignment-client/src/entities/EntityTreeSendThread.cpp @@ -160,12 +160,11 @@ bool EntityTreeSendThread::traverseTreeAndSendContents(SharedNodePointer node, O if (sendComplete && nodeData->wantReportInitialCompletion() && _traversal.finished()) { // Dealt with all nearby entities. nodeData->setReportInitialCompletion(false); - resetState(); // Send EntityQueryInitialResultsComplete reliable packet ... - auto initialCompletion = NLPacket::create(PacketType::EntityQueryInitialResultsComplete, -1, true); - QDataStream initialCompletionStream(initialCompletion.get()); - initialCompletionStream << OCTREE_PACKET_SEQUENCE(nodeData->getSequenceNumber() - 1U); + auto initialCompletion = NLPacket::create(PacketType::EntityQueryInitialResultsComplete, + sizeof(OCTREE_PACKET_SEQUENCE), true); + initialCompletion->writePrimitive(OCTREE_PACKET_SEQUENCE(nodeData->getSequenceNumber() - 1U)); DependencyManager::get()->sendPacket(std::move(initialCompletion), *node.data()); } diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index bbb8dc8161..3969e7617e 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -5483,6 +5483,7 @@ void Application::update(float deltaTime) { // we've received a new full-scene octree stats packet, or it's been long enough to try again anyway _lastPhysicsCheckTime = now; _fullSceneCounterAtLastPhysicsCheck = _fullSceneReceivedCounter; + _lastQueriedViews.clear(); // Force new view. // process octree stats packets are sent in between full sends of a scene (this isn't currently true). // We keep physics disabled until we've received a full scene and everything near the avatar in that diff --git a/interface/src/octree/OctreePacketProcessor.cpp b/interface/src/octree/OctreePacketProcessor.cpp index 62dcd056e9..76f62bcc4e 100644 --- a/interface/src/octree/OctreePacketProcessor.cpp +++ b/interface/src/octree/OctreePacketProcessor.cpp @@ -135,7 +135,7 @@ void OctreePacketProcessor::resetCompletionSequenceNumber() { namespace { template bool lessThanWraparound(int a, int b) { constexpr int MAX_T_VALUE = std::numeric_limits::max(); - if (b < a) { + if (b <= a) { b += MAX_T_VALUE; } return (b - a) < (MAX_T_VALUE / 2); @@ -146,5 +146,5 @@ bool OctreePacketProcessor::octreeSequenceIsComplete(int sequenceNumber) const { Locker lock(_completionMutex); // If we've received the flagged seq # and the current one is >= it. return _completionSequenceNumberValid && - !lessThanWraparound(_completionSequenceNumber, sequenceNumber); + !lessThanWraparound(sequenceNumber, _completionSequenceNumber); } diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index bb9666ee37..13ffcb5120 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -95,7 +95,7 @@ PacketVersion versionForPacketType(PacketType packetType) { case PacketType::AvatarIdentityRequest: return 22; default: - return 22; + return 21; } } diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 7cba3baaf0..073f3f7c42 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -126,13 +126,13 @@ public: EntityScriptCallMethod, ChallengeOwnershipRequest, ChallengeOwnershipReply, - EntityQueryInitialResultsComplete, OctreeDataFileRequest, OctreeDataFileReply, OctreeDataPersist, EntityClone, + EntityQueryInitialResultsComplete, NUM_PACKET_TYPE }; diff --git a/tools/dissectors/1-hfudt.lua b/tools/dissectors/1-hfudt.lua index 9bed892885..26494bb515 100644 --- a/tools/dissectors/1-hfudt.lua +++ b/tools/dissectors/1-hfudt.lua @@ -156,11 +156,11 @@ local packet_types = { [92] = "EntityScriptCallMethod", [93] = "ChallengeOwnershipRequest", [94] = "ChallengeOwnershipReply", - [95] = "EntityQueryInitialResultsComplete", - [96] = "OctreeDataFileRequest", - [97] = "OctreeDataFileReply", - [98] = "OctreeDataPersist", - [99] = "EntityClone" + [95] = "OctreeDataFileRequest", + [96] = "OctreeDataFileReply", + [97] = "OctreeDataPersist", + [98] = "EntityClone", + [99] = "EntityQueryInitialResultsComplete" } local unsourced_packet_types = { From bbdc7ba38025fa7dfe5b0eb233bdd1e5f4c789df Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 31 Jul 2018 10:19:12 -0700 Subject: [PATCH 55/75] 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 4b41804326c8cda1e182e25e078d3579965ae301 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Tue, 31 Jul 2018 14:52:01 -0700 Subject: [PATCH 56/75] Fix MS17168: Filter My Purchases when clicking View link on Confirmation --- interface/resources/qml/hifi/commerce/checkout/Checkout.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml index cac62d3976..4d47479589 100644 --- a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml +++ b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml @@ -876,7 +876,7 @@ Rectangle { horizontalAlignment: Text.AlignLeft; verticalAlignment: Text.AlignVCenter; onLinkActivated: { - sendToScript({method: 'checkout_goToPurchases'}); + sendToScript({method: 'checkout_goToPurchases', filterText: root.itemName}); } } From 003e826d6072118d9fc29984d5ab72adde45244e Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Wed, 1 Aug 2018 00:23:34 +0200 Subject: [PATCH 57/75] 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 64fc3e1091c3ee4a7777c7641341117e54f3d624 Mon Sep 17 00:00:00 2001 From: Simon Walton Date: Tue, 31 Jul 2018 15:30:33 -0700 Subject: [PATCH 58/75] ThreadedAssignment calls virtual stop() upon domain disconnect --- assignment-client/src/Agent.cpp | 16 ++++++---------- assignment-client/src/Agent.h | 6 ++++++ assignment-client/src/audio/AudioMixer.cpp | 1 - assignment-client/src/entities/EntityServer.cpp | 1 - .../src/scripts/EntityScriptServer.cpp | 2 -- libraries/networking/src/ThreadedAssignment.cpp | 6 ++++-- libraries/networking/src/ThreadedAssignment.h | 2 +- 7 files changed, 17 insertions(+), 17 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 0be691662d..cd4f59332a 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -336,7 +336,6 @@ void Agent::scriptRequestFinished() { } setFinished(true); - ThreadedAssignment::aboutToFinish(); } request->deleteLater(); @@ -499,7 +498,6 @@ void Agent::executeScript() { DependencyManager::destroy(); setFinished(true); - ThreadedAssignment::aboutToFinish(); } QUuid Agent::getSessionUUID() const { @@ -827,14 +825,6 @@ void Agent::processAgentAvatarAudio() { void Agent::aboutToFinish() { setIsAvatar(false);// will stop timers for sending identity packets - // If script engine not started yet then finish up, else will be done when - // script engine exits. - if (_scriptEngine) { - _scriptEngine->stop(); - } else { - ThreadedAssignment::aboutToFinish(); - } - // our entity tree is going to go away so tell that to the EntityScriptingInterface DependencyManager::get()->setEntityTree(nullptr); @@ -864,3 +854,9 @@ void Agent::aboutToFinish() { _encoder = nullptr; } } + +void Agent::stop() { + if (_scriptEngine) { + _scriptEngine->stop(); + } +} diff --git a/assignment-client/src/Agent.h b/assignment-client/src/Agent.h index 0fc3fbe1f9..a5883805bb 100644 --- a/assignment-client/src/Agent.h +++ b/assignment-client/src/Agent.h @@ -97,6 +97,12 @@ public slots: */ bool isAvatar() const { return _isAvatar; } + /**jsdoc + * @function Agent.stop + * @deprecated This function is being removed from the API. + */ + Q_INVOKABLE virtual void stop() override; + private slots: void requestScript(); void scriptRequestFinished(); diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index ec9f26b53c..d56b22466e 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -109,7 +109,6 @@ AudioMixer::AudioMixer(ReceivedMessage& message) : void AudioMixer::aboutToFinish() { DependencyManager::destroy(); - ThreadedAssignment::aboutToFinish(); } void AudioMixer::queueAudioPacket(QSharedPointer message, SharedNodePointer node) { diff --git a/assignment-client/src/entities/EntityServer.cpp b/assignment-client/src/entities/EntityServer.cpp index 6303cafde8..8b86ba5eb2 100644 --- a/assignment-client/src/entities/EntityServer.cpp +++ b/assignment-client/src/entities/EntityServer.cpp @@ -72,7 +72,6 @@ void EntityServer::aboutToFinish() { DependencyManager::get()->cleanup(); OctreeServer::aboutToFinish(); - ThreadedAssignment::aboutToFinish(); } void EntityServer::handleEntityPacket(QSharedPointer message, SharedNodePointer senderNode) { diff --git a/assignment-client/src/scripts/EntityScriptServer.cpp b/assignment-client/src/scripts/EntityScriptServer.cpp index b40ffbcfb3..ebe25b11bf 100644 --- a/assignment-client/src/scripts/EntityScriptServer.cpp +++ b/assignment-client/src/scripts/EntityScriptServer.cpp @@ -587,6 +587,4 @@ void EntityScriptServer::aboutToFinish() { _codec->releaseEncoder(_encoder); _encoder = nullptr; } - - ThreadedAssignment::aboutToFinish(); } diff --git a/libraries/networking/src/ThreadedAssignment.cpp b/libraries/networking/src/ThreadedAssignment.cpp index d6c09d2a6c..13d4e0bf8b 100644 --- a/libraries/networking/src/ThreadedAssignment.cpp +++ b/libraries/networking/src/ThreadedAssignment.cpp @@ -66,6 +66,8 @@ void ThreadedAssignment::setFinished(bool isFinished) { // call our virtual aboutToFinish method - this gives the ThreadedAssignment subclass a chance to cleanup aboutToFinish(); + + emit finished(); } } } @@ -118,7 +120,7 @@ void ThreadedAssignment::checkInWithDomainServerOrExit() { if (_numQueuedCheckIns >= MAX_SILENT_DOMAIN_SERVER_CHECK_INS) { qCDebug(networking) << "At least" << MAX_SILENT_DOMAIN_SERVER_CHECK_INS << "have been queued without a response from domain-server" << "Stopping the current assignment"; - setFinished(true); + stop(); } else { auto nodeList = DependencyManager::get(); QMetaObject::invokeMethod(nodeList.data(), "sendDomainServerCheckIn"); @@ -130,5 +132,5 @@ void ThreadedAssignment::checkInWithDomainServerOrExit() { void ThreadedAssignment::domainSettingsRequestFailed() { qCDebug(networking) << "Failed to retreive settings object from domain-server. Bailing on assignment."; - setFinished(true); + stop(); } diff --git a/libraries/networking/src/ThreadedAssignment.h b/libraries/networking/src/ThreadedAssignment.h index f245ec917f..9372cfa667 100644 --- a/libraries/networking/src/ThreadedAssignment.h +++ b/libraries/networking/src/ThreadedAssignment.h @@ -25,7 +25,7 @@ public: ~ThreadedAssignment() { stop(); } void setFinished(bool isFinished); - virtual void aboutToFinish() { emit finished(); }; + virtual void aboutToFinish() { }; void addPacketStatsAndSendStatsPacket(QJsonObject statsObject); public slots: From d991dd230faa7e14887c97392c853729b685922f Mon Sep 17 00:00:00 2001 From: Simon Walton Date: Tue, 31 Jul 2018 15:39:38 -0700 Subject: [PATCH 59/75] Remove call to aboutToFinish from AssetServer --- assignment-client/src/assets/AssetServer.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 4ff4078255..e0c35b7148 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -342,7 +342,6 @@ void AssetServer::aboutToFinish() { while (_pendingBakes.size() > 0) { QCoreApplication::processEvents(); } - ThreadedAssignment::aboutToFinish(); } void AssetServer::run() { From acf1afea01fd90911bbf9647eaa84c9f1531c382 Mon Sep 17 00:00:00 2001 From: Liv Erickson Date: Tue, 31 Jul 2018 15:41:59 -0700 Subject: [PATCH 60/75] 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 33a46a6a827082956192af2d47d61b84474a19b8 Mon Sep 17 00:00:00 2001 From: Simon Walton Date: Tue, 31 Jul 2018 15:46:43 -0700 Subject: [PATCH 61/75] Make ThreadedAssignment::setFinished() protected --- libraries/networking/src/ThreadedAssignment.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/ThreadedAssignment.h b/libraries/networking/src/ThreadedAssignment.h index 9372cfa667..6eb72cfe0b 100644 --- a/libraries/networking/src/ThreadedAssignment.h +++ b/libraries/networking/src/ThreadedAssignment.h @@ -24,7 +24,6 @@ public: ThreadedAssignment(ReceivedMessage& message); ~ThreadedAssignment() { stop(); } - void setFinished(bool isFinished); virtual void aboutToFinish() { }; void addPacketStatsAndSendStatsPacket(QJsonObject statsObject); @@ -61,6 +60,7 @@ signals: protected: void commonInit(const QString& targetName, NodeType_t nodeType); + void setFinished(bool isFinished); bool _isFinished; QTimer _domainServerTimer; From 5a92032bdd5f4812a8a8961f427cb6e96181a29e Mon Sep 17 00:00:00 2001 From: Simon Walton Date: Tue, 31 Jul 2018 16:14:00 -0700 Subject: [PATCH 62/75] ThreadedAssignment::stop no longer deprecated --- assignment-client/src/Agent.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/assignment-client/src/Agent.h b/assignment-client/src/Agent.h index 4bc6beb431..7d47c8e713 100644 --- a/assignment-client/src/Agent.h +++ b/assignment-client/src/Agent.h @@ -67,10 +67,6 @@ public slots: void setIsAvatar(bool isAvatar); bool isAvatar() const { return _isAvatar; } - /**jsdoc - * @function Agent.stop - * @deprecated This function is being removed from the API. - */ Q_INVOKABLE virtual void stop() override; private slots: From e8068fea0a2f495318ea781b0492a983af9509bd Mon Sep 17 00:00:00 2001 From: David Back Date: Tue, 31 Jul 2018 17:18:35 -0700 Subject: [PATCH 63/75] 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 6f61642cb09e75e2f21596a30d11a1878a52d076 Mon Sep 17 00:00:00 2001 From: Simon Walton Date: Tue, 31 Jul 2018 18:10:49 -0700 Subject: [PATCH 64/75] Call setFinished() if script engine hasn't started up --- assignment-client/src/Agent.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index fb09efe287..23090e0d84 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -857,5 +857,7 @@ void Agent::aboutToFinish() { void Agent::stop() { if (_scriptEngine) { _scriptEngine->stop(); + } else { + setFinished(true); } } From fd780845bbf2e2da9260f8abfadbe8372992f581 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Tue, 31 Jul 2018 18:25:04 -0700 Subject: [PATCH 65/75] 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 ed75fe673e82b1efdc15356c6ba714bfee0a9b4a Mon Sep 17 00:00:00 2001 From: Simon Walton Date: Tue, 31 Jul 2018 18:28:14 -0700 Subject: [PATCH 66/75] Replace int+bool with single atomic int --- interface/src/octree/OctreePacketProcessor.cpp | 8 ++------ interface/src/octree/OctreePacketProcessor.h | 5 +---- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/interface/src/octree/OctreePacketProcessor.cpp b/interface/src/octree/OctreePacketProcessor.cpp index 76f62bcc4e..9196699473 100644 --- a/interface/src/octree/OctreePacketProcessor.cpp +++ b/interface/src/octree/OctreePacketProcessor.cpp @@ -116,9 +116,7 @@ void OctreePacketProcessor::processPacket(QSharedPointer messag OCTREE_PACKET_SEQUENCE completionNumber; message->readPrimitive(&completionNumber); - Locker lock(_completionMutex); _completionSequenceNumber = completionNumber; - _completionSequenceNumberValid = true; } break; default: { @@ -128,8 +126,7 @@ void OctreePacketProcessor::processPacket(QSharedPointer messag } void OctreePacketProcessor::resetCompletionSequenceNumber() { - Locker lock(_completionMutex); - _completionSequenceNumber = false; + _completionSequenceNumber = -1; } namespace { @@ -143,8 +140,7 @@ namespace { } bool OctreePacketProcessor::octreeSequenceIsComplete(int sequenceNumber) const { - Locker lock(_completionMutex); // If we've received the flagged seq # and the current one is >= it. - return _completionSequenceNumberValid && + return _completionSequenceNumber != -1 && !lessThanWraparound(sequenceNumber, _completionSequenceNumber); } diff --git a/interface/src/octree/OctreePacketProcessor.h b/interface/src/octree/OctreePacketProcessor.h index ad1ab6c36c..9c5eaca8ec 100644 --- a/interface/src/octree/OctreePacketProcessor.h +++ b/interface/src/octree/OctreePacketProcessor.h @@ -37,10 +37,7 @@ private slots: void handleOctreePacket(QSharedPointer message, SharedNodePointer senderNode); private: - mutable std::mutex _completionMutex; - using Locker = std::lock_guard; - bool _completionSequenceNumberValid { false }; - int _completionSequenceNumber { 0 }; + std::atomic _completionSequenceNumber { -1 }; }; #endif // hifi_OctreePacketProcessor_h From 6369cee0d1aa69cd48defc0eeaf218f0b95ac4c0 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 24 Jul 2018 16:17:03 -0700 Subject: [PATCH 67/75] 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); From b18c1f0e1eed058b9bc30dc36588c82e25334bcb Mon Sep 17 00:00:00 2001 From: Simon Walton Date: Wed, 1 Aug 2018 10:10:45 -0700 Subject: [PATCH 68/75] Use defined value for invalid sequence number --- interface/src/octree/OctreePacketProcessor.cpp | 4 ++-- interface/src/octree/OctreePacketProcessor.h | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/interface/src/octree/OctreePacketProcessor.cpp b/interface/src/octree/OctreePacketProcessor.cpp index 9196699473..063b07f699 100644 --- a/interface/src/octree/OctreePacketProcessor.cpp +++ b/interface/src/octree/OctreePacketProcessor.cpp @@ -126,7 +126,7 @@ void OctreePacketProcessor::processPacket(QSharedPointer messag } void OctreePacketProcessor::resetCompletionSequenceNumber() { - _completionSequenceNumber = -1; + _completionSequenceNumber = INVALID_SEQUENCE; } namespace { @@ -141,6 +141,6 @@ namespace { bool OctreePacketProcessor::octreeSequenceIsComplete(int sequenceNumber) const { // If we've received the flagged seq # and the current one is >= it. - return _completionSequenceNumber != -1 && + return _completionSequenceNumber != INVALID_SEQUENCE && !lessThanWraparound(sequenceNumber, _completionSequenceNumber); } diff --git a/interface/src/octree/OctreePacketProcessor.h b/interface/src/octree/OctreePacketProcessor.h index 9c5eaca8ec..edba48a238 100644 --- a/interface/src/octree/OctreePacketProcessor.h +++ b/interface/src/octree/OctreePacketProcessor.h @@ -37,7 +37,8 @@ private slots: void handleOctreePacket(QSharedPointer message, SharedNodePointer senderNode); private: - std::atomic _completionSequenceNumber { -1 }; + static constexpr int INVALID_SEQUENCE = -1; + std::atomic _completionSequenceNumber { INVALID_SEQUENCE }; }; #endif // hifi_OctreePacketProcessor_h From 9d42a6e08fbbbb9eab4ba52335621eac2beefa02 Mon Sep 17 00:00:00 2001 From: Simon Walton Date: Wed, 1 Aug 2018 10:37:28 -0700 Subject: [PATCH 69/75] Change method name per coding standards --- assignment-client/src/AssignmentClientMonitor.cpp | 4 ++-- assignment-client/src/AssignmentClientMonitor.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/assignment-client/src/AssignmentClientMonitor.cpp b/assignment-client/src/AssignmentClientMonitor.cpp index eb764a128c..330023dae0 100644 --- a/assignment-client/src/AssignmentClientMonitor.cpp +++ b/assignment-client/src/AssignmentClientMonitor.cpp @@ -74,7 +74,7 @@ AssignmentClientMonitor::AssignmentClientMonitor(const unsigned int numAssignmen auto& packetReceiver = DependencyManager::get()->getPacketReceiver(); packetReceiver.registerListener(PacketType::AssignmentClientStatus, this, "handleChildStatusPacket"); - adjustOsResources(std::max(_numAssignmentClientForks, _maxAssignmentClientForks)); + adjustOSResources(std::max(_numAssignmentClientForks, _maxAssignmentClientForks)); // use QProcess to fork off a process for each of the child assignment clients for (unsigned int i = 0; i < _numAssignmentClientForks; i++) { spawnChildClient(); @@ -377,7 +377,7 @@ bool AssignmentClientMonitor::handleHTTPRequest(HTTPConnection* connection, cons return true; } -void AssignmentClientMonitor::adjustOsResources(unsigned int numForks) const +void AssignmentClientMonitor::adjustOSResources(unsigned int numForks) const { #ifdef _POSIX_SOURCE // QProcess on Unix uses six (I think) descriptors, some temporarily, for each child proc. diff --git a/assignment-client/src/AssignmentClientMonitor.h b/assignment-client/src/AssignmentClientMonitor.h index 659ff4b001..5e32c50e0d 100644 --- a/assignment-client/src/AssignmentClientMonitor.h +++ b/assignment-client/src/AssignmentClientMonitor.h @@ -55,7 +55,7 @@ public slots: private: void spawnChildClient(); void simultaneousWaitOnChildren(int waitMsecs); - void adjustOsResources(unsigned int numForks) const; + void adjustOSResources(unsigned int numForks) const; QTimer _checkSparesTimer; // every few seconds see if it need fewer or more spare children From 0d92e2de0ac3dfe2cc75ac2b74950431e21af1e2 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 1 Aug 2018 11:21:54 -0700 Subject: [PATCH 70/75] remove bits from other-avatar collision mask --- libraries/shared/src/PhysicsCollisionGroups.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/libraries/shared/src/PhysicsCollisionGroups.h b/libraries/shared/src/PhysicsCollisionGroups.h index 9d99ec3532..ef18cb0b0e 100644 --- a/libraries/shared/src/PhysicsCollisionGroups.h +++ b/libraries/shared/src/PhysicsCollisionGroups.h @@ -59,7 +59,11 @@ const int32_t BULLET_COLLISION_MASK_KINEMATIC = BULLET_COLLISION_MASK_STATIC; // MY_AVATAR does not collide with itself const int32_t BULLET_COLLISION_MASK_MY_AVATAR = ~(BULLET_COLLISION_GROUP_COLLISIONLESS | BULLET_COLLISION_GROUP_MY_AVATAR); -const int32_t BULLET_COLLISION_MASK_OTHER_AVATAR = BULLET_COLLISION_MASK_DEFAULT; +// OTHER_AVATARs are dynamic, but are slammed to whatever the avatar-mixer says, which means +// their motion can't actually be affected by the local physics simulation -- we rely on the remote simulation +// to move its avatar around correctly and to communicate its motion through the avatar-mixer. +// Therefore, they only need to collide against things that can be affected by their motion: dynamic and MyAvatar +const int32_t BULLET_COLLISION_MASK_OTHER_AVATAR = BULLET_COLLISION_GROUP_DYNAMIC | BULLET_COLLISION_GROUP_MY_AVATAR; // COLLISIONLESS gets an empty mask. const int32_t BULLET_COLLISION_MASK_COLLISIONLESS = 0; From c9396998796d10768bdac8e43ea70a6ff66e73c8 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 1 Aug 2018 11:22:58 -0700 Subject: [PATCH 71/75] ignore other-avatar angularVelocity in physics simulation --- interface/src/avatar/AvatarMotionState.cpp | 29 ++++++++++++++++++--- interface/src/avatar/AvatarMotionState.h | 3 +++ libraries/physics/src/ObjectMotionState.cpp | 2 +- libraries/physics/src/ObjectMotionState.h | 2 +- 4 files changed, 30 insertions(+), 6 deletions(-) diff --git a/interface/src/avatar/AvatarMotionState.cpp b/interface/src/avatar/AvatarMotionState.cpp index 50c715b14a..298701ca5d 100644 --- a/interface/src/avatar/AvatarMotionState.cpp +++ b/interface/src/avatar/AvatarMotionState.cpp @@ -19,6 +19,7 @@ AvatarMotionState::AvatarMotionState(AvatarSharedPointer avatar, const btCollisionShape* shape) : ObjectMotionState(shape), _avatar(avatar) { assert(_avatar); _type = MOTIONSTATE_TYPE_AVATAR; + cacheShapeDiameter(); } void AvatarMotionState::handleEasyChanges(uint32_t& flags) { @@ -57,9 +58,6 @@ PhysicsMotionType AvatarMotionState::computePhysicsMotionType() const { const btCollisionShape* AvatarMotionState::computeNewShape() { ShapeInfo shapeInfo; std::static_pointer_cast(_avatar)->computeShapeInfo(shapeInfo); - glm::vec3 halfExtents = shapeInfo.getHalfExtents(); - halfExtents.y = 0.0f; - _diameter = 2.0f * glm::length(halfExtents); return getShapeManager()->getShape(shapeInfo); } @@ -141,7 +139,10 @@ glm::vec3 AvatarMotionState::getObjectLinearVelocity() const { // virtual glm::vec3 AvatarMotionState::getObjectAngularVelocity() const { - return _avatar->getWorldAngularVelocity(); + // HACK: avatars use a capusle collision shape and their angularVelocity in the local simulation is unimportant. + // Therefore, as optimization toward support for larger crowds we ignore it and return zero. + //return _avatar->getWorldAngularVelocity(); + return glm::vec3(0.0f); } // virtual @@ -174,3 +175,23 @@ float AvatarMotionState::getMass() const { return std::static_pointer_cast(_avatar)->computeMass(); } +void AvatarMotionState::cacheShapeDiameter() { + if (_shape) { + // measure XZ diameter of capsule shape + btVector3 aabbMin, aabbMax; + btTransform transform; + transform.setIdentity(); + _shape->getAabb(transform, aabbMin, aabbMax); + aabbMax -= aabbMin; + aabbMax.setY(0.0f); + const float SQRT_TWO = 1.414213562f; + _diameter = SQRT_TWO * aabbMax.length(); + } else { + _diameter = 0.0f; + } +} + +void AvatarMotionState::setShape(const btCollisionShape* shape) { + cacheShapeDiameter(); + ObjectMotionState::setShape(shape); +} diff --git a/interface/src/avatar/AvatarMotionState.h b/interface/src/avatar/AvatarMotionState.h index 9228641b25..62fbc566f3 100644 --- a/interface/src/avatar/AvatarMotionState.h +++ b/interface/src/avatar/AvatarMotionState.h @@ -74,6 +74,9 @@ public: friend class Avatar; protected: + void setShape(const btCollisionShape* shape) override; + void cacheShapeDiameter(); + // the dtor had been made protected to force the compiler to verify that it is only // ever called by the Avatar class dtor. ~AvatarMotionState(); diff --git a/libraries/physics/src/ObjectMotionState.cpp b/libraries/physics/src/ObjectMotionState.cpp index 310cf7cec1..c814140930 100644 --- a/libraries/physics/src/ObjectMotionState.cpp +++ b/libraries/physics/src/ObjectMotionState.cpp @@ -64,9 +64,9 @@ ShapeManager* ObjectMotionState::getShapeManager() { } ObjectMotionState::ObjectMotionState(const btCollisionShape* shape) : - _shape(shape), _lastKinematicStep(worldSimulationStep) { + setShape(shape); } ObjectMotionState::~ObjectMotionState() { diff --git a/libraries/physics/src/ObjectMotionState.h b/libraries/physics/src/ObjectMotionState.h index 7439c1c38d..269117b28c 100644 --- a/libraries/physics/src/ObjectMotionState.h +++ b/libraries/physics/src/ObjectMotionState.h @@ -181,7 +181,7 @@ protected: MotionStateType _type { MOTIONSTATE_TYPE_INVALID }; // type of MotionState PhysicsMotionType _motionType { MOTION_TYPE_STATIC }; // type of motion: KINEMATIC, DYNAMIC, or STATIC - const btCollisionShape* _shape; + const btCollisionShape* _shape { nullptr }; btRigidBody* _body { nullptr }; float _density { 1.0f }; From bd6f00e707c4df82b8b9c26db4f2297f4c3bb919 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 1 Aug 2018 11:58:52 -0700 Subject: [PATCH 72/75] eliminate angular dynamics of other-avatars --- interface/src/avatar/AvatarMotionState.cpp | 12 ++++++++++++ interface/src/avatar/AvatarMotionState.h | 1 + libraries/physics/src/ObjectMotionState.h | 2 +- 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/interface/src/avatar/AvatarMotionState.cpp b/interface/src/avatar/AvatarMotionState.cpp index 298701ca5d..bff5233f1d 100644 --- a/interface/src/avatar/AvatarMotionState.cpp +++ b/interface/src/avatar/AvatarMotionState.cpp @@ -96,6 +96,10 @@ void AvatarMotionState::setWorldTransform(const btTransform& worldTrans) { btVector3 velocity = glmToBullet(getObjectLinearVelocity()) + (1.0f / SPRING_TIMESCALE) * offsetToTarget; _body->setLinearVelocity(velocity); _body->setAngularVelocity(glmToBullet(getObjectAngularVelocity())); + // slam its rotation + btTransform newTransform = worldTrans; + newTransform.setRotation(glmToBullet(getObjectRotation())); + _body->setWorldTransform(newTransform); } } @@ -191,6 +195,14 @@ void AvatarMotionState::cacheShapeDiameter() { } } +void AvatarMotionState::setRigidBody(btRigidBody* body) { + ObjectMotionState::setRigidBody(body); + if (_body) { + // remove angular dynamics from this body + _body->setAngularFactor(0.0f); + } +} + void AvatarMotionState::setShape(const btCollisionShape* shape) { cacheShapeDiameter(); ObjectMotionState::setShape(shape); diff --git a/interface/src/avatar/AvatarMotionState.h b/interface/src/avatar/AvatarMotionState.h index 62fbc566f3..a458704b1a 100644 --- a/interface/src/avatar/AvatarMotionState.h +++ b/interface/src/avatar/AvatarMotionState.h @@ -74,6 +74,7 @@ public: friend class Avatar; protected: + void setRigidBody(btRigidBody* body) override; void setShape(const btCollisionShape* shape) override; void cacheShapeDiameter(); diff --git a/libraries/physics/src/ObjectMotionState.h b/libraries/physics/src/ObjectMotionState.h index 269117b28c..74173c3f47 100644 --- a/libraries/physics/src/ObjectMotionState.h +++ b/libraries/physics/src/ObjectMotionState.h @@ -175,7 +175,7 @@ protected: virtual void setMotionType(PhysicsMotionType motionType); void updateCCDConfiguration(); - void setRigidBody(btRigidBody* body); + virtual void setRigidBody(btRigidBody* body); virtual void setShape(const btCollisionShape* shape); MotionStateType _type { MOTIONSTATE_TYPE_INVALID }; // type of MotionState From 67528cb64636c70bcef7d8ab09471b2019b06ab5 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Wed, 1 Aug 2018 15:34:53 -0700 Subject: [PATCH 73/75] Fix MS17215: Auto-show Confirmed txns in Recent Activity when many Pending txns present --- .../qml/hifi/commerce/wallet/WalletHome.qml | 50 +++++++++++++++---- .../qml/hifi/models/PSFListModel.qml | 33 ++++++++++++ 2 files changed, 72 insertions(+), 11 deletions(-) diff --git a/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml b/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml index a0c6057b3b..50208793fe 100644 --- a/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml +++ b/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml @@ -142,7 +142,7 @@ Item { Timer { id: refreshTimer; - interval: 4000; + interval: 6000; onTriggered: { if (transactionHistory.atYBeginning) { console.log("Refreshing 1st Page of Recent Activity..."); @@ -211,6 +211,7 @@ Item { HifiModels.PSFListModel { id: transactionHistoryModel; + property int lastPendingCount: 0; listModelName: "transaction history"; // For debugging. Alternatively, we could specify endpoint for that purpose, even though it's not used directly. listView: transactionHistory; itemsPerPage: 6; @@ -221,8 +222,26 @@ Item { processPage: function (data) { console.debug('processPage', transactionHistoryModel.listModelName, JSON.stringify(data)); var result, pending; // Set up or get the accumulator for pending. - if (transactionHistoryModel.currentPageToRetrieve == 1) { - pending = {transaction_type: "pendingCount", count: 0}; + if (transactionHistoryModel.currentPageToRetrieve === 1) { + // The initial data elements inside the ListModel MUST contain all keys + // that will be used in future data. + pending = { + transaction_type: "pendingCount", + count: 0, + created_at: 0, + hfc_text: "", + id: "", + message: "", + place_name: "", + received_certs: 0, + received_money: 0, + recipient_name: "", + sender_name: "", + sent_certs: 0, + sent_money: 0, + status: "", + transaction_text: "" + }; result = [pending]; } else { pending = transactionHistoryModel.get(0); @@ -239,6 +258,15 @@ Item { } }); + if (lastPendingCount === 0) { + lastPendingCount = pending.count; + } else { + if (lastPendingCount !== pending.count) { + transactionHistoryModel.getNextPageIfNotEnoughVerticalResults(); + } + lastPendingCount = pending.count; + } + // Only auto-refresh if the user hasn't scrolled // and there is more data to grab if (transactionHistory.atYBeginning && data.history.length) { @@ -257,13 +285,13 @@ Item { ListView { id: transactionHistory; ScrollBar.vertical: ScrollBar { - policy: transactionHistory.contentHeight > parent.parent.height ? ScrollBar.AlwaysOn : ScrollBar.AsNeeded; - parent: transactionHistory.parent; - anchors.top: transactionHistory.top; - anchors.left: transactionHistory.right; - anchors.leftMargin: 4; - anchors.bottom: transactionHistory.bottom; - width: 20; + policy: transactionHistory.contentHeight > parent.parent.height ? ScrollBar.AlwaysOn : ScrollBar.AsNeeded; + parent: transactionHistory.parent; + anchors.top: transactionHistory.top; + anchors.left: transactionHistory.right; + anchors.leftMargin: 4; + anchors.bottom: transactionHistory.bottom; + width: 20; } anchors.centerIn: parent; width: parent.width - 12; @@ -340,7 +368,7 @@ Item { } HifiControlsUit.Separator { - colorScheme: 1; + colorScheme: 1; anchors.left: parent.left; anchors.right: parent.right; anchors.bottom: parent.bottom; diff --git a/interface/resources/qml/hifi/models/PSFListModel.qml b/interface/resources/qml/hifi/models/PSFListModel.qml index 542145904f..ad9fbcc8ef 100644 --- a/interface/resources/qml/hifi/models/PSFListModel.qml +++ b/interface/resources/qml/hifi/models/PSFListModel.qml @@ -38,6 +38,16 @@ ListModel { onSearchFilterChanged: if (initialized) { getFirstPage('delayClear'); } onTagsFilterChanged: if (initialized) { getFirstPage('delayClear'); } + // When considering a value for `itemsPerPage` in YOUR model, consider the following: + // - If your ListView delegates are of variable width/height, ensure you select + // an `itemsPerPage` value that would be sufficient to show one full page of data + // if all of the delegates were at their minimum heights. + // - If your first ListView delegate contains some special data (as in WalletHome's + // "Recent Activity" view), beware that your `itemsPerPage` value may _never_ reasonably be + // high enough such that the first page of data causes the view to be one-screen in height + // after retrieving the first page. This means data will automatically pop-in (after a short delay) + // until the combined heights of your View's delegates reach one-screen in height OR there is + // no more data to retrieve. See "needsMoreVerticalResults()" below. property int itemsPerPage: 100; // State. @@ -81,12 +91,35 @@ ListModel { function getNextPageIfVerticalScroll() { if (needsEarlyYFetch()) { getNextPage(); } } + function needsMoreHorizontalResults() { + return flickable + && currentPageToRetrieve > 0 + && flickable.contentWidth < flickable.width; + } + function needsMoreVerticalResults() { + return flickable + && currentPageToRetrieve > 0 + && flickable.contentHeight < flickable.height; + } + function getNextPageIfNotEnoughHorizontalResults() { + if (needsMoreHorizontalResults()) { + getNextPage(); + } + } + function getNextPageIfNotEnoughVerticalResults() { + if (needsMoreVerticalResults()) { + getNextPage(); + } + } + Component.onCompleted: { initialized = true; if (flickable && pageAhead > 0.0) { // Pun: Scrollers are usually one direction or another, such that only one of the following will actually fire. flickable.contentXChanged.connect(getNextPageIfHorizontalScroll); flickable.contentYChanged.connect(getNextPageIfVerticalScroll); + flickable.contentWidthChanged.connect(getNextPageIfNotEnoughHorizontalResults); + flickable.contentHeightChanged.connect(getNextPageIfNotEnoughVerticalResults); } } From 6f1487bbf8f779f5876c812e2543001eed228c56 Mon Sep 17 00:00:00 2001 From: Simon Walton Date: Wed, 1 Aug 2018 17:11:26 -0700 Subject: [PATCH 74/75] Don't explicitly use data method of shared node pointer --- assignment-client/src/entities/EntityTreeSendThread.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assignment-client/src/entities/EntityTreeSendThread.cpp b/assignment-client/src/entities/EntityTreeSendThread.cpp index 7e4ccc88cd..f7ca05fbf2 100644 --- a/assignment-client/src/entities/EntityTreeSendThread.cpp +++ b/assignment-client/src/entities/EntityTreeSendThread.cpp @@ -165,7 +165,7 @@ bool EntityTreeSendThread::traverseTreeAndSendContents(SharedNodePointer node, O auto initialCompletion = NLPacket::create(PacketType::EntityQueryInitialResultsComplete, sizeof(OCTREE_PACKET_SEQUENCE), true); initialCompletion->writePrimitive(OCTREE_PACKET_SEQUENCE(nodeData->getSequenceNumber() - 1U)); - DependencyManager::get()->sendPacket(std::move(initialCompletion), *node.data()); + DependencyManager::get()->sendPacket(std::move(initialCompletion), *node); } return sendComplete; From e336c9276dde27f5e3f6ca73f4e08d6f3c37c508 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 1 Aug 2018 17:39:57 -0700 Subject: [PATCH 75/75] first set shape THEN use it --- interface/src/avatar/AvatarMotionState.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/interface/src/avatar/AvatarMotionState.cpp b/interface/src/avatar/AvatarMotionState.cpp index bff5233f1d..07e6b3f6b0 100644 --- a/interface/src/avatar/AvatarMotionState.cpp +++ b/interface/src/avatar/AvatarMotionState.cpp @@ -181,15 +181,12 @@ float AvatarMotionState::getMass() const { void AvatarMotionState::cacheShapeDiameter() { if (_shape) { - // measure XZ diameter of capsule shape + // shape is capsuleY btVector3 aabbMin, aabbMax; btTransform transform; transform.setIdentity(); _shape->getAabb(transform, aabbMin, aabbMax); - aabbMax -= aabbMin; - aabbMax.setY(0.0f); - const float SQRT_TWO = 1.414213562f; - _diameter = SQRT_TWO * aabbMax.length(); + _diameter = (aabbMax - aabbMin).getX(); } else { _diameter = 0.0f; } @@ -204,6 +201,6 @@ void AvatarMotionState::setRigidBody(btRigidBody* body) { } void AvatarMotionState::setShape(const btCollisionShape* shape) { - cacheShapeDiameter(); ObjectMotionState::setShape(shape); + cacheShapeDiameter(); }