From bbe507ec0504fda0f67a084079692649aedc2e51 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 11 Mar 2016 09:53:10 +1300 Subject: [PATCH 01/77] Add file headers and update Qt versions in VR menu QML files --- .../resources/qml/menus/MenuMouseHandler.qml | 10 ++++++++++ interface/resources/qml/menus/VrMenuItem.qml | 16 +++++++++++++--- interface/resources/qml/menus/VrMenuView.qml | 17 +++++++++++++---- 3 files changed, 36 insertions(+), 7 deletions(-) diff --git a/interface/resources/qml/menus/MenuMouseHandler.qml b/interface/resources/qml/menus/MenuMouseHandler.qml index 6f507dd445..d99b7f7828 100644 --- a/interface/resources/qml/menus/MenuMouseHandler.qml +++ b/interface/resources/qml/menus/MenuMouseHandler.qml @@ -1,3 +1,13 @@ +// +// MessageDialog.qml +// +// Created by Bradley Austin Davis on 18 Jan 2016 +// Copyright 2016 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 +// + import QtQuick 2.5 import QtQuick.Controls 1.4 diff --git a/interface/resources/qml/menus/VrMenuItem.qml b/interface/resources/qml/menus/VrMenuItem.qml index c23a54a2c7..955ab86167 100644 --- a/interface/resources/qml/menus/VrMenuItem.qml +++ b/interface/resources/qml/menus/VrMenuItem.qml @@ -1,6 +1,16 @@ -import QtQuick 2.4 -import QtQuick.Controls 1.3 -import QtQuick.Controls.Styles 1.3 +// +// VrMenuItem.qml +// +// Created by Bradley Austin Davis on 29 Apr 2015 +// Copyright 2015 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 +// + +import QtQuick 2.5 +import QtQuick.Controls 1.4 +import QtQuick.Controls.Styles 1.4 import "../controls" import "../styles" diff --git a/interface/resources/qml/menus/VrMenuView.qml b/interface/resources/qml/menus/VrMenuView.qml index bbb9bd706e..8b0673229c 100644 --- a/interface/resources/qml/menus/VrMenuView.qml +++ b/interface/resources/qml/menus/VrMenuView.qml @@ -1,10 +1,19 @@ -import QtQuick 2.4 -import QtQuick.Controls 1.3 -import QtQuick.Controls.Styles 1.3 +// +// VrMenuView.qml +// +// Created by Bradley Austin Davis on 18 Jan 2016 +// Copyright 2016 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 +// + +import QtQuick 2.5 +import QtQuick.Controls 1.4 +import QtQuick.Controls.Styles 1.4 import "../styles" - FocusScope { id: root implicitHeight: border.height From 2b45971f8cfea55ffd894a5479b3a52904a6e755 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 11 Mar 2016 11:42:49 +1300 Subject: [PATCH 02/77] Style HMD menu backgrounds --- .../resources/qml/menus/MenuMouseHandler.qml | 4 ++-- interface/resources/qml/menus/VrMenuView.qml | 23 +++++++++++-------- .../qml/styles-uit/HifiConstants.qml | 2 ++ 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/interface/resources/qml/menus/MenuMouseHandler.qml b/interface/resources/qml/menus/MenuMouseHandler.qml index d99b7f7828..9ba158cb28 100644 --- a/interface/resources/qml/menus/MenuMouseHandler.qml +++ b/interface/resources/qml/menus/MenuMouseHandler.qml @@ -104,8 +104,8 @@ Item { function buildMenu(items, targetPosition) { var model = toModel(items); - // Menu's must be childed to desktop for Z-ordering - var newMenu = menuViewMaker.createObject(desktop, { model: model, z: topMenu ? topMenu.z + 1 : desktop.zLevels.menu }); + // Menus must be childed to desktop for Z-ordering + var newMenu = menuViewMaker.createObject(desktop, { model: model, z: topMenu ? topMenu.z + 1 : desktop.zLevels.menu, isSubMenu: topMenu !== null }); if (targetPosition) { newMenu.x = targetPosition.x newMenu.y = targetPosition.y - newMenu.height / 3 * 1 diff --git a/interface/resources/qml/menus/VrMenuView.qml b/interface/resources/qml/menus/VrMenuView.qml index 8b0673229c..8778bc4bd1 100644 --- a/interface/resources/qml/menus/VrMenuView.qml +++ b/interface/resources/qml/menus/VrMenuView.qml @@ -12,33 +12,35 @@ import QtQuick 2.5 import QtQuick.Controls 1.4 import QtQuick.Controls.Styles 1.4 -import "../styles" +import "../styles-uit" FocusScope { id: root - implicitHeight: border.height - implicitWidth: border.width + implicitHeight: background.height + implicitWidth: background.width property alias currentItem: listView.currentItem property alias model: listView.model + property bool isSubMenu: false signal selected(var item) + HifiConstants { id: hifi } - Border { - id: border + Rectangle { + id: background anchors.fill: listView - anchors.margins: -8 - border.color: hifi.colors.hifiBlue - color: hifi.colors.window - // color: "#7f7f7f7f" + radius: hifi.dimensions.borderRadius + border.width: hifi.dimensions.borderWidth + border.color: hifi.colors.lightGrayText80 + color: isSubMenu ? hifi.colors.faintGray : hifi.colors.faintGray80 } ListView { id: listView x: 8; y: 8 - HifiConstants { id: hifi } width: 128 height: count * 32 + topMargin: hifi.dimensions.menuPadding onEnabledChanged: recalcSize(); onVisibleChanged: recalcSize(); onCountChanged: recalcSize(); @@ -84,6 +86,7 @@ FocusScope { newHeight += currentItem.implicitHeight } } + newHeight += 2 * hifi.dimensions.menuPadding; // White space at top and bottom. if (maxWidth > width) { width = maxWidth; } diff --git a/interface/resources/qml/styles-uit/HifiConstants.qml b/interface/resources/qml/styles-uit/HifiConstants.qml index eb4c84b5b8..4f06b676e6 100644 --- a/interface/resources/qml/styles-uit/HifiConstants.qml +++ b/interface/resources/qml/styles-uit/HifiConstants.qml @@ -70,6 +70,7 @@ Item { readonly property color baseGrayHighlight40: "#66575757" readonly property color baseGrayHighlight15: "#26575757" readonly property color lightGrayText80: "#ccafafaf" + readonly property color faintGray80: "#cce3e3e3" readonly property color faintGray50: "#80e3e3e3" // Other colors @@ -135,6 +136,7 @@ Item { readonly property real modalDialogTitleHeight: 40 readonly property real controlLineHeight: 29 // Height of spinbox control on 1920 x 1080 monitor readonly property real controlInterlineHeight: 22 // 75% of controlLineHeight + readonly property real menuPadding: 12 } Item { From fb0f97264c29f5f9af8b96cb92e9abab1865430d Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 11 Mar 2016 15:24:35 +1300 Subject: [PATCH 03/77] Style HMD menu items --- interface/resources/qml/menus/VrMenuItem.qml | 55 ++++++++++++------- interface/resources/qml/menus/VrMenuView.qml | 14 +++-- .../qml/styles-uit/HifiConstants.qml | 5 +- 3 files changed, 48 insertions(+), 26 deletions(-) diff --git a/interface/resources/qml/menus/VrMenuItem.qml b/interface/resources/qml/menus/VrMenuItem.qml index 955ab86167..f2c077a59e 100644 --- a/interface/resources/qml/menus/VrMenuItem.qml +++ b/interface/resources/qml/menus/VrMenuItem.qml @@ -12,8 +12,8 @@ import QtQuick 2.5 import QtQuick.Controls 1.4 import QtQuick.Controls.Styles 1.4 -import "../controls" -import "../styles" +import "../controls-uit" +import "../styles-uit" Item { id: root @@ -21,24 +21,28 @@ Item { property alias text: label.text property var source - implicitHeight: source.visible ? label.implicitHeight * 1.5 : 0 - implicitWidth: label.width + label.height * 2.5 + implicitHeight: source.visible ? 2 * label.implicitHeight : 0 + implicitWidth: 2 * hifi.dimensions.menuPadding.x + check.width + label.width + tail.width visible: source.visible width: parent.width FontAwesome { clip: true id: check - verticalAlignment: Text.AlignVCenter - horizontalAlignment: Text.AlignHCenter - anchors.verticalCenter: parent.verticalCenter + verticalAlignment: Text.AlignVCenter + anchors { + verticalCenter: parent.verticalCenter + left: parent.left + leftMargin: hifi.dimensions.menuPadding.x + } + width: 1.5 * hifi.dimensions.menuPadding.x color: label.color text: checkText() size: label.height visible: source.visible font.pixelSize: size function checkText() { - if (!source || source.type != 1 || !source.checkable) { + if (!source || source.type !== 1 || !source.checkable) { return "" } // FIXME this works for native QML menus but I don't think it will @@ -50,25 +54,36 @@ Item { } } - Text { + RalewaySemiBold { id: label + size: hifi.fontSizes.rootMenu + font.capitalization: Font.AllUppercase anchors.left: check.right - anchors.leftMargin: 4 anchors.verticalCenter: parent.verticalCenter verticalAlignment: Text.AlignVCenter - color: source.enabled ? hifi.colors.text : hifi.colors.disabledText + color: source.enabled ? hifi.colors.baseGrayShadow : hifi.colors.baseGrayShadow50 enabled: source.visible && (source.type !== 0 ? source.enabled : false) visible: source.visible } - FontAwesome { - id: tag - x: root.parent.width - width - size: label.height - width: implicitWidth - visible: source.visible && (source.type == 2) - text: "\uF0DA" - anchors.verticalCenter: parent.verticalCenter - color: label.color + Item { + // Space for shortcut key or disclosure icon. + id: tail + width: 4 * hifi.dimensions.menuPadding.x + anchors { + verticalCenter: parent.verticalCenter + right: parent.right + rightMargin: hifi.dimensions.menuPadding.x + } + + HiFiGlyphs { + text: hifi.glyphs.disclosureExpand + color: source.enabled ? hifi.colors.baseGrayShadow : hifi.colors.baseGrayShadow25 + size: 2 * hifi.fontSizes.rootMenuDisclosure + anchors.verticalCenter: parent.verticalCenter + anchors.right: parent.right + horizontalAlignment: Text.AlignRight + visible: source.visible && (source.type === 2) + } } } diff --git a/interface/resources/qml/menus/VrMenuView.qml b/interface/resources/qml/menus/VrMenuView.qml index 8778bc4bd1..d8cc0e6667 100644 --- a/interface/resources/qml/menus/VrMenuView.qml +++ b/interface/resources/qml/menus/VrMenuView.qml @@ -40,16 +40,20 @@ FocusScope { x: 8; y: 8 width: 128 height: count * 32 - topMargin: hifi.dimensions.menuPadding + topMargin: hifi.dimensions.menuPadding.y onEnabledChanged: recalcSize(); onVisibleChanged: recalcSize(); onCountChanged: recalcSize(); focus: true highlight: Rectangle { - width: listView.currentItem ? listView.currentItem.width : 0 - height: listView.currentItem ? listView.currentItem.height : 0 - color: "lightsteelblue"; radius: 3 + anchors { + left: parent ? parent.left : undefined + right: parent ? parent.right : undefined + leftMargin: hifi.dimensions.borderWidth + rightMargin: hifi.dimensions.borderWidth + } + color: hifi.colors.white } delegate: VrMenuItem { @@ -86,7 +90,7 @@ FocusScope { newHeight += currentItem.implicitHeight } } - newHeight += 2 * hifi.dimensions.menuPadding; // White space at top and bottom. + newHeight += 2 * hifi.dimensions.menuPadding.y; // White space at top and bottom. if (maxWidth > width) { width = maxWidth; } diff --git a/interface/resources/qml/styles-uit/HifiConstants.qml b/interface/resources/qml/styles-uit/HifiConstants.qml index 4f06b676e6..3b6eb2d9fc 100644 --- a/interface/resources/qml/styles-uit/HifiConstants.qml +++ b/interface/resources/qml/styles-uit/HifiConstants.qml @@ -67,6 +67,8 @@ Item { readonly property color darkGray30: "#4d121212" readonly property color darkGray0: "#00121212" readonly property color baseGrayShadow60: "#99252525" + readonly property color baseGrayShadow50: "#80252525" + readonly property color baseGrayShadow25: "#40252525" readonly property color baseGrayHighlight40: "#66575757" readonly property color baseGrayHighlight15: "#26575757" readonly property color lightGrayText80: "#ccafafaf" @@ -136,7 +138,7 @@ Item { readonly property real modalDialogTitleHeight: 40 readonly property real controlLineHeight: 29 // Height of spinbox control on 1920 x 1080 monitor readonly property real controlInterlineHeight: 22 // 75% of controlLineHeight - readonly property real menuPadding: 12 + readonly property vector2d menuPadding: Qt.vector2d(12, 12) } Item { @@ -154,6 +156,7 @@ Item { readonly property real logs: dimensions.largeScreen ? 16 : 12 readonly property real code: dimensions.largeScreen ? 16 : 12 readonly property real rootMenu: dimensions.largeScreen ? 15 : 11 + readonly property real rootMenuDisclosure: dimensions.largeScreen ? 20 : 16 readonly property real menuItem: dimensions.largeScreen ? 15 : 11 readonly property real shortcutText: dimensions.largeScreen ? 13 : 9 readonly property real carat: dimensions.largeScreen ? 38 : 30 From e175c1975464fe3a22fbf46b5509ca7ecc42f0d2 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 11 Mar 2016 15:51:27 +1300 Subject: [PATCH 04/77] Style checkbox for menu items --- interface/resources/qml/menus/VrMenuItem.qml | 28 ++++++++----------- .../qml/styles-uit/HifiConstants.qml | 2 +- 2 files changed, 12 insertions(+), 18 deletions(-) diff --git a/interface/resources/qml/menus/VrMenuItem.qml b/interface/resources/qml/menus/VrMenuItem.qml index f2c077a59e..636728c890 100644 --- a/interface/resources/qml/menus/VrMenuItem.qml +++ b/interface/resources/qml/menus/VrMenuItem.qml @@ -26,31 +26,25 @@ Item { visible: source.visible width: parent.width - FontAwesome { - clip: true + CheckBox { id: check - verticalAlignment: Text.AlignVCenter + // FIXME: Shouild use radio buttons if source.exclusiveGroup. anchors { - verticalCenter: parent.verticalCenter left: parent.left leftMargin: hifi.dimensions.menuPadding.x + top: label.top + topMargin: 0 } - width: 1.5 * hifi.dimensions.menuPadding.x - color: label.color - text: checkText() - size: label.height - visible: source.visible - font.pixelSize: size - function checkText() { + width: 20 + visible: source.visible && source.type === 1 && source.checkable + checked: setChecked() + function setChecked() { if (!source || source.type !== 1 || !source.checkable) { - return "" + return false; } // FIXME this works for native QML menus but I don't think it will // for proxied QML menus - if (source.exclusiveGroup) { - return source.checked ? "\uF05D" : "\uF10C" - } - return source.checked ? "\uF046" : "\uF096" + return source.checked; } } @@ -69,7 +63,7 @@ Item { Item { // Space for shortcut key or disclosure icon. id: tail - width: 4 * hifi.dimensions.menuPadding.x + width: 48 anchors { verticalCenter: parent.verticalCenter right: parent.right diff --git a/interface/resources/qml/styles-uit/HifiConstants.qml b/interface/resources/qml/styles-uit/HifiConstants.qml index 3b6eb2d9fc..718c1e32cb 100644 --- a/interface/resources/qml/styles-uit/HifiConstants.qml +++ b/interface/resources/qml/styles-uit/HifiConstants.qml @@ -138,7 +138,7 @@ Item { readonly property real modalDialogTitleHeight: 40 readonly property real controlLineHeight: 29 // Height of spinbox control on 1920 x 1080 monitor readonly property real controlInterlineHeight: 22 // 75% of controlLineHeight - readonly property vector2d menuPadding: Qt.vector2d(12, 12) + readonly property vector2d menuPadding: Qt.vector2d(14, 12) } Item { From 807d31743c5b6786306d2e43c52654e0b587ed96 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Thu, 10 Mar 2016 19:33:31 -0800 Subject: [PATCH 05/77] Removed Hand, HandData & PalmData Instead, we just store two controller::Poses in MyAvatar. Existing behavior and scripting APIs have been preserved. The hand controller debug drawing is slightly different, but still works. --- interface/src/Application.cpp | 52 +----- interface/src/Application.h | 4 +- interface/src/Menu.cpp | 3 +- interface/src/avatar/Avatar.cpp | 12 -- interface/src/avatar/Avatar.h | 3 +- interface/src/avatar/AvatarActionHold.cpp | 79 ++++---- interface/src/avatar/Hand.cpp | 101 ---------- interface/src/avatar/Hand.h | 36 ---- interface/src/avatar/MyAvatar.cpp | 110 +++++++---- interface/src/avatar/MyAvatar.h | 9 + interface/src/avatar/SkeletonModel.cpp | 28 +-- interface/src/avatar/SkeletonModel.h | 1 - .../ControllerScriptingInterface.cpp | 1 - libraries/avatars/src/AvatarData.cpp | 7 - libraries/avatars/src/AvatarData.h | 4 +- libraries/avatars/src/HandData.cpp | 110 ----------- libraries/avatars/src/HandData.h | 174 ------------------ 17 files changed, 149 insertions(+), 585 deletions(-) delete mode 100644 interface/src/avatar/Hand.cpp delete mode 100644 interface/src/avatar/Hand.h delete mode 100644 libraries/avatars/src/HandData.cpp delete mode 100644 libraries/avatars/src/HandData.h diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 4ae63f817a..728691a0e1 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3216,11 +3216,10 @@ void Application::update(float deltaTime) { myAvatar->setDriveKeys(ZOOM, userInputMapper->getActionState(controller::Action::TRANSLATE_CAMERA_Z)); } - controller::Pose leftHand = userInputMapper->getPoseState(controller::Action::LEFT_HAND); - controller::Pose rightHand = userInputMapper->getPoseState(controller::Action::RIGHT_HAND); - Hand* hand = DependencyManager::get()->getMyAvatar()->getHand(); - setPalmData(hand, leftHand, deltaTime, HandData::LeftHand, userInputMapper->getActionState(controller::Action::LEFT_HAND_CLICK)); - setPalmData(hand, rightHand, deltaTime, HandData::RightHand, userInputMapper->getActionState(controller::Action::RIGHT_HAND_CLICK)); + controller::Pose leftHandPose = userInputMapper->getPoseState(controller::Action::LEFT_HAND); + controller::Pose rightHandPose = userInputMapper->getPoseState(controller::Action::RIGHT_HAND); + myAvatar->setHandControllerPoses(leftHandPose, rightHandPose); + updateThreads(deltaTime); // If running non-threaded, then give the threads some time to process... updateDialogs(deltaTime); // update various stats dialogs if present @@ -4979,49 +4978,6 @@ mat4 Application::getHMDSensorPose() const { return mat4(); } -void Application::setPalmData(Hand* hand, const controller::Pose& pose, float deltaTime, HandData::Hand whichHand, float triggerValue) { - - // NOTE: the Hand::modifyPalm() will allow the lambda to modify the palm data while ensuring some other user isn't - // reading or writing to the Palms. This is definitely not the best way of handling this, and I'd like to see more - // of this palm manipulation in the Hand class itself. But unfortunately the Hand and Palm don't knbow about - // controller::Pose. More work is needed to clean this up. - hand->modifyPalm(whichHand, [&](PalmData& palm) { - palm.setActive(pose.isValid()); - - // controller pose is in Avatar frame. - glm::vec3 position = pose.getTranslation(); - glm::quat rotation = pose.getRotation(); - glm::vec3 rawVelocity = pose.getVelocity(); - glm::vec3 angularVelocity = pose.getAngularVelocity(); - - palm.setRawVelocity(rawVelocity); - palm.setRawAngularVelocity(angularVelocity); - - if (controller::InputDevice::getLowVelocityFilter()) { - // Use a velocity sensitive filter to damp small motions and preserve large ones with - // no latency. - float velocityFilter = glm::clamp(1.0f - glm::length(rawVelocity), 0.0f, 1.0f); - position = palm.getRawPosition() * velocityFilter + position * (1.0f - velocityFilter); - rotation = safeMix(palm.getRawRotation(), rotation, 1.0f - velocityFilter); - } - palm.setRawPosition(position); - palm.setRawRotation(rotation); - - // Store the one fingertip in the palm structure so we can track velocity - const float FINGER_LENGTH = 0.3f; // meters - const glm::vec3 FINGER_VECTOR(0.0f, FINGER_LENGTH, 0.0f); - const glm::vec3 newTipPosition = position + rotation * FINGER_VECTOR; - glm::vec3 oldTipPosition = palm.getTipRawPosition(); - if (deltaTime > 0.0f) { - palm.setTipVelocity((newTipPosition - oldTipPosition) / deltaTime); - } else { - palm.setTipVelocity(glm::vec3(0.0f)); - } - palm.setTipPosition(newTipPosition); - palm.setTrigger(triggerValue); // FIXME - we want to get rid of this idea of PalmData having a trigger - }); -} - void Application::crashApplication() { qCDebug(interfaceapp) << "Intentionally crashed Interface"; QObject* object = nullptr; diff --git a/interface/src/Application.h b/interface/src/Application.h index c93b7431f3..14b90877df 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -299,7 +299,7 @@ private slots: void loadSettings(); void saveSettings(); - + bool acceptSnapshot(const QString& urlString); bool askToSetAvatarUrl(const QString& url); bool askToLoadScript(const QString& scriptFilenameOrURL); @@ -327,8 +327,6 @@ private: void update(float deltaTime); - void setPalmData(Hand* hand, const controller::Pose& pose, float deltaTime, HandData::Hand whichHand, float triggerValue); - // Various helper functions called during update() void updateLOD(); void updateThreads(float deltaTime); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 15fae25646..ab1b7238df 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -479,7 +479,8 @@ Menu::Menu() { // Developer > Hands >>> MenuWrapper* handOptionsMenu = developerMenu->addMenu("Hands"); - addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::DisplayHandTargets, 0, false); + addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::DisplayHandTargets, 0, false, + avatar, SLOT(setEnableDebugDrawHandControllers(bool))); addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::LowVelocityFilter, 0, true, qApp, SLOT(setLowVelocityFilter(bool))); diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 292e4c637e..ca242a2ca2 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -35,7 +35,6 @@ #include "Avatar.h" #include "AvatarManager.h" #include "AvatarMotionState.h" -#include "Hand.h" #include "Head.h" #include "Menu.h" #include "Physics.h" @@ -101,7 +100,6 @@ Avatar::Avatar(RigPointer rig) : // give the pointer to our head to inherited _headData variable from AvatarData _headData = static_cast(new Head(this)); - _handData = static_cast(new Hand(this)); } Avatar::~Avatar() { @@ -190,11 +188,6 @@ void Avatar::simulate(float deltaTime) { float boundingRadius = getBoundingRadius(); bool inView = qApp->getViewFrustum()->sphereIntersectsFrustum(getPosition(), boundingRadius); - { - PerformanceTimer perfTimer("hand"); - getHand()->simulate(deltaTime, false); - } - if (_shouldAnimate && !_shouldSkipRender && inView) { { PerformanceTimer perfTimer("skeleton"); @@ -578,11 +571,6 @@ void Avatar::renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, floa if (_skeletonModel.isRenderable() && getHead()->getFaceModel().isRenderable()) { getHead()->render(renderArgs, 1.0f, renderFrustum); } - - if (renderArgs->_renderMode != RenderArgs::SHADOW_RENDER_MODE && - Menu::getInstance()->isOptionChecked(MenuOption::DisplayHandTargets)) { - getHand()->renderHandTargets(renderArgs, false); - } } getHead()->renderLookAts(renderArgs); } diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index f9e21febd5..7020de377f 100644 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -22,7 +22,6 @@ #include -#include "Hand.h" #include "Head.h" #include "SkeletonModel.h" #include "world.h" @@ -91,7 +90,7 @@ public: float getUniformScale() const { return getScale().y; } const Head* getHead() const { return static_cast(_headData); } Head* getHead() { return static_cast(_headData); } - Hand* getHand() { return static_cast(_handData); } + glm::quat getWorldAlignedOrientation() const; AABox getBounds() const; diff --git a/interface/src/avatar/AvatarActionHold.cpp b/interface/src/avatar/AvatarActionHold.cpp index b62cae1d58..0ce0b5a190 100644 --- a/interface/src/avatar/AvatarActionHold.cpp +++ b/interface/src/avatar/AvatarActionHold.cpp @@ -104,48 +104,57 @@ std::shared_ptr AvatarActionHold::getTarget(float deltaTimeStep, glm::qu withReadLock([&]{ bool isRightHand = (_hand == "right"); + glm::vec3 palmPosition; glm::quat palmRotation; - PalmData palmData = holdingAvatar->getHand()->getCopyOfPalmData(isRightHand ? HandData::RightHand : HandData::LeftHand); - - if (palmData.isValid()) { - // TODO: adjust according to _relativePosition and _relativeRotation? - linearVelocity = palmData.getVelocity(); - angularVelocity = palmData.getAngularVelocity(); - } - - if (_ignoreIK && holdingAvatar->isMyAvatar() && palmData.isValid()) { - // We cannot ignore other avatars IK and this is not the point of this option - // This is meant to make the grabbing behavior more reactive. - palmPosition = palmData.getPosition(); - palmRotation = palmData.getRotation(); - } else if (holdingAvatar->isMyAvatar()) { - glm::vec3 avatarRigidBodyPosition; - glm::quat avatarRigidBodyRotation; - getAvatarRigidBodyLocation(avatarRigidBodyPosition, avatarRigidBodyRotation); - - // the offset and rotation between the avatar's rigid body and the palm were determined earlier - // in prepareForPhysicsSimulation. At this point, the avatar's rigid body has been moved by bullet - // and the data in the Avatar class is stale. This means that the result of get*PalmPosition will - // be stale. Instead, determine the current palm position with the current avatar's rigid body - // location and the saved offsets. - - // this line is more correct but breaks for the current way avatar data is updated. - // palmPosition = avatarRigidBodyPosition + avatarRigidBodyRotation * _palmOffsetFromRigidBody; - // instead, use this for now: - palmPosition = avatarRigidBodyPosition + _palmOffsetFromRigidBody; - - // the item jitters the least by getting the rotation based on the opinion of Avatar.h rather - // than that of the rigid body. leaving this next line here for future reference: - // palmRotation = avatarRigidBodyRotation * _palmRotationFromRigidBody; + if (holdingAvatar->isMyAvatar()) { + // fetch the hand controller pose + controller::Pose pose; if (isRightHand) { - palmRotation = holdingAvatar->getRightPalmRotation(); + pose = avatarManager->getMyAvatar()->getRightHandControllerPose(); } else { - palmRotation = holdingAvatar->getLeftPalmRotation(); + pose = avatarManager->getMyAvatar()->getLeftHandControllerPose(); } - } else { + + if (pose.isValid()) { + linearVelocity = pose.getVelocity(); + angularVelocity = pose.getAngularVelocity(); + } + + if (_ignoreIK && pose.isValid()) { + // We cannot ignore other avatars IK and this is not the point of this option + // This is meant to make the grabbing behavior more reactive. + palmPosition = pose.getTranslation(); + palmRotation = pose.getRotation(); + } else { + glm::vec3 avatarRigidBodyPosition; + glm::quat avatarRigidBodyRotation; + getAvatarRigidBodyLocation(avatarRigidBodyPosition, avatarRigidBodyRotation); + + // the offset and rotation between the avatar's rigid body and the palm were determined earlier + // in prepareForPhysicsSimulation. At this point, the avatar's rigid body has been moved by bullet + // and the data in the Avatar class is stale. This means that the result of get*PalmPosition will + // be stale. Instead, determine the current palm position with the current avatar's rigid body + // location and the saved offsets. + + // this line is more correct but breaks for the current way avatar data is updated. + // palmPosition = avatarRigidBodyPosition + avatarRigidBodyRotation * _palmOffsetFromRigidBody; + // instead, use this for now: + palmPosition = avatarRigidBodyPosition + _palmOffsetFromRigidBody; + + // the item jitters the least by getting the rotation based on the opinion of Avatar.h rather + // than that of the rigid body. leaving this next line here for future reference: + // palmRotation = avatarRigidBodyRotation * _palmRotationFromRigidBody; + + if (isRightHand) { + palmRotation = holdingAvatar->getRightPalmRotation(); + } else { + palmRotation = holdingAvatar->getLeftPalmRotation(); + } + } + } else { // regular avatar if (isRightHand) { palmPosition = holdingAvatar->getRightPalmPosition(); palmRotation = holdingAvatar->getRightPalmRotation(); diff --git a/interface/src/avatar/Hand.cpp b/interface/src/avatar/Hand.cpp deleted file mode 100644 index 5371fe5736..0000000000 --- a/interface/src/avatar/Hand.cpp +++ /dev/null @@ -1,101 +0,0 @@ -// -// Hand.cpp -// interface/src/avatar -// -// Copyright 2013 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 "Hand.h" - -#include - -#include -#include - -#include "Avatar.h" -#include "AvatarManager.h" -#include "MyAvatar.h" -#include "Util.h" -#include "world.h" - -using namespace std; - -Hand::Hand(Avatar* owningAvatar) : - HandData((AvatarData*)owningAvatar), - _owningAvatar(owningAvatar) -{ -} - -void Hand::simulate(float deltaTime, bool isMine) { - // nothing to do here -} - -void Hand::renderHandTargets(RenderArgs* renderArgs, bool isMine) { - float avatarScale = 1.0f; - if (_owningAvatar) { - avatarScale = _owningAvatar->getUniformScale(); - } - - const float alpha = 1.0f; - const glm::vec3 redColor(1.0f, 0.0f, 0.0f); // Color the hand targets red to be different than skin - const glm::vec3 greenColor(0.0f, 1.0f, 0.0f); // Color the hand targets red to be different than skin - const glm::vec3 blueColor(0.0f, 0.0f, 1.0f); // Color the hand targets red to be different than skin - const glm::vec3 grayColor(0.5f); - const float SPHERE_RADIUS = 0.03f * avatarScale; - - auto palms = getCopyOfPalms(); - - gpu::Batch& batch = *renderArgs->_batch; - if (isMine) { - for (const auto& palm : palms) { - if (!palm.isActive()) { - continue; - } - // draw a gray sphere at the target position of the "Hand" joint - glm::vec3 position = palm.getPosition(); - Transform transform = Transform(); - transform.setTranslation(position); - transform.setRotation(palm.getRotation()); - transform.postScale(SPHERE_RADIUS); - batch.setModelTransform(transform); - DependencyManager::get()->renderSolidSphereInstance(batch, grayColor); - - // draw a green sphere at the old "finger tip" - transform = Transform(); - position = palm.getTipPosition(); - transform.setTranslation(position); - transform.setRotation(palm.getRotation()); - transform.postScale(SPHERE_RADIUS); - batch.setModelTransform(transform); - DependencyManager::get()->renderSolidSphereInstance(batch, greenColor); - } - } - - const float AXIS_RADIUS = 0.1f * SPHERE_RADIUS; - const float AXIS_LENGTH = 10.0f * SPHERE_RADIUS; - - // Draw the coordinate frames of the hand targets - for (const auto& palm : palms) { - if (palm.isActive()) { - glm::vec3 root = palm.getPosition(); - - const glm::vec3 yAxis(0.0f, 1.0f, 0.0f); - glm::quat palmRotation = palm.getRotation(); - Transform transform = Transform(); - transform.setTranslation(glm::vec3()); - batch.setModelTransform(transform); - glm::vec3 tip = root + palmRotation * glm::vec3(AXIS_LENGTH, 0.0f, 0.0f); - Avatar::renderJointConnectingCone(batch, root, tip, AXIS_RADIUS, AXIS_RADIUS, glm::vec4(redColor.r, redColor.g, redColor.b, alpha)); - - tip = root + palmRotation * glm::vec3(0.0f, AXIS_LENGTH, 0.0f); - Avatar::renderJointConnectingCone(batch, root, tip, AXIS_RADIUS, AXIS_RADIUS, glm::vec4(greenColor.r, greenColor.g, greenColor.b, alpha)); - - tip = root + palmRotation * glm::vec3(0.0f, 0.0f, AXIS_LENGTH); - Avatar::renderJointConnectingCone(batch, root, tip, AXIS_RADIUS, AXIS_RADIUS, glm::vec4(blueColor.r, blueColor.g, blueColor.b, alpha)); - } - } -} - diff --git a/interface/src/avatar/Hand.h b/interface/src/avatar/Hand.h deleted file mode 100644 index 2ece3e9f9e..0000000000 --- a/interface/src/avatar/Hand.h +++ /dev/null @@ -1,36 +0,0 @@ -// -// Hand.h -// interface/src/avatar -// -// Copyright 2013 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 -// - -#ifndef hifi_Hand_h -#define hifi_Hand_h - -#include - -class Avatar; -class RenderArgs; - -class Hand : public HandData { -public: - Hand(Avatar* owningAvatar); - - void simulate(float deltaTime, bool isMine); - void renderHandTargets(RenderArgs* renderArgs, bool isMine); - -private: - // disallow copies of the Hand, copy of owning Avatar is disallowed too - Hand(const Hand&); - Hand& operator= (const Hand&); - - int _controllerButtons; /// Button states read from hand-held controllers - - Avatar* _owningAvatar; -}; - -#endif // hifi_Hand_h diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 26e0ce56dd..016e2a464c 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -341,12 +341,6 @@ void MyAvatar::simulate(float deltaTime) { updatePosition(deltaTime); } - { - PerformanceTimer perfTimer("hand"); - // update avatar skeleton and simulate hand and head - getHand()->simulate(deltaTime, true); - } - { PerformanceTimer perfTimer("skeleton"); _skeletonModel.simulate(deltaTime); @@ -520,47 +514,49 @@ void MyAvatar::updateFromTrackers(float deltaTime) { glm::vec3 MyAvatar::getLeftHandPosition() const { - auto palmData = getHandData()->getCopyOfPalmData(HandData::LeftHand); - return palmData.isValid() ? palmData.getPosition() : glm::vec3(0.0f); + auto pose = getLeftHandControllerPose(); + return pose.isValid() ? pose.getTranslation() : glm::vec3(0.0f); } glm::vec3 MyAvatar::getRightHandPosition() const { - auto palmData = getHandData()->getCopyOfPalmData(HandData::RightHand); - return palmData.isValid() ? palmData.getPosition() : glm::vec3(0.0f); + auto pose = getRightHandControllerPose(); + return pose.isValid() ? pose.getTranslation() : glm::vec3(0.0f); } glm::vec3 MyAvatar::getLeftHandTipPosition() const { - auto palmData = getHandData()->getCopyOfPalmData(HandData::LeftHand); - return palmData.isValid() ? palmData.getTipPosition() : glm::vec3(0.0f); + const float TIP_LENGTH = 0.3f; + auto pose = getLeftHandControllerPose(); + return pose.isValid() ? pose.getTranslation() * pose.getRotation() + glm::vec3(0.0f, TIP_LENGTH, 0.0f) : glm::vec3(0.0f); } glm::vec3 MyAvatar::getRightHandTipPosition() const { - auto palmData = getHandData()->getCopyOfPalmData(HandData::RightHand); - return palmData.isValid() ? palmData.getTipPosition() : glm::vec3(0.0f); + const float TIP_LENGTH = 0.3f; + auto pose = getRightHandControllerPose(); + return pose.isValid() ? pose.getTranslation() * pose.getRotation() + glm::vec3(0.0f, TIP_LENGTH, 0.0f) : glm::vec3(0.0f); } controller::Pose MyAvatar::getLeftHandPose() const { - auto palmData = getHandData()->getCopyOfPalmData(HandData::LeftHand); - return palmData.isValid() ? controller::Pose(palmData.getPosition(), palmData.getRotation(), - palmData.getVelocity(), palmData.getRawAngularVelocity()) : controller::Pose(); + return getLeftHandControllerPose(); } controller::Pose MyAvatar::getRightHandPose() const { - auto palmData = getHandData()->getCopyOfPalmData(HandData::RightHand); - return palmData.isValid() ? controller::Pose(palmData.getPosition(), palmData.getRotation(), - palmData.getVelocity(), palmData.getRawAngularVelocity()) : controller::Pose(); + return getRightHandControllerPose(); } controller::Pose MyAvatar::getLeftHandTipPose() const { - auto palmData = getHandData()->getCopyOfPalmData(HandData::LeftHand); - return palmData.isValid() ? controller::Pose(palmData.getTipPosition(), palmData.getRotation(), - palmData.getTipVelocity(), palmData.getRawAngularVelocity()) : controller::Pose(); + auto pose = getLeftHandControllerPose(); + glm::vec3 tipTrans = getLeftHandTipPosition(); + pose.velocity += glm::cross(pose.getAngularVelocity(), pose.getTranslation() - tipTrans); + pose.translation = tipTrans; + return pose; } controller::Pose MyAvatar::getRightHandTipPose() const { - auto palmData = getHandData()->getCopyOfPalmData(HandData::RightHand); - return palmData.isValid() ? controller::Pose(palmData.getTipPosition(), palmData.getRotation(), - palmData.getTipVelocity(), palmData.getRawAngularVelocity()) : controller::Pose(); + auto pose = getRightHandControllerPose(); + glm::vec3 tipTrans = getRightHandTipPosition(); + pose.velocity += glm::cross(pose.getAngularVelocity(), pose.getTranslation() - tipTrans); + pose.translation = tipTrans; + return pose; } // virtual @@ -698,6 +694,14 @@ void MyAvatar::setEnableDebugDrawPosition(bool isEnabled) { } } +void MyAvatar::setEnableDebugDrawHandControllers(bool isEnabled) { + _enableDebugDrawHandControllers = isEnabled; + if (!isEnabled) { + DebugDraw::getInstance().removeMyAvatarMarker("leftHandController"); + DebugDraw::getInstance().removeMyAvatarMarker("rightHandController"); + } +} + void MyAvatar::setEnableMeshVisible(bool isEnabled) { render::ScenePointer scene = qApp->getMain3DScene(); _skeletonModel.setVisibleInScene(isEnabled, scene); @@ -1080,6 +1084,38 @@ void MyAvatar::rebuildCollisionShape() { _characterController.setLocalBoundingBox(corner, diagonal); } +static controller::Pose applyLowVelocityFilter(const controller::Pose& oldPose, const controller::Pose& newPose) { + controller::Pose finalPose = newPose; + if (newPose.isValid()) { + // Use a velocity sensitive filter to damp small motions and preserve large ones with + // no latency. + float velocityFilter = glm::clamp(1.0f - glm::length(oldPose.getVelocity()), 0.0f, 1.0f); + finalPose.translation = oldPose.getTranslation() * velocityFilter + newPose.getTranslation() * (1.0f - velocityFilter); + finalPose.rotation = safeMix(oldPose.getRotation(), newPose.getRotation(), 1.0f - velocityFilter); + } + return finalPose; +} + +void MyAvatar::setHandControllerPoses(const controller::Pose& left, const controller::Pose& right) { + if (controller::InputDevice::getLowVelocityFilter()) { + auto oldLeftPose = getLeftHandControllerPose(); + auto oldRightPose = getRightHandControllerPose(); + _leftHandControllerPoseCache.set(applyLowVelocityFilter(oldLeftPose, left)); + _rightHandControllerPoseCache.set(applyLowVelocityFilter(oldRightPose, right)); + } else { + _leftHandControllerPoseCache.set(left); + _rightHandControllerPoseCache.set(right); + } +} + +controller::Pose MyAvatar::getLeftHandControllerPose() const { + return _leftHandControllerPoseCache.get(); +} + +controller::Pose MyAvatar::getRightHandControllerPose() const { + return _rightHandControllerPoseCache.get(); +} + void MyAvatar::prepareForPhysicsSimulation() { relayDriveKeysToCharacterController(); @@ -1215,11 +1251,6 @@ void MyAvatar::renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, fl } else { getHead()->renderLookAts(renderArgs); } - - if (renderArgs->_renderMode != RenderArgs::SHADOW_RENDER_MODE && - Menu::getInstance()->isOptionChecked(MenuOption::DisplayHandTargets)) { - getHand()->renderHandTargets(renderArgs, true); - } } void MyAvatar::setVisibleInSceneIfReady(Model* model, render::ScenePointer scene, bool visible) { @@ -1328,6 +1359,23 @@ void MyAvatar::preRender(RenderArgs* renderArgs) { } } + if (_enableDebugDrawHandControllers) { + auto leftHandPose = getLeftHandControllerPose(); + auto rightHandPose = getRightHandControllerPose(); + + if (leftHandPose.isValid()) { + DebugDraw::getInstance().addMyAvatarMarker("leftHandController", leftHandPose.getRotation(), leftHandPose.getTranslation(), glm::vec4(1)); + } else { + DebugDraw::getInstance().removeMyAvatarMarker("leftHandController"); + } + + if (rightHandPose.isValid()) { + DebugDraw::getInstance().addMyAvatarMarker("rightHandController", rightHandPose.getRotation(), rightHandPose.getTranslation(), glm::vec4(1)); + } else { + DebugDraw::getInstance().removeMyAvatarMarker("rightHandController"); + } + } + DebugDraw::getInstance().updateMyAvatarPos(getPosition()); DebugDraw::getInstance().updateMyAvatarRot(getOrientation()); diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index fd5c2920a9..0092280762 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -249,6 +249,10 @@ public: virtual void rebuildCollisionShape() override; + void setHandControllerPoses(const controller::Pose& left, const controller::Pose& right); + controller::Pose MyAvatar::getLeftHandControllerPose() const; + controller::Pose MyAvatar::getRightHandControllerPose() const; + public slots: void increaseSize(); void decreaseSize(); @@ -271,6 +275,7 @@ public slots: void setEnableDebugDrawDefaultPose(bool isEnabled); void setEnableDebugDrawAnimPose(bool isEnabled); void setEnableDebugDrawPosition(bool isEnabled); + void setEnableDebugDrawHandControllers(bool isEnabled); bool getEnableMeshVisible() const { return _skeletonModel.isVisible(); } void setEnableMeshVisible(bool isEnabled); void setUseAnimPreAndPostRotations(bool isEnabled); @@ -434,6 +439,7 @@ private: bool _enableDebugDrawDefaultPose { false }; bool _enableDebugDrawAnimPose { false }; + bool _enableDebugDrawHandControllers { false }; AudioListenerMode _audioListenerMode; glm::vec3 _customListenPosition; @@ -444,6 +450,9 @@ private: bool _hoverReferenceCameraFacingIsCaptured { false }; glm::vec3 _hoverReferenceCameraFacing { 0.0f, 0.0f, -1.0f }; // hmd sensor space + ThreadSafeValueCache _leftHandControllerPoseCache { controller::Pose() }; + ThreadSafeValueCache _rightHandControllerPoseCache { controller::Pose() }; + float AVATAR_MOVEMENT_ENERGY_CONSTANT { 0.001f }; float AUDIO_ENERGY_CONSTANT { 0.000001f }; float MAX_AVATAR_MOVEMENT_PER_FRAME { 30.0f }; diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 711ed17231..d659d79dd9 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -16,7 +16,6 @@ #include "Application.h" #include "Avatar.h" -#include "Hand.h" #include "Menu.h" #include "SkeletonModel.h" #include "Util.h" @@ -127,20 +126,20 @@ void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) { Rig::HandParameters handParams; - auto leftPalm = myAvatar->getHand()->getCopyOfPalmData(HandData::LeftHand); - if (leftPalm.isValid() && leftPalm.isActive()) { + auto leftPose = myAvatar->getLeftHandControllerPose(); + if (leftPose.isValid()) { handParams.isLeftEnabled = true; - handParams.leftPosition = Quaternions::Y_180 * leftPalm.getRawPosition(); - handParams.leftOrientation = Quaternions::Y_180 * leftPalm.getRawRotation(); + handParams.leftPosition = Quaternions::Y_180 * leftPose.getTranslation(); + handParams.leftOrientation = Quaternions::Y_180 * leftPose.getRotation(); } else { handParams.isLeftEnabled = false; } - auto rightPalm = myAvatar->getHand()->getCopyOfPalmData(HandData::RightHand); - if (rightPalm.isValid() && rightPalm.isActive()) { + auto rightPose = myAvatar->getRightHandControllerPose(); + if (rightPose.isValid()) { handParams.isRightEnabled = true; - handParams.rightPosition = Quaternions::Y_180 * rightPalm.getRawPosition(); - handParams.rightOrientation = Quaternions::Y_180 * rightPalm.getRawRotation(); + handParams.rightPosition = Quaternions::Y_180 * rightPose.getTranslation(); + handParams.rightOrientation = Quaternions::Y_180 * rightPose.getRotation(); } else { handParams.isRightEnabled = false; } @@ -247,17 +246,6 @@ bool operator<(const IndexValue& firstIndex, const IndexValue& secondIndex) { return firstIndex.value < secondIndex.value; } -void SkeletonModel::applyPalmData(int jointIndex, const PalmData& palm) { - if (jointIndex == -1 || jointIndex >= _rig->getJointStateCount()) { - return; - } - const FBXGeometry& geometry = _geometry->getFBXGeometry(); - int parentJointIndex = geometry.joints.at(jointIndex).parentIndex; - if (parentJointIndex == -1) { - return; - } -} - bool SkeletonModel::getLeftGrabPosition(glm::vec3& position) const { int knuckleIndex = _rig->indexOfJoint("LeftHandMiddle1"); int handIndex = _rig->indexOfJoint("LeftHand"); diff --git a/interface/src/avatar/SkeletonModel.h b/interface/src/avatar/SkeletonModel.h index b57d54020d..6c6a7472f7 100644 --- a/interface/src/avatar/SkeletonModel.h +++ b/interface/src/avatar/SkeletonModel.h @@ -111,7 +111,6 @@ protected: void computeBoundingShape(); - void applyPalmData(int jointIndex, const PalmData& palm); private: bool getEyeModelPositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePosition) const; diff --git a/interface/src/scripting/ControllerScriptingInterface.cpp b/interface/src/scripting/ControllerScriptingInterface.cpp index 9ca1e2c6c6..f6e5b6364f 100644 --- a/interface/src/scripting/ControllerScriptingInterface.cpp +++ b/interface/src/scripting/ControllerScriptingInterface.cpp @@ -13,7 +13,6 @@ #include #include -#include #include #include diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index d14df7b05a..067ab0603b 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -57,7 +57,6 @@ AvatarData::AvatarData() : _hasNewJointRotations(true), _hasNewJointTranslations(true), _headData(NULL), - _handData(NULL), _faceModelURL("http://invalid.com"), _displayNameTargetAlpha(1.0f), _displayNameAlpha(1.0f), @@ -74,7 +73,6 @@ AvatarData::AvatarData() : AvatarData::~AvatarData() { delete _headData; - delete _handData; } // We cannot have a file-level variable (const or otherwise) in the header if it uses PathUtils, because that references Application, which will not yet initialized. @@ -418,11 +416,6 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { _headData = new HeadData(this); } - // lazily allocate memory for HandData in case we're not an Avatar instance - if (!_handData) { - _handData = new HandData(this); - } - const unsigned char* startPosition = reinterpret_cast(buffer.data()); const unsigned char* sourceBuffer = startPosition; quint64 now = usecTimestampNow(); diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index cf6cf80162..6ffcaed0da 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -52,9 +52,9 @@ typedef unsigned long long quint64; #include #include #include +#include #include "AABox.h" -#include "HandData.h" #include "HeadData.h" #include "PathUtils.h" @@ -290,7 +290,6 @@ public: KeyState keyState() const { return _keyState; } const HeadData* getHeadData() const { return _headData; } - const HandData* getHandData() const { return _handData; } bool hasIdentityChangedAfterParsing(const QByteArray& data); QByteArray identityByteArray(); @@ -383,7 +382,6 @@ protected: bool _hasNewJointTranslations; // set in AvatarData, cleared in Avatar HeadData* _headData; - HandData* _handData; QUrl _faceModelURL; // These need to be empty so that on first time setting them they will not short circuit QUrl _skeletonModelURL; // These need to be empty so that on first time setting them they will not short circuit diff --git a/libraries/avatars/src/HandData.cpp b/libraries/avatars/src/HandData.cpp deleted file mode 100644 index 7ba23b01ad..0000000000 --- a/libraries/avatars/src/HandData.cpp +++ /dev/null @@ -1,110 +0,0 @@ -// -// HandData.cpp -// libraries/avatars/src -// -// Created by Stephen Birarda on 5/20/13. -// Copyright 2013 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 - -#include -#include - -#include "AvatarData.h" -#include "HandData.h" - - -HandData::HandData(AvatarData* owningAvatar) : - _owningAvatarData(owningAvatar) -{ - addNewPalm(LeftHand); - addNewPalm(RightHand); -} - -glm::vec3 HandData::worldToLocalVector(const glm::vec3& worldVector) const { - return glm::inverse(getBaseOrientation()) * worldVector / getBaseScale(); -} - -PalmData& HandData::addNewPalm(Hand whichHand) { - QWriteLocker locker(&_palmsLock); - _palms.push_back(PalmData(this, whichHand)); - return _palms.back(); -} - -PalmData HandData::getCopyOfPalmData(Hand hand) const { - QReadLocker locker(&_palmsLock); - - // the palms are not necessarily added in left-right order, - // so we have to search for the correct hand - for (const auto& palm : _palms) { - if (palm.whichHand() == hand && palm.isActive()) { - return palm; - } - } - return PalmData(); // invalid hand -} - -PalmData::PalmData(HandData* owningHandData, HandData::Hand hand) : -_rawRotation(0.0f, 0.0f, 0.0f, 1.0f), -_rawPosition(0.0f), -_rawVelocity(0.0f), -_rawAngularVelocity(0.0f), -_totalPenetration(0.0f), -_isActive(false), -_numFramesWithoutData(0), -_owningHandData(owningHandData), -_hand(hand) { -} - -void PalmData::addToPosition(const glm::vec3& delta) { - _rawPosition += _owningHandData->worldToLocalVector(delta); -} - -bool HandData::findSpherePenetration(const glm::vec3& penetratorCenter, float penetratorRadius, glm::vec3& penetration, - const PalmData*& collidingPalm) const { - QReadLocker locker(&_palmsLock); - - for (const auto& palm : _palms) { - if (!palm.isActive()) { - continue; - } - glm::vec3 palmPosition = palm.getPosition(); - const float PALM_RADIUS = 0.05f; // in world (not voxel) coordinates - if (findSphereSpherePenetration(penetratorCenter, penetratorRadius, palmPosition, PALM_RADIUS, penetration)) { - collidingPalm = &palm; - return true; - } - } - return false; -} - -glm::quat HandData::getBaseOrientation() const { - return _owningAvatarData->getOrientation(); -} - -glm::vec3 HandData::getBasePosition() const { - return _owningAvatarData->getPosition(); -} - -float HandData::getBaseScale() const { - return _owningAvatarData->getTargetScale(); -} - -glm::vec3 PalmData::getFingerDirection() const { - // finger points along yAxis in hand-frame - const glm::vec3 LOCAL_FINGER_DIRECTION(0.0f, 1.0f, 0.0f); - return glm::normalize(_owningHandData->localToWorldDirection(_rawRotation * LOCAL_FINGER_DIRECTION)); -} - -glm::vec3 PalmData::getNormal() const { - // palm normal points along zAxis in hand-frame - const glm::vec3 LOCAL_PALM_DIRECTION(0.0f, 0.0f, 1.0f); - return glm::normalize(_owningHandData->localToWorldDirection(_rawRotation * LOCAL_PALM_DIRECTION)); -} - - - diff --git a/libraries/avatars/src/HandData.h b/libraries/avatars/src/HandData.h deleted file mode 100644 index 63af43e399..0000000000 --- a/libraries/avatars/src/HandData.h +++ /dev/null @@ -1,174 +0,0 @@ -// -// HandData.h -// libraries/avatars/src -// -// Created by Eric Johnston on 6/26/13. -// Copyright 2013 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 -// - -#ifndef hifi_HandData_h -#define hifi_HandData_h - -#include -#include -#include - -#include -#include - -#include - -#include -#include - -class AvatarData; -class PalmData; - -class HandData { -public: - enum Hand { - LeftHand, - RightHand, - UnknownHand, - NUMBER_OF_HANDS - }; - - HandData(AvatarData* owningAvatar); - virtual ~HandData() {} - - // position conversion - glm::vec3 localToWorldPosition(const glm::vec3& localPosition) { - return getBasePosition() + getBaseOrientation() * localPosition * getBaseScale(); - } - - glm::vec3 localToWorldDirection(const glm::vec3& localVector) { - return getBaseOrientation() * localVector * getBaseScale(); - } - - glm::vec3 worldToLocalVector(const glm::vec3& worldVector) const; - - PalmData getCopyOfPalmData(Hand hand) const; - - std::vector getCopyOfPalms() const { QReadLocker locker(&_palmsLock); return _palms; } - - /// Checks for penetration between the described sphere and the hand. - /// \param penetratorCenter the center of the penetration test sphere - /// \param penetratorRadius the radius of the penetration test sphere - /// \param penetration[out] the vector in which to store the penetration - /// \param collidingPalm[out] a const PalmData* to the palm that was collided with - /// \return whether or not the sphere penetrated - bool findSpherePenetration(const glm::vec3& penetratorCenter, float penetratorRadius, glm::vec3& penetration, - const PalmData*& collidingPalm) const; - - glm::quat getBaseOrientation() const; - - /// Allows a lamda function write access to the specific palm for this Hand, this might - /// modify the _palms vector - template void modifyPalm(Hand whichHand, PalmModifierFunction callback); - - friend class AvatarData; -protected: - AvatarData* _owningAvatarData; - std::vector _palms; - mutable QReadWriteLock _palmsLock{ QReadWriteLock::Recursive }; - - glm::vec3 getBasePosition() const; - float getBaseScale() const; - - PalmData& addNewPalm(Hand whichHand); - PalmData& getPalmData(Hand hand); - -private: - // privatize copy ctor and assignment operator so copies of this object cannot be made - HandData(const HandData&); - HandData& operator= (const HandData&); -}; - - -class PalmData { -public: - PalmData(HandData* owningHandData = nullptr, HandData::Hand hand = HandData::UnknownHand); - glm::vec3 getPosition() const { return _owningHandData->localToWorldPosition(_rawPosition); } - glm::vec3 getVelocity() const { return _owningHandData->localToWorldDirection(_rawVelocity); } - glm::vec3 getAngularVelocity() const { return _owningHandData->localToWorldDirection(_rawAngularVelocity); } - - const glm::vec3& getRawPosition() const { return _rawPosition; } - bool isActive() const { return _isActive; } - bool isValid() const { return _owningHandData; } - - void setActive(bool active) { _isActive = active; } - - HandData::Hand whichHand() const { return _hand; } - void setHand(HandData::Hand hand) { _hand = hand; } - - void setRawRotation(const glm::quat& rawRotation) { _rawRotation = rawRotation; }; - glm::quat getRawRotation() const { return _rawRotation; } - glm::quat getRotation() const { return _owningHandData->getBaseOrientation() * _rawRotation; } - void setRawPosition(const glm::vec3& pos) { _rawPosition = pos; } - void setRawVelocity(const glm::vec3& velocity) { _rawVelocity = velocity; } - const glm::vec3& getRawVelocity() const { return _rawVelocity; } - - void setRawAngularVelocity(const glm::vec3& angularVelocity) { _rawAngularVelocity = angularVelocity; } - const glm::vec3& getRawAngularVelocity() const { return _rawAngularVelocity; } - - void addToPosition(const glm::vec3& delta); - - void addToPenetration(const glm::vec3& penetration) { _totalPenetration += penetration; } - void resolvePenetrations() { addToPosition(-_totalPenetration); _totalPenetration = glm::vec3(0.0f); } - - void setTipPosition(const glm::vec3& position) { _tipPosition = position; } - const glm::vec3 getTipPosition() const { return _owningHandData->localToWorldPosition(_tipPosition); } - const glm::vec3& getTipRawPosition() const { return _tipPosition; } - - void setTipVelocity(const glm::vec3& velocity) { _tipVelocity = velocity; } - const glm::vec3 getTipVelocity() const { return _owningHandData->localToWorldDirection(_tipVelocity); } - const glm::vec3& getTipRawVelocity() const { return _tipVelocity; } - - void incrementFramesWithoutData() { _numFramesWithoutData++; } - void resetFramesWithoutData() { _numFramesWithoutData = 0; } - int getFramesWithoutData() const { return _numFramesWithoutData; } - - // FIXME - these are used in SkeletonModel::updateRig() the skeleton/rig should probably get this information - // from an action and/or the UserInputMapper instead of piping it through here. - void setTrigger(float trigger) { _trigger = trigger; } - float getTrigger() const { return _trigger; } - - // return world-frame: - glm::vec3 getFingerDirection() const; - glm::vec3 getNormal() const; - -private: - // unless marked otherwise, these are all in the model-frame - glm::quat _rawRotation; - glm::vec3 _rawPosition; - glm::vec3 _rawVelocity; - glm::vec3 _rawAngularVelocity; - glm::quat _rawDeltaRotation; - glm::quat _lastRotation; - - glm::vec3 _tipPosition; - glm::vec3 _tipVelocity; - glm::vec3 _totalPenetration; /// accumulator for per-frame penetrations - - float _trigger; - - bool _isActive; /// This has current valid data - int _numFramesWithoutData; /// after too many frames without data, this tracked object assumed lost. - HandData* _owningHandData; - HandData::Hand _hand; -}; - -template void HandData::modifyPalm(Hand whichHand, PalmModifierFunction callback) { - QReadLocker locker(&_palmsLock); - for (auto& palm : _palms) { - if (palm.whichHand() == whichHand && palm.isValid()) { - callback(palm); - return; - } - } -} - -#endif // hifi_HandData_h From ab19d3e5a2a4ec261377c42a53efa768a803b386 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Thu, 10 Mar 2016 20:44:35 -0800 Subject: [PATCH 06/77] Moved animation after physics, hand poses are in world frame. There are still some debug hacks enabled so I can test in the vive room. --- interface/src/Application.cpp | 7 +- interface/src/avatar/AvatarActionHold.cpp | 4 +- interface/src/avatar/MyAvatar.cpp | 68 ++++++++++++-------- interface/src/avatar/MyAvatar.h | 13 ++-- interface/src/avatar/SkeletonModel.cpp | 4 +- libraries/render-utils/src/AnimDebugDraw.cpp | 7 +- plugins/hifiSixense/src/SixenseManager.cpp | 6 ++ 7 files changed, 68 insertions(+), 41 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 728691a0e1..42430b3a4c 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3218,13 +3218,12 @@ void Application::update(float deltaTime) { controller::Pose leftHandPose = userInputMapper->getPoseState(controller::Action::LEFT_HAND); controller::Pose rightHandPose = userInputMapper->getPoseState(controller::Action::RIGHT_HAND); - myAvatar->setHandControllerPoses(leftHandPose, rightHandPose); + auto myAvatarMatrix = createMatFromQuatAndPos(myAvatar->getOrientation(), myAvatar->getPosition()); + myAvatar->setHandControllerPosesInWorldFrame(leftHandPose.transform(myAvatarMatrix), rightHandPose.transform(myAvatarMatrix)); updateThreads(deltaTime); // If running non-threaded, then give the threads some time to process... updateDialogs(deltaTime); // update various stats dialogs if present - _avatarUpdate->synchronousProcess(); - if (_physicsEnabled) { PerformanceTimer perfTimer("physics"); AvatarManager* avatarManager = DependencyManager::get().data(); @@ -3296,6 +3295,8 @@ void Application::update(float deltaTime) { } } + _avatarUpdate->synchronousProcess(); + { PerformanceTimer perfTimer("overlays"); _overlays.update(deltaTime); diff --git a/interface/src/avatar/AvatarActionHold.cpp b/interface/src/avatar/AvatarActionHold.cpp index 0ce0b5a190..5087f7955d 100644 --- a/interface/src/avatar/AvatarActionHold.cpp +++ b/interface/src/avatar/AvatarActionHold.cpp @@ -113,9 +113,9 @@ std::shared_ptr AvatarActionHold::getTarget(float deltaTimeStep, glm::qu // fetch the hand controller pose controller::Pose pose; if (isRightHand) { - pose = avatarManager->getMyAvatar()->getRightHandControllerPose(); + pose = avatarManager->getMyAvatar()->getRightHandControllerPoseInWorldFrame(); } else { - pose = avatarManager->getMyAvatar()->getLeftHandControllerPose(); + pose = avatarManager->getMyAvatar()->getLeftHandControllerPoseInWorldFrame(); } if (pose.isValid()) { diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 016e2a464c..c018a76168 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -512,39 +512,38 @@ void MyAvatar::updateFromTrackers(float deltaTime) { -MAX_LEAN, MAX_LEAN)); } - glm::vec3 MyAvatar::getLeftHandPosition() const { - auto pose = getLeftHandControllerPose(); + auto pose = getLeftHandControllerPoseInAvatarFrame(); return pose.isValid() ? pose.getTranslation() : glm::vec3(0.0f); } glm::vec3 MyAvatar::getRightHandPosition() const { - auto pose = getRightHandControllerPose(); + auto pose = getRightHandControllerPoseInAvatarFrame(); return pose.isValid() ? pose.getTranslation() : glm::vec3(0.0f); } glm::vec3 MyAvatar::getLeftHandTipPosition() const { const float TIP_LENGTH = 0.3f; - auto pose = getLeftHandControllerPose(); + auto pose = getLeftHandControllerPoseInAvatarFrame(); return pose.isValid() ? pose.getTranslation() * pose.getRotation() + glm::vec3(0.0f, TIP_LENGTH, 0.0f) : glm::vec3(0.0f); } glm::vec3 MyAvatar::getRightHandTipPosition() const { const float TIP_LENGTH = 0.3f; - auto pose = getRightHandControllerPose(); + auto pose = getRightHandControllerPoseInAvatarFrame(); return pose.isValid() ? pose.getTranslation() * pose.getRotation() + glm::vec3(0.0f, TIP_LENGTH, 0.0f) : glm::vec3(0.0f); } controller::Pose MyAvatar::getLeftHandPose() const { - return getLeftHandControllerPose(); + return getLeftHandControllerPoseInAvatarFrame(); } controller::Pose MyAvatar::getRightHandPose() const { - return getRightHandControllerPose(); + return getRightHandControllerPoseInAvatarFrame(); } controller::Pose MyAvatar::getLeftHandTipPose() const { - auto pose = getLeftHandControllerPose(); + auto pose = getLeftHandControllerPoseInAvatarFrame(); glm::vec3 tipTrans = getLeftHandTipPosition(); pose.velocity += glm::cross(pose.getAngularVelocity(), pose.getTranslation() - tipTrans); pose.translation = tipTrans; @@ -552,7 +551,7 @@ controller::Pose MyAvatar::getLeftHandTipPose() const { } controller::Pose MyAvatar::getRightHandTipPose() const { - auto pose = getRightHandControllerPose(); + auto pose = getRightHandControllerPoseInAvatarFrame(); glm::vec3 tipTrans = getRightHandTipPosition(); pose.velocity += glm::cross(pose.getAngularVelocity(), pose.getTranslation() - tipTrans); pose.translation = tipTrans; @@ -697,8 +696,8 @@ void MyAvatar::setEnableDebugDrawPosition(bool isEnabled) { void MyAvatar::setEnableDebugDrawHandControllers(bool isEnabled) { _enableDebugDrawHandControllers = isEnabled; if (!isEnabled) { - DebugDraw::getInstance().removeMyAvatarMarker("leftHandController"); - DebugDraw::getInstance().removeMyAvatarMarker("rightHandController"); + DebugDraw::getInstance().removeMarker("leftHandController"); + DebugDraw::getInstance().removeMarker("rightHandController"); } } @@ -1096,24 +1095,34 @@ static controller::Pose applyLowVelocityFilter(const controller::Pose& oldPose, return finalPose; } -void MyAvatar::setHandControllerPoses(const controller::Pose& left, const controller::Pose& right) { +void MyAvatar::setHandControllerPosesInWorldFrame(const controller::Pose& left, const controller::Pose& right) { if (controller::InputDevice::getLowVelocityFilter()) { - auto oldLeftPose = getLeftHandControllerPose(); - auto oldRightPose = getRightHandControllerPose(); - _leftHandControllerPoseCache.set(applyLowVelocityFilter(oldLeftPose, left)); - _rightHandControllerPoseCache.set(applyLowVelocityFilter(oldRightPose, right)); + auto oldLeftPose = getLeftHandControllerPoseInWorldFrame(); + auto oldRightPose = getRightHandControllerPoseInWorldFrame(); + _leftHandControllerPoseInWorldFrameCache.set(applyLowVelocityFilter(oldLeftPose, left)); + _rightHandControllerPoseInWorldFrameCache.set(applyLowVelocityFilter(oldRightPose, right)); } else { - _leftHandControllerPoseCache.set(left); - _rightHandControllerPoseCache.set(right); + _leftHandControllerPoseInWorldFrameCache.set(left); + _rightHandControllerPoseInWorldFrameCache.set(right); } } -controller::Pose MyAvatar::getLeftHandControllerPose() const { - return _leftHandControllerPoseCache.get(); +controller::Pose MyAvatar::getLeftHandControllerPoseInWorldFrame() const { + return _leftHandControllerPoseInWorldFrameCache.get(); } -controller::Pose MyAvatar::getRightHandControllerPose() const { - return _rightHandControllerPoseCache.get(); +controller::Pose MyAvatar::getRightHandControllerPoseInWorldFrame() const { + return _rightHandControllerPoseInWorldFrameCache.get(); +} + +controller::Pose MyAvatar::getLeftHandControllerPoseInAvatarFrame() const { + glm::mat4 invAvatarMatrix = glm::inverse(createMatFromQuatAndPos(getOrientation(), getPosition())); + return getLeftHandControllerPoseInWorldFrame().transform(invAvatarMatrix); +} + +controller::Pose MyAvatar::getRightHandControllerPoseInAvatarFrame() const { + glm::mat4 invAvatarMatrix = glm::inverse(createMatFromQuatAndPos(getOrientation(), getPosition())); + return getRightHandControllerPoseInWorldFrame().transform(invAvatarMatrix); } void MyAvatar::prepareForPhysicsSimulation() { @@ -1360,20 +1369,23 @@ void MyAvatar::preRender(RenderArgs* renderArgs) { } if (_enableDebugDrawHandControllers) { - auto leftHandPose = getLeftHandControllerPose(); - auto rightHandPose = getRightHandControllerPose(); + auto leftHandPose = getLeftHandControllerPoseInWorldFrame(); + auto rightHandPose = getRightHandControllerPoseInWorldFrame(); if (leftHandPose.isValid()) { - DebugDraw::getInstance().addMyAvatarMarker("leftHandController", leftHandPose.getRotation(), leftHandPose.getTranslation(), glm::vec4(1)); + DebugDraw::getInstance().addMarker("leftHandController", leftHandPose.getRotation(), leftHandPose.getTranslation(), glm::vec4(1)); } else { - DebugDraw::getInstance().removeMyAvatarMarker("leftHandController"); + DebugDraw::getInstance().removeMarker("leftHandController"); } if (rightHandPose.isValid()) { - DebugDraw::getInstance().addMyAvatarMarker("rightHandController", rightHandPose.getRotation(), rightHandPose.getTranslation(), glm::vec4(1)); + DebugDraw::getInstance().addMarker("rightHandController", rightHandPose.getRotation(), rightHandPose.getTranslation(), glm::vec4(1)); } else { - DebugDraw::getInstance().removeMyAvatarMarker("rightHandController"); + DebugDraw::getInstance().removeMarker("rightHandController"); } + + // AJT: REMOVE + DebugDraw::getInstance().addMyAvatarMarker("REFERENCE", glm::quat(), glm::vec3(0.0f, 0.7f, -0.5f), glm::vec4(1)); } DebugDraw::getInstance().updateMyAvatarPos(getPosition()); diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 0092280762..2301e37a5b 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -249,9 +249,11 @@ public: virtual void rebuildCollisionShape() override; - void setHandControllerPoses(const controller::Pose& left, const controller::Pose& right); - controller::Pose MyAvatar::getLeftHandControllerPose() const; - controller::Pose MyAvatar::getRightHandControllerPose() const; + void setHandControllerPosesInWorldFrame(const controller::Pose& left, const controller::Pose& right); + controller::Pose getLeftHandControllerPoseInWorldFrame() const; + controller::Pose getRightHandControllerPoseInWorldFrame() const; + controller::Pose getLeftHandControllerPoseInAvatarFrame() const; + controller::Pose getRightHandControllerPoseInAvatarFrame() const; public slots: void increaseSize(); @@ -450,8 +452,9 @@ private: bool _hoverReferenceCameraFacingIsCaptured { false }; glm::vec3 _hoverReferenceCameraFacing { 0.0f, 0.0f, -1.0f }; // hmd sensor space - ThreadSafeValueCache _leftHandControllerPoseCache { controller::Pose() }; - ThreadSafeValueCache _rightHandControllerPoseCache { controller::Pose() }; + // These are stored in WORLD frame + ThreadSafeValueCache _leftHandControllerPoseInWorldFrameCache { controller::Pose() }; + ThreadSafeValueCache _rightHandControllerPoseInWorldFrameCache { controller::Pose() }; float AVATAR_MOVEMENT_ENERGY_CONSTANT { 0.001f }; float AUDIO_ENERGY_CONSTANT { 0.000001f }; diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index d659d79dd9..46a091cf35 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -126,7 +126,7 @@ void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) { Rig::HandParameters handParams; - auto leftPose = myAvatar->getLeftHandControllerPose(); + auto leftPose = myAvatar->getLeftHandControllerPoseInAvatarFrame(); if (leftPose.isValid()) { handParams.isLeftEnabled = true; handParams.leftPosition = Quaternions::Y_180 * leftPose.getTranslation(); @@ -135,7 +135,7 @@ void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) { handParams.isLeftEnabled = false; } - auto rightPose = myAvatar->getRightHandControllerPose(); + auto rightPose = myAvatar->getRightHandControllerPoseInAvatarFrame(); if (rightPose.isValid()) { handParams.isRightEnabled = true; handParams.rightPosition = Quaternions::Y_180 * rightPose.getTranslation(); diff --git a/libraries/render-utils/src/AnimDebugDraw.cpp b/libraries/render-utils/src/AnimDebugDraw.cpp index c9abf71fad..44bf533739 100644 --- a/libraries/render-utils/src/AnimDebugDraw.cpp +++ b/libraries/render-utils/src/AnimDebugDraw.cpp @@ -392,13 +392,18 @@ void AnimDebugDraw::update() { assert(numVerts == (v - verts)); + // This render item bound shit is broken. + // Fuck that, use the big ass bound instead. + /* render::Item::Bound theBound; for (int i = 0; i < numVerts; i++) { theBound += verts[i].pos; } + */ data._isVisible = (numVerts > 0); - data._bound = theBound; + + //data._bound = theBound; data._indexBuffer->resize(sizeof(uint16_t) * numVerts); uint16_t* indices = (uint16_t*)data._indexBuffer->editData(); for (int i = 0; i < numVerts; i++) { diff --git a/plugins/hifiSixense/src/SixenseManager.cpp b/plugins/hifiSixense/src/SixenseManager.cpp index 9fdce3add4..67192edebd 100644 --- a/plugins/hifiSixense/src/SixenseManager.cpp +++ b/plugins/hifiSixense/src/SixenseManager.cpp @@ -481,6 +481,12 @@ void SixenseManager::InputDevice::handlePoseEvent(float deltaTime, const control // transform pose into avatar frame. auto nextPose = controller::Pose(pos, rot, velocity, angularVelocity).transform(controllerToAvatar); + if (!left) { + // AJT: HACK TO DEBUG IK + nextPose.translation = glm::vec3(0.25f, 0.7f, -0.5f); + nextPose.rotation = glm::quat(); + } + if (prevPose.isValid() && (deltaTime > std::numeric_limits::epsilon())) { nextPose.velocity = (nextPose.getTranslation() - prevPose.getTranslation()) / deltaTime; From 7ae9006b30f331f99bd68f553e47cb7b5ffdef77 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Thu, 10 Mar 2016 22:42:53 -0800 Subject: [PATCH 07/77] add current version to console menu --- server-console/src/main.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/server-console/src/main.js b/server-console/src/main.js index e05106aa6f..fedd934029 100644 --- a/server-console/src/main.js +++ b/server-console/src/main.js @@ -532,10 +532,13 @@ function buildMenuArray(serverState) { { type: 'separator' }, - { + { label: 'Quit', accelerator: 'Command+Q', click: function() { shutdown(); } + }, + { + label: 'Current Version: '+buildInfo.buildIdentifier } ]; @@ -776,6 +779,7 @@ app.on('ready', function() { } catch (e) { } + if (currentVersion !== null) { const CHECK_FOR_UPDATES_INTERVAL_SECONDS = 60 * 30; var hasShownUpdateNotification = false; From 5eeb4ca594aae5de25b81f1e90987a059c9d7399 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Fri, 11 Mar 2016 09:28:25 -0800 Subject: [PATCH 08/77] Fix one frame lag controller lag/jitter Move userInputMapper->update() after inputPlugin->pluginUpdate(). --- interface/src/Application.cpp | 3 ++- interface/src/avatar/MyAvatar.cpp | 3 --- libraries/shared/src/GLMHelpers.cpp | 8 ++++++++ libraries/shared/src/GLMHelpers.h | 2 ++ plugins/hifiSixense/src/SixenseManager.cpp | 6 ------ 5 files changed, 12 insertions(+), 10 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 42430b3a4c..2e4cb1db0f 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3179,7 +3179,6 @@ void Application::update(float deltaTime) { auto myAvatar = getMyAvatar(); auto userInputMapper = DependencyManager::get(); - userInputMapper->update(deltaTime); controller::InputCalibrationData calibrationData = { myAvatar->getSensorToWorldMatrix(), @@ -3197,6 +3196,8 @@ void Application::update(float deltaTime) { } } + userInputMapper->update(deltaTime); + _controllerScriptingInterface->updateInputControllers(); // Transfer the user inputs to the driveKeys diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index c018a76168..8be8b601a4 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1383,9 +1383,6 @@ void MyAvatar::preRender(RenderArgs* renderArgs) { } else { DebugDraw::getInstance().removeMarker("rightHandController"); } - - // AJT: REMOVE - DebugDraw::getInstance().addMyAvatarMarker("REFERENCE", glm::quat(), glm::vec3(0.0f, 0.7f, -0.5f), glm::vec4(1)); } DebugDraw::getInstance().updateMyAvatarPos(getPosition()); diff --git a/libraries/shared/src/GLMHelpers.cpp b/libraries/shared/src/GLMHelpers.cpp index b2294f9ef3..d21d88d212 100644 --- a/libraries/shared/src/GLMHelpers.cpp +++ b/libraries/shared/src/GLMHelpers.cpp @@ -471,3 +471,11 @@ bool isNaN(glm::quat value) { return isNaN(value.w) || isNaN(value.x) || isNaN(value.y) || isNaN(value.z); } +glm::mat4 orthoInverse(const glm::mat4& m) { + glm::mat4 r = m; + r[3] = glm::vec4(0.0f, 0.0f, 0.0f, 1.0f); + r = glm::transpose(r); + r[3] = -(r * m[3]); + r[3][3] = 1.0f; + return r; +} diff --git a/libraries/shared/src/GLMHelpers.h b/libraries/shared/src/GLMHelpers.h index 4a37d68240..469ca1fc81 100644 --- a/libraries/shared/src/GLMHelpers.h +++ b/libraries/shared/src/GLMHelpers.h @@ -232,4 +232,6 @@ glm::vec2 getFacingDir2D(const glm::mat4& m); bool isNaN(glm::vec3 value); bool isNaN(glm::quat value); +glm::mat4 orthoInverse(const glm::mat4& m); + #endif // hifi_GLMHelpers_h diff --git a/plugins/hifiSixense/src/SixenseManager.cpp b/plugins/hifiSixense/src/SixenseManager.cpp index 67192edebd..9fdce3add4 100644 --- a/plugins/hifiSixense/src/SixenseManager.cpp +++ b/plugins/hifiSixense/src/SixenseManager.cpp @@ -481,12 +481,6 @@ void SixenseManager::InputDevice::handlePoseEvent(float deltaTime, const control // transform pose into avatar frame. auto nextPose = controller::Pose(pos, rot, velocity, angularVelocity).transform(controllerToAvatar); - if (!left) { - // AJT: HACK TO DEBUG IK - nextPose.translation = glm::vec3(0.25f, 0.7f, -0.5f); - nextPose.rotation = glm::quat(); - } - if (prevPose.isValid() && (deltaTime > std::numeric_limits::epsilon())) { nextPose.velocity = (nextPose.getTranslation() - prevPose.getTranslation()) / deltaTime; From 18f5b14e7ae65f932528a2cdd7b214ab0c56772e Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Fri, 11 Mar 2016 11:45:29 -0800 Subject: [PATCH 09/77] make all toggle menu items work properly through Menu scripting interface --- libraries/ui/src/ui/Menu.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/libraries/ui/src/ui/Menu.cpp b/libraries/ui/src/ui/Menu.cpp index 1b70213876..83fc191b7d 100644 --- a/libraries/ui/src/ui/Menu.cpp +++ b/libraries/ui/src/ui/Menu.cpp @@ -222,8 +222,11 @@ void Menu::setIsOptionChecked(const QString& menuOption, bool isChecked) { return; } QAction* menu = _actionHash.value(menuOption); - if (menu) { - menu->setChecked(isChecked); + if (menu && menu->isCheckable()) { + auto wasChecked = menu->isChecked(); + if (wasChecked != isChecked) { + menu->trigger(); + } } } From d32611a7f9a6cef19d1259847fde539a7a83d657 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Fri, 11 Mar 2016 11:45:52 -0800 Subject: [PATCH 10/77] make away show overlays if they are hidden when you enter away --- examples/away.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/examples/away.js b/examples/away.js index 82b9c881c6..840c5ab48a 100644 --- a/examples/away.js +++ b/examples/away.js @@ -152,6 +152,7 @@ function maybeMoveOverlay() { // MAIN CONTROL var wasMuted, isAway; +var wasOverlaysVisible = Menu.isOptionChecked("Overlays"); var eventMappingName = "io.highfidelity.away"; // goActive on hand controller button events, too. var eventMapping = Controller.newMapping(eventMappingName); @@ -169,6 +170,13 @@ function goAway() { playAwayAnimation(); // animation is still seen by others showOverlay(); + // remember the View > Overlays state... + wasOverlaysVisible = Menu.isOptionChecked("Overlays"); + print("wasOverlaysVisible:" + wasOverlaysVisible); + + // show overlays so that people can see the "Away" message + Menu.setIsOptionChecked("Overlays", true); + // tell the Reticle, we want to stop capturing the mouse until we come back Reticle.allowMouseCapture = false; if (HMD.active) { @@ -188,6 +196,9 @@ function goActive() { stopAwayAnimation(); hideOverlay(); + // restore overlays state to what it was when we went "away" + Menu.setIsOptionChecked("Overlays", wasOverlaysVisible); + // tell the Reticle, we are ready to capture the mouse again and it should be visible Reticle.allowMouseCapture = true; Reticle.visible = true; From e341419090ea4305b123b0b7713e0d00fabc5711 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Fri, 11 Mar 2016 11:56:39 -0800 Subject: [PATCH 11/77] enter away mode when you remove the Vive HMD --- examples/away.js | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/examples/away.js b/examples/away.js index 840c5ab48a..6bd685fcff 100644 --- a/examples/away.js +++ b/examples/away.js @@ -156,6 +156,15 @@ var wasOverlaysVisible = Menu.isOptionChecked("Overlays"); var eventMappingName = "io.highfidelity.away"; // goActive on hand controller button events, too. var eventMapping = Controller.newMapping(eventMappingName); +// backward compatible version of getting HMD.mounted, so it works in old clients +function safeGetHMDMounted() { + if (HMD.mounted === undefined) { + return true; + } + return HMD.mounted; +} +var wasHmdMounted = safeGetHMDMounted(); + function goAway() { if (isAway) { return; @@ -182,7 +191,9 @@ function goAway() { if (HMD.active) { Reticle.visible = false; } + wasHmdMounted = safeGetHMDMounted(); // always remember the correct state } + function goActive() { if (!isAway) { return; @@ -205,6 +216,7 @@ function goActive() { if (HMD.active) { Reticle.position = HMD.getHUDLookAtPosition2D(); } + wasHmdMounted = safeGetHMDMounted(); // always remember the correct state } function maybeGoActive(event) { @@ -217,6 +229,7 @@ function maybeGoActive(event) { goActive(); } } + var wasHmdActive = HMD.active; var wasMouseCaptured = Reticle.mouseCaptured; @@ -236,6 +249,13 @@ function maybeGoAway() { goAway(); } } + + // If you've removed your HMD from your head, and we can detect it, we will also go away... + var hmdMounted = safeGetHMDMounted(); + if (HMD.active && !hmdMounted && wasHmdMounted) { + wasHmdMounted = hmdMounted; + goAway(); + } } Script.update.connect(maybeMoveOverlay); From f611d8f747f61347db4429ee8a84bc2b81b6cb70 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 11 Mar 2016 12:41:18 -0800 Subject: [PATCH 12/77] if needed, set querryAACube when dimensions are updated --- .../src/RenderableModelEntityItem.cpp | 37 ++++++++++++++----- libraries/entities/src/EntityItem.cpp | 3 +- libraries/entities/src/EntityItem.h | 4 +- .../entities/src/EntityScriptingInterface.cpp | 6 ++- 4 files changed, 37 insertions(+), 13 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 71b04d06a1..f3c205dadc 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -75,6 +75,23 @@ void RenderableModelEntityItem::loader() { void RenderableModelEntityItem::setDimensions(const glm::vec3& value) { _dimensionsInitialized = true; ModelEntityItem::setDimensions(value); + + bool success; + AACube maxAACube = getMaximumAACube(success); + if (!success) { + return; + } + AACube queryAACube = getQueryAACube(success); + + if (!success || !queryAACube.contains(maxAACube)) { + EntityItemProperties properties; + properties.setQueryAACube(maxAACube); + qCDebug(entitiesrenderer) << "Auto-setting queryAACube:" << (!getName().isEmpty() ? getName() : getModelURL()); + QMetaObject::invokeMethod(DependencyManager::get().data(), "editEntity", + Qt::QueuedConnection, + Q_ARG(QUuid, getEntityItemID()), + Q_ARG(EntityItemProperties, properties)); + } } bool RenderableModelEntityItem::setProperties(const EntityItemProperties& properties) { @@ -512,15 +529,17 @@ bool RenderableModelEntityItem::needsToCallUpdate() const { void RenderableModelEntityItem::update(const quint64& now) { if (!_dimensionsInitialized && _model && _model->isActive()) { - EntityItemProperties properties; - auto extents = _model->getMeshExtents(); - properties.setDimensions(extents.maximum - extents.minimum); - - qCDebug(entitiesrenderer) << "Autoresizing:" << (!getName().isEmpty() ? getName() : getModelURL()); - QMetaObject::invokeMethod(DependencyManager::get().data(), "editEntity", - Qt::QueuedConnection, - Q_ARG(QUuid, getEntityItemID()), - Q_ARG(EntityItemProperties, properties)); + const QSharedPointer renderNetworkGeometry = _model->getGeometry(); + if (renderNetworkGeometry && renderNetworkGeometry->isLoaded()) { + EntityItemProperties properties; + auto extents = _model->getMeshExtents(); + properties.setDimensions(extents.maximum - extents.minimum); + qCDebug(entitiesrenderer) << "Autoresizing:" << (!getName().isEmpty() ? getName() : getModelURL()); + QMetaObject::invokeMethod(DependencyManager::get().data(), "editEntity", + Qt::QueuedConnection, + Q_ARG(QUuid, getEntityItemID()), + Q_ARG(EntityItemProperties, properties)); + } } ModelEntityItem::update(now); diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 3c918a0a77..8f6d497461 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1307,8 +1307,7 @@ AACube EntityItem::getQueryAACube(bool& success) const { // this is for when we've loaded an older json file that didn't have queryAACube properties. result = getMaximumAACube(success); if (success) { - _queryAACube = result; - _queryAACubeSet = true; + getThisPointer()->setQueryAACube(result); } return result; } diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 5bd761b4e3..577bb406bc 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -75,7 +75,9 @@ public: EntityItem(const EntityItemID& entityItemID); virtual ~EntityItem(); - inline EntityItemPointer getThisPointer() { return std::static_pointer_cast(shared_from_this()); } + inline EntityItemPointer getThisPointer() const { + return std::static_pointer_cast(std::const_pointer_cast(shared_from_this())); + } EntityItemID getEntityItemID() const { return EntityItemID(_id); } diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 702b1ed916..c195d12ca3 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -148,7 +148,11 @@ QUuid EntityScriptingInterface::addEntity(const EntityItemProperties& properties if (entity) { if (propertiesWithSimID.parentRelatedPropertyChanged()) { // due to parenting, the server may not know where something is in world-space, so include the bounding cube. - propertiesWithSimID.setQueryAACube(entity->getQueryAACube()); + bool success; + AACube queryAACube = entity->getQueryAACube(success); + if (success) { + propertiesWithSimID.setQueryAACube(queryAACube); + } } if (_bidOnSimulationOwnership) { From 082bb8c4b8d773add9c0fbacb4668c762cf24fa2 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Fri, 11 Mar 2016 12:49:42 -0800 Subject: [PATCH 13/77] auto-show reticle on mouse click --- examples/depthReticle.js | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/examples/depthReticle.js b/examples/depthReticle.js index 14215bff3d..52392b2466 100644 --- a/examples/depthReticle.js +++ b/examples/depthReticle.js @@ -21,7 +21,7 @@ var MINIMUM_DEPTH_ADJUST = 0.01; var NON_LINEAR_DIVISOR = 2; var MINIMUM_SEEK_DISTANCE = 0.01; -var lastMouseMove = Date.now(); +var lastMouseMoveOrClick = Date.now(); var lastMouseX = Reticle.position.x; var lastMouseY = Reticle.position.y; var HIDE_STATIC_MOUSE_AFTER = 3000; // 3 seconds @@ -32,6 +32,14 @@ var WEIGHTING = 1/20; // simple moving average over last 20 samples var ONE_MINUS_WEIGHTING = 1 - WEIGHTING; var AVERAGE_MOUSE_VELOCITY_FOR_SEEK_TO = 50; +function showReticleOnMouseClick() { + Reticle.visible = true; + lastMouseMoveOrClick = Date.now(); // move or click +} + +Controller.mousePressEvent.connect(showReticleOnMouseClick); +Controller.mouseDoublePressEvent.connect(showReticleOnMouseClick); + Controller.mouseMoveEvent.connect(function(mouseEvent) { var now = Date.now(); @@ -47,7 +55,7 @@ Controller.mouseMoveEvent.connect(function(mouseEvent) { if (HMD.active && !shouldSeekToLookAt && Reticle.allowMouseCapture) { var dx = Reticle.position.x - lastMouseX; var dy = Reticle.position.y - lastMouseY; - var dt = Math.max(1, (now - lastMouseMove)); // mSecs since last mouse move + var dt = Math.max(1, (now - lastMouseMoveOrClick)); // mSecs since last mouse move var mouseMoveDistance = Math.sqrt((dx*dx) + (dy*dy)); var mouseVelocity = mouseMoveDistance / dt; averageMouseVelocity = (ONE_MINUS_WEIGHTING * averageMouseVelocity) + (WEIGHTING * mouseVelocity); @@ -56,7 +64,7 @@ Controller.mouseMoveEvent.connect(function(mouseEvent) { } } } - lastMouseMove = now; + lastMouseMoveOrClick = now; lastMouseX = mouseEvent.x; lastMouseY = mouseEvent.y; }); @@ -94,7 +102,7 @@ function autoHideReticle() { // system overlay (like a window), then hide the reticle if (Reticle.visible && !Reticle.pointingAtSystemOverlay) { var now = Date.now(); - var timeSinceLastMouseMove = now - lastMouseMove; + var timeSinceLastMouseMove = now - lastMouseMoveOrClick; if (timeSinceLastMouseMove > HIDE_STATIC_MOUSE_AFTER) { Reticle.visible = false; } From 7a4dad8e51a1d04a33325de537c7485baea0ab4e Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 11 Mar 2016 13:20:52 -0800 Subject: [PATCH 14/77] allow entity-server to patch up broken queryAACubes --- libraries/entities/src/EntityItem.cpp | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 8f6d497461..15d358475f 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1300,16 +1300,22 @@ AABox EntityItem::getAABox(bool& success) const { } AACube EntityItem::getQueryAACube(bool& success) const { - AACube result = SpatiallyNestable::getQueryAACube(success); + AACube queryAACube = SpatiallyNestable::getQueryAACube(success); + bool maxAACubeSuccess; + AACube maxAACube = getMaximumAACube(maxAACubeSuccess); if (success) { - return result; + // allow server to patch up broken queryAACubes + if (maxAACubeSuccess && !queryAACube.contains(maxAACube)) { + getThisPointer()->setQueryAACube(maxAACube); + } + return _queryAACube; } // this is for when we've loaded an older json file that didn't have queryAACube properties. - result = getMaximumAACube(success); - if (success) { - getThisPointer()->setQueryAACube(result); + success = maxAACubeSuccess; + if (maxAACubeSuccess) { + getThisPointer()->setQueryAACube(maxAACube); } - return result; + return _queryAACube; } From 0ce004c8a7db7d555755544b1cd7ab824cbf990f Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Fri, 11 Mar 2016 13:35:27 -0800 Subject: [PATCH 15/77] Removed passive-aggressive comment, (it was a late night) --- libraries/render-utils/src/AnimDebugDraw.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/libraries/render-utils/src/AnimDebugDraw.cpp b/libraries/render-utils/src/AnimDebugDraw.cpp index 44bf533739..a0f7d7eca1 100644 --- a/libraries/render-utils/src/AnimDebugDraw.cpp +++ b/libraries/render-utils/src/AnimDebugDraw.cpp @@ -392,18 +392,20 @@ void AnimDebugDraw::update() { assert(numVerts == (v - verts)); - // This render item bound shit is broken. - // Fuck that, use the big ass bound instead. + // The RenderItem culling is not working correctly + // Workaround this issue by using the default constructed + // item._bound which is a 16 km cube. /* render::Item::Bound theBound; for (int i = 0; i < numVerts; i++) { theBound += verts[i].pos; } + data._bound = theBound; */ data._isVisible = (numVerts > 0); - //data._bound = theBound; + data._indexBuffer->resize(sizeof(uint16_t) * numVerts); uint16_t* indices = (uint16_t*)data._indexBuffer->editData(); for (int i = 0; i < numVerts; i++) { From fce83697087d657c3b76ec35f09150dbbb57d7f3 Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Fri, 11 Mar 2016 14:23:47 -0800 Subject: [PATCH 16/77] Remove logging that implies a problem that isn't there. --- libraries/script-engine/src/ScriptCache.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/libraries/script-engine/src/ScriptCache.cpp b/libraries/script-engine/src/ScriptCache.cpp index ae422313aa..3ebd3d53ce 100644 --- a/libraries/script-engine/src/ScriptCache.cpp +++ b/libraries/script-engine/src/ScriptCache.cpp @@ -115,9 +115,6 @@ void ScriptCache::getScriptContents(const QString& scriptOrURL, contentAvailable auto scriptContent = _scriptCache[url]; lock.unlock(); qCDebug(scriptengine) << "Found script in cache:" << url.toString(); - #if 1 // def THREAD_DEBUGGING - qCDebug(scriptengine) << "ScriptCache::getScriptContents() about to call contentAvailable() on thread [" << QThread::currentThread() << "] expected thread [" << thread() << "]"; - #endif contentAvailable(url.toString(), scriptContent, true, true); } else { bool alreadyWaiting = _contentCallbacks.contains(url); From 2ad15f75682ea97dc98f08a09fe6b40b7438d517 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 11 Mar 2016 14:38:31 -0800 Subject: [PATCH 17/77] try harder to get queryAABoxes to be correct --- .../src/RenderableModelEntityItem.cpp | 6 ++- libraries/entities/src/EntityItem.cpp | 44 ++++++++++--------- libraries/entities/src/EntityItem.h | 7 +-- 3 files changed, 32 insertions(+), 25 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index f3c205dadc..2734d968a9 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -74,14 +74,16 @@ void RenderableModelEntityItem::loader() { void RenderableModelEntityItem::setDimensions(const glm::vec3& value) { _dimensionsInitialized = true; - ModelEntityItem::setDimensions(value); bool success; + AACube queryAACube = getQueryAACube(success); + + ModelEntityItem::setDimensions(value); + AACube maxAACube = getMaximumAACube(success); if (!success) { return; } - AACube queryAACube = getQueryAACube(success); if (!success || !queryAACube.contains(maxAACube)) { EntityItemProperties properties; diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 15d358475f..71be12682b 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1202,11 +1202,35 @@ const Transform EntityItem::getTransformToCenter(bool& success) const { return result; } +void EntityItem::checkAndAdjustQueryAACube() { + bool maxAACubeSuccess; + AACube maxAACube = getMaximumAACube(maxAACubeSuccess); + if (maxAACubeSuccess) { + if (!_queryAACubeSet || !_queryAACube.contains(maxAACube)) { + // allow server to patch up broken queryAACubes + EntityTreePointer tree = getTree(); + if (tree) { + qDebug() << "EntityItem::checkAndAdjustQueryAACube" << getName(); + EntityItemProperties properties; + properties.setQueryAACube(maxAACube); + tree->updateEntity(getID(), properties); + } + } + } +} + +void EntityItem::setParentID(const QUuid& parentID) { + SpatiallyNestable::setParentID(parentID); + checkAndAdjustQueryAACube(); +} + + void EntityItem::setDimensions(const glm::vec3& value) { if (value.x <= 0.0f || value.y <= 0.0f || value.z <= 0.0f) { return; } setScale(value); + checkAndAdjustQueryAACube(); } /// The maximum bounding cube for the entity, independent of it's rotation. @@ -1299,26 +1323,6 @@ AABox EntityItem::getAABox(bool& success) const { return _cachedAABox; } -AACube EntityItem::getQueryAACube(bool& success) const { - AACube queryAACube = SpatiallyNestable::getQueryAACube(success); - bool maxAACubeSuccess; - AACube maxAACube = getMaximumAACube(maxAACubeSuccess); - if (success) { - // allow server to patch up broken queryAACubes - if (maxAACubeSuccess && !queryAACube.contains(maxAACube)) { - getThisPointer()->setQueryAACube(maxAACube); - } - return _queryAACube; - } - // this is for when we've loaded an older json file that didn't have queryAACube properties. - success = maxAACubeSuccess; - if (maxAACubeSuccess) { - getThisPointer()->setQueryAACube(maxAACube); - } - return _queryAACube; -} - - // NOTE: This should only be used in cases of old bitstreams which only contain radius data // 0,0,0 --> maxDimension,maxDimension,maxDimension // ... has a corner to corner distance of glm::length(maxDimension,maxDimension,maxDimension) diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 577bb406bc..7ce1d0c783 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -179,6 +179,10 @@ public: QString getDescription() const { return _description; } void setDescription(QString value) { _description = value; } + void checkAndAdjustQueryAACube(); + + virtual void setParentID(const QUuid& parentID); + /// Dimensions in meters (0.0 - TREE_SCALE) inline const glm::vec3 getDimensions() const { return getScale(); } virtual void setDimensions(const glm::vec3& value); @@ -238,9 +242,6 @@ public: AACube getMinimumAACube(bool& success) const; AABox getAABox(bool& success) const; /// axis aligned bounding box in world-frame (meters) - using SpatiallyNestable::getQueryAACube; - virtual AACube getQueryAACube(bool& success) const override; - const QString& getScript() const { return _script; } void setScript(const QString& value) { _script = value; } From df9ccf76ab98d56252a78d3df7b6edd583e3d360 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 10 Mar 2016 13:48:27 -0800 Subject: [PATCH 18/77] fix animation-tests --- .../animation/src/AnimInverseKinematics.cpp | 7 + .../src/AnimInverseKinematicsTests.cpp | 123 +++++++++++------- tests/animation/src/AnimTests.cpp | 62 ++++----- 3 files changed, 114 insertions(+), 78 deletions(-) diff --git a/libraries/animation/src/AnimInverseKinematics.cpp b/libraries/animation/src/AnimInverseKinematics.cpp index 6a29ad61ac..4a6c3d819c 100644 --- a/libraries/animation/src/AnimInverseKinematics.cpp +++ b/libraries/animation/src/AnimInverseKinematics.cpp @@ -22,7 +22,13 @@ AnimInverseKinematics::AnimInverseKinematics(const QString& id) : AnimNode(AnimN } AnimInverseKinematics::~AnimInverseKinematics() { + std::cout << "adebug dtor" << std::endl; // adebug clearConstraints(); + std::cout << "adebug dtor 002" << std::endl; // adebug + _accumulators.clear(); + std::cout << "adebug dtor 003 targetVarVec.size() = " << _targetVarVec.size() << std::endl; // adebug + _targetVarVec.clear(); + std::cout << "adebug dtor 004 targetVarVec.size() = " << _targetVarVec.size() << std::endl; // adebug } void AnimInverseKinematics::loadDefaultPoses(const AnimPoseVec& poses) { @@ -485,6 +491,7 @@ RotationConstraint* AnimInverseKinematics::getConstraint(int index) { } void AnimInverseKinematics::clearConstraints() { + std::cout << "adebug clearConstraints size = " << _constraints.size() << std::endl; // adebug std::map::iterator constraintItr = _constraints.begin(); while (constraintItr != _constraints.end()) { delete constraintItr->second; diff --git a/tests/animation/src/AnimInverseKinematicsTests.cpp b/tests/animation/src/AnimInverseKinematicsTests.cpp index bb15a1d257..2b10892f82 100644 --- a/tests/animation/src/AnimInverseKinematicsTests.cpp +++ b/tests/animation/src/AnimInverseKinematicsTests.cpp @@ -29,7 +29,7 @@ const glm::quat identity = glm::quat(); const glm::quat quaterTurnAroundZ = glm::angleAxis(0.5f * PI, zAxis); -void makeTestFBXJoints(std::vector& fbxJoints) { +void makeTestFBXJoints(FBXGeometry& geometry) { FBXJoint joint; joint.isFree = false; joint.freeLineage.clear(); @@ -61,29 +61,29 @@ void makeTestFBXJoints(std::vector& fbxJoints) { joint.name = "A"; joint.parentIndex = -1; joint.translation = origin; - fbxJoints.push_back(joint); + geometry.joints.push_back(joint); joint.name = "B"; joint.parentIndex = 0; joint.translation = xAxis; - fbxJoints.push_back(joint); + geometry.joints.push_back(joint); joint.name = "C"; joint.parentIndex = 1; joint.translation = xAxis; - fbxJoints.push_back(joint); + geometry.joints.push_back(joint); joint.name = "D"; joint.parentIndex = 2; joint.translation = xAxis; - fbxJoints.push_back(joint); + geometry.joints.push_back(joint); // compute each joint's transform - for (int i = 1; i < (int)fbxJoints.size(); ++i) { - FBXJoint& j = fbxJoints[i]; + for (int i = 1; i < (int)geometry.joints.size(); ++i) { + FBXJoint& j = geometry.joints[i]; int parentIndex = j.parentIndex; // World = ParentWorld * T * (Roff * Rp) * Rpre * R * Rpost * (Rp-1 * Soff * Sp * S * Sp-1) - j.transform = fbxJoints[parentIndex].transform * + j.transform = geometry.joints[parentIndex].transform * glm::translate(j.translation) * j.preTransform * glm::mat4_cast(j.preRotation * j.rotation * j.postRotation) * @@ -94,14 +94,14 @@ void makeTestFBXJoints(std::vector& fbxJoints) { } void AnimInverseKinematicsTests::testSingleChain() { - std::vector fbxJoints; - makeTestFBXJoints(fbxJoints); + FBXGeometry geometry; + makeTestFBXJoints(geometry); // create a skeleton and doll AnimPose offset; - AnimSkeleton* skeleton = new AnimSkeleton(fbxJoints, offset); - AnimSkeleton::Pointer skeletonPtr(skeleton); + AnimSkeleton::Pointer skeletonPtr = std::make_shared(geometry); AnimInverseKinematics ikDoll("doll"); + ikDoll.setSkeleton(skeletonPtr); { // easy test IK of joint C @@ -113,11 +113,11 @@ void AnimInverseKinematicsTests::testSingleChain() { pose.rot = identity; pose.trans = origin; - std::vector poses; + AnimPoseVec poses; poses.push_back(pose); pose.trans = xAxis; - for (int i = 1; i < (int)fbxJoints.size(); ++i) { + for (int i = 1; i < (int)geometry.joints.size(); ++i) { poses.push_back(pose); } ikDoll.loadPoses(poses); @@ -134,7 +134,8 @@ void AnimInverseKinematicsTests::testSingleChain() { AnimVariantMap varMap; varMap.set("positionD", targetPosition); varMap.set("rotationD", targetRotation); - ikDoll.setTargetVars("D", "positionD", "rotationD"); + varMap.set("targetType", (int)IKTarget::Type::RotationAndPosition); + ikDoll.setTargetVars(QString("D"), QString("positionD"), QString("rotationD"), QString("targetType")); AnimNode::Triggers triggers; // the IK solution should be: @@ -144,38 +145,49 @@ void AnimInverseKinematicsTests::testSingleChain() { // | // A------>B------>C // + + // iterate several times float dt = 1.0f; - ikDoll.evaluate(varMap, dt, triggers); + ikDoll.overlay(varMap, dt, triggers, poses); + ikDoll.overlay(varMap, dt, triggers, poses); + ikDoll.overlay(varMap, dt, triggers, poses); + + ikDoll.overlay(varMap, dt, triggers, poses); + ikDoll.overlay(varMap, dt, triggers, poses); + ikDoll.overlay(varMap, dt, triggers, poses); + const AnimPoseVec& relativePoses = ikDoll.overlay(varMap, dt, triggers, poses); // verify absolute results // NOTE: since we expect this solution to converge very quickly (one loop) // we can impose very tight error thresholds. - std::vector absolutePoses; + AnimPoseVec absolutePoses; + for (auto pose : poses) { + absolutePoses.push_back(pose); + } ikDoll.computeAbsolutePoses(absolutePoses); - float acceptableAngle = 0.0001f; - QCOMPARE_QUATS(absolutePoses[0].rot, identity, acceptableAngle); - QCOMPARE_QUATS(absolutePoses[1].rot, identity, acceptableAngle); - QCOMPARE_QUATS(absolutePoses[2].rot, quaterTurnAroundZ, acceptableAngle); - QCOMPARE_QUATS(absolutePoses[3].rot, quaterTurnAroundZ, acceptableAngle); + const float acceptableAngleError = 0.001f; + QCOMPARE_QUATS(absolutePoses[0].rot, identity, acceptableAngleError); + QCOMPARE_QUATS(absolutePoses[1].rot, identity, acceptableAngleError); + QCOMPARE_QUATS(absolutePoses[2].rot, quaterTurnAroundZ, acceptableAngleError); + QCOMPARE_QUATS(absolutePoses[3].rot, quaterTurnAroundZ, acceptableAngleError); - QCOMPARE_WITH_ABS_ERROR(absolutePoses[0].trans, origin, EPSILON); - QCOMPARE_WITH_ABS_ERROR(absolutePoses[1].trans, xAxis, EPSILON); - QCOMPARE_WITH_ABS_ERROR(absolutePoses[2].trans, 2.0f * xAxis, EPSILON); - QCOMPARE_WITH_ABS_ERROR(absolutePoses[3].trans, targetPosition, EPSILON); + const float acceptableTranslationError = 0.025f; + QCOMPARE_WITH_ABS_ERROR(absolutePoses[0].trans, origin, acceptableTranslationError); + QCOMPARE_WITH_ABS_ERROR(absolutePoses[1].trans, xAxis, acceptableTranslationError); + QCOMPARE_WITH_ABS_ERROR(absolutePoses[2].trans, 2.0f * xAxis, acceptableTranslationError); + QCOMPARE_WITH_ABS_ERROR(absolutePoses[3].trans, targetPosition, acceptableTranslationError); // verify relative results - const std::vector& relativePoses = ikDoll.getRelativePoses(); - QCOMPARE_QUATS(relativePoses[0].rot, identity, acceptableAngle); - QCOMPARE_QUATS(relativePoses[1].rot, identity, acceptableAngle); - QCOMPARE_QUATS(relativePoses[2].rot, quaterTurnAroundZ, acceptableAngle); - QCOMPARE_QUATS(relativePoses[3].rot, identity, acceptableAngle); + QCOMPARE_QUATS(relativePoses[0].rot, identity, acceptableAngleError); + QCOMPARE_QUATS(relativePoses[1].rot, identity, acceptableAngleError); + QCOMPARE_QUATS(relativePoses[2].rot, quaterTurnAroundZ, acceptableAngleError); + QCOMPARE_QUATS(relativePoses[3].rot, identity, acceptableAngleError); - QCOMPARE_WITH_ABS_ERROR(relativePoses[0].trans, origin, EPSILON); - QCOMPARE_WITH_ABS_ERROR(relativePoses[1].trans, xAxis, EPSILON); - QCOMPARE_WITH_ABS_ERROR(relativePoses[2].trans, xAxis, EPSILON); - QCOMPARE_WITH_ABS_ERROR(relativePoses[3].trans, xAxis, EPSILON); + QCOMPARE_WITH_ABS_ERROR(relativePoses[0].trans, origin, acceptableTranslationError); + QCOMPARE_WITH_ABS_ERROR(relativePoses[1].trans, xAxis, acceptableTranslationError); + QCOMPARE_WITH_ABS_ERROR(relativePoses[2].trans, xAxis, acceptableTranslationError); + QCOMPARE_WITH_ABS_ERROR(relativePoses[3].trans, xAxis, acceptableTranslationError); } - { // hard test IK of joint C // load intial poses that look like this: // @@ -188,8 +200,8 @@ void AnimInverseKinematicsTests::testSingleChain() { pose.scale = glm::vec3(1.0f); pose.rot = identity; pose.trans = origin; - - std::vector poses; + + AnimPoseVec poses; poses.push_back(pose); pose.trans = xAxis; @@ -211,15 +223,26 @@ void AnimInverseKinematicsTests::testSingleChain() { AnimVariantMap varMap; varMap.set("positionD", targetPosition); varMap.set("rotationD", targetRotation); - ikDoll.setTargetVars("D", "positionD", "rotationD"); + varMap.set("targetType", (int)IKTarget::Type::RotationAndPosition); + ikDoll.setTargetVars(QString("D"), QString("positionD"), QString("rotationD"), QString("targetType")); AnimNode::Triggers triggers; // the IK solution should be: // // A------>B------>C------>D // + + // iterate several times float dt = 1.0f; - ikDoll.evaluate(varMap, dt, triggers); + ikDoll.overlay(varMap, dt, triggers, poses); + ikDoll.overlay(varMap, dt, triggers, poses); + ikDoll.overlay(varMap, dt, triggers, poses); + ikDoll.overlay(varMap, dt, triggers, poses); + ikDoll.overlay(varMap, dt, triggers, poses); + ikDoll.overlay(varMap, dt, triggers, poses); + ikDoll.overlay(varMap, dt, triggers, poses); + ikDoll.overlay(varMap, dt, triggers, poses); + const AnimPoseVec& relativePoses = ikDoll.overlay(varMap, dt, triggers, poses); // verify absolute results // NOTE: the IK algorithm doesn't converge very fast for full-reach targets, @@ -228,31 +251,33 @@ void AnimInverseKinematicsTests::testSingleChain() { // NOTE: constraints may help speed up convergence since some joints may get clamped // to maximum extension. TODO: experiment with tightening the error thresholds when // constraints are working. - std::vector absolutePoses; + AnimPoseVec absolutePoses; + for (auto pose : poses) { + absolutePoses.push_back(pose); + } ikDoll.computeAbsolutePoses(absolutePoses); - float acceptableAngle = 0.1f; // radians + float acceptableAngle = 0.01f; // radians QCOMPARE_QUATS(absolutePoses[0].rot, identity, acceptableAngle); QCOMPARE_QUATS(absolutePoses[1].rot, identity, acceptableAngle); QCOMPARE_QUATS(absolutePoses[2].rot, identity, acceptableAngle); QCOMPARE_QUATS(absolutePoses[3].rot, identity, acceptableAngle); - float acceptableDistance = 0.4f; - QCOMPARE_WITH_ABS_ERROR(absolutePoses[0].trans, origin, EPSILON); + float acceptableDistance = 0.03f; + QCOMPARE_WITH_ABS_ERROR(absolutePoses[0].trans, origin, acceptableDistance); QCOMPARE_WITH_ABS_ERROR(absolutePoses[1].trans, xAxis, acceptableDistance); QCOMPARE_WITH_ABS_ERROR(absolutePoses[2].trans, 2.0f * xAxis, acceptableDistance); QCOMPARE_WITH_ABS_ERROR(absolutePoses[3].trans, 3.0f * xAxis, acceptableDistance); // verify relative results - const std::vector& relativePoses = ikDoll.getRelativePoses(); QCOMPARE_QUATS(relativePoses[0].rot, identity, acceptableAngle); QCOMPARE_QUATS(relativePoses[1].rot, identity, acceptableAngle); QCOMPARE_QUATS(relativePoses[2].rot, identity, acceptableAngle); QCOMPARE_QUATS(relativePoses[3].rot, identity, acceptableAngle); - QCOMPARE_WITH_ABS_ERROR(relativePoses[0].trans, origin, EPSILON); - QCOMPARE_WITH_ABS_ERROR(relativePoses[1].trans, xAxis, EPSILON); - QCOMPARE_WITH_ABS_ERROR(relativePoses[2].trans, xAxis, EPSILON); - QCOMPARE_WITH_ABS_ERROR(relativePoses[3].trans, xAxis, EPSILON); + QCOMPARE_WITH_ABS_ERROR(relativePoses[0].trans, origin, acceptableDistance); + QCOMPARE_WITH_ABS_ERROR(relativePoses[1].trans, xAxis, acceptableDistance); + QCOMPARE_WITH_ABS_ERROR(relativePoses[2].trans, xAxis, acceptableDistance); + QCOMPARE_WITH_ABS_ERROR(relativePoses[3].trans, xAxis, acceptableDistance); } } diff --git a/tests/animation/src/AnimTests.cpp b/tests/animation/src/AnimTests.cpp index 6812bb63b6..130b692fb0 100644 --- a/tests/animation/src/AnimTests.cpp +++ b/tests/animation/src/AnimTests.cpp @@ -38,8 +38,9 @@ void AnimTests::testClipInternalState() { float endFrame = 20.0f; float timeScale = 1.1f; bool loopFlag = true; + bool mirrorFlag = false; - AnimClip clip(id, url, startFrame, endFrame, timeScale, loopFlag); + AnimClip clip(id, url, startFrame, endFrame, timeScale, loopFlag, mirrorFlag); QVERIFY(clip.getID() == id); QVERIFY(clip.getType() == AnimNode::Type::Clip); @@ -49,6 +50,7 @@ void AnimTests::testClipInternalState() { QVERIFY(clip._endFrame == endFrame); QVERIFY(clip._timeScale == timeScale); QVERIFY(clip._loopFlag == loopFlag); + QVERIFY(clip._mirrorFlag == mirrorFlag); } static float framesToSec(float secs) { @@ -62,12 +64,13 @@ void AnimTests::testClipEvaulate() { float startFrame = 2.0f; float endFrame = 22.0f; float timeScale = 1.0f; - float loopFlag = true; + bool loopFlag = true; + bool mirrorFlag = false; auto vars = AnimVariantMap(); vars.set("FalseVar", false); - AnimClip clip(id, url, startFrame, endFrame, timeScale, loopFlag); + AnimClip clip(id, url, startFrame, endFrame, timeScale, loopFlag, mirrorFlag); AnimNode::Triggers triggers; clip.evaluate(vars, framesToSec(10.0f), triggers); @@ -97,7 +100,8 @@ void AnimTests::testClipEvaulateWithVars() { float startFrame = 2.0f; float endFrame = 22.0f; float timeScale = 1.0f; - float loopFlag = true; + bool loopFlag = true; + bool mirrorFlag = false; float startFrame2 = 22.0f; float endFrame2 = 100.0f; @@ -110,7 +114,7 @@ void AnimTests::testClipEvaulateWithVars() { vars.set("timeScale2", timeScale2); vars.set("loopFlag2", loopFlag2); - AnimClip clip(id, url, startFrame, endFrame, timeScale, loopFlag); + AnimClip clip(id, url, startFrame, endFrame, timeScale, loopFlag, mirrorFlag); clip.setStartFrameVar("startFrame2"); clip.setEndFrameVar("endFrame2"); clip.setTimeScaleVar("timeScale2"); @@ -583,23 +587,23 @@ void AnimTests::testExpressionEvaluator() { TEST_BOOL_EXPR(false && false); TEST_BOOL_EXPR(false && true); - TEST_BOOL_EXPR(true || false && true); - TEST_BOOL_EXPR(true || false && false); - TEST_BOOL_EXPR(true || true && true); - TEST_BOOL_EXPR(true || true && false); - TEST_BOOL_EXPR(false || false && true); - TEST_BOOL_EXPR(false || false && false); - TEST_BOOL_EXPR(false || true && true); - TEST_BOOL_EXPR(false || true && false); + TEST_BOOL_EXPR(true || (false && true)); + TEST_BOOL_EXPR(true || (false && false)); + TEST_BOOL_EXPR(true || (true && true)); + TEST_BOOL_EXPR(true || (true && false)); + TEST_BOOL_EXPR(false || (false && true)); + TEST_BOOL_EXPR(false || (false && false)); + TEST_BOOL_EXPR(false || (true && true)); + TEST_BOOL_EXPR(false || (true && false)); - TEST_BOOL_EXPR(true && false || true); - TEST_BOOL_EXPR(true && false || false); - TEST_BOOL_EXPR(true && true || true); - TEST_BOOL_EXPR(true && true || false); - TEST_BOOL_EXPR(false && false || true); - TEST_BOOL_EXPR(false && false || false); - TEST_BOOL_EXPR(false && true || true); - TEST_BOOL_EXPR(false && true || false); + TEST_BOOL_EXPR((true && false) || true); + TEST_BOOL_EXPR((true && false) || false); + TEST_BOOL_EXPR((true && true) || true); + TEST_BOOL_EXPR((true && true) || false); + TEST_BOOL_EXPR((false && false) || true); + TEST_BOOL_EXPR((false && false) || false); + TEST_BOOL_EXPR((false && true) || true); + TEST_BOOL_EXPR((false && true) || false); TEST_BOOL_EXPR(t || false); TEST_BOOL_EXPR(t || true); @@ -610,14 +614,14 @@ void AnimTests::testExpressionEvaluator() { TEST_BOOL_EXPR(!false); TEST_BOOL_EXPR(!true || true); - TEST_BOOL_EXPR(!true && !false || !true); - TEST_BOOL_EXPR(!true && !false || true); - TEST_BOOL_EXPR(!true && false || !true); - TEST_BOOL_EXPR(!true && false || true); - TEST_BOOL_EXPR(true && !false || !true); - TEST_BOOL_EXPR(true && !false || true); - TEST_BOOL_EXPR(true && false || !true); - TEST_BOOL_EXPR(true && false || true); + TEST_BOOL_EXPR((!true && !false) || !true); + TEST_BOOL_EXPR((!true && !false) || true); + TEST_BOOL_EXPR((!true && false) || !true); + TEST_BOOL_EXPR((!true && false) || true); + TEST_BOOL_EXPR((true && !false) || !true); + TEST_BOOL_EXPR((true && !false) || true); + TEST_BOOL_EXPR((true && false) || !true); + TEST_BOOL_EXPR((true && false) || true); TEST_BOOL_EXPR(!(true && f) || !t); TEST_BOOL_EXPR(!!!(t) && (!!f || true)); From 6ebb94b1f4605cbe11a1459782a3bb67eadd1aa7 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 10 Mar 2016 13:48:32 -0800 Subject: [PATCH 19/77] minor API cleanup of SwingLimitFunction API --- libraries/animation/src/SwingTwistConstraint.cpp | 11 ++--------- libraries/animation/src/SwingTwistConstraint.h | 3 --- 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/libraries/animation/src/SwingTwistConstraint.cpp b/libraries/animation/src/SwingTwistConstraint.cpp index 3bf661612e..3a2606c5ce 100644 --- a/libraries/animation/src/SwingTwistConstraint.cpp +++ b/libraries/animation/src/SwingTwistConstraint.cpp @@ -24,15 +24,8 @@ const int LAST_CLAMP_NO_BOUNDARY = 0; const int LAST_CLAMP_HIGH_BOUNDARY = 1; SwingTwistConstraint::SwingLimitFunction::SwingLimitFunction() { - setCone(PI); -} - -void SwingTwistConstraint::SwingLimitFunction::setCone(float maxAngle) { - _minDots.clear(); - float minDot = glm::clamp(maxAngle, MIN_MINDOT, MAX_MINDOT); - _minDots.push_back(minDot); - // push the first value to the back to establish cyclic boundary conditions - _minDots.push_back(minDot); + _minDots.push_back(-1.0f); + _minDots.push_back(-1.0f); } void SwingTwistConstraint::SwingLimitFunction::setMinDots(const std::vector& minDots) { diff --git a/libraries/animation/src/SwingTwistConstraint.h b/libraries/animation/src/SwingTwistConstraint.h index f73bbfb233..620e63e98b 100644 --- a/libraries/animation/src/SwingTwistConstraint.h +++ b/libraries/animation/src/SwingTwistConstraint.h @@ -59,9 +59,6 @@ public: public: SwingLimitFunction(); - /// \brief use a uniform conical swing limit - void setCone(float maxAngle); - /// \brief use a vector of lookup values for swing limits void setMinDots(const std::vector& minDots); From 749dcf2c1de2cd094bcb080a088f00ffb7421a2f Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 11 Mar 2016 10:19:50 -0800 Subject: [PATCH 20/77] dynamic adjustment for swing --- .../animation/src/SwingTwistConstraint.cpp | 167 +++++++++++- .../animation/src/SwingTwistConstraint.h | 26 +- .../animation/src/RotationConstraintTests.cpp | 253 +++++++++++++++++- tests/animation/src/RotationConstraintTests.h | 4 +- 4 files changed, 432 insertions(+), 18 deletions(-) diff --git a/libraries/animation/src/SwingTwistConstraint.cpp b/libraries/animation/src/SwingTwistConstraint.cpp index 3a2606c5ce..dd0a9ce0e8 100644 --- a/libraries/animation/src/SwingTwistConstraint.cpp +++ b/libraries/animation/src/SwingTwistConstraint.cpp @@ -26,23 +26,150 @@ const int LAST_CLAMP_HIGH_BOUNDARY = 1; SwingTwistConstraint::SwingLimitFunction::SwingLimitFunction() { _minDots.push_back(-1.0f); _minDots.push_back(-1.0f); + + _minDotIndexA = -1; + _minDotIndexB = -1; } +// In order to support the dynamic adjustment to swing limits we require +// that minDots have a minimum number of elements: +const int MIN_NUM_DOTS = 8; + void SwingTwistConstraint::SwingLimitFunction::setMinDots(const std::vector& minDots) { - uint32_t numDots = (uint32_t)minDots.size(); + int numDots = (int)minDots.size(); _minDots.clear(); if (numDots == 0) { - // push two copies of MIN_MINDOT - _minDots.push_back(MIN_MINDOT); + // push multiple copies of MIN_MINDOT + for (int i = 0; i < MIN_NUM_DOTS; ++i) { + _minDots.push_back(MIN_MINDOT); + } + // push one more for cyclic boundary conditions _minDots.push_back(MIN_MINDOT); } else { - _minDots.reserve(numDots); - for (uint32_t i = 0; i < numDots; ++i) { - _minDots.push_back(glm::clamp(minDots[i], MIN_MINDOT, MAX_MINDOT)); + // for minimal fidelity in the dynamic adjustment we expand the swing limit data until + // we have enough data points + int trueNumDots = numDots; + int numFiller = 0; + while(trueNumDots < MIN_NUM_DOTS) { + numFiller++; + trueNumDots += numDots; } - // push the first value to the back to establish cyclic boundary conditions + _minDots.reserve(trueNumDots); + + for (int i = 0; i < numDots; ++i) { + // push the next value + _minDots.push_back(glm::clamp(minDots[i], MIN_MINDOT, MAX_MINDOT)); + + if (numFiller > 0) { + // compute endpoints of line segment + float nearDot = glm::clamp(minDots[i], MIN_MINDOT, MAX_MINDOT); + int k = (i + 1) % numDots; + float farDot = glm::clamp(minDots[k], MIN_MINDOT, MAX_MINDOT); + + // fill the gap with interpolated values + for (int j = 0; j < numFiller; ++j) { + float delta = (float)(j + 1) / float(numFiller + 1); + _minDots.push_back((1.0f - delta) * nearDot + delta * farDot); + } + } + } + // push the first value to the back to for cyclic boundary conditions _minDots.push_back(_minDots[0]); } + _minDotIndexA = -1; + _minDotIndexB = -1; +} + +/// \param angle radian angle to update +/// \param minDotAdjustment minimum dot limit at that angle +void SwingTwistConstraint::SwingLimitFunction::dynamicallyAdjustMinDots(float theta, float minDotAdjustment) { + // What does "dynamic adjustment" mean? + // + // Consider a limitFunction that looks like this: + // + // 1+ + // | valid space + // | + // +-----+-----+-----+-----+-----+-----+-----+-----+ + // | + // | invalid space + // 0+------------------------------------------------ + // 0 pi/2 pi 3pi/2 2pi + // theta ---> + // + // If we wanted to modify the envelope to accept a single invalid point X + // then we would need to modify neighboring values A and B accordingly: + // + // 1+ adjustment for X at some thetaX + // | | + // | | + // +-----+. V .+-----+-----+-----+-----+ + // | - - + // | ' A--X--B ' + // 0+------------------------------------------------ + // 0 pi/2 pi 3pi/2 2pi + // + // The code below computes the values of A and B such that the line between them + // passes through the point X, and we get reasonable interpolation for nearby values + // of theta. The old AB values are saved for later restore. + + if (_minDotIndexA > -1) { + // retstore old values + _minDots[_minDotIndexA] = _minDotA; + _minDots[_minDotIndexB] = _minDotB; + + // handle cyclic boundary conditions + int lastIndex = (int)_minDots.size() - 1; + if (_minDotIndexA == 0) { + _minDots[lastIndex] = _minDotA; + } else if (_minDotIndexB == lastIndex) { + _minDots[0] = _minDotB; + } + } + + // extract the positive normalized fractional part of the theta + float integerPart; + float normalizedAngle = modff(theta / TWO_PI, &integerPart); + if (normalizedAngle < 0.0f) { + normalizedAngle += 1.0f; + } + + // interpolate between the two nearest points in the curve + float delta = modff(normalizedAngle * (float)(_minDots.size() - 1), &integerPart); + int indexA = (int)(integerPart); + int indexB = (indexA + 1) % _minDots.size(); + float interpolatedDot = _minDots[indexA] * (1.0f - delta) + _minDots[indexB] * delta; + + if (minDotAdjustment < interpolatedDot) { + // minDotAdjustment is outside the existing bounds so we must modify + + // remember the indices + _minDotIndexA = indexA; + _minDotIndexB = indexB; + + // save the old minDots + _minDotA = _minDots[_minDotIndexA]; + _minDotB = _minDots[_minDotIndexB]; + + // compute replacement values to _minDots that will provide a line segment + // that passes through minDotAdjustment while balancing the distortion between A and B. + // Note: the derivation of these formulae is left as an exercise to the reader. + float twiceUndershoot = 2.0f * (minDotAdjustment - interpolatedDot); + _minDots[_minDotIndexA] -= twiceUndershoot * (delta + 0.5f) * (delta - 1.0f); + _minDots[_minDotIndexB] -= twiceUndershoot * delta * (delta - 1.5f); + + // handle cyclic boundary conditions + int lastIndex = (int)_minDots.size() - 1; + if (_minDotIndexA == 0) { + _minDots[lastIndex] = _minDots[_minDotIndexA]; + } else if (_minDotIndexB == lastIndex) { + _minDots[0] = _minDots[_minDotIndexB]; + } + } else { + // minDotAdjustment is inside bounds so there is nothing to do + _minDotIndexA = -1; + _minDotIndexB = -1; + } } float SwingTwistConstraint::SwingLimitFunction::getMinDot(float theta) const { @@ -83,12 +210,12 @@ void SwingTwistConstraint::setSwingLimits(const std::vector& swungDir }; std::vector limits; - uint32_t numLimits = (uint32_t)swungDirections.size(); + int numLimits = (int)swungDirections.size(); limits.reserve(numLimits); // compute the limit pairs: const glm::vec3 yAxis = glm::vec3(0.0f, 1.0f, 0.0f); - for (uint32_t i = 0; i < numLimits; ++i) { + for (int i = 0; i < numLimits; ++i) { float directionLength = glm::length(swungDirections[i]); if (directionLength > EPSILON) { glm::vec3 swingAxis = glm::cross(yAxis, swungDirections[i]); @@ -101,7 +228,7 @@ void SwingTwistConstraint::setSwingLimits(const std::vector& swungDir } std::vector minDots; - numLimits = (uint32_t)limits.size(); + numLimits = (int)limits.size(); if (numLimits == 0) { // trivial case: nearly free constraint std::vector minDots; @@ -119,10 +246,10 @@ void SwingTwistConstraint::setSwingLimits(const std::vector& swungDir // extrapolate evenly distributed limits for fast lookup table float deltaTheta = TWO_PI / (float)(numLimits); - uint32_t rightIndex = 0; - for (uint32_t i = 0; i < numLimits; ++i) { + int rightIndex = 0; + for (int i = 0; i < numLimits; ++i) { float theta = (float)i * deltaTheta; - uint32_t leftIndex = (rightIndex - 1) % numLimits; + int leftIndex = (rightIndex - 1) % numLimits; while (rightIndex < numLimits && theta > limits[rightIndex]._theta) { leftIndex = rightIndex++; } @@ -245,6 +372,20 @@ bool SwingTwistConstraint::apply(glm::quat& rotation) const { return false; } +void SwingTwistConstraint::dynamicallyAdjustLimits(const glm::quat& rotation) { + glm::quat postRotation = rotation * glm::inverse(_referenceRotation); + glm::quat swingRotation, twistRotation; + + const glm::vec3 yAxis(0.0f, 1.0f, 0.0f); + swingTwistDecomposition(postRotation, yAxis, swingRotation, twistRotation); + + // we currently only handle swing limits + glm::vec3 swungY = swingRotation * yAxis; + glm::vec3 swingAxis = glm::cross(yAxis, swungY); + float theta = atan2f(-swingAxis.z, swingAxis.x); + _swingLimitFunction.dynamicallyAdjustMinDots(theta, swungY.y); +} + void SwingTwistConstraint::clearHistory() { _lastTwistBoundary = LAST_CLAMP_NO_BOUNDARY; } diff --git a/libraries/animation/src/SwingTwistConstraint.h b/libraries/animation/src/SwingTwistConstraint.h index 620e63e98b..df9da8cabe 100644 --- a/libraries/animation/src/SwingTwistConstraint.h +++ b/libraries/animation/src/SwingTwistConstraint.h @@ -53,8 +53,18 @@ public: void setLowerSpine(bool lowerSpine) { _lowerSpine = lowerSpine; } virtual bool isLowerSpine() const override { return _lowerSpine; } + /// \param rotation rotation to allow + /// \brief clear previous adjustment and adjust constraint limits to allow rotation + void dynamicallyAdjustLimits(const glm::quat& rotation); + + // for testing purposes + const std::vector& getMinDots() { return _swingLimitFunction.getMinDots(); } + // SwingLimitFunction is an implementation of the constraint check described in the paper: // "The Parameterization of Joint Rotation with the Unit Quaternion" by Quang Liu and Edmond C. Prakash + // + // The "dynamic adjustment" feature allows us to change the limits on the fly for one particular theta angle. + // class SwingLimitFunction { public: SwingLimitFunction(); @@ -62,12 +72,26 @@ public: /// \brief use a vector of lookup values for swing limits void setMinDots(const std::vector& minDots); + /// \param theta radian angle to new minDot + /// \param minDot minimum dot limit + /// \brief updates swing constraint to permit minDot at theta + void dynamicallyAdjustMinDots(float theta, float minDot); + /// \return minimum dotProduct between reference and swung axes float getMinDot(float theta) const; - protected: + // for testing purposes + const std::vector& getMinDots() { return _minDots; } + + private: // the limits are stored in a lookup table with cyclic boundary conditions std::vector _minDots; + + // these values used to restore dynamic adjustment + float _minDotA; + float _minDotB; + int8_t _minDotIndexA; + int8_t _minDotIndexB; }; /// \return reference to SwingLimitFunction instance for unit-testing diff --git a/tests/animation/src/RotationConstraintTests.cpp b/tests/animation/src/RotationConstraintTests.cpp index 7aacf26826..b0351721ae 100644 --- a/tests/animation/src/RotationConstraintTests.cpp +++ b/tests/animation/src/RotationConstraintTests.cpp @@ -56,7 +56,7 @@ void RotationConstraintTests::testElbowConstraint() { float startAngle = minAngle + smallAngle; float endAngle = maxAngle - smallAngle; float deltaAngle = (endAngle - startAngle) / (float)(numChecks - 1); - + for (float angle = startAngle; angle < endAngle + 0.5f * deltaAngle; angle += deltaAngle) { glm::quat inputRotation = glm::angleAxis(angle, hingeAxis) * referenceRotation; glm::quat outputRotation = inputRotation; @@ -115,9 +115,9 @@ void RotationConstraintTests::testSwingTwistConstraint() { shoulder.setTwistLimits(minTwistAngle, maxTwistAngle); float lowDot = 0.25f; float highDot = 0.75f; - // The swing constriants are more interesting: a vector of minimum dot products + // The swing constriants are more interesting: a vector of minimum dot products // as a function of theta around the twist axis. Our test function will be shaped - // like the square wave with amplitudes 0.25 and 0.75: + // like a square wave with amplitudes 0.25 and 0.75: // // | // 0.75 - o---o---o---o @@ -308,3 +308,250 @@ void RotationConstraintTests::testSwingTwistConstraint() { } } +void RotationConstraintTests::testDynamicSwingLimitFunction() { + SwingTwistConstraint::SwingLimitFunction limitFunction; + const float ACCEPTABLE_ERROR = 1.0e-6f; + + const float adjustmentDot = -0.5f; + + const float MIN_DOT = 0.5f; + { // initialize limitFunction + std::vector minDots; + minDots.push_back(MIN_DOT); + limitFunction.setMinDots(minDots); + } + + std::vector referenceDots; + { // verify limits and initialize referenceDots + const int MIN_NUM_DOTS = 8; + const std::vector& minDots = limitFunction.getMinDots(); + QVERIFY(minDots.size() >= MIN_NUM_DOTS); + + int numDots = (int)minDots.size(); + for (int i = 0; i < numDots; ++i) { + QCOMPARE_WITH_RELATIVE_ERROR(minDots[i], MIN_DOT, ACCEPTABLE_ERROR); + referenceDots.push_back(minDots[i]); + } + } + { // dynamically adjust limits + const std::vector& minDots = limitFunction.getMinDots(); + int numDots = (int)minDots.size(); + + float deltaTheta = TWO_PI / (float)(numDots - 1); + int indexA = 2; + int indexB = (indexA + 1) % numDots; + + { // dynamically adjust a data point + float theta = deltaTheta * (float)indexA; + float interpolatedDot = limitFunction.getMinDot(theta); + + // change indexA + limitFunction.dynamicallyAdjustMinDots(theta, adjustmentDot); + QCOMPARE_WITH_ABS_ERROR(limitFunction.getMinDot(theta), adjustmentDot, ACCEPTABLE_ERROR); // adjustmentDot at theta + QCOMPARE_WITH_ABS_ERROR(minDots[indexA], adjustmentDot, ACCEPTABLE_ERROR); // indexA has changed + QCOMPARE_WITH_ABS_ERROR(minDots[indexB], referenceDots[indexB], ACCEPTABLE_ERROR); // indexB has not changed + + // change indexB + theta = deltaTheta * (float)indexB; + limitFunction.dynamicallyAdjustMinDots(theta, adjustmentDot); + QCOMPARE_WITH_ABS_ERROR(limitFunction.getMinDot(theta), adjustmentDot, ACCEPTABLE_ERROR); // adjustmentDot at theta + QCOMPARE_WITH_ABS_ERROR(minDots[indexA], referenceDots[indexA], ACCEPTABLE_ERROR); // indexA has been restored + QCOMPARE_WITH_ABS_ERROR(minDots[indexB], adjustmentDot, ACCEPTABLE_ERROR); // indexB has changed + + // restore + limitFunction.dynamicallyAdjustMinDots(theta, referenceDots[indexB] + 0.01f); // restore with a larger dot + QCOMPARE_WITH_ABS_ERROR(limitFunction.getMinDot(theta), interpolatedDot, ACCEPTABLE_ERROR); // restored + QCOMPARE_WITH_ABS_ERROR(minDots[indexA], referenceDots[indexA], ACCEPTABLE_ERROR); // indexA is restored + QCOMPARE_WITH_ABS_ERROR(minDots[indexB], referenceDots[indexB], ACCEPTABLE_ERROR); // indexB is restored + } + { // dynamically adjust halfway between data points + float theta = deltaTheta * 0.5f * (float)(indexA + indexB); // halfway between two points + float interpolatedDot = limitFunction.getMinDot(theta); + float deltaDot = adjustmentDot - interpolatedDot; + limitFunction.dynamicallyAdjustMinDots(theta, adjustmentDot); + QCOMPARE_WITH_ABS_ERROR(limitFunction.getMinDot(theta), adjustmentDot, ACCEPTABLE_ERROR); // adjustmentDot at theta + QCOMPARE_WITH_ABS_ERROR(minDots[indexA], referenceDots[indexA] + deltaDot, ACCEPTABLE_ERROR); // indexA has changed + QCOMPARE_WITH_ABS_ERROR(minDots[indexB], referenceDots[indexB] + deltaDot, ACCEPTABLE_ERROR); // indexB has changed + + limitFunction.dynamicallyAdjustMinDots(theta, interpolatedDot + 0.01f); // reset with something larger + QCOMPARE_WITH_ABS_ERROR(limitFunction.getMinDot(theta), interpolatedDot, ACCEPTABLE_ERROR); // restored + QCOMPARE_WITH_ABS_ERROR(minDots[indexA], referenceDots[indexA], ACCEPTABLE_ERROR); // indexA is restored + QCOMPARE_WITH_ABS_ERROR(minDots[indexB], referenceDots[indexB], ACCEPTABLE_ERROR); // indexB is restored + } + { // dynamically adjust one-quarter between data points + float theta = deltaTheta * ((float)indexA + 0.25f); // one quarter past A towards B + float interpolatedDot = limitFunction.getMinDot(theta); + limitFunction.dynamicallyAdjustMinDots(theta, adjustmentDot); + QCOMPARE_WITH_ABS_ERROR(limitFunction.getMinDot(theta), adjustmentDot, ACCEPTABLE_ERROR); // adjustmentDot at theta + QVERIFY(minDots[indexA] < adjustmentDot); // indexA should be less than minDot + QVERIFY(minDots[indexB] > adjustmentDot); // indexB should be larger than minDot + QVERIFY(minDots[indexB] < referenceDots[indexB]); // indexB should be less than what it was + + limitFunction.dynamicallyAdjustMinDots(theta, interpolatedDot + 0.01f); // reset with something larger + QCOMPARE_WITH_ABS_ERROR(limitFunction.getMinDot(theta), interpolatedDot, ACCEPTABLE_ERROR); // restored + QCOMPARE_WITH_ABS_ERROR(minDots[indexA], referenceDots[indexA], ACCEPTABLE_ERROR); // indexA is restored + QCOMPARE_WITH_ABS_ERROR(minDots[indexB], referenceDots[indexB], ACCEPTABLE_ERROR); // indexB is restored + } + { // halfway between first two data points (boundary condition) + indexA = 0; + indexB = 1; + int indexZ = minDots.size() - 1; // far boundary condition + float theta = deltaTheta * 0.5f * (float)(indexA + indexB); // halfway between two points + float interpolatedDot = limitFunction.getMinDot(theta); + float deltaDot = adjustmentDot - interpolatedDot; + limitFunction.dynamicallyAdjustMinDots(theta, adjustmentDot); + QCOMPARE_WITH_ABS_ERROR(limitFunction.getMinDot(theta), adjustmentDot, ACCEPTABLE_ERROR); // adjustmentDot at theta + QCOMPARE_WITH_ABS_ERROR(minDots[indexA], referenceDots[indexA] + deltaDot, ACCEPTABLE_ERROR); // indexA has changed + QCOMPARE_WITH_ABS_ERROR(minDots[indexB], referenceDots[indexB] + deltaDot, ACCEPTABLE_ERROR); // indexB has changed + QCOMPARE_WITH_ABS_ERROR(minDots[indexZ], referenceDots[indexZ] + deltaDot, ACCEPTABLE_ERROR); // indexZ has changed + + limitFunction.dynamicallyAdjustMinDots(theta, interpolatedDot + 0.01f); // reset with something larger + QCOMPARE_WITH_ABS_ERROR(limitFunction.getMinDot(theta), interpolatedDot, ACCEPTABLE_ERROR); // restored + QCOMPARE_WITH_ABS_ERROR(minDots[indexA], referenceDots[indexA], ACCEPTABLE_ERROR); // indexA is restored + QCOMPARE_WITH_ABS_ERROR(minDots[indexB], referenceDots[indexB], ACCEPTABLE_ERROR); // indexB is restored + QCOMPARE_WITH_ABS_ERROR(minDots[indexZ], referenceDots[indexZ], ACCEPTABLE_ERROR); // indexZ is restored + } + { // halfway between first two data points (boundary condition) + indexB = minDots.size() - 1; + indexA = indexB - 1; + int indexZ = 0; // far boundary condition + float theta = deltaTheta * 0.5f * (float)(indexA + indexB); // halfway between two points + float interpolatedDot = limitFunction.getMinDot(theta); + float deltaDot = adjustmentDot - interpolatedDot; + limitFunction.dynamicallyAdjustMinDots(theta, adjustmentDot); + QCOMPARE_WITH_ABS_ERROR(limitFunction.getMinDot(theta), adjustmentDot, ACCEPTABLE_ERROR); // adjustmentDot at theta + QCOMPARE_WITH_ABS_ERROR(minDots[indexA], referenceDots[indexA] + deltaDot, ACCEPTABLE_ERROR); // indexA has changed + QCOMPARE_WITH_ABS_ERROR(minDots[indexB], referenceDots[indexB] + deltaDot, ACCEPTABLE_ERROR); // indexB has changed + QCOMPARE_WITH_ABS_ERROR(minDots[indexZ], referenceDots[indexZ] + deltaDot, ACCEPTABLE_ERROR); // indexZ has changed + + limitFunction.dynamicallyAdjustMinDots(theta, interpolatedDot + 0.01f); // reset with something larger + QCOMPARE_WITH_ABS_ERROR(limitFunction.getMinDot(theta), interpolatedDot, ACCEPTABLE_ERROR); // restored + QCOMPARE_WITH_ABS_ERROR(minDots[indexA], referenceDots[indexA], ACCEPTABLE_ERROR); // indexA is restored + QCOMPARE_WITH_ABS_ERROR(minDots[indexB], referenceDots[indexB], ACCEPTABLE_ERROR); // indexB is restored + QCOMPARE_WITH_ABS_ERROR(minDots[indexZ], referenceDots[indexZ], ACCEPTABLE_ERROR); // indexZ is restored + } + } +} + +void RotationConstraintTests::testDynamicSwingTwistConstraint() { + + const float ACCEPTABLE_ERROR = 1.0e-6f; + + // referenceRotation is the default rotation + float referenceAngle = 1.23f; + glm::vec3 referenceAxis = glm::normalize(glm::vec3(1.0f, 2.0f, -3.0f)); + glm::quat referenceRotation = glm::angleAxis(referenceAngle, referenceAxis); + + // the angle limits of the constriant about the hinge axis + float minTwistAngle = -PI / 2.0f; + float maxTwistAngle = PI / 2.0f; + + // build the constraint + SwingTwistConstraint shoulder; + shoulder.setReferenceRotation(referenceRotation); + shoulder.setTwistLimits(minTwistAngle, maxTwistAngle); + std::vector minDots; + const float MIN_DOT = 0.5f; + minDots.push_back(MIN_DOT); + shoulder.setSwingLimits(minDots); + + // verify resolution of the swing limits + const std::vector& shoulderMinDots = shoulder.getMinDots(); + const int MIN_NUM_DOTS = 8; + int numDots = shoulderMinDots.size(); + QVERIFY(numDots >= MIN_NUM_DOTS); + + // verify values of the swing limits + QCOMPARE_WITH_ABS_ERROR(shoulderMinDots[0], shoulderMinDots[numDots - 1], ACCEPTABLE_ERROR); // endpoints should be the same + for (int i = 0; i < numDots; ++i) { + QCOMPARE_WITH_ABS_ERROR(shoulderMinDots[i], MIN_DOT, ACCEPTABLE_ERROR); // all values should be the same + } + + float deltaTheta = TWO_PI / (float)(numDots - 1); + float theta = 1.5f * deltaTheta; + glm::vec3 swingAxis(cosf(theta), 0.0f, sinf(theta)); + float deltaSwing = 0.1f; + + { // compute rotation that should NOT be constrained + float swingAngle = acosf(MIN_DOT) - deltaSwing; + glm::quat swingRotation = glm::angleAxis(swingAngle, swingAxis); + glm::quat totalRotation = swingRotation * referenceRotation; + + // verify rotation is NOT constrained + glm::quat constrainedRotation = totalRotation; + QVERIFY(!shoulder.apply(constrainedRotation)); + } + + { // compute a rotation that should be barely constrained + float swingAngle = acosf(MIN_DOT) + deltaSwing; + glm::quat swingRotation = glm::angleAxis(swingAngle, swingAxis); + glm::quat totalRotation = swingRotation * referenceRotation; + + // verify rotation is constrained + glm::quat constrainedRotation = totalRotation; + QVERIFY(shoulder.apply(constrainedRotation)); // should FAIL + } + + { // make a dynamic adjustment to the swing limits + const float SMALLER_MIN_DOT = -0.5f; + float swingAngle = acosf(SMALLER_MIN_DOT); + glm::quat swingRotation = glm::angleAxis(swingAngle, swingAxis); + glm::quat badRotation = swingRotation * referenceRotation; + + { // verify rotation is constrained + glm::quat constrainedRotation = badRotation; + QVERIFY(shoulder.apply(constrainedRotation)); + + // now poke the SMALLER_MIN_DOT into the swing limits + shoulder.dynamicallyAdjustLimits(badRotation); + + // verify that if rotation is constrained then it is only by a little bit + constrainedRotation = badRotation; + bool constrained = shoulder.apply(constrainedRotation); + if (constrained) { + // Note: Q1 = dQ * Q0 --> dQ = Q1 * Q0^ + glm::quat dQ = constrainedRotation * glm::inverse(badRotation); + const float acceptableClampAngle = 0.01f; + float deltaAngle = glm::angle(dQ); + QVERIFY(deltaAngle < acceptableClampAngle); + } + } + + { // verify that other swing axes still use the old non-adjusted limits + float deltaTheta = TWO_PI / (float)(numDots - 1); + float otherTheta = 3.5f * deltaTheta; + glm::vec3 otherSwingAxis(cosf(otherTheta), 0.0f, sinf(otherTheta)); + + { // inside rotations should be unconstrained + float goodAngle = acosf(MIN_DOT) - deltaSwing; + glm::quat goodRotation = glm::angleAxis(goodAngle, otherSwingAxis) * referenceRotation; + QVERIFY(!shoulder.apply(goodRotation)); + } + { // outside rotations should be constrained + float badAngle = acosf(MIN_DOT) + deltaSwing; + glm::quat otherBadRotation = glm::angleAxis(badAngle, otherSwingAxis) * referenceRotation; + QVERIFY(shoulder.apply(otherBadRotation)); + + float constrainedAngle = glm::angle(otherBadRotation); + QCOMPARE_WITH_ABS_ERROR(constrainedAngle, acosf(MIN_DOT), 0.1f * deltaSwing); + } + } + + { // clear dynamic adjustment + float goodAngle = acosf(MIN_DOT) - deltaSwing; + glm::quat goodRotation = glm::angleAxis(goodAngle, swingAxis) * referenceRotation; + + // when we update with a goodRotation the dynamic adjustment is cleared + shoulder.dynamicallyAdjustLimits(goodRotation); + + // verify that the old badRotation, which was not constrained dynamically, is now constrained + glm::quat constrainedRotation = badRotation; + QVERIFY(shoulder.apply(constrainedRotation)); + + // and the good rotation should not be constrained + constrainedRotation = goodRotation; + QVERIFY(!shoulder.apply(constrainedRotation)); + } + } +} + diff --git a/tests/animation/src/RotationConstraintTests.h b/tests/animation/src/RotationConstraintTests.h index 4fed3588e4..7c6d80d3eb 100644 --- a/tests/animation/src/RotationConstraintTests.h +++ b/tests/animation/src/RotationConstraintTests.h @@ -15,10 +15,12 @@ class RotationConstraintTests : public QObject { Q_OBJECT - + private slots: void testElbowConstraint(); void testSwingTwistConstraint(); + void testDynamicSwingLimitFunction(); + void testDynamicSwingTwistConstraint(); }; #endif // hifi_RotationConstraintTests_h From 4b7514479759fff0a09f027d927d3f6b070a06e5 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 11 Mar 2016 10:20:40 -0800 Subject: [PATCH 21/77] remove debug cruft --- libraries/animation/src/AnimInverseKinematics.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/libraries/animation/src/AnimInverseKinematics.cpp b/libraries/animation/src/AnimInverseKinematics.cpp index 4a6c3d819c..46e17c39d8 100644 --- a/libraries/animation/src/AnimInverseKinematics.cpp +++ b/libraries/animation/src/AnimInverseKinematics.cpp @@ -22,13 +22,9 @@ AnimInverseKinematics::AnimInverseKinematics(const QString& id) : AnimNode(AnimN } AnimInverseKinematics::~AnimInverseKinematics() { - std::cout << "adebug dtor" << std::endl; // adebug clearConstraints(); - std::cout << "adebug dtor 002" << std::endl; // adebug _accumulators.clear(); - std::cout << "adebug dtor 003 targetVarVec.size() = " << _targetVarVec.size() << std::endl; // adebug _targetVarVec.clear(); - std::cout << "adebug dtor 004 targetVarVec.size() = " << _targetVarVec.size() << std::endl; // adebug } void AnimInverseKinematics::loadDefaultPoses(const AnimPoseVec& poses) { @@ -491,7 +487,6 @@ RotationConstraint* AnimInverseKinematics::getConstraint(int index) { } void AnimInverseKinematics::clearConstraints() { - std::cout << "adebug clearConstraints size = " << _constraints.size() << std::endl; // adebug std::map::iterator constraintItr = _constraints.begin(); while (constraintItr != _constraints.end()) { delete constraintItr->second; From c9f988d34048de746cae6db4fc15611709ad5d72 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 11 Mar 2016 11:06:58 -0800 Subject: [PATCH 22/77] dynamic adjustment for twist --- .../animation/src/SwingTwistConstraint.cpp | 120 +++++++++++------- .../animation/src/SwingTwistConstraint.h | 7 + 2 files changed, 83 insertions(+), 44 deletions(-) diff --git a/libraries/animation/src/SwingTwistConstraint.cpp b/libraries/animation/src/SwingTwistConstraint.cpp index dd0a9ce0e8..72659ff09d 100644 --- a/libraries/animation/src/SwingTwistConstraint.cpp +++ b/libraries/animation/src/SwingTwistConstraint.cpp @@ -13,6 +13,7 @@ #include #include +#include #include @@ -31,7 +32,7 @@ SwingTwistConstraint::SwingLimitFunction::SwingLimitFunction() { _minDotIndexB = -1; } -// In order to support the dynamic adjustment to swing limits we require +// In order to support the dynamic adjustment to swing limits we require // that minDots have a minimum number of elements: const int MIN_NUM_DOTS = 8; @@ -214,11 +215,10 @@ void SwingTwistConstraint::setSwingLimits(const std::vector& swungDir limits.reserve(numLimits); // compute the limit pairs: - const glm::vec3 yAxis = glm::vec3(0.0f, 1.0f, 0.0f); for (int i = 0; i < numLimits; ++i) { float directionLength = glm::length(swungDirections[i]); if (directionLength > EPSILON) { - glm::vec3 swingAxis = glm::cross(yAxis, swungDirections[i]); + glm::vec3 swingAxis = glm::cross(Vectors::UNIT_Y, swungDirections[i]); float theta = atan2f(-swingAxis.z, swingAxis.x); if (theta < 0.0f) { theta += TWO_PI; @@ -285,51 +285,57 @@ void SwingTwistConstraint::setTwistLimits(float minTwist, float maxTwist) { _maxTwist = glm::max(minTwist, maxTwist); _lastTwistBoundary = LAST_CLAMP_NO_BOUNDARY; + _twistAdjusted = false; +} + +// private +float SwingTwistConstraint::handleTwistBoundaryConditions(float twistAngle) const { + // adjust measured twistAngle according to clamping history + switch (_lastTwistBoundary) { + case LAST_CLAMP_LOW_BOUNDARY: + // clamp to min + if (twistAngle > _maxTwist) { + twistAngle -= TWO_PI; + } + break; + case LAST_CLAMP_HIGH_BOUNDARY: + // clamp to max + if (twistAngle < _minTwist) { + twistAngle += TWO_PI; + } + break; + default: // LAST_CLAMP_NO_BOUNDARY + // clamp to nearest boundary + float midBoundary = 0.5f * (_maxTwist + _minTwist + TWO_PI); + if (twistAngle > midBoundary) { + // lower boundary is closer --> phase down one cycle + twistAngle -= TWO_PI; + } else if (twistAngle < midBoundary - TWO_PI) { + // higher boundary is closer --> phase up one cycle + twistAngle += TWO_PI; + } + break; + } + return twistAngle; } bool SwingTwistConstraint::apply(glm::quat& rotation) const { // decompose the rotation into first twist about yAxis, then swing about something perp - const glm::vec3 yAxis(0.0f, 1.0f, 0.0f); // NOTE: rotation = postRotation * referenceRotation glm::quat postRotation = rotation * glm::inverse(_referenceRotation); glm::quat swingRotation, twistRotation; - swingTwistDecomposition(postRotation, yAxis, swingRotation, twistRotation); + swingTwistDecomposition(postRotation, Vectors::UNIT_Y, swingRotation, twistRotation); // NOTE: postRotation = swingRotation * twistRotation - // compute twistAngle + // compute raw twistAngle float twistAngle = 2.0f * acosf(fabsf(twistRotation.w)); - const glm::vec3 xAxis = glm::vec3(1.0f, 0.0f, 0.0f); - glm::vec3 twistedX = twistRotation * xAxis; - twistAngle *= copysignf(1.0f, glm::dot(glm::cross(xAxis, twistedX), yAxis)); + glm::vec3 twistedX = twistRotation * Vectors::UNIT_X; + twistAngle *= copysignf(1.0f, glm::dot(glm::cross(Vectors::UNIT_X, twistedX), Vectors::UNIT_Y)); bool somethingClamped = false; if (_minTwist != _maxTwist) { - // adjust measured twistAngle according to clamping history - switch (_lastTwistBoundary) { - case LAST_CLAMP_LOW_BOUNDARY: - // clamp to min - if (twistAngle > _maxTwist) { - twistAngle -= TWO_PI; - } - break; - case LAST_CLAMP_HIGH_BOUNDARY: - // clamp to max - if (twistAngle < _minTwist) { - twistAngle += TWO_PI; - } - break; - default: // LAST_CLAMP_NO_BOUNDARY - // clamp to nearest boundary - float midBoundary = 0.5f * (_maxTwist + _minTwist + TWO_PI); - if (twistAngle > midBoundary) { - // lower boundary is closer --> phase down one cycle - twistAngle -= TWO_PI; - } else if (twistAngle < midBoundary - TWO_PI) { - // higher boundary is closer --> phase up one cycle - twistAngle += TWO_PI; - } - break; - } + // twist limits apply --> figure out which limit we're hitting, if any + twistAngle = handleTwistBoundaryConditions(twistAngle); // clamp twistAngle float clampedTwistAngle = glm::clamp(twistAngle, _minTwist, _maxTwist); @@ -346,15 +352,15 @@ bool SwingTwistConstraint::apply(glm::quat& rotation) const { // clamp the swing // The swingAxis is always perpendicular to the reference axis (yAxis in the constraint's frame). - glm::vec3 swungY = swingRotation * yAxis; - glm::vec3 swingAxis = glm::cross(yAxis, swungY); + glm::vec3 swungY = swingRotation * Vectors::UNIT_Y; + glm::vec3 swingAxis = glm::cross(Vectors::UNIT_Y, swungY); float axisLength = glm::length(swingAxis); if (axisLength > EPSILON) { // The limit of swing is a function of "theta" which can be computed from the swingAxis // (which is in the constraint's ZX plane). float theta = atan2f(-swingAxis.z, swingAxis.x); float minDot = _swingLimitFunction.getMinDot(theta); - if (glm::dot(swungY, yAxis) < minDot) { + if (glm::dot(swungY, Vectors::UNIT_Y) < minDot) { // The swing limits are violated so we extract the angle from midDot and // use it to supply a new rotation. swingAxis /= axisLength; @@ -365,7 +371,7 @@ bool SwingTwistConstraint::apply(glm::quat& rotation) const { if (somethingClamped) { // update the rotation - twistRotation = glm::angleAxis(twistAngle, yAxis); + twistRotation = glm::angleAxis(twistAngle, Vectors::UNIT_Y); rotation = swingRotation * twistRotation * _referenceRotation; return true; } @@ -376,14 +382,40 @@ void SwingTwistConstraint::dynamicallyAdjustLimits(const glm::quat& rotation) { glm::quat postRotation = rotation * glm::inverse(_referenceRotation); glm::quat swingRotation, twistRotation; - const glm::vec3 yAxis(0.0f, 1.0f, 0.0f); - swingTwistDecomposition(postRotation, yAxis, swingRotation, twistRotation); + swingTwistDecomposition(postRotation, Vectors::UNIT_Y, swingRotation, twistRotation); - // we currently only handle swing limits - glm::vec3 swungY = swingRotation * yAxis; - glm::vec3 swingAxis = glm::cross(yAxis, swungY); + // adjust swing limits + glm::vec3 swungY = swingRotation * Vectors::UNIT_Y; + glm::vec3 swingAxis = glm::cross(Vectors::UNIT_Y, swungY); float theta = atan2f(-swingAxis.z, swingAxis.x); _swingLimitFunction.dynamicallyAdjustMinDots(theta, swungY.y); + + // restore twist limits + if (_twistAdjusted) { + _minTwist = _oldMinTwist; + _maxTwist = _oldMaxTwist; + _twistAdjusted = false; + } + + if (_minTwist != _maxTwist) { + // compute twistAngle + float twistAngle = 2.0f * acosf(fabsf(twistRotation.w)); + glm::vec3 twistedX = twistRotation * Vectors::UNIT_X; + twistAngle *= copysignf(1.0f, glm::dot(glm::cross(Vectors::UNIT_X, twistedX), Vectors::UNIT_Y)); + twistAngle = handleTwistBoundaryConditions(twistAngle); + + if (twistAngle < _minTwist || twistAngle > _maxTwist) { + // expand twist limits + _twistAdjusted = true; + _oldMinTwist = _minTwist; + _oldMaxTwist = _maxTwist; + if (twistAngle < _minTwist) { + _minTwist = twistAngle; + } else if (twistAngle > _maxTwist) { + _maxTwist = twistAngle; + } + } + } } void SwingTwistConstraint::clearHistory() { diff --git a/libraries/animation/src/SwingTwistConstraint.h b/libraries/animation/src/SwingTwistConstraint.h index df9da8cabe..4734aa8b9d 100644 --- a/libraries/animation/src/SwingTwistConstraint.h +++ b/libraries/animation/src/SwingTwistConstraint.h @@ -100,15 +100,22 @@ public: /// \brief exposed for unit testing void clearHistory(); +private: + float handleTwistBoundaryConditions(float twistAngle) const; + protected: SwingLimitFunction _swingLimitFunction; float _minTwist; float _maxTwist; + float _oldMinTwist; + float _oldMaxTwist; + // We want to remember the LAST clamped boundary, so we an use it even when the far boundary is closer. // This reduces "pops" when the input twist angle goes far beyond and wraps around toward the far boundary. mutable int _lastTwistBoundary; bool _lowerSpine { false }; + bool _twistAdjusted { false }; }; #endif // hifi_SwingTwistConstraint_h From 71a81331d19a80e37c3dfb774ba5a9b7db858ff2 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 11 Mar 2016 13:20:03 -0800 Subject: [PATCH 23/77] unit tests for dynamic twist limit adjustment --- .../animation/src/RotationConstraintTests.cpp | 101 +++++++++++++++++- tests/animation/src/RotationConstraintTests.h | 3 +- 2 files changed, 100 insertions(+), 4 deletions(-) diff --git a/tests/animation/src/RotationConstraintTests.cpp b/tests/animation/src/RotationConstraintTests.cpp index b0351721ae..f828201a81 100644 --- a/tests/animation/src/RotationConstraintTests.cpp +++ b/tests/animation/src/RotationConstraintTests.cpp @@ -13,6 +13,7 @@ #include #include +#include #include #include @@ -433,8 +434,7 @@ void RotationConstraintTests::testDynamicSwingLimitFunction() { } } -void RotationConstraintTests::testDynamicSwingTwistConstraint() { - +void RotationConstraintTests::testDynamicSwing() { const float ACCEPTABLE_ERROR = 1.0e-6f; // referenceRotation is the default rotation @@ -489,7 +489,7 @@ void RotationConstraintTests::testDynamicSwingTwistConstraint() { // verify rotation is constrained glm::quat constrainedRotation = totalRotation; - QVERIFY(shoulder.apply(constrainedRotation)); // should FAIL + QVERIFY(shoulder.apply(constrainedRotation)); } { // make a dynamic adjustment to the swing limits @@ -555,3 +555,98 @@ void RotationConstraintTests::testDynamicSwingTwistConstraint() { } } +void RotationConstraintTests::testDynamicTwist() { + // referenceRotation is the default rotation + float referenceAngle = 1.23f; + glm::vec3 referenceAxis = glm::normalize(glm::vec3(1.0f, 2.0f, -3.0f)); + glm::quat referenceRotation = glm::angleAxis(referenceAngle, referenceAxis); + + // the angle limits of the constriant about the hinge axis + const float minTwistAngle = -PI / 2.0f; + const float maxTwistAngle = PI / 2.0f; + + // build the constraint + SwingTwistConstraint shoulder; + shoulder.setReferenceRotation(referenceRotation); + shoulder.setTwistLimits(minTwistAngle, maxTwistAngle); + + glm::vec3 twistAxis = Vectors::UNIT_Y; + float deltaTwist = 0.1f; + + { // compute min rotation that should NOT be constrained + float twistAngle = minTwistAngle + deltaTwist; + glm::quat twistRotation = glm::angleAxis(twistAngle, twistAxis); + glm::quat totalRotation = twistRotation * referenceRotation; + + // verify rotation is NOT constrained + glm::quat constrainedRotation = totalRotation; + QVERIFY(!shoulder.apply(constrainedRotation)); + } + { // compute max rotation that should NOT be constrained + float twistAngle = maxTwistAngle - deltaTwist; + glm::quat twistRotation = glm::angleAxis(twistAngle, twistAxis); + glm::quat totalRotation = twistRotation * referenceRotation; + + // verify rotation is NOT constrained + glm::quat constrainedRotation = totalRotation; + QVERIFY(!shoulder.apply(constrainedRotation)); + } + { // compute a min rotation that should be barely constrained + float twistAngle = minTwistAngle - deltaTwist; + glm::quat twistRotation = glm::angleAxis(twistAngle, twistAxis); + glm::quat totalRotation = twistRotation * referenceRotation; + + // verify rotation is constrained + glm::quat constrainedRotation = totalRotation; + QVERIFY(shoulder.apply(constrainedRotation)); + + // adjust the constraint and verify rotation is NOT constrained + shoulder.dynamicallyAdjustLimits(totalRotation); + constrainedRotation = totalRotation; + bool constrained = shoulder.apply(constrainedRotation); + if (constrained) { + // or, if it is constrained then the adjustment is very small + // Note: Q1 = dQ * Q0 --> dQ = Q1 * Q0^ + glm::quat dQ = constrainedRotation * glm::inverse(totalRotation); + const float acceptableClampAngle = 0.01f; + float deltaAngle = glm::angle(dQ); + QVERIFY(deltaAngle < acceptableClampAngle); + } + + // clear the adjustment using a null rotation + shoulder.dynamicallyAdjustLimits(glm::quat()); + + // verify that rotation is constrained again + constrainedRotation = totalRotation; + QVERIFY(shoulder.apply(constrainedRotation)); + } + { // compute a min rotation that should be barely constrained + float twistAngle = maxTwistAngle + deltaTwist; + glm::quat twistRotation = glm::angleAxis(twistAngle, twistAxis); + glm::quat totalRotation = twistRotation * referenceRotation; + + // verify rotation is constrained + glm::quat constrainedRotation = totalRotation; + QVERIFY(shoulder.apply(constrainedRotation)); + + // adjust the constraint and verify rotation is NOT constrained + shoulder.dynamicallyAdjustLimits(totalRotation); + constrainedRotation = totalRotation; + bool constrained = shoulder.apply(constrainedRotation); + if (constrained) { + // or, if it is constrained then the adjustment is very small + // Note: Q1 = dQ * Q0 --> dQ = Q1 * Q0^ + glm::quat dQ = constrainedRotation * glm::inverse(totalRotation); + const float acceptableClampAngle = 0.01f; + float deltaAngle = glm::angle(dQ); + QVERIFY(deltaAngle < acceptableClampAngle); + } + + // clear the adjustment using a null rotation + shoulder.dynamicallyAdjustLimits(glm::quat()); + + // verify that rotation is constrained again + constrainedRotation = totalRotation; + QVERIFY(shoulder.apply(constrainedRotation)); + } +} diff --git a/tests/animation/src/RotationConstraintTests.h b/tests/animation/src/RotationConstraintTests.h index 7c6d80d3eb..e63d08bc1f 100644 --- a/tests/animation/src/RotationConstraintTests.h +++ b/tests/animation/src/RotationConstraintTests.h @@ -20,7 +20,8 @@ private slots: void testElbowConstraint(); void testSwingTwistConstraint(); void testDynamicSwingLimitFunction(); - void testDynamicSwingTwistConstraint(); + void testDynamicSwing(); + void testDynamicTwist(); }; #endif // hifi_RotationConstraintTests_h From 48efbba335c93dd6f31f0984ad2b34148d3b3791 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 11 Mar 2016 14:44:43 -0800 Subject: [PATCH 24/77] use dynamic constraints for IK --- libraries/animation/src/AnimInverseKinematics.cpp | 11 +++++++++++ libraries/animation/src/RotationConstraint.h | 4 ++++ libraries/animation/src/SwingTwistConstraint.h | 2 +- 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/libraries/animation/src/AnimInverseKinematics.cpp b/libraries/animation/src/AnimInverseKinematics.cpp index 46e17c39d8..f4df7ada82 100644 --- a/libraries/animation/src/AnimInverseKinematics.cpp +++ b/libraries/animation/src/AnimInverseKinematics.cpp @@ -396,6 +396,17 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars } _relativePoses[i].trans = underPoses[i].trans; } + + if (!_relativePoses.empty()) { + // Sometimes the underpose itself can violate the constraints. Rather than + // clamp the animation we dynamically expand each constraint to accomodate it. + std::map::iterator constraintItr = _constraints.begin(); + while (constraintItr != _constraints.end()) { + int index = constraintItr->first; + constraintItr->second->dynamicallyAdjustLimits(_relativePoses[index].rot); + ++constraintItr; + } + } } if (!_relativePoses.empty()) { diff --git a/libraries/animation/src/RotationConstraint.h b/libraries/animation/src/RotationConstraint.h index 0745500582..9e34537cab 100644 --- a/libraries/animation/src/RotationConstraint.h +++ b/libraries/animation/src/RotationConstraint.h @@ -31,6 +31,10 @@ public: /// \return true if this constraint is part of lower spine virtual bool isLowerSpine() const { return false; } + /// \param rotation rotation to allow + /// \brief clear previous adjustment and adjust constraint limits to allow rotation + virtual void dynamicallyAdjustLimits(const glm::quat& rotation) {} + protected: glm::quat _referenceRotation = glm::quat(); }; diff --git a/libraries/animation/src/SwingTwistConstraint.h b/libraries/animation/src/SwingTwistConstraint.h index 4734aa8b9d..93d7449d8f 100644 --- a/libraries/animation/src/SwingTwistConstraint.h +++ b/libraries/animation/src/SwingTwistConstraint.h @@ -55,7 +55,7 @@ public: /// \param rotation rotation to allow /// \brief clear previous adjustment and adjust constraint limits to allow rotation - void dynamicallyAdjustLimits(const glm::quat& rotation); + virtual void dynamicallyAdjustLimits(const glm::quat& rotation) override; // for testing purposes const std::vector& getMinDots() { return _swingLimitFunction.getMinDots(); } From 1e8706b1da6eaee6396a6174c36bcb70ffd1dff9 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 11 Mar 2016 14:47:53 -0800 Subject: [PATCH 25/77] remove debug print --- libraries/entities/src/EntityItem.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 71be12682b..c4d1280ef3 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1210,7 +1210,6 @@ void EntityItem::checkAndAdjustQueryAACube() { // allow server to patch up broken queryAACubes EntityTreePointer tree = getTree(); if (tree) { - qDebug() << "EntityItem::checkAndAdjustQueryAACube" << getName(); EntityItemProperties properties; properties.setQueryAACube(maxAACube); tree->updateEntity(getID(), properties); From 973022f0e104ab1430e4958205b5377db3bf7d7c Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Fri, 11 Mar 2016 14:51:36 -0800 Subject: [PATCH 26/77] version attempts --- server-console/src/main.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/server-console/src/main.js b/server-console/src/main.js index fedd934029..c9e33e2ce4 100644 --- a/server-console/src/main.js +++ b/server-console/src/main.js @@ -538,7 +538,11 @@ function buildMenuArray(serverState) { click: function() { shutdown(); } }, { - label: 'Current Version: '+buildInfo.buildIdentifier + type: 'separator' + }, + { + label: 'Current Version: '+buildInfo.buildIdentifier, + enabled: false } ]; @@ -776,6 +780,7 @@ app.on('ready', function() { var currentVersion = null; try { currentVersion = parseInt(buildInfo.buildIdentifier); + console.log('CURRENT VERSION:: ',currentVersion) } catch (e) { } From ecf67282d5b43ae43473e9b6736625867c5badfe Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sat, 12 Mar 2016 12:29:52 +1300 Subject: [PATCH 27/77] Add separators to HMD menus --- interface/resources/qml/menus/VrMenuItem.qml | 22 ++++++++++++++++++- .../qml/styles-uit/HifiConstants.qml | 1 + libraries/ui/src/VrMenu.cpp | 14 ++++++++++++ libraries/ui/src/VrMenu.h | 1 + libraries/ui/src/ui/Menu.cpp | 6 ++++- 5 files changed, 42 insertions(+), 2 deletions(-) diff --git a/interface/resources/qml/menus/VrMenuItem.qml b/interface/resources/qml/menus/VrMenuItem.qml index 636728c890..5854a75ef5 100644 --- a/interface/resources/qml/menus/VrMenuItem.qml +++ b/interface/resources/qml/menus/VrMenuItem.qml @@ -28,7 +28,7 @@ Item { CheckBox { id: check - // FIXME: Shouild use radio buttons if source.exclusiveGroup. + // FIXME: Should use radio buttons if source.exclusiveGroup. anchors { left: parent.left leftMargin: hifi.dimensions.menuPadding.x @@ -60,6 +60,26 @@ Item { visible: source.visible } + Item { + id: separator + anchors { + fill: parent + leftMargin: hifi.dimensions.menuPadding.x + check.width + rightMargin: hifi.dimensions.menuPadding.x + tail.width + } + visible: source.type === MenuItemType.Separator + + Rectangle { + anchors { + left: parent.left + right: parent.right + verticalCenter: parent.verticalCenter + } + height: 1 + color: hifi.colors.lightGray50 + } + } + Item { // Space for shortcut key or disclosure icon. id: tail diff --git a/interface/resources/qml/styles-uit/HifiConstants.qml b/interface/resources/qml/styles-uit/HifiConstants.qml index 718c1e32cb..2a1053c2b6 100644 --- a/interface/resources/qml/styles-uit/HifiConstants.qml +++ b/interface/resources/qml/styles-uit/HifiConstants.qml @@ -71,6 +71,7 @@ Item { readonly property color baseGrayShadow25: "#40252525" readonly property color baseGrayHighlight40: "#66575757" readonly property color baseGrayHighlight15: "#26575757" + readonly property color lightGray50: "#806a6a6a" readonly property color lightGrayText80: "#ccafafaf" readonly property color faintGray80: "#cce3e3e3" readonly property color faintGray50: "#80e3e3e3" diff --git a/libraries/ui/src/VrMenu.cpp b/libraries/ui/src/VrMenu.cpp index 76acf5d18a..41768a5349 100644 --- a/libraries/ui/src/VrMenu.cpp +++ b/libraries/ui/src/VrMenu.cpp @@ -190,6 +190,20 @@ void VrMenu::addAction(QMenu* menu, QAction* action) { bindActionToQmlAction(result, action); } +void VrMenu::addSeparator(QMenu* menu) { + Q_ASSERT(MenuUserData::forObject(menu)); + MenuUserData* userData = MenuUserData::forObject(menu); + if (!userData) { + return; + } + QObject* menuQml = findMenuObject(userData->uuid.toString()); + Q_ASSERT(menuQml); + + bool invokeResult = QMetaObject::invokeMethod(menuQml, "addSeparator", Qt::DirectConnection); + Q_ASSERT(invokeResult); + Q_UNUSED(invokeResult); // FIXME - apparently we haven't upgraded the Qt on our unix Jenkins environments to 5.5.x +} + void VrMenu::insertAction(QAction* before, QAction* action) { QObject* beforeQml{ nullptr }; { diff --git a/libraries/ui/src/VrMenu.h b/libraries/ui/src/VrMenu.h index b092b63566..d03887821f 100644 --- a/libraries/ui/src/VrMenu.h +++ b/libraries/ui/src/VrMenu.h @@ -28,6 +28,7 @@ public: VrMenu(QObject* parent = nullptr); void addMenu(QMenu* menu); void addAction(QMenu* parent, QAction* action); + void addSeparator(QMenu* parent); void insertAction(QAction* before, QAction* action); void removeAction(QAction* action); diff --git a/libraries/ui/src/ui/Menu.cpp b/libraries/ui/src/ui/Menu.cpp index 1b70213876..a5d801869d 100644 --- a/libraries/ui/src/ui/Menu.cpp +++ b/libraries/ui/src/ui/Menu.cpp @@ -511,7 +511,11 @@ void MenuWrapper::setEnabled(bool enabled) { } QAction* MenuWrapper::addSeparator() { - return _realMenu->addSeparator(); + QAction* action = _realMenu->addSeparator(); + VrMenu::executeOrQueue([=](VrMenu* vrMenu) { + vrMenu->addSeparator(_realMenu); + }); + return action; } void MenuWrapper::addAction(QAction* action) { From 9da64e540dd7485b8fdcdd64e2f5a27e040030e2 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sat, 12 Mar 2016 12:53:16 +1300 Subject: [PATCH 28/77] Add shortcut keys to HMD menu --- interface/resources/qml/menus/VrMenuItem.qml | 14 ++++++++++++-- libraries/ui/src/VrMenu.cpp | 1 + 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/interface/resources/qml/menus/VrMenuItem.qml b/interface/resources/qml/menus/VrMenuItem.qml index 5854a75ef5..0b18811ccf 100644 --- a/interface/resources/qml/menus/VrMenuItem.qml +++ b/interface/resources/qml/menus/VrMenuItem.qml @@ -81,15 +81,25 @@ Item { } Item { - // Space for shortcut key or disclosure icon. id: tail - width: 48 + width: 48 + (shortcut.visible ? shortcut.width : 0) anchors { verticalCenter: parent.verticalCenter right: parent.right rightMargin: hifi.dimensions.menuPadding.x } + RalewayLight { + id: shortcut + text: source.shortcut ? source.shortcut : "" + size: hifi.fontSizes.shortcutText + color: hifi.colors.baseGrayShadow + anchors.verticalCenter: parent.verticalCenter + anchors.right: parent.right + anchors.rightMargin: 15 + visible: source.visible && text != "" + } + HiFiGlyphs { text: hifi.glyphs.disclosureExpand color: source.enabled ? hifi.colors.baseGrayShadow : hifi.colors.baseGrayShadow25 diff --git a/libraries/ui/src/VrMenu.cpp b/libraries/ui/src/VrMenu.cpp index 41768a5349..5acf81c319 100644 --- a/libraries/ui/src/VrMenu.cpp +++ b/libraries/ui/src/VrMenu.cpp @@ -104,6 +104,7 @@ void updateQmlItemFromAction(QObject* target, QAction* source) { target->setProperty("checkable", source->isCheckable()); target->setProperty("enabled", source->isEnabled()); target->setProperty("text", source->text()); + target->setProperty("shortcut", source->shortcut().toString()); target->setProperty("checked", source->isChecked()); target->setProperty("visible", source->isVisible()); } From 5f05d576cc5e5abff9d4632c40345c8fb653d1be Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 11 Mar 2016 15:55:42 -0800 Subject: [PATCH 29/77] move checkAndAdjustQueryAACube into SpatiallyNestable --- libraries/entities/src/EntityItem.cpp | 46 ++++++++++++++-------- libraries/entities/src/EntityItem.h | 4 +- libraries/entities/src/EntityTree.cpp | 22 +++++++---- libraries/shared/src/SpatiallyNestable.cpp | 11 +++++- libraries/shared/src/SpatiallyNestable.h | 3 +- 5 files changed, 57 insertions(+), 29 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index c4d1280ef3..efd6b26600 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1202,25 +1202,24 @@ const Transform EntityItem::getTransformToCenter(bool& success) const { return result; } -void EntityItem::checkAndAdjustQueryAACube() { - bool maxAACubeSuccess; - AACube maxAACube = getMaximumAACube(maxAACubeSuccess); - if (maxAACubeSuccess) { - if (!_queryAACubeSet || !_queryAACube.contains(maxAACube)) { - // allow server to patch up broken queryAACubes - EntityTreePointer tree = getTree(); - if (tree) { - EntityItemProperties properties; - properties.setQueryAACube(maxAACube); - tree->updateEntity(getID(), properties); - } - } - } -} +// void EntityItem::checkAndAdjustQueryAACube() { +// bool maxAACubeSuccess; +// AACube maxAACube = getMaximumAACube(maxAACubeSuccess); +// if (maxAACubeSuccess) { +// if (!_queryAACubeSet || !_queryAACube.contains(maxAACube)) { +// // allow server to patch up broken queryAACubes +// EntityTreePointer tree = getTree(); +// if (tree) { +// EntityItemProperties properties; +// properties.setQueryAACube(maxAACube); +// tree->updateEntity(getID(), properties); +// } +// } +// } +// } void EntityItem::setParentID(const QUuid& parentID) { SpatiallyNestable::setParentID(parentID); - checkAndAdjustQueryAACube(); } @@ -1229,7 +1228,6 @@ void EntityItem::setDimensions(const glm::vec3& value) { return; } setScale(value); - checkAndAdjustQueryAACube(); } /// The maximum bounding cube for the entity, independent of it's rotation. @@ -1322,6 +1320,20 @@ AABox EntityItem::getAABox(bool& success) const { return _cachedAABox; } +AACube EntityItem::getQueryAACube(bool& success) const { + AACube result = SpatiallyNestable::getQueryAACube(success); + if (success) { + return result; + } + // this is for when we've loaded an older json file that didn't have queryAACube properties. + result = getMaximumAACube(success); + if (success) { + _queryAACube = result; + _queryAACubeSet = true; + } + return result; +} + // NOTE: This should only be used in cases of old bitstreams which only contain radius data // 0,0,0 --> maxDimension,maxDimension,maxDimension // ... has a corner to corner distance of glm::length(maxDimension,maxDimension,maxDimension) diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 7ce1d0c783..41dd423f92 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -179,8 +179,6 @@ public: QString getDescription() const { return _description; } void setDescription(QString value) { _description = value; } - void checkAndAdjustQueryAACube(); - virtual void setParentID(const QUuid& parentID); /// Dimensions in meters (0.0 - TREE_SCALE) @@ -242,6 +240,8 @@ public: AACube getMinimumAACube(bool& success) const; AABox getAABox(bool& success) const; /// axis aligned bounding box in world-frame (meters) + using SpatiallyNestable::getQueryAACube; + virtual AACube getQueryAACube(bool& success) const override; const QString& getScript() const { return _script; } void setScript(const QString& value) { _script = value; } diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 4c3412edd3..2a37d19dd9 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -992,15 +992,21 @@ void EntityTree::fixupMissingParents() { EntityItemWeakPointer entityWP = iter.next(); EntityItemPointer entity = entityWP.lock(); if (entity) { - bool success; - AACube newCube = entity->getQueryAACube(success); - if (success) { - // this entity's parent (or ancestry) was previously not fully known, and now is. Update its - // location in the EntityTree. - moveOperator.addEntityToMoveList(entity, newCube); - iter.remove(); - entity->markAncestorMissing(false); + bool maxAACubeSuccess; + AACube maxAACube = entity->getMaximumAACube(maxAACubeSuccess); + bool queryAACubeSuccess; + AACube newCube = entity->getQueryAACube(queryAACubeSuccess); + if (!maxAACubeSuccess || !queryAACubeSuccess) { + continue; } + if (!newCube.contains(maxAACube)) { + newCube = maxAACube; + } + // this entity's parent (or ancestry) was previously not fully known, and now is. Update its + // location in the EntityTree. + moveOperator.addEntityToMoveList(entity, newCube); + iter.remove(); + entity->markAncestorMissing(false); } else { // entity was deleted before we found its parent. iter.remove(); diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index c8dceaa905..cc4ff2cf1c 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -752,6 +752,7 @@ void SpatiallyNestable::forEachDescendant(std::functionlocationChanged(); }); @@ -761,13 +762,21 @@ AACube SpatiallyNestable::getMaximumAACube(bool& success) const { return AACube(getPosition(success) - glm::vec3(defaultAACubeSize / 2.0f), defaultAACubeSize); } +void SpatiallyNestable::checkAndAdjustQueryAACube() { + bool success; + AACube maxAACube = getMaximumAACube(success); + if (success && (!_queryAACubeSet || !_queryAACube.contains(maxAACube))) { + setQueryAACube(maxAACube); + } +} + void SpatiallyNestable::setQueryAACube(const AACube& queryAACube) { if (queryAACube.containsNaN()) { qDebug() << "SpatiallyNestable::setQueryAACube -- cube contains NaN"; return; } _queryAACube = queryAACube; - if (queryAACube.getScale() > 0.0f) { + if (_queryAACube.getScale() > 0.0f) { _queryAACubeSet = true; } } diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index ee6cccc7a8..e6728bc923 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -81,6 +81,7 @@ public: virtual glm::vec3 getParentAngularVelocity(bool& success) const; virtual AACube getMaximumAACube(bool& success) const; + virtual void checkAndAdjustQueryAACube(); virtual bool computePuffedQueryAACube(); virtual void setQueryAACube(const AACube& queryAACube); @@ -156,7 +157,7 @@ protected: mutable QHash _children; virtual void locationChanged(); // called when a this object's location has changed - virtual void dimensionsChanged() {} // called when a this object's dimensions have changed + virtual void dimensionsChanged() { checkAndAdjustQueryAACube(); } // called when a this object's dimensions have changed // _queryAACube is used to decide where something lives in the octree mutable AACube _queryAACube; From 3bf1afb80ba22e2f36f72f18568e3c0d46182100 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sat, 12 Mar 2016 12:56:38 +1300 Subject: [PATCH 30/77] HMD submenus not allcaps --- interface/resources/qml/menus/VrMenuItem.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/resources/qml/menus/VrMenuItem.qml b/interface/resources/qml/menus/VrMenuItem.qml index 0b18811ccf..38d2b57c03 100644 --- a/interface/resources/qml/menus/VrMenuItem.qml +++ b/interface/resources/qml/menus/VrMenuItem.qml @@ -51,7 +51,7 @@ Item { RalewaySemiBold { id: label size: hifi.fontSizes.rootMenu - font.capitalization: Font.AllUppercase + font.capitalization: isSubMenu ? Font.MixedCase : Font.AllUppercase anchors.left: check.right anchors.verticalCenter: parent.verticalCenter verticalAlignment: Text.AlignVCenter From 3deb30d699488f1ed7860f3d435d9bfdc7131b0a Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sat, 12 Mar 2016 13:06:29 +1300 Subject: [PATCH 31/77] Remove no longer need font type --- .../resources/qml/styles-uit/FontAwesome.qml | 26 ------------------- 1 file changed, 26 deletions(-) delete mode 100644 interface/resources/qml/styles-uit/FontAwesome.qml diff --git a/interface/resources/qml/styles-uit/FontAwesome.qml b/interface/resources/qml/styles-uit/FontAwesome.qml deleted file mode 100644 index 5c03ef09b2..0000000000 --- a/interface/resources/qml/styles-uit/FontAwesome.qml +++ /dev/null @@ -1,26 +0,0 @@ -// -// FontAwesome.qml -// -// Created by Bradley Austin Davis on 24 Apr 2015 -// Copyright 2015 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 -// - -import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 - -Text { - id: root - FontLoader { id: iconFont; source: "../../fonts/fontawesome-webfont.ttf"; } - property int size: 32 - width: size - height: size - font.pixelSize: size - verticalAlignment: Text.AlignVCenter - horizontalAlignment: Text.AlignLeft - font.family: iconFont.name -} - From 01659cf93b49cf511db242841ff4500fd9744bbf Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 11 Mar 2016 16:21:20 -0800 Subject: [PATCH 32/77] try, try again --- .../src/RenderableModelEntityItem.cpp | 19 ---------------- libraries/entities/src/EntityItem.cpp | 22 +------------------ libraries/entities/src/EntityItem.h | 3 +-- libraries/shared/src/SpatiallyNestable.cpp | 4 +++- 4 files changed, 5 insertions(+), 43 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 2734d968a9..c637cf4bb9 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -74,26 +74,7 @@ void RenderableModelEntityItem::loader() { void RenderableModelEntityItem::setDimensions(const glm::vec3& value) { _dimensionsInitialized = true; - - bool success; - AACube queryAACube = getQueryAACube(success); - ModelEntityItem::setDimensions(value); - - AACube maxAACube = getMaximumAACube(success); - if (!success) { - return; - } - - if (!success || !queryAACube.contains(maxAACube)) { - EntityItemProperties properties; - properties.setQueryAACube(maxAACube); - qCDebug(entitiesrenderer) << "Auto-setting queryAACube:" << (!getName().isEmpty() ? getName() : getModelURL()); - QMetaObject::invokeMethod(DependencyManager::get().data(), "editEntity", - Qt::QueuedConnection, - Q_ARG(QUuid, getEntityItemID()), - Q_ARG(EntityItemProperties, properties)); - } } bool RenderableModelEntityItem::setProperties(const EntityItemProperties& properties) { diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index efd6b26600..3c918a0a77 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1202,27 +1202,6 @@ const Transform EntityItem::getTransformToCenter(bool& success) const { return result; } -// void EntityItem::checkAndAdjustQueryAACube() { -// bool maxAACubeSuccess; -// AACube maxAACube = getMaximumAACube(maxAACubeSuccess); -// if (maxAACubeSuccess) { -// if (!_queryAACubeSet || !_queryAACube.contains(maxAACube)) { -// // allow server to patch up broken queryAACubes -// EntityTreePointer tree = getTree(); -// if (tree) { -// EntityItemProperties properties; -// properties.setQueryAACube(maxAACube); -// tree->updateEntity(getID(), properties); -// } -// } -// } -// } - -void EntityItem::setParentID(const QUuid& parentID) { - SpatiallyNestable::setParentID(parentID); -} - - void EntityItem::setDimensions(const glm::vec3& value) { if (value.x <= 0.0f || value.y <= 0.0f || value.z <= 0.0f) { return; @@ -1334,6 +1313,7 @@ AACube EntityItem::getQueryAACube(bool& success) const { return result; } + // NOTE: This should only be used in cases of old bitstreams which only contain radius data // 0,0,0 --> maxDimension,maxDimension,maxDimension // ... has a corner to corner distance of glm::length(maxDimension,maxDimension,maxDimension) diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 41dd423f92..577bb406bc 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -179,8 +179,6 @@ public: QString getDescription() const { return _description; } void setDescription(QString value) { _description = value; } - virtual void setParentID(const QUuid& parentID); - /// Dimensions in meters (0.0 - TREE_SCALE) inline const glm::vec3 getDimensions() const { return getScale(); } virtual void setDimensions(const glm::vec3& value); @@ -242,6 +240,7 @@ public: using SpatiallyNestable::getQueryAACube; virtual AACube getQueryAACube(bool& success) const override; + const QString& getScript() const { return _script; } void setScript(const QString& value) { _script = value; } diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index cc4ff2cf1c..10d851ec5a 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -55,6 +55,7 @@ void SpatiallyNestable::setParentID(const QUuid& parentID) { _parentKnowsMe = false; } }); + checkAndAdjustQueryAACube(); } Transform SpatiallyNestable::getParentTransform(bool& success, int depth) const { @@ -139,6 +140,7 @@ void SpatiallyNestable::forgetChild(SpatiallyNestablePointer newChild) const { void SpatiallyNestable::setParentJointIndex(quint16 parentJointIndex) { _parentJointIndex = parentJointIndex; + checkAndAdjustQueryAACube(); } glm::vec3 SpatiallyNestable::worldToLocal(const glm::vec3& position, @@ -776,7 +778,7 @@ void SpatiallyNestable::setQueryAACube(const AACube& queryAACube) { return; } _queryAACube = queryAACube; - if (_queryAACube.getScale() > 0.0f) { + if (queryAACube.getScale() > 0.0f) { _queryAACubeSet = true; } } From 23fd2e93b523a370dca7605eaa9bf9f93ecf8584 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Fri, 11 Mar 2016 16:26:14 -0800 Subject: [PATCH 33/77] add version number --- server-console/src/main.js | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/server-console/src/main.js b/server-console/src/main.js index c9e33e2ce4..667094710d 100644 --- a/server-console/src/main.js +++ b/server-console/src/main.js @@ -493,6 +493,10 @@ function buildMenuArray(serverState) { label: 'Server - Stopped', enabled: false }, + { + label: 'Version - '+buildInfo.buildIdentifier, + enabled: false + }, { type: 'separator' }, @@ -536,14 +540,7 @@ function buildMenuArray(serverState) { label: 'Quit', accelerator: 'Command+Q', click: function() { shutdown(); } - }, - { - type: 'separator' - }, - { - label: 'Current Version: '+buildInfo.buildIdentifier, - enabled: false - } + } ]; var foundStackManagerContent = isStackManagerContentPresent(); From 801f2b3f9f4ca5e8daf657c112334f5d7cd2cc45 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Fri, 11 Mar 2016 16:38:39 -0800 Subject: [PATCH 34/77] add animated urchin --- .../Home/fishTank/createFishTank.js | 27 ++++++++++++++++--- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/unpublishedScripts/DomainContent/Home/fishTank/createFishTank.js b/unpublishedScripts/DomainContent/Home/fishTank/createFishTank.js index cd03b1efa2..79645b6e77 100644 --- a/unpublishedScripts/DomainContent/Home/fishTank/createFishTank.js +++ b/unpublishedScripts/DomainContent/Home/fishTank/createFishTank.js @@ -34,7 +34,15 @@ var DEBUG_COLOR = { blue: 255 } -var center = Vec3.sum(MyAvatar.position, Vec3.multiply(Quat.getFront(MyAvatar.orientation), 1 * TANK_WIDTH)); + +var centerVertical = { + x: 0, + y: 1, + z: 0 +} + +var upCenter = Vec3.sum(centerVertical, MyAvatar.position); +var center = Vec3.sum(upCenter, Vec3.multiply(Quat.getFront(MyAvatar.orientation), 2)); var TANK_POSITION = center; @@ -52,7 +60,7 @@ var TANK_BASE_DIMENSIONS = { z: 2.1936 }; -var BASE_VERTICAL_OFFSET = 0.42; +var BASE_VERTICAL_OFFSET = 0.47; var BUBBLE_SYSTEM_FORWARD_OFFSET = TANK_DIMENSIONS.x + 0.06; var BUBBLE_SYSTEM_LATERAL_OFFSET = 0.025; @@ -73,8 +81,8 @@ var URCHIN_LATERAL_OFFSET = -0.05; var URCHIN_VERTICAL_OFFSET = -0.12; -var URCHIN_MODEL_URL = 'http://hifi-content.s3.amazonaws.com/DomainContent/Home/fishTank/Urchin.fbx'; - +var URCHIN_MODEL_URL = 'http://hifi-content.s3.amazonaws.com/DomainContent/Home/fishTank/anemone.fbx'; +var URCHIN_ANIMATION_URL = 'http://hifi-content.s3.amazonaws.com/DomainContent/Home/fishTank/anemone.fbx'; var URCHIN_DIMENSIONS = { x: 0.4, y: 0.4, @@ -308,10 +316,21 @@ function createUrchin() { var properties = { name: 'hifi-home-fishtank-urchin', type: 'Model', + animationURL: URCHIN_ANIMATION_URL, + animationIsPlaying: true, + animationFPS:15, + animationSettings: JSON.stringify({ + + hold: false, + loop: true, + running: true, + startAutomatically: true + }), parentID: fishTank, modelURL: URCHIN_MODEL_URL, position: finalPosition, shapeType: 'Sphere', + rotation: Quat.fromPitchYawRollDegrees(0, 90, 0), dimensions: URCHIN_DIMENSIONS } From 68cc87298f208baf3fd152fa4381946b9b448ddb Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Fri, 11 Mar 2016 16:39:58 -0800 Subject: [PATCH 35/77] cleanup --- .../DomainContent/Home/fishTank/createFishTank.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/unpublishedScripts/DomainContent/Home/fishTank/createFishTank.js b/unpublishedScripts/DomainContent/Home/fishTank/createFishTank.js index 79645b6e77..3c168fc668 100644 --- a/unpublishedScripts/DomainContent/Home/fishTank/createFishTank.js +++ b/unpublishedScripts/DomainContent/Home/fishTank/createFishTank.js @@ -318,9 +318,8 @@ function createUrchin() { type: 'Model', animationURL: URCHIN_ANIMATION_URL, animationIsPlaying: true, - animationFPS:15, + animationFPS: 15, animationSettings: JSON.stringify({ - hold: false, loop: true, running: true, From 608370615136d1b4d8ef57439632023b9bce53cd Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Fri, 11 Mar 2016 16:47:16 -0800 Subject: [PATCH 36/77] CR feedback --- examples/away.js | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/away.js b/examples/away.js index 6bd685fcff..643edbd149 100644 --- a/examples/away.js +++ b/examples/away.js @@ -181,7 +181,6 @@ function goAway() { // remember the View > Overlays state... wasOverlaysVisible = Menu.isOptionChecked("Overlays"); - print("wasOverlaysVisible:" + wasOverlaysVisible); // show overlays so that people can see the "Away" message Menu.setIsOptionChecked("Overlays", true); From 42e3d0bdadc40c96e8e9a1aee915d7869dc120ca Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Fri, 11 Mar 2016 16:57:50 -0800 Subject: [PATCH 37/77] remove logging --- server-console/src/main.js | 165 ++++++++++++++++++++----------------- 1 file changed, 88 insertions(+), 77 deletions(-) diff --git a/server-console/src/main.js b/server-console/src/main.js index 667094710d..15dbf698bc 100644 --- a/server-console/src/main.js +++ b/server-console/src/main.js @@ -1,7 +1,7 @@ 'use strict'; const electron = require('electron'); -const app = electron.app; // Module to control application life. +const app = electron.app; // Module to control application life. const BrowserWindow = electron.BrowserWindow; const nativeImage = electron.nativeImage; @@ -57,7 +57,10 @@ function getBuildInfo() { } } - const DEFAULT_BUILD_INFO = { releaseType: "", buildIdentifier: "dev" }; + const DEFAULT_BUILD_INFO = { + releaseType: "", + buildIdentifier: "dev" + }; var buildInfo = DEFAULT_BUILD_INFO; if (buildInfoPath) { @@ -104,6 +107,7 @@ const ipcMain = electron.ipcMain; var isShuttingDown = false; + function shutdown() { if (!isShuttingDown) { // if the home server is running, show a prompt before quit to ask if the user is sure @@ -283,8 +287,7 @@ function openFileBrowser(path) { // NOTE: this looks like it does nothing, but it's very important. // Without it the default behaviour is to quit the app once all windows closed // which is absolutely not what we want for a taskbar application. -app.on('window-all-closed', function() { -}); +app.on('window-all-closed', function() {}); function startInterface(url) { var argArray = []; @@ -320,7 +323,11 @@ LogWindow.prototype = { return; } // Create the browser window. - this.window = new BrowserWindow({ width: 700, height: 500, icon: appIcon }); + this.window = new BrowserWindow({ + width: 700, + height: 500, + icon: appIcon + }); this.window.loadURL('file://' + __dirname + '/log.html'); if (!debug) { @@ -367,7 +374,7 @@ function isStackManagerContentPresent() { if (stats.isFile()) { console.log("Stack Manager entities file discovered at " + modelsPath) - // we found a content file + // we found a content file return true; } } catch (e) { @@ -481,74 +488,72 @@ function buildMenuArray(serverState) { var menuArray = null; if (isShuttingDown) { - menuArray = [ - { - label: "Shutting down...", - enabled: false - } - ]; + menuArray = [{ + label: "Shutting down...", + enabled: false + }]; } else { - menuArray = [ - { - label: 'Server - Stopped', - enabled: false + menuArray = [{ + label: 'Server - Stopped', + enabled: false + }, { + label: 'Version - ' + buildInfo.buildIdentifier, + enabled: false + }, { + type: 'separator' + }, { + label: 'Go Home', + click: goHomeClicked, + enabled: false + }, { + type: 'separator' + }, { + label: 'Start Server', + click: function() { + homeServer.restart(); + } + }, { + label: 'Stop Server', + visible: false, + click: function() { + homeServer.stop(); + } + }, { + label: 'Settings', + click: function() { + shell.openExternal('http://localhost:40100/settings'); }, - { - label: 'Version - '+buildInfo.buildIdentifier, - enabled: false - }, - { - type: 'separator' - }, - { - label: 'Go Home', - click: goHomeClicked, - enabled: false - }, - { - type: 'separator' - }, - { - label: 'Start Server', - click: function() { homeServer.restart(); } - }, - { - label: 'Stop Server', - visible: false, - click: function() { homeServer.stop(); } - }, - { - label: 'Settings', - click: function() { shell.openExternal('http://localhost:40100/settings'); }, - enabled: false - }, - { - label: 'View Logs', - click: function() { logWindow.open(); } - }, - { - type: 'separator' - }, - { - label: 'Share', - click: function() { shell.openExternal('http://localhost:40100/settings/?action=share') } - }, - { - type: 'separator' - }, - { - label: 'Quit', - accelerator: 'Command+Q', - click: function() { shutdown(); } - } - ]; + enabled: false + }, { + label: 'View Logs', + click: function() { + logWindow.open(); + } + }, { + type: 'separator' + }, { + label: 'Share', + click: function() { + shell.openExternal('http://localhost:40100/settings/?action=share') + } + }, { + type: 'separator' + }, { + label: 'Quit', + accelerator: 'Command+Q', + click: function() { + shutdown(); + } + }]; var foundStackManagerContent = isStackManagerContentPresent(); if (foundStackManagerContent) { // add a separator and the stack manager content migration option menuArray.splice(menuArray.length - 1, 0, { label: 'Migrate Stack Manager Content', - click: function() { promptToMigrateContent(); } + click: function() { + promptToMigrateContent(); + } }, { type: 'separator' }); @@ -647,9 +652,13 @@ function maybeInstallDefaultContentSet(onComplete) { electron.ipcMain.on('ready', function() { console.log("got ready"); + function sendStateUpdate(state, args) { // console.log(state, window, args); - window.webContents.send('update', { state: state, args: args }); + window.webContents.send('update', { + state: state, + args: args + }); } var aborted = false; @@ -673,7 +682,9 @@ function maybeInstallDefaultContentSet(onComplete) { } else { sendStateUpdate('installing'); } - }), { throttle: 250 }).on('progress', function(state) { + }), { + throttle: 250 + }).on('progress', function(state) { if (!aborted) { // Update progress popup sendStateUpdate('downloading', state); @@ -687,7 +698,7 @@ function maybeInstallDefaultContentSet(onComplete) { console.log("Done", arguments); sendStateUpdate('complete'); }); - unzipper.on('error', function (err) { + unzipper.on('error', function(err) { console.log("aborting"); aborted = true; req.abort(); @@ -777,10 +788,7 @@ app.on('ready', function() { var currentVersion = null; try { currentVersion = parseInt(buildInfo.buildIdentifier); - console.log('CURRENT VERSION:: ',currentVersion) - } catch (e) { - } - + } catch (e) {} if (currentVersion !== null) { const CHECK_FOR_UPDATES_INTERVAL_SECONDS = 60 * 30; @@ -810,8 +818,9 @@ app.on('ready', function() { if (dsPath && acPath) { domainServer = new Process('domain-server', dsPath, ["--get-temp-name"], logPath); acMonitor = new ACMonitorProcess('ac-monitor', acPath, ['-n6', - '--log-directory', logPath, - '--http-status-port', httpStatusPort], httpStatusPort, logPath); + '--log-directory', logPath, + '--http-status-port', httpStatusPort + ], httpStatusPort, logPath); homeServer = new ProcessGroup('home', [domainServer, acMonitor]); logWindow = new LogWindow(acMonitor, domainServer); @@ -820,10 +829,12 @@ app.on('ready', function() { }; // handle process updates - homeServer.on('state-update', function(processGroup) { updateTrayMenu(processGroup.state); }); + homeServer.on('state-update', function(processGroup) { + updateTrayMenu(processGroup.state); + }); // start the home server homeServer.start(); } }); -}); +}); \ No newline at end of file From 9823ecffa716c63cc215903a5dc5e231a1d55236 Mon Sep 17 00:00:00 2001 From: PhilipRosedale Date: Fri, 11 Mar 2016 17:00:44 -0800 Subject: [PATCH 38/77] new test sound script --- examples/playTestSound.js | 96 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 examples/playTestSound.js diff --git a/examples/playTestSound.js b/examples/playTestSound.js new file mode 100644 index 0000000000..318df6a257 --- /dev/null +++ b/examples/playTestSound.js @@ -0,0 +1,96 @@ +// +// playTestSound.js +// examples +// +// Created by Philip Rosedale +// Copyright 2014 High Fidelity, Inc. +// +// Creates an object in front of you that changes color and plays a light +// at the start of a drum clip that loops. As you move away it will tell you in the +// log how many meters you are from the source. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +var sound = SoundCache.getSound("https://s3.amazonaws.com/hifi-public/sounds/Drums/deepdrum1.wav"); + +var position = Vec3.sum(Vec3.sum(MyAvatar.position, { x: 0, y: 0.5, z: 0 }), Quat.getFront(MyAvatar.orientation)); + +var time; +var soundPlaying = null; + +var baseColor = { red: 100, green: 100, blue: 100 }; +var litColor = { red: 255, green: 100, blue: 0 }; + +var lightTime = 250; + +var distance = 0.0; + +// Create object for visual reference +var box = Entities.addEntity({ + type: "Box", + dimensions: { x: 0.25, y: 0.5, z: 0.25 }, + color: baseColor, + position: position + }); + + +function checkSound(deltaTime) { + var started = false; + if (!sound.downloaded) { + return; + } + if (soundPlaying == null) { + soundPlaying = Audio.playSound(sound, { + position: position, + volume: 1.0, + loop: false } ); + started = true; + } else if (!soundPlaying.isPlaying) { + soundPlaying.restart(); + started = true; + } + if (started) { + Entities.editEntity(box, { color: litColor }); + Entities.addEntity({ + type: "Light", + intensity: 5.0, + falloffRadius: 10.0, + dimensions: { + x: 40, + y: 40, + z: 40 + }, + position: Vec3.sum(position, { x: 0, y: 1, z: 0 }), + color: litColor, + lifetime: lightTime / 1000 + }); + Script.setTimeout(resetColor, lightTime); + } + var currentDistance = Vec3.distance(MyAvatar.position, position); + if (Math.abs(currentDistance - distance) > 1.0) { + print("Distance from source: " + currentDistance); + distance = currentDistance; + } +} + +function resetColor() { + Entities.editEntity(box, { color: baseColor }); +} + + +function scriptEnding() { + Entities.deleteEntity(box); + if (soundPlaying) { + print("stop injector"); + soundPlaying.stop(); + } +} + + + +// Connect a call back that happens every frame +Script.scriptEnding.connect(scriptEnding); +Script.update.connect(checkSound); + From 9fb897476e21b02c3b65d9ccefdc256ea0c809c4 Mon Sep 17 00:00:00 2001 From: Anthony Thibault Date: Fri, 11 Mar 2016 17:29:18 -0800 Subject: [PATCH 39/77] Application: fix for mouse control in third-person camera Process the keyboard & mouse input plugin after the userInputMapper()->update(). --- interface/src/Application.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 9bd4b00246..ce8f4e48d9 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3186,9 +3186,12 @@ void Application::update(float deltaTime) { myAvatar->getHMDSensorMatrix() }; + InputPluginPointer keyboardMousePlugin; bool jointsCaptured = false; for (auto inputPlugin : PluginManager::getInstance()->getInputPlugins()) { - if (inputPlugin->isActive()) { + if (inputPlugin->getName() == KeyboardMouseDevice::NAME) { + keyboardMousePlugin = inputPlugin; + } else if (inputPlugin->isActive()) { inputPlugin->pluginUpdate(deltaTime, calibrationData, jointsCaptured); if (inputPlugin->isJointController()) { jointsCaptured = true; @@ -3198,6 +3201,10 @@ void Application::update(float deltaTime) { userInputMapper->update(deltaTime); + if (keyboardMousePlugin && keyboardMousePlugin->isActive()) { + keyboardMousePlugin->pluginUpdate(deltaTime, calibrationData, jointsCaptured); + } + _controllerScriptingInterface->updateInputControllers(); // Transfer the user inputs to the driveKeys From cecebc9ae499ea6f3136620e6d45c683b7c0792e Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Fri, 11 Mar 2016 22:01:01 -0800 Subject: [PATCH 40/77] add example --- examples/data_visualization/photo_sphere.js | 60 +++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 examples/data_visualization/photo_sphere.js diff --git a/examples/data_visualization/photo_sphere.js b/examples/data_visualization/photo_sphere.js new file mode 100644 index 0000000000..8ea599d4f9 --- /dev/null +++ b/examples/data_visualization/photo_sphere.js @@ -0,0 +1,60 @@ +// photo_sphere.js +// +// Created by James B. Pollack on 3/11/2015 +// Copyright 2016 High Fidelity, Inc. +// +// This script creates a photo sphere around you. +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +var photoSphere, light;; + +//equirectangular +var url = 'http://hifi-content.s3.amazonaws.com/james/projection_objects/IMG_9167.JPG'; + +var MODEL_URL = 'http://hifi-content.s3.amazonaws.com/james/projection_objects/photosphere2.fbx'; + +function createPhotoSphere() { + + var textureString = 'photo:"' + url + '"' + print('ADDING TEXTURE:: ' + textureString); + var properties = { + type: 'Model', + modelURL: MODEL_URL, + name: 'hifi-photo-sphere', + dimensions: { + x: 32, + y: 32, + z: 32 + }, + position: MyAvatar.position, + textures: textureString + } + photoSphere = Entities.addEntity(properties); +} + +function createLight() { + var properties = { + name: 'hifi-photo-sphere-light', + type: 'Light', + dimensions: { + x: 36, + y: 36, + z: 36, + }, + intensity: 4.0, + falloffRadius: 22, + position: MyAvatar.position + } + light = Entities.addEntity(properties); +} + +function cleanup() { + Entities.deleteEntity(photoSphere); + Entities.deleteEntity(light); +} + +Script.scriptEnding.connect(cleanup); +createPhotoSphere(); +createLight(); \ No newline at end of file From b0109133c0af3f95370177192ba1c25fa87f7ff5 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Fri, 11 Mar 2016 22:02:49 -0800 Subject: [PATCH 41/77] add git handle --- examples/data_visualization/photo_sphere.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/data_visualization/photo_sphere.js b/examples/data_visualization/photo_sphere.js index 8ea599d4f9..d8be423bd7 100644 --- a/examples/data_visualization/photo_sphere.js +++ b/examples/data_visualization/photo_sphere.js @@ -1,6 +1,6 @@ // photo_sphere.js // -// Created by James B. Pollack on 3/11/2015 +// Created by James B. Pollack @imgntn on 3/11/2015 // Copyright 2016 High Fidelity, Inc. // // This script creates a photo sphere around you. @@ -18,7 +18,7 @@ var MODEL_URL = 'http://hifi-content.s3.amazonaws.com/james/projection_objects/p function createPhotoSphere() { var textureString = 'photo:"' + url + '"' - print('ADDING TEXTURE:: ' + textureString); + var properties = { type: 'Model', modelURL: MODEL_URL, From f7c6725f6319ad85292eac1c809912d84f84ba1b Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sat, 12 Mar 2016 23:24:52 +1300 Subject: [PATCH 42/77] Improve text3d rendering --- libraries/render-utils/src/sdf_text3D.slf | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/libraries/render-utils/src/sdf_text3D.slf b/libraries/render-utils/src/sdf_text3D.slf index 1e11cd984d..854221a5cf 100644 --- a/libraries/render-utils/src/sdf_text3D.slf +++ b/libraries/render-utils/src/sdf_text3D.slf @@ -21,12 +21,10 @@ in vec3 _normal; in vec2 _texCoord0; const float gamma = 2.2; -const float smoothing = 256.0; +const float smoothing = 32.0; const float interiorCutoff = 0.8; const float outlineExpansion = 0.2; - - void main() { // retrieve signed distance float sdf = texture(Font, _texCoord0).g; From d036e0618d88e1338de8af3e5b0d5a147ba02906 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 12 Mar 2016 07:54:59 -0800 Subject: [PATCH 43/77] don't build oculus-legacy plugin on linux --- plugins/oculusLegacy/CMakeLists.txt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/plugins/oculusLegacy/CMakeLists.txt b/plugins/oculusLegacy/CMakeLists.txt index 88b55b7a79..9e97b3791c 100644 --- a/plugins/oculusLegacy/CMakeLists.txt +++ b/plugins/oculusLegacy/CMakeLists.txt @@ -6,7 +6,9 @@ # See the accompanying file LICENSE or http:#www.apache.org/licenses/LICENSE-2.0.html # -if (NOT WIN32) +# Windows doesn't need this, and building it currently make Linux unstable. +# if (NOT WIN32) +if (APPLE) set(TARGET_NAME oculusLegacy) setup_hifi_plugin() @@ -19,4 +21,4 @@ if (NOT WIN32) target_include_directories(${TARGET_NAME} PRIVATE ${LIBOVR_INCLUDE_DIRS}) target_link_libraries(${TARGET_NAME} ${LIBOVR_LIBRARIES}) -endif() \ No newline at end of file +endif() From 90f5dd50a52d12f96f537292d39a6d2fd54a0895 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Sat, 12 Mar 2016 08:38:41 -0800 Subject: [PATCH 44/77] Revert "Show Server Console Version" --- server-console/src/main.js | 157 +++++++++++++++++-------------------- 1 file changed, 70 insertions(+), 87 deletions(-) diff --git a/server-console/src/main.js b/server-console/src/main.js index 15dbf698bc..e05106aa6f 100644 --- a/server-console/src/main.js +++ b/server-console/src/main.js @@ -1,7 +1,7 @@ 'use strict'; const electron = require('electron'); -const app = electron.app; // Module to control application life. +const app = electron.app; // Module to control application life. const BrowserWindow = electron.BrowserWindow; const nativeImage = electron.nativeImage; @@ -57,10 +57,7 @@ function getBuildInfo() { } } - const DEFAULT_BUILD_INFO = { - releaseType: "", - buildIdentifier: "dev" - }; + const DEFAULT_BUILD_INFO = { releaseType: "", buildIdentifier: "dev" }; var buildInfo = DEFAULT_BUILD_INFO; if (buildInfoPath) { @@ -107,7 +104,6 @@ const ipcMain = electron.ipcMain; var isShuttingDown = false; - function shutdown() { if (!isShuttingDown) { // if the home server is running, show a prompt before quit to ask if the user is sure @@ -287,7 +283,8 @@ function openFileBrowser(path) { // NOTE: this looks like it does nothing, but it's very important. // Without it the default behaviour is to quit the app once all windows closed // which is absolutely not what we want for a taskbar application. -app.on('window-all-closed', function() {}); +app.on('window-all-closed', function() { +}); function startInterface(url) { var argArray = []; @@ -323,11 +320,7 @@ LogWindow.prototype = { return; } // Create the browser window. - this.window = new BrowserWindow({ - width: 700, - height: 500, - icon: appIcon - }); + this.window = new BrowserWindow({ width: 700, height: 500, icon: appIcon }); this.window.loadURL('file://' + __dirname + '/log.html'); if (!debug) { @@ -374,7 +367,7 @@ function isStackManagerContentPresent() { if (stats.isFile()) { console.log("Stack Manager entities file discovered at " + modelsPath) - // we found a content file + // we found a content file return true; } } catch (e) { @@ -488,72 +481,70 @@ function buildMenuArray(serverState) { var menuArray = null; if (isShuttingDown) { - menuArray = [{ - label: "Shutting down...", - enabled: false - }]; + menuArray = [ + { + label: "Shutting down...", + enabled: false + } + ]; } else { - menuArray = [{ - label: 'Server - Stopped', - enabled: false - }, { - label: 'Version - ' + buildInfo.buildIdentifier, - enabled: false - }, { - type: 'separator' - }, { - label: 'Go Home', - click: goHomeClicked, - enabled: false - }, { - type: 'separator' - }, { - label: 'Start Server', - click: function() { - homeServer.restart(); - } - }, { - label: 'Stop Server', - visible: false, - click: function() { - homeServer.stop(); - } - }, { - label: 'Settings', - click: function() { - shell.openExternal('http://localhost:40100/settings'); + menuArray = [ + { + label: 'Server - Stopped', + enabled: false }, - enabled: false - }, { - label: 'View Logs', - click: function() { - logWindow.open(); + { + type: 'separator' + }, + { + label: 'Go Home', + click: goHomeClicked, + enabled: false + }, + { + type: 'separator' + }, + { + label: 'Start Server', + click: function() { homeServer.restart(); } + }, + { + label: 'Stop Server', + visible: false, + click: function() { homeServer.stop(); } + }, + { + label: 'Settings', + click: function() { shell.openExternal('http://localhost:40100/settings'); }, + enabled: false + }, + { + label: 'View Logs', + click: function() { logWindow.open(); } + }, + { + type: 'separator' + }, + { + label: 'Share', + click: function() { shell.openExternal('http://localhost:40100/settings/?action=share') } + }, + { + type: 'separator' + }, + { + label: 'Quit', + accelerator: 'Command+Q', + click: function() { shutdown(); } } - }, { - type: 'separator' - }, { - label: 'Share', - click: function() { - shell.openExternal('http://localhost:40100/settings/?action=share') - } - }, { - type: 'separator' - }, { - label: 'Quit', - accelerator: 'Command+Q', - click: function() { - shutdown(); - } - }]; + ]; var foundStackManagerContent = isStackManagerContentPresent(); if (foundStackManagerContent) { // add a separator and the stack manager content migration option menuArray.splice(menuArray.length - 1, 0, { label: 'Migrate Stack Manager Content', - click: function() { - promptToMigrateContent(); - } + click: function() { promptToMigrateContent(); } }, { type: 'separator' }); @@ -652,13 +643,9 @@ function maybeInstallDefaultContentSet(onComplete) { electron.ipcMain.on('ready', function() { console.log("got ready"); - function sendStateUpdate(state, args) { // console.log(state, window, args); - window.webContents.send('update', { - state: state, - args: args - }); + window.webContents.send('update', { state: state, args: args }); } var aborted = false; @@ -682,9 +669,7 @@ function maybeInstallDefaultContentSet(onComplete) { } else { sendStateUpdate('installing'); } - }), { - throttle: 250 - }).on('progress', function(state) { + }), { throttle: 250 }).on('progress', function(state) { if (!aborted) { // Update progress popup sendStateUpdate('downloading', state); @@ -698,7 +683,7 @@ function maybeInstallDefaultContentSet(onComplete) { console.log("Done", arguments); sendStateUpdate('complete'); }); - unzipper.on('error', function(err) { + unzipper.on('error', function (err) { console.log("aborting"); aborted = true; req.abort(); @@ -788,7 +773,8 @@ app.on('ready', function() { var currentVersion = null; try { currentVersion = parseInt(buildInfo.buildIdentifier); - } catch (e) {} + } catch (e) { + } if (currentVersion !== null) { const CHECK_FOR_UPDATES_INTERVAL_SECONDS = 60 * 30; @@ -818,9 +804,8 @@ app.on('ready', function() { if (dsPath && acPath) { domainServer = new Process('domain-server', dsPath, ["--get-temp-name"], logPath); acMonitor = new ACMonitorProcess('ac-monitor', acPath, ['-n6', - '--log-directory', logPath, - '--http-status-port', httpStatusPort - ], httpStatusPort, logPath); + '--log-directory', logPath, + '--http-status-port', httpStatusPort], httpStatusPort, logPath); homeServer = new ProcessGroup('home', [domainServer, acMonitor]); logWindow = new LogWindow(acMonitor, domainServer); @@ -829,12 +814,10 @@ app.on('ready', function() { }; // handle process updates - homeServer.on('state-update', function(processGroup) { - updateTrayMenu(processGroup.state); - }); + homeServer.on('state-update', function(processGroup) { updateTrayMenu(processGroup.state); }); // start the home server homeServer.start(); } }); -}); \ No newline at end of file +}); From f409127f1dc88a928d5b553c26b7e2ced5660ff6 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Sat, 12 Mar 2016 12:18:54 -0800 Subject: [PATCH 45/77] start --- server-console/src/main.js | 187 +++++++++++++++++++------------------ 1 file changed, 97 insertions(+), 90 deletions(-) diff --git a/server-console/src/main.js b/server-console/src/main.js index e05106aa6f..c17c959320 100644 --- a/server-console/src/main.js +++ b/server-console/src/main.js @@ -477,118 +477,125 @@ function performContentMigration() { var logWindow = null; + +var labels = { + serverRunningState: { + label: 'Server - Stopped', + enabled: false + }, + version: { + label: 'Version - ' + buildInfo.buildIdentifier, + }, + startServer: { + label: 'Start Server', + click: function() { + homeServer.restart(); + } + }, + stopServer: { + label: 'Stop Server', + visible: false, + click: function() { + homeServer.stop(); + } + }, + + goHome: { + label: 'Go Home', + click: goHomeClicked, + enabled: false + }, + quit: { + label: 'Quit', + accelerator: 'Command+Q', + click: function() { + shutdown(); + } + }, + + settings: { + label: 'Settings', + click: function() { + shell.openExternal('http://localhost:40100/settings'); + }, + enabled: false + }, + viewLogs: { + label: 'View Logs', + click: function() { + logWindow.open(); + } + }, + migrateContent: { + label: 'Migrate Stack Manager Content', + click: function() { + promptToMigrateContent(); + } + }, + shuttingDown: { + label: "Shutting down...", + enabled: false + }, +} + +var separator = { + type: 'separator' +}; + + function buildMenuArray(serverState) { - var menuArray = null; + + updateLabels(serverState); + + var menuArray = []; if (isShuttingDown) { - menuArray = [ - { - label: "Shutting down...", - enabled: false - } - ]; + menuArray.push(labels.shuttingDown); } else { - menuArray = [ - { - label: 'Server - Stopped', - enabled: false - }, - { - type: 'separator' - }, - { - label: 'Go Home', - click: goHomeClicked, - enabled: false - }, - { - type: 'separator' - }, - { - label: 'Start Server', - click: function() { homeServer.restart(); } - }, - { - label: 'Stop Server', - visible: false, - click: function() { homeServer.stop(); } - }, - { - label: 'Settings', - click: function() { shell.openExternal('http://localhost:40100/settings'); }, - enabled: false - }, - { - label: 'View Logs', - click: function() { logWindow.open(); } - }, - { - type: 'separator' - }, - { - label: 'Share', - click: function() { shell.openExternal('http://localhost:40100/settings/?action=share') } - }, - { - type: 'separator' - }, - { - label: 'Quit', - accelerator: 'Command+Q', - click: function() { shutdown(); } - } - ]; + menuArray.push(labels.stopped); + // menuArray.push(version); + menuArray.push(separator); + menuArray.push(labels.goHome); + menuArray.push(separator); + menuArray.push(labels.startServer); + menuArray.push(labels.stopServer); + menuArray.push(labels.settings); + menuArray.push(labels.logs); + menuArray.push(separator); + menuArray.push(labels.share); + menuArray.push(separator); + menuArray.push(labels.quit); var foundStackManagerContent = isStackManagerContentPresent(); if (foundStackManagerContent) { // add a separator and the stack manager content migration option - menuArray.splice(menuArray.length - 1, 0, { - label: 'Migrate Stack Manager Content', - click: function() { promptToMigrateContent(); } - }, { - type: 'separator' - }); + menuArray.splice(menuArray.length - 1, 0, labels.migrateContent, separator); } - updateMenuArray(menuArray, serverState); } return menuArray; + } -const GO_HOME_INDEX = 2; -const SERVER_LABEL_INDEX = 0; -const RESTART_INDEX = 4; -const STOP_INDEX = 5; -const SETTINGS_INDEX = 6; +function updateLabels(serverState) { -function updateMenuArray(menuArray, serverState) { // update the tray menu state var running = serverState == ProcessGroupStates.STARTED; - var serverLabelItem = menuArray[SERVER_LABEL_INDEX]; - var restartItem = menuArray[RESTART_INDEX]; - - // Go Home is only enabled if running - menuArray[GO_HOME_INDEX].enabled = running; - - // Stop is only visible if running - menuArray[STOP_INDEX].visible = running; - - // Settings is only visible if running - menuArray[SETTINGS_INDEX].enabled = running; - + labels.goHome.enabled = running; + labels.stop.visible = running; + labels.settings.enabled = running; if (serverState == ProcessGroupStates.STARTED) { - serverLabelItem.label = "Server - Started"; - restartItem.label = "Restart Server"; + labels.serverState.label = "Server - Started"; + labels.restart.label = "Restart Server"; } else if (serverState == ProcessGroupStates.STOPPED) { - serverLabelItem.label = "Server - Stopped"; - restartItem.label = "Start Server"; + labels.serverState.label = "Server - Stopped"; + labels.restart.label = "Start Server"; } else if (serverState == ProcessGroupStates.STOPPING) { - serverLabelItem.label = "Server - Stopping"; - - restartItem.label = "Restart Server"; - restartItem.enabled = false; + labels.serverState.label = "Server - Stopping"; + labels.restart.label = "Restart Server"; + labels.restart.enabled = false; } } From f1992af38e3d682719a3eaf10c1048848794d737 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 12 Mar 2016 10:13:13 -0800 Subject: [PATCH 46/77] started to add grabbable psuedo properties to edit.js --- examples/attachedEntitiesManager.js | 1 - examples/controllers/handControllerGrab.js | 8 +-- examples/html/entityProperties.html | 60 +++++++++++++++++++--- 3 files changed, 56 insertions(+), 13 deletions(-) diff --git a/examples/attachedEntitiesManager.js b/examples/attachedEntitiesManager.js index 4dda76f4df..ef85f8cb98 100644 --- a/examples/attachedEntitiesManager.js +++ b/examples/attachedEntitiesManager.js @@ -213,7 +213,6 @@ function AttachedEntitiesManager() { var props = Entities.getEntityProperties(entityID); if (props.parentID == MyAvatar.sessionUUID) { grabData = getEntityCustomData('grabKey', entityID, {}); - grabbableData = getEntityCustomData('grabbableKey', entityID, {}); var wearableData = getEntityCustomData('wearable', entityID, DEFAULT_WEARABLE_DATA); var currentJointName = MyAvatar.getJointNames()[props.parentJointIndex]; wearableData.joints[currentJointName] = [props.localPosition, props.localRotation]; diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 964fca4136..43c18da72d 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -1006,7 +1006,7 @@ function MyController(hand) { // else this thing isn't physical. grab it by reparenting it (but not if we've already // grabbed it). - if (grabbableData.refCount < 1) { + if (refCount < 1) { this.setState(this.state == STATE_SEARCHING ? STATE_NEAR_GRABBING : STATE_EQUIP); return; } else { @@ -1120,7 +1120,6 @@ function MyController(hand) { var controllerRotation = Quat.multiply(MyAvatar.orientation, avatarControllerPose.rotation); var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); - var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); if (this.state == STATE_CONTINUE_DISTANCE_HOLDING && this.bumperSqueezed() && this.hasPresetOffsets()) { @@ -1307,7 +1306,6 @@ function MyController(hand) { this.nearGrabbing = function() { var now = Date.now(); - var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); if (this.state == STATE_NEAR_GRABBING && this.triggerSmoothedReleased()) { this.setState(STATE_RELEASE); @@ -1330,10 +1328,9 @@ function MyController(hand) { var handRotation = (this.hand === RIGHT_HAND) ? MyAvatar.getRightPalmRotation() : MyAvatar.getLeftPalmRotation(); var handPosition = this.getHandPosition(); - var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); - var hasPresetPosition = false; if (this.state != STATE_NEAR_GRABBING && this.hasPresetOffsets()) { + var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); // if an object is "equipped" and has a predefined offset, use it. this.ignoreIK = grabbableData.ignoreIK ? grabbableData.ignoreIK : false; this.offsetPosition = this.getPresetPosition(); @@ -1676,7 +1673,6 @@ function MyController(hand) { }; this.activateEntity = function(entityID, grabbedProperties, wasLoaded) { - var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, entityID, DEFAULT_GRABBABLE_DATA); var data = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, {}); var now = Date.now(); diff --git a/examples/html/entityProperties.html b/examples/html/entityProperties.html index 1101a08acb..92df997ac2 100644 --- a/examples/html/entityProperties.html +++ b/examples/html/entityProperties.html @@ -243,6 +243,21 @@ } + function createUserDataChanger(groupName, keyName, propertyElement, userData) { + return function() { + var properties = {}; + // // this.checked + // properties['userData'] = ... JSON.stringify (...) + // EventBridge.emitWebEvent( + // JSON.stringify({ + // type: "update", + // properties: properties, + // }) + // ); + } + }; + + function loaded() { openEventBridge(function() { var allSections = []; @@ -305,6 +320,11 @@ var elCollideMyAvatar = document.getElementById("property-collide-myAvatar"); var elCollideOtherAvatar = document.getElementById("property-collide-otherAvatar"); var elCollisionSoundURL = document.getElementById("property-collision-sound-url"); + + var elGrabbable = document.getElementById("property-grabbable" ); + var elWantsTrigger = document.getElementById("property-wants-trigger" ); + var elIgnoreIK = document.getElementById("property-ignore-ik" ); + var elLifetime = document.getElementById("property-lifetime"); var elScriptURL = document.getElementById("property-script-url"); var elScriptTimestamp = document.getElementById("property-script-timestamp"); @@ -408,7 +428,7 @@ var elXTextureURL = document.getElementById("property-x-texture-url"); var elYTextureURL = document.getElementById("property-y-texture-url"); var elZTextureURL = document.getElementById("property-z-texture-url"); - + var elPreviewCameraButton = document.getElementById("preview-camera-button"); if (window.EventBridge !== undefined) { @@ -518,13 +538,15 @@ elCollisionless.checked = properties.collisionless; elDynamic.checked = properties.dynamic; - elCollideStatic.checked = properties.collidesWith.indexOf("static") > -1; elCollideKinematic.checked = properties.collidesWith.indexOf("kinematic") > -1; elCollideDynamic.checked = properties.collidesWith.indexOf("dynamic") > -1; elCollideMyAvatar.checked = properties.collidesWith.indexOf("myAvatar") > -1; elCollideOtherAvatar.checked = properties.collidesWith.indexOf("otherAvatar") > -1; + elGrabbable.checked = properties.collidesWith.indexOf("grabbable") > -1; + elWantsTrigger.checked = properties.collidesWith.indexOf("wantsTrigger") > -1; + elIgnoreIK.checked = properties.collidesWith.indexOf("ignoreIK") > -1; elCollisionSoundURL.value = properties.collisionSoundURL; elLifetime.value = properties.lifetime; @@ -737,9 +759,6 @@ elCollisionless.addEventListener('change', createEmitCheckedPropertyUpdateFunction('collisionless')); elDynamic.addEventListener('change', createEmitCheckedPropertyUpdateFunction('dynamic')); - - - elCollideDynamic.addEventListener('change', function() { updateCheckedSubProperty("collidesWith", properties.collidesWith, elCollideDynamic, 'dynamic'); }); @@ -758,6 +777,12 @@ updateCheckedSubProperty("collidesWith", properties.collidesWith, elCollideOtherAvatar, 'otherAvatar'); }); + elGrabbable.addEventListener('change', createUserDataChanger("grabbableKey", "grabbable", + elGrabbable, properties.userData)); + elWantsTrigger.addEventListener('change', createUserDataChanger("grabbableKey", "wantsTrigger", + elWantsTrigger, properties.userData)); + elIgnoreIK.addEventListener('change', createUserDataChanger("grabbableKey", "ignoreIK", + elIgnoreIK, properties.userData)); elCollisionSoundURL.addEventListener('change', createEmitTextPropertyUpdateFunction('collisionSoundURL')); @@ -954,7 +979,7 @@ action: "previewCamera" })); }); - + window.onblur = function() { // Fake a change event var ev = document.createEvent("HTMLEvents"); @@ -1476,6 +1501,29 @@ +
Grabbable:
+
+
+ grabbable + + + +
+ +
+ triggerable + + + +
+ +
+ ignore inverse-kinematics + + + +
+
From be51040420e363394bb1c3aa1cc5da8874a2ae54 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 12 Mar 2016 13:17:42 -0800 Subject: [PATCH 47/77] grabbable controlls are working --- examples/html/entityProperties.html | 73 ++++++++++++++++++++--------- 1 file changed, 50 insertions(+), 23 deletions(-) diff --git a/examples/html/entityProperties.html b/examples/html/entityProperties.html index 92df997ac2..cdba00d245 100644 --- a/examples/html/entityProperties.html +++ b/examples/html/entityProperties.html @@ -243,18 +243,26 @@ } - function createUserDataChanger(groupName, keyName, propertyElement, userData) { - return function() { - var properties = {}; - // // this.checked - // properties['userData'] = ... JSON.stringify (...) - // EventBridge.emitWebEvent( - // JSON.stringify({ - // type: "update", - // properties: properties, - // }) - // ); + function userDataChanger(groupName, keyName, checkBoxElement, userDataElement) { + var properties = {}; + var parsedData = {}; + try { + parsedData = JSON.parse(userDataElement.value); + } catch(e) {} + + if (!(groupName in parsedData)) { + parsedData[groupName] = {} } + parsedData[groupName][keyName] = checkBoxElement.checked; + properties['userData'] = JSON.stringify(parsedData); + userDataElement.value = properties['userData']; + + EventBridge.emitWebEvent( + JSON.stringify({ + type: "update", + properties: properties, + }) + ); }; @@ -321,9 +329,9 @@ var elCollideOtherAvatar = document.getElementById("property-collide-otherAvatar"); var elCollisionSoundURL = document.getElementById("property-collision-sound-url"); - var elGrabbable = document.getElementById("property-grabbable" ); - var elWantsTrigger = document.getElementById("property-wants-trigger" ); - var elIgnoreIK = document.getElementById("property-ignore-ik" ); + var elGrabbable = document.getElementById("property-grabbable"); + var elWantsTrigger = document.getElementById("property-wants-trigger"); + var elIgnoreIK = document.getElementById("property-ignore-ik"); var elLifetime = document.getElementById("property-lifetime"); var elScriptURL = document.getElementById("property-script-url"); @@ -544,9 +552,25 @@ elCollideMyAvatar.checked = properties.collidesWith.indexOf("myAvatar") > -1; elCollideOtherAvatar.checked = properties.collidesWith.indexOf("otherAvatar") > -1; - elGrabbable.checked = properties.collidesWith.indexOf("grabbable") > -1; - elWantsTrigger.checked = properties.collidesWith.indexOf("wantsTrigger") > -1; - elIgnoreIK.checked = properties.collidesWith.indexOf("ignoreIK") > -1; + elGrabbable.checked = false; + elWantsTrigger.checked = false; + elIgnoreIK.checked = false; + var parsedUserData = {} + try { + debugPrint("OKOKOK:" + properties.userData); + parsedUserData = JSON.parse(properties.userData); + } catch(e) {} + if ("grabbableKey" in parsedUserData) { + if (parsedUserData["grabbableKey"].grabbable) { + elGrabbable.checked = true; + } + if (parsedUserData["grabbableKey"].wantsTrigger) { + elWantsTrigger.checked = true; + } + if (parsedUserData["grabbableKey"].ignoreIK) { + elIgnoreIK.checked = true; + } + } elCollisionSoundURL.value = properties.collisionSoundURL; elLifetime.value = properties.lifetime; @@ -777,12 +801,15 @@ updateCheckedSubProperty("collidesWith", properties.collidesWith, elCollideOtherAvatar, 'otherAvatar'); }); - elGrabbable.addEventListener('change', createUserDataChanger("grabbableKey", "grabbable", - elGrabbable, properties.userData)); - elWantsTrigger.addEventListener('change', createUserDataChanger("grabbableKey", "wantsTrigger", - elWantsTrigger, properties.userData)); - elIgnoreIK.addEventListener('change', createUserDataChanger("grabbableKey", "ignoreIK", - elIgnoreIK, properties.userData)); + elGrabbable.addEventListener('change', function() { + userDataChanger("grabbableKey", "grabbable", elGrabbable, elUserData); + }); + elWantsTrigger.addEventListener('change', function() { + userDataChanger("grabbableKey", "wantsTrigger", elWantsTrigger, elUserData); + }); + elIgnoreIK.addEventListener('change', function() { + userDataChanger("grabbableKey", "ignoreIK", elIgnoreIK, elUserData); + }); elCollisionSoundURL.addEventListener('change', createEmitTextPropertyUpdateFunction('collisionSoundURL')); From 50e7bd77424580f972f2507572d631dd4541555f Mon Sep 17 00:00:00 2001 From: James Pollack Date: Sat, 12 Mar 2016 13:42:18 -0800 Subject: [PATCH 48/77] claenup --- server-console/src/main.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/server-console/src/main.js b/server-console/src/main.js index c17c959320..a90080e3b4 100644 --- a/server-console/src/main.js +++ b/server-console/src/main.js @@ -479,14 +479,14 @@ var logWindow = null; var labels = { - serverRunningState: { + serverState: { label: 'Server - Stopped', enabled: false }, version: { label: 'Version - ' + buildInfo.buildIdentifier, }, - startServer: { + restart: { label: 'Start Server', click: function() { homeServer.restart(); @@ -584,7 +584,7 @@ function updateLabels(serverState) { var running = serverState == ProcessGroupStates.STARTED; labels.goHome.enabled = running; - labels.stop.visible = running; + labels.stopServer.visible = running; labels.settings.enabled = running; if (serverState == ProcessGroupStates.STARTED) { labels.serverState.label = "Server - Started"; From cca4a93b2b604b036588e32135d8062f251e5057 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 12 Mar 2016 14:09:52 -0800 Subject: [PATCH 49/77] don't full up userData with default grabbable data --- examples/html/entityProperties.html | 46 ++++++++++++++++++++--------- 1 file changed, 32 insertions(+), 14 deletions(-) diff --git a/examples/html/entityProperties.html b/examples/html/entityProperties.html index cdba00d245..ae42ea7caf 100644 --- a/examples/html/entityProperties.html +++ b/examples/html/entityProperties.html @@ -243,7 +243,13 @@ } - function userDataChanger(groupName, keyName, checkBoxElement, userDataElement) { + function isGrabbableByDefault(properties) { + return properties.type == "Box" || + properties.type == "Sphere" || + properties.dynamic + } + + function userDataChanger(groupName, keyName, checkBoxElement, userDataElement, defaultValue) { var properties = {}; var parsedData = {}; try { @@ -253,8 +259,20 @@ if (!(groupName in parsedData)) { parsedData[groupName] = {} } - parsedData[groupName][keyName] = checkBoxElement.checked; - properties['userData'] = JSON.stringify(parsedData); + delete parsedData[groupName][keyName]; + if (checkBoxElement.checked !== defaultValue) { + parsedData[groupName][keyName] = checkBoxElement.checked; + } + + if (Object.keys(parsedData[groupName]).length == 0) { + delete parsedData[groupName]; + } + if (Object.keys(parsedData).length > 0) { + properties['userData'] = JSON.stringify(parsedData); + } else { + properties['userData'] = ''; + } + userDataElement.value = properties['userData']; EventBridge.emitWebEvent( @@ -552,23 +570,23 @@ elCollideMyAvatar.checked = properties.collidesWith.indexOf("myAvatar") > -1; elCollideOtherAvatar.checked = properties.collidesWith.indexOf("otherAvatar") > -1; - elGrabbable.checked = false; + // boxes and sphere are grabbable by default + elGrabbable.checked = isGrabbableByDefault(properties); elWantsTrigger.checked = false; elIgnoreIK.checked = false; var parsedUserData = {} try { - debugPrint("OKOKOK:" + properties.userData); parsedUserData = JSON.parse(properties.userData); } catch(e) {} if ("grabbableKey" in parsedUserData) { - if (parsedUserData["grabbableKey"].grabbable) { - elGrabbable.checked = true; + if ("grabbable" in parsedUserData["grabbableKey"]) { + elGrabbable.checked = parsedUserData["grabbableKey"].grabbable; } - if (parsedUserData["grabbableKey"].wantsTrigger) { - elWantsTrigger.checked = true; + if ("wantsTrigger" in parsedUserData["grabbableKey"]) { + elWantsTrigger.checked = parsedUserData["grabbableKey"].wantsTrigger; } - if (parsedUserData["grabbableKey"].ignoreIK) { - elIgnoreIK.checked = true; + if ("ignoreIK" in parsedUserData["grabbableKey"]) { + elIgnoreIK.checked = parsedUserData["grabbableKey"].ignoreIK; } } @@ -802,13 +820,13 @@ }); elGrabbable.addEventListener('change', function() { - userDataChanger("grabbableKey", "grabbable", elGrabbable, elUserData); + userDataChanger("grabbableKey", "grabbable", elGrabbable, elUserData, isGrabbableByDefault(properties)); }); elWantsTrigger.addEventListener('change', function() { - userDataChanger("grabbableKey", "wantsTrigger", elWantsTrigger, elUserData); + userDataChanger("grabbableKey", "wantsTrigger", elWantsTrigger, elUserData, false); }); elIgnoreIK.addEventListener('change', function() { - userDataChanger("grabbableKey", "ignoreIK", elIgnoreIK, elUserData); + userDataChanger("grabbableKey", "ignoreIK", elIgnoreIK, elUserData, false); }); elCollisionSoundURL.addEventListener('change', createEmitTextPropertyUpdateFunction('collisionSoundURL')); From ea95295e662d36f3c63f3cf67134354b4c5d40cf Mon Sep 17 00:00:00 2001 From: Anthony Thibault Date: Sat, 12 Mar 2016 14:52:26 -0800 Subject: [PATCH 50/77] ApplicationOveraly: Fix for gray line at top of HMD UI overlay --- interface/src/ui/ApplicationOverlay.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index 14a3475610..54b56ea4f8 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -284,7 +284,8 @@ void ApplicationOverlay::buildFramebufferObject() { // If the overlay framebuffer still has no color attachment, no textures were available for rendering, so build a new one if (!_overlayFramebuffer->getRenderBuffer(0)) { - auto colorBuffer = gpu::TexturePointer(gpu::Texture::create2D(COLOR_FORMAT, width, height, DEFAULT_SAMPLER)); + const gpu::Sampler OVERLAY_SAMPLER(gpu::Sampler::FILTER_MIN_MAG_LINEAR, gpu::Sampler::WRAP_CLAMP); + auto colorBuffer = gpu::TexturePointer(gpu::Texture::create2D(COLOR_FORMAT, width, height, OVERLAY_SAMPLER)); _overlayFramebuffer->setRenderBuffer(0, colorBuffer); } } From 03a109b60f1000e0562ad719732ebb535b26dbad Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Sat, 12 Mar 2016 14:54:10 -0800 Subject: [PATCH 51/77] menu --- server-console/src/main.js | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/server-console/src/main.js b/server-console/src/main.js index a90080e3b4..5fc373b070 100644 --- a/server-console/src/main.js +++ b/server-console/src/main.js @@ -477,14 +477,14 @@ function performContentMigration() { var logWindow = null; - var labels = { serverState: { label: 'Server - Stopped', enabled: false }, version: { - label: 'Version - ' + buildInfo.buildIdentifier, + label: 'Version - ' + buildInfo.buildIdentifier, + enabled: false }, restart: { label: 'Start Server', @@ -499,7 +499,6 @@ var labels = { homeServer.stop(); } }, - goHome: { label: 'Go Home', click: goHomeClicked, @@ -512,7 +511,6 @@ var labels = { shutdown(); } }, - settings: { label: 'Settings', click: function() { @@ -526,6 +524,12 @@ var labels = { logWindow.open(); } }, + share: { + label: 'Share', + click: function() { + shell.openExternal('http://localhost:40100/settings/?action=share') + } + }, migrateContent: { label: 'Migrate Stack Manager Content', click: function() { @@ -552,15 +556,15 @@ function buildMenuArray(serverState) { if (isShuttingDown) { menuArray.push(labels.shuttingDown); } else { - menuArray.push(labels.stopped); - // menuArray.push(version); + menuArray.push(labels.serverState); + menuArray.push(labels.version); menuArray.push(separator); menuArray.push(labels.goHome); menuArray.push(separator); - menuArray.push(labels.startServer); + menuArray.push(labels.restart); menuArray.push(labels.stopServer); menuArray.push(labels.settings); - menuArray.push(labels.logs); + menuArray.push(labels.viewLogs); menuArray.push(separator); menuArray.push(labels.share); menuArray.push(separator); @@ -574,6 +578,7 @@ function buildMenuArray(serverState) { } + return menuArray; } From 98d4f34d642bfade7b9c51e0bb4c720d97036b24 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Sat, 12 Mar 2016 14:59:54 -0800 Subject: [PATCH 52/77] enable --- server-console/src/main.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/server-console/src/main.js b/server-console/src/main.js index 5fc373b070..d75dda182f 100644 --- a/server-console/src/main.js +++ b/server-console/src/main.js @@ -587,7 +587,8 @@ function updateLabels(serverState) { // update the tray menu state var running = serverState == ProcessGroupStates.STARTED; - + console.log('RUNNING??? ' + running) + console.log('SERVERSTATE?' + serverState) labels.goHome.enabled = running; labels.stopServer.visible = running; labels.settings.enabled = running; @@ -597,6 +598,7 @@ function updateLabels(serverState) { } else if (serverState == ProcessGroupStates.STOPPED) { labels.serverState.label = "Server - Stopped"; labels.restart.label = "Start Server"; + labels.restart.enabled = true; } else if (serverState == ProcessGroupStates.STOPPING) { labels.serverState.label = "Server - Stopping"; labels.restart.label = "Restart Server"; From b929089af7644977621f13fc8a3ff06b5b4cd837 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Sat, 12 Mar 2016 15:01:34 -0800 Subject: [PATCH 53/77] options --- server-console/src/main.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/server-console/src/main.js b/server-console/src/main.js index d75dda182f..18cffdb81b 100644 --- a/server-console/src/main.js +++ b/server-console/src/main.js @@ -587,8 +587,6 @@ function updateLabels(serverState) { // update the tray menu state var running = serverState == ProcessGroupStates.STARTED; - console.log('RUNNING??? ' + running) - console.log('SERVERSTATE?' + serverState) labels.goHome.enabled = running; labels.stopServer.visible = running; labels.settings.enabled = running; From 96bc17cd5ee84dda5f2a9c7280b2c8befcada4cd Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Sat, 12 Mar 2016 16:01:10 -0800 Subject: [PATCH 54/77] Update photo_sphere.js --- examples/data_visualization/photo_sphere.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/data_visualization/photo_sphere.js b/examples/data_visualization/photo_sphere.js index d8be423bd7..c62fb7d122 100644 --- a/examples/data_visualization/photo_sphere.js +++ b/examples/data_visualization/photo_sphere.js @@ -8,7 +8,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -var photoSphere, light;; +var photoSphere, light; //equirectangular var url = 'http://hifi-content.s3.amazonaws.com/james/projection_objects/IMG_9167.JPG'; @@ -57,4 +57,4 @@ function cleanup() { Script.scriptEnding.connect(cleanup); createPhotoSphere(); -createLight(); \ No newline at end of file +createLight(); From 27ecdffeb304f289a3e3e9c3577997e642484359 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Sat, 12 Mar 2016 16:46:15 -0800 Subject: [PATCH 55/77] Fix iDate uniform in procedurals to be continuous --- libraries/procedural/src/procedural/Procedural.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/procedural/src/procedural/Procedural.cpp b/libraries/procedural/src/procedural/Procedural.cpp index 922d466d42..9b8d0fe294 100644 --- a/libraries/procedural/src/procedural/Procedural.cpp +++ b/libraries/procedural/src/procedural/Procedural.cpp @@ -374,7 +374,8 @@ void Procedural::setupUniforms() { v.y = date.month() - 1; // But not the day... go figure v.z = date.day(); - v.w = (time.hour() * 3600) + (time.minute() * 60) + time.second(); + float fractSeconds = (time.msec() / 1000.0f); + v.w = (time.hour() * 3600) + (time.minute() * 60) + time.second() + fractSeconds; batch._glUniform(_standardUniformSlots[DATE], v); }); } From 27033e5bb513b9f486cf48ea6648c4ce14439355 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Sat, 12 Mar 2016 21:48:36 -0800 Subject: [PATCH 56/77] Fix vive crash on deactivate --- plugins/openvr/src/OpenVrDisplayPlugin.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/plugins/openvr/src/OpenVrDisplayPlugin.cpp b/plugins/openvr/src/OpenVrDisplayPlugin.cpp index 4568d670c6..47b3e233cf 100644 --- a/plugins/openvr/src/OpenVrDisplayPlugin.cpp +++ b/plugins/openvr/src/OpenVrDisplayPlugin.cpp @@ -86,13 +86,16 @@ void OpenVrDisplayPlugin::activate() { } void OpenVrDisplayPlugin::deactivate() { + // Base class deactivate must come before our local deactivate + // because the OpenGL base class handles the wait for the present + // thread before continuing + HmdDisplayPlugin::deactivate(); _container->setIsOptionChecked(StandingHMDSensorMode, false); if (_system) { releaseOpenVrSystem(); _system = nullptr; } _compositor = nullptr; - HmdDisplayPlugin::deactivate(); } void OpenVrDisplayPlugin::customizeContext() { From 0a2fb77698143db3e61776484998fada944c610e Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sun, 13 Mar 2016 07:04:50 -0700 Subject: [PATCH 57/77] delete child entities when parent is deleted --- .../src/entities/EntityServer.cpp | 12 ++++++++++ assignment-client/src/entities/EntityServer.h | 2 ++ assignment-client/src/octree/OctreeServer.h | 4 ++-- libraries/entities/src/EntityTree.cpp | 23 +++++++++++++++++++ libraries/entities/src/EntityTree.h | 11 +++++++-- 5 files changed, 48 insertions(+), 4 deletions(-) diff --git a/assignment-client/src/entities/EntityServer.cpp b/assignment-client/src/entities/EntityServer.cpp index b177d2a9a0..867412f6c0 100644 --- a/assignment-client/src/entities/EntityServer.cpp +++ b/assignment-client/src/entities/EntityServer.cpp @@ -272,6 +272,18 @@ void EntityServer::readAdditionalConfiguration(const QJsonObject& settingsSectio tree->setWantTerseEditLogging(wantTerseEditLogging); } +void EntityServer::nodeAdded(SharedNodePointer node) { + EntityTreePointer tree = std::static_pointer_cast(_tree); + tree->knowAvatarID(node->getUUID()); + OctreeServer::nodeAdded(node); +} + +void EntityServer::nodeKilled(SharedNodePointer node) { + EntityTreePointer tree = std::static_pointer_cast(_tree); + tree->deleteDescendantsOfAvatar(node->getUUID()); + tree->forgetAvatarID(node->getUUID()); + OctreeServer::nodeKilled(node); +} // FIXME - this stats tracking is somewhat temporary to debug the Whiteboard issues. It's not a bad // set of stats to have, but we'd probably want a different data structure if we keep it very long. diff --git a/assignment-client/src/entities/EntityServer.h b/assignment-client/src/entities/EntityServer.h index 74057bfa5d..ec58cda6cd 100644 --- a/assignment-client/src/entities/EntityServer.h +++ b/assignment-client/src/entities/EntityServer.h @@ -58,6 +58,8 @@ public: virtual void trackViewerGone(const QUuid& sessionID) override; public slots: + virtual void nodeAdded(SharedNodePointer node); + virtual void nodeKilled(SharedNodePointer node); void pruneDeletedEntities(); protected: diff --git a/assignment-client/src/octree/OctreeServer.h b/assignment-client/src/octree/OctreeServer.h index 1430715571..c96c4bb5ad 100644 --- a/assignment-client/src/octree/OctreeServer.h +++ b/assignment-client/src/octree/OctreeServer.h @@ -127,8 +127,8 @@ public: public slots: /// runs the octree server assignment void run(); - void nodeAdded(SharedNodePointer node); - void nodeKilled(SharedNodePointer node); + virtual void nodeAdded(SharedNodePointer node); + virtual void nodeKilled(SharedNodePointer node); void sendStatsPacket(); private slots: diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 4c3412edd3..416fc5add3 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -448,6 +448,18 @@ void EntityTree::processRemovedEntities(const DeleteEntityOperator& theOperator) const RemovedEntities& entities = theOperator.getEntities(); foreach(const EntityToDeleteDetails& details, entities) { EntityItemPointer theEntity = details.entity; + + qDebug() << "processRemovedEntities on " << theEntity->getID() << theEntity->getName(); + if (getIsServer()) { + QSet childrenIDs; + theEntity->forEachChild([&](SpatiallyNestablePointer child) { + if (child->getNestableType() == NestableType::Entity) { + childrenIDs += child->getID(); + } + }); + deleteEntities(childrenIDs, true, true); + } + theEntity->die(); if (getIsServer()) { @@ -1000,6 +1012,10 @@ void EntityTree::fixupMissingParents() { moveOperator.addEntityToMoveList(entity, newCube); iter.remove(); entity->markAncestorMissing(false); + } else if (_avatarIDs.contains(entity->getParentID())) { + _childrenOfAvatars[entity->getParentID()] += entity->getEntityItemID(); + iter.remove(); + entity->markAncestorMissing(false); } } else { // entity was deleted before we found its parent. @@ -1014,6 +1030,13 @@ void EntityTree::fixupMissingParents() { } +void EntityTree::deleteDescendantsOfAvatar(QUuid avatarID) { + if (_childrenOfAvatars.contains(avatarID)) { + deleteEntities(_childrenOfAvatars[avatarID]); + _childrenOfAvatars.remove(avatarID); + } +} + void EntityTree::update() { fixupMissingParents(); if (_simulation) { diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index 8190f7225b..1c5a696b17 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -241,6 +241,10 @@ public: Q_INVOKABLE int getJointIndex(const QUuid& entityID, const QString& name) const; Q_INVOKABLE QStringList getJointNames(const QUuid& entityID) const; + void knowAvatarID(QUuid avatarID) { _avatarIDs += avatarID; } + void forgetAvatarID(QUuid avatarID) { _avatarIDs -= avatarID; } + void deleteDescendantsOfAvatar(QUuid avatarID); + public slots: void callLoader(EntityItemID entityID); @@ -313,8 +317,11 @@ protected: quint64 _maxEditDelta = 0; quint64 _treeResetTime = 0; - void fixupMissingParents(); - QVector _missingParent; + void fixupMissingParents(); // try to hook members of _missingParent to parent instances + QVector _missingParent; // entites with a parentID but no (yet) known parent instance + // we maintain a list of avatarIDs to notice when an entity is a child of one. + QSet _avatarIDs; // IDs of avatars connected to entity server + QHash> _childrenOfAvatars; // which entities are children of which avatars }; #endif // hifi_EntityTree_h From 415f21c189a7dbf79530fda644161036afba3641 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sun, 13 Mar 2016 08:35:21 -0700 Subject: [PATCH 58/77] be more aggressive about putting entities into the missing-its-parent list --- libraries/entities/src/EntityTree.cpp | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 416fc5add3..82cef91ca5 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -86,6 +86,11 @@ void EntityTree::postAddEntity(EntityItemPointer entity) { if (_simulation) { _simulation->addEntity(entity); } + + if (!entity->isParentIDValid()) { + _missingParent.append(entity); + } + _isDirty = true; maybeNotifyNewCollisionSoundURL("", entity->getCollisionSoundURL()); emit addingEntity(entity->getEntityItemID()); @@ -252,6 +257,9 @@ bool EntityTree::updateEntityWithElement(EntityItemPointer entity, const EntityI _missingParent.append(childEntity); continue; } + if (!childEntity->isParentIDValid()) { + _missingParent.append(childEntity); + } UpdateEntityOperator theChildOperator(getThisPointer(), containingElement, childEntity, queryCube); recurseTreeWithOperator(&theChildOperator); @@ -1004,15 +1012,20 @@ void EntityTree::fixupMissingParents() { EntityItemWeakPointer entityWP = iter.next(); EntityItemPointer entity = entityWP.lock(); if (entity) { - bool success; - AACube newCube = entity->getQueryAACube(success); - if (success) { - // this entity's parent (or ancestry) was previously not fully known, and now is. Update its - // location in the EntityTree. + if (entity->isParentIDValid()) { + // this entity's parent was previously not known, and now is. Update its location in the EntityTree... + bool success; + AACube newCube = entity->getQueryAACube(success); + if (!success) { + continue; + } moveOperator.addEntityToMoveList(entity, newCube); iter.remove(); entity->markAncestorMissing(false); } else if (_avatarIDs.contains(entity->getParentID())) { + if (!_childrenOfAvatars.contains(entity->getParentID())) { + _childrenOfAvatars[entity->getParentID()] = QSet(); + } _childrenOfAvatars[entity->getParentID()] += entity->getEntityItemID(); iter.remove(); entity->markAncestorMissing(false); From 7641b1e99d6d649e97da3795a18a36bc753e9480 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sun, 13 Mar 2016 08:45:23 -0700 Subject: [PATCH 59/77] remove debug print --- libraries/entities/src/EntityTree.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 82cef91ca5..34ed55e0bb 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -457,7 +457,6 @@ void EntityTree::processRemovedEntities(const DeleteEntityOperator& theOperator) foreach(const EntityToDeleteDetails& details, entities) { EntityItemPointer theEntity = details.entity; - qDebug() << "processRemovedEntities on " << theEntity->getID() << theEntity->getName(); if (getIsServer()) { QSet childrenIDs; theEntity->forEachChild([&](SpatiallyNestablePointer child) { From dbd548a8c70eae0bfaa20959711a4e1c20a22f97 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sun, 13 Mar 2016 11:01:11 -0700 Subject: [PATCH 60/77] fix a crash --- libraries/entities-renderer/src/EntityTreeRenderer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 39111dd3eb..cdd01d414e 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -141,7 +141,7 @@ void EntityTreeRenderer::update() { // check if the texture loaded and apply it if (!updated && ( (_pendingSkyboxTexture && (!_skyboxTexture || _skyboxTexture->isLoaded())) || - (_pendingAmbientTexture && (!_ambientTexture && _ambientTexture->isLoaded())))) { + (_pendingAmbientTexture && (!_ambientTexture || _ambientTexture->isLoaded())))) { applyZonePropertiesToScene(_bestZone); } From b921ac77574c58dcc89f58cebdeac7ad5b8e4d03 Mon Sep 17 00:00:00 2001 From: Anthony Thibault Date: Sun, 13 Mar 2016 11:32:48 -0700 Subject: [PATCH 61/77] MyAvatar: prevent roll and pitch in avatar via snapshot url. --- interface/src/avatar/MyAvatar.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 9302c3b47d..1754b0b8ff 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1787,7 +1787,7 @@ void MyAvatar::goToLocation(const glm::vec3& newPosition, << newOrientation.x << ", " << newOrientation.y << ", " << newOrientation.z << ", " << newOrientation.w; // orient the user to face the target - glm::quat quatOrientation = newOrientation; + glm::quat quatOrientation = cancelOutRollAndPitch(newOrientation); if (shouldFaceLocation) { quatOrientation = newOrientation * glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)); From 02b2281defcf2e42d2f2018dcd6aee434e562294 Mon Sep 17 00:00:00 2001 From: Anthony Thibault Date: Sun, 13 Mar 2016 16:51:57 -0700 Subject: [PATCH 62/77] AnimVarient.h: cppcheck fixes * make all constructors explicit. * remove static string comparison in assert. --- libraries/animation/src/AnimVariant.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/libraries/animation/src/AnimVariant.h b/libraries/animation/src/AnimVariant.h index 531e2c4a2d..3466013ff6 100644 --- a/libraries/animation/src/AnimVariant.h +++ b/libraries/animation/src/AnimVariant.h @@ -37,12 +37,12 @@ public: static const AnimVariant False; AnimVariant() : _type(Type::Bool) { memset(&_val, 0, sizeof(_val)); } - AnimVariant(bool value) : _type(Type::Bool) { _val.boolVal = value; } - AnimVariant(int value) : _type(Type::Int) { _val.intVal = value; } - AnimVariant(float value) : _type(Type::Float) { _val.floats[0] = value; } - AnimVariant(const glm::vec3& value) : _type(Type::Vec3) { *reinterpret_cast(&_val) = value; } - AnimVariant(const glm::quat& value) : _type(Type::Quat) { *reinterpret_cast(&_val) = value; } - AnimVariant(const QString& value) : _type(Type::String) { _stringVal = value; } + explicit AnimVariant(bool value) : _type(Type::Bool) { _val.boolVal = value; } + explicit AnimVariant(int value) : _type(Type::Int) { _val.intVal = value; } + explicit AnimVariant(float value) : _type(Type::Float) { _val.floats[0] = value; } + explicit AnimVariant(const glm::vec3& value) : _type(Type::Vec3) { *reinterpret_cast(&_val) = value; } + explicit AnimVariant(const glm::quat& value) : _type(Type::Quat) { *reinterpret_cast(&_val) = value; } + explicit AnimVariant(const QString& value) : _type(Type::String) { _stringVal = value; } bool isBool() const { return _type == Type::Bool; } bool isInt() const { return _type == Type::Int; } @@ -250,7 +250,7 @@ public: qCDebug(animation) << " " << pair.first << "=" << pair.second.getString(); break; default: - assert("AnimVariant::Type" == "valid"); + assert(("invalid AnimVariant::Type", false)); } } } From 11fcf00b2adb29f2fd679542130cf1a6b22c22b9 Mon Sep 17 00:00:00 2001 From: Anthony Thibault Date: Sun, 13 Mar 2016 16:55:34 -0700 Subject: [PATCH 63/77] AnimSkeleton.h: made single argument ctors explicit --- libraries/animation/src/AnimSkeleton.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/animation/src/AnimSkeleton.h b/libraries/animation/src/AnimSkeleton.h index fc246bc4c0..e2cd20d63e 100644 --- a/libraries/animation/src/AnimSkeleton.h +++ b/libraries/animation/src/AnimSkeleton.h @@ -23,8 +23,8 @@ public: using Pointer = std::shared_ptr; using ConstPointer = std::shared_ptr; - AnimSkeleton(const FBXGeometry& fbxGeometry); - AnimSkeleton(const std::vector& joints); + explicit AnimSkeleton(const FBXGeometry& fbxGeometry); + explicit AnimSkeleton(const std::vector& joints); int nameToJointIndex(const QString& jointName) const; const QString& getJointName(int jointIndex) const; int getNumJoints() const; From 9f305560841f5ccf77ad293edbef8350d4b82cc2 Mon Sep 17 00:00:00 2001 From: Anthony Thibault Date: Sun, 13 Mar 2016 17:17:34 -0700 Subject: [PATCH 64/77] libraries/animation: cppcheck fixes * Fix for potential bug in AnimLoop due to _maxFrameIndexHint being uninitialized. * made more single argument constructors explicit. --- libraries/animation/src/AnimExpression.h | 8 ++++---- libraries/animation/src/AnimInverseKinematics.h | 2 +- libraries/animation/src/AnimNodeLoader.h | 2 +- libraries/animation/src/AnimStateMachine.h | 2 +- libraries/animation/src/AnimationCache.h | 4 ++-- libraries/animation/src/AnimationLoop.cpp | 2 ++ libraries/animation/src/AnimationLoop.h | 2 +- libraries/animation/src/Rig.cpp | 12 +----------- libraries/animation/src/Rig.h | 1 + 9 files changed, 14 insertions(+), 21 deletions(-) diff --git a/libraries/animation/src/AnimExpression.h b/libraries/animation/src/AnimExpression.h index 468217f5b3..87fb3ca20c 100644 --- a/libraries/animation/src/AnimExpression.h +++ b/libraries/animation/src/AnimExpression.h @@ -21,7 +21,7 @@ class AnimExpression { public: friend class AnimTests; - AnimExpression(const QString& str); + explicit AnimExpression(const QString& str); protected: struct Token { enum Type { @@ -49,8 +49,8 @@ protected: Comma, Error }; - Token(Type type) : type {type} {} - Token(const QStringRef& strRef) : type {Type::Identifier}, strVal {strRef.toString()} {} + explicit Token(Type type) : type {type} {} + explicit Token(const QStringRef& strRef) : type {Type::Identifier}, strVal {strRef.toString()} {} explicit Token(int val) : type {Type::Int}, intVal {val} {} explicit Token(bool val) : type {Type::Bool}, intVal {val} {} explicit Token(float val) : type {Type::Float}, floatVal {val} {} @@ -82,7 +82,7 @@ protected: Modulus, UnaryMinus }; - OpCode(Type type) : type {type} {} + explicit OpCode(Type type) : type {type} {} explicit OpCode(const QStringRef& strRef) : type {Type::Identifier}, strVal {strRef.toString()} {} explicit OpCode(const QString& str) : type {Type::Identifier}, strVal {str} {} explicit OpCode(int val) : type {Type::Int}, intVal {val} {} diff --git a/libraries/animation/src/AnimInverseKinematics.h b/libraries/animation/src/AnimInverseKinematics.h index aeb718668a..182e7b3492 100644 --- a/libraries/animation/src/AnimInverseKinematics.h +++ b/libraries/animation/src/AnimInverseKinematics.h @@ -25,7 +25,7 @@ class RotationConstraint; class AnimInverseKinematics : public AnimNode { public: - AnimInverseKinematics(const QString& id); + explicit AnimInverseKinematics(const QString& id); virtual ~AnimInverseKinematics() override; void loadDefaultPoses(const AnimPoseVec& poses); diff --git a/libraries/animation/src/AnimNodeLoader.h b/libraries/animation/src/AnimNodeLoader.h index bc7d574c39..27b94f81bb 100644 --- a/libraries/animation/src/AnimNodeLoader.h +++ b/libraries/animation/src/AnimNodeLoader.h @@ -25,7 +25,7 @@ class AnimNodeLoader : public QObject { Q_OBJECT public: - AnimNodeLoader(const QUrl& url); + explicit AnimNodeLoader(const QUrl& url); signals: void success(AnimNode::Pointer node); diff --git a/libraries/animation/src/AnimStateMachine.h b/libraries/animation/src/AnimStateMachine.h index 6a28ef1825..d92b94d1b5 100644 --- a/libraries/animation/src/AnimStateMachine.h +++ b/libraries/animation/src/AnimStateMachine.h @@ -110,7 +110,7 @@ protected: public: - AnimStateMachine(const QString& id); + explicit AnimStateMachine(const QString& id); virtual ~AnimStateMachine() override; virtual const AnimPoseVec& evaluate(const AnimVariantMap& animVars, float dt, Triggers& triggersOut) override; diff --git a/libraries/animation/src/AnimationCache.h b/libraries/animation/src/AnimationCache.h index 6143d9b42e..e6a795c864 100644 --- a/libraries/animation/src/AnimationCache.h +++ b/libraries/animation/src/AnimationCache.h @@ -38,7 +38,7 @@ protected: virtual QSharedPointer createResource(const QUrl& url, const QSharedPointer& fallback, bool delayLoad, const void* extra); private: - AnimationCache(QObject* parent = NULL); + explicit AnimationCache(QObject* parent = NULL); virtual ~AnimationCache() { } }; @@ -51,7 +51,7 @@ class Animation : public Resource { public: - Animation(const QUrl& url); + explicit Animation(const QUrl& url); const FBXGeometry& getGeometry() const { return *_geometry; } diff --git a/libraries/animation/src/AnimationLoop.cpp b/libraries/animation/src/AnimationLoop.cpp index f6a2877966..3d7bca863f 100644 --- a/libraries/animation/src/AnimationLoop.cpp +++ b/libraries/animation/src/AnimationLoop.cpp @@ -40,6 +40,7 @@ AnimationLoop::AnimationLoop(const AnimationDetails& animationDetails) : _lastFrame(animationDetails.lastFrame), _running(animationDetails.running), _currentFrame(animationDetails.currentFrame), + _maxFrameIndexHint(MAXIMUM_POSSIBLE_FRAME), _resetOnRunning(true), _lastSimulated(usecTimestampNow()) { @@ -55,6 +56,7 @@ AnimationLoop::AnimationLoop(float fps, bool loop, bool hold, bool startAutomati _lastFrame(lastFrame), _running(running), _currentFrame(currentFrame), + _maxFrameIndexHint(MAXIMUM_POSSIBLE_FRAME), _resetOnRunning(true), _lastSimulated(usecTimestampNow()) { diff --git a/libraries/animation/src/AnimationLoop.h b/libraries/animation/src/AnimationLoop.h index 10664c47e7..6adfbf35e2 100644 --- a/libraries/animation/src/AnimationLoop.h +++ b/libraries/animation/src/AnimationLoop.h @@ -19,7 +19,7 @@ public: static const float MAXIMUM_POSSIBLE_FRAME; AnimationLoop(); - AnimationLoop(const AnimationDetails& animationDetails); + explicit AnimationLoop(const AnimationDetails& animationDetails); AnimationLoop(float fps, bool loop, bool hold, bool startAutomatically, float firstFrame, float lastFrame, bool running, float currentFrame); diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index bca90b242a..ae9adc71c2 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -37,17 +37,7 @@ static bool isEqual(const glm::quat& p, const glm::quat& q) { return 1.0f - fabsf(glm::dot(p, q)) <= EPSILON; } -#ifdef NDEBUG -#define ASSERT(cond) -#else -#define ASSERT(cond) \ - do { \ - if (!(cond)) { \ - int* ptr = nullptr; \ - *ptr = 10; \ - } \ - } while (0) -#endif +#define ASSERT(cond) assert(cond) // 2 meter tall dude const glm::vec3 DEFAULT_RIGHT_EYE_POS(-0.3f, 0.9f, 0.0f); diff --git a/libraries/animation/src/Rig.h b/libraries/animation/src/Rig.h index 50313d10e7..1f9a02d8ab 100644 --- a/libraries/animation/src/Rig.h +++ b/libraries/animation/src/Rig.h @@ -83,6 +83,7 @@ public: Hover }; + Rig() {} virtual ~Rig() {} void destroyAnimGraph(); From 54cc49283cb831214c9f620b896f32d91d77c933 Mon Sep 17 00:00:00 2001 From: Anthony Thibault Date: Sun, 13 Mar 2016 18:19:42 -0700 Subject: [PATCH 65/77] libraries/avatars: cppcheck warning fixes --- libraries/avatars/src/AvatarData.cpp | 4 ++-- libraries/avatars/src/HeadData.cpp | 2 ++ libraries/avatars/src/HeadData.h | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 067ab0603b..adb942417d 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -1115,7 +1115,7 @@ void AvatarData::detachOne(const QString& modelURL, const QString& jointName) { return; } QVector attachmentData = getAttachmentData(); - for (QVector::iterator it = attachmentData.begin(); it != attachmentData.end(); it++) { + for (QVector::iterator it = attachmentData.begin(); it != attachmentData.end(); ++it) { if (it->modelURL == modelURL && (jointName.isEmpty() || it->jointName == jointName)) { attachmentData.erase(it); setAttachmentData(attachmentData); @@ -1134,7 +1134,7 @@ void AvatarData::detachAll(const QString& modelURL, const QString& jointName) { if (it->modelURL == modelURL && (jointName.isEmpty() || it->jointName == jointName)) { it = attachmentData.erase(it); } else { - it++; + ++it; } } setAttachmentData(attachmentData); diff --git a/libraries/avatars/src/HeadData.cpp b/libraries/avatars/src/HeadData.cpp index 1d664aa3ff..b98112d6e0 100644 --- a/libraries/avatars/src/HeadData.cpp +++ b/libraries/avatars/src/HeadData.cpp @@ -42,6 +42,8 @@ HeadData::HeadData(AvatarData* owningAvatar) : _rightEyeBlink(0.0f), _averageLoudness(0.0f), _browAudioLift(0.0f), + _audioAverageLoudness(0.0f), + _pupilDilation(0.0f), _owningAvatar(owningAvatar) { diff --git a/libraries/avatars/src/HeadData.h b/libraries/avatars/src/HeadData.h index dac266f4a2..fef77c6f8f 100644 --- a/libraries/avatars/src/HeadData.h +++ b/libraries/avatars/src/HeadData.h @@ -32,7 +32,7 @@ class QJsonObject; class HeadData { public: - HeadData(AvatarData* owningAvatar); + explicit HeadData(AvatarData* owningAvatar); virtual ~HeadData() { }; // degrees From 1e94d9bdf58f04e65cc299fef0fdf37f2117b757 Mon Sep 17 00:00:00 2001 From: Anthony Thibault Date: Sun, 13 Mar 2016 18:56:15 -0700 Subject: [PATCH 66/77] interface/src/avatar: cppcheck fixes --- examples/utilities/tools/developerMenuItems.js | 6 +++--- interface/src/avatar/Avatar.cpp | 3 +-- interface/src/avatar/Avatar.h | 2 +- interface/src/avatar/AvatarActionHold.cpp | 1 - interface/src/avatar/AvatarManager.cpp | 4 ++-- interface/src/avatar/AvatarManager.h | 4 ++-- interface/src/avatar/AvatarUpdate.cpp | 2 +- interface/src/avatar/Head.h | 2 +- interface/src/avatar/MyAvatar.cpp | 6 +++--- interface/src/avatar/MyAvatar.h | 8 ++++---- interface/src/avatar/MyCharacterController.cpp | 11 ++++++----- interface/src/avatar/MyCharacterController.h | 2 +- 12 files changed, 25 insertions(+), 26 deletions(-) diff --git a/examples/utilities/tools/developerMenuItems.js b/examples/utilities/tools/developerMenuItems.js index 2e6c5a1141..549bed0bc4 100644 --- a/examples/utilities/tools/developerMenuItems.js +++ b/examples/utilities/tools/developerMenuItems.js @@ -36,11 +36,11 @@ var AUDIO_LISTENER_MODE_CUSTOM = "Audio from custom position"; // be sure that the audio listener options are in the right order (same as the enumerator) var AUDIO_LISTENER_OPTIONS = [ - // MyAvatar.FROM_HEAD (0) + // MyAvatar.audioListenerModeHead (0) AUDIO_LISTENER_MODE_FROM_HEAD, - // MyAvatar.FROM_CAMERA (1) + // MyAvatar.audioListenerModeCamera (1) AUDIO_LISTENER_MODE_FROM_CAMERA, - // MyAvatar.CUSTOM (2) + // MyAvatar.audioListenerCustom (2) AUDIO_LISTENER_MODE_CUSTOM ]; var AUDIO_STEREO_INPUT = "Stereo Input"; diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index ca242a2ca2..2a94ed30e2 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -972,7 +972,6 @@ void Avatar::renderJointConnectingCone(gpu::Batch& batch, glm::vec3 position1, g glm::vec3 perpCos = glm::normalize(glm::cross(axis, perpSin)); perpSin = glm::cross(perpCos, axis); - float anglea = 0.0f; float angleb = 0.0f; QVector points; @@ -980,7 +979,7 @@ void Avatar::renderJointConnectingCone(gpu::Batch& batch, glm::vec3 position1, g // the rectangles that comprise the sides of the cone section are // referenced by "a" and "b" in one dimension, and "1", and "2" in the other dimension. - anglea = angleb; + int anglea = angleb; angleb = ((float)(i+1) / (float)NUM_BODY_CONE_SIDES) * TWO_PI; float sa = sinf(anglea); diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index 7020de377f..01548c9066 100644 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -57,7 +57,7 @@ class Avatar : public AvatarData { Q_PROPERTY(glm::vec3 skeletonOffset READ getSkeletonOffset WRITE setSkeletonOffset) public: - Avatar(RigPointer rig = nullptr); + explicit Avatar(RigPointer rig = nullptr); ~Avatar(); typedef render::Payload Payload; diff --git a/interface/src/avatar/AvatarActionHold.cpp b/interface/src/avatar/AvatarActionHold.cpp index 5087f7955d..629b3aac12 100644 --- a/interface/src/avatar/AvatarActionHold.cpp +++ b/interface/src/avatar/AvatarActionHold.cpp @@ -308,7 +308,6 @@ bool AvatarActionHold::updateArguments(QVariantMap arguments) { hand = _hand; } - ok = true; auto myAvatar = DependencyManager::get()->getMyAvatar(); holderID = myAvatar->getSessionUUID(); diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 8e48237b8e..bcb54d6c52 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -63,11 +63,11 @@ void AvatarManager::registerMetaTypes(QScriptEngine* engine) { } AvatarManager::AvatarManager(QObject* parent) : - _avatarFades() + _avatarFades(), + _myAvatar(std::make_shared(std::make_shared())) { // register a meta type for the weak pointer we'll use for the owning avatar mixer for each avatar qRegisterMetaType >("NodeWeakPointer"); - _myAvatar = std::make_shared(std::make_shared()); auto& packetReceiver = DependencyManager::get()->getPacketReceiver(); packetReceiver.registerListener(PacketType::BulkAvatarData, this, "processAvatarDataPacket"); diff --git a/interface/src/avatar/AvatarManager.h b/interface/src/avatar/AvatarManager.h index 2aff98a1d2..57fc1022ea 100644 --- a/interface/src/avatar/AvatarManager.h +++ b/interface/src/avatar/AvatarManager.h @@ -71,8 +71,8 @@ public slots: void updateAvatarRenderStatus(bool shouldRenderAvatars); private: - AvatarManager(QObject* parent = 0); - AvatarManager(const AvatarManager& other); + explicit AvatarManager(QObject* parent = 0); + explicit AvatarManager(const AvatarManager& other); void simulateAvatarFades(float deltaTime); diff --git a/interface/src/avatar/AvatarUpdate.cpp b/interface/src/avatar/AvatarUpdate.cpp index 4881e3eaec..a52b584527 100644 --- a/interface/src/avatar/AvatarUpdate.cpp +++ b/interface/src/avatar/AvatarUpdate.cpp @@ -16,7 +16,7 @@ #include #include "InterfaceLogging.h" -AvatarUpdate::AvatarUpdate() : GenericThread(), _lastAvatarUpdate(0) { +AvatarUpdate::AvatarUpdate() : GenericThread(), _lastAvatarUpdate(0), _isHMDMode(false) { setObjectName("Avatar Update"); // GenericThread::initialize uses this to set the thread name. Settings settings; const int DEFAULT_TARGET_AVATAR_SIMRATE = 60; diff --git a/interface/src/avatar/Head.h b/interface/src/avatar/Head.h index ec88b295f7..614e286329 100644 --- a/interface/src/avatar/Head.h +++ b/interface/src/avatar/Head.h @@ -28,7 +28,7 @@ class Avatar; class Head : public HeadData { public: - Head(Avatar* owningAvatar); + explicit Head(Avatar* owningAvatar); void init(); void reset(); diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 9302c3b47d..d0be9c0be0 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1522,9 +1522,9 @@ glm::vec3 MyAvatar::applyKeyboardMotor(float deltaTime, const glm::vec3& localVe // (1) braking --> short timescale (aggressive motor assertion) // (2) pushing --> medium timescale (mild motor assertion) // (3) inactive --> long timescale (gentle friction for low speeds) - float MIN_KEYBOARD_MOTOR_TIMESCALE = 0.125f; - float MAX_KEYBOARD_MOTOR_TIMESCALE = 0.4f; - float MIN_KEYBOARD_BRAKE_SPEED = 0.3f; + const float MIN_KEYBOARD_MOTOR_TIMESCALE = 0.125f; + const float MAX_KEYBOARD_MOTOR_TIMESCALE = 0.4f; + const float MIN_KEYBOARD_BRAKE_SPEED = 0.3f; float timescale = MAX_KEYBOARD_MOTOR_TIMESCALE; bool isThrust = (glm::length2(_thrust) > EPSILON); if (_isPushing || isThrust || diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index f834a627b2..37a2e752e6 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -63,9 +63,9 @@ class MyAvatar : public Avatar { Q_PROPERTY(AudioListenerMode audioListenerMode READ getAudioListenerMode WRITE setAudioListenerMode) Q_PROPERTY(glm::vec3 customListenPosition READ getCustomListenPosition WRITE setCustomListenPosition) Q_PROPERTY(glm::quat customListenOrientation READ getCustomListenOrientation WRITE setCustomListenOrientation) - Q_PROPERTY(AudioListenerMode FROM_HEAD READ getAudioListenerModeHead) - Q_PROPERTY(AudioListenerMode FROM_CAMERA READ getAudioListenerModeCamera) - Q_PROPERTY(AudioListenerMode CUSTOM READ getAudioListenerModeCustom) + Q_PROPERTY(AudioListenerMode audioListenerModeHead READ getAudioListenerModeHead) + Q_PROPERTY(AudioListenerMode audioListenerModeCamera READ getAudioListenerModeCamera) + Q_PROPERTY(AudioListenerMode audioListenerModeCustom READ getAudioListenerModeCustom) //TODO: make gravity feature work Q_PROPERTY(glm::vec3 gravity READ getGravity WRITE setGravity) @@ -84,7 +84,7 @@ class MyAvatar : public Avatar { Q_PROPERTY(float energy READ getEnergy WRITE setEnergy) public: - MyAvatar(RigPointer rig); + explicit MyAvatar(RigPointer rig); ~MyAvatar(); virtual void simulateAttachments(float deltaTime) override; diff --git a/interface/src/avatar/MyCharacterController.cpp b/interface/src/avatar/MyCharacterController.cpp index ee77859337..6e52f4a949 100644 --- a/interface/src/avatar/MyCharacterController.cpp +++ b/interface/src/avatar/MyCharacterController.cpp @@ -46,14 +46,15 @@ void MyCharacterController::updateShapeIfNecessary() { // NOTE: _shapeLocalOffset is already computed if (_radius > 0.0f) { - // HACK: use some simple mass property defaults for now - float mass = 100.0f; - btVector3 inertia(30.0f, 8.0f, 30.0f); - // create RigidBody if it doesn't exist if (!_rigidBody) { + + // HACK: use some simple mass property defaults for now + const float DEFAULT_AVATAR_MASS = 100.0f; + const btVector3 DEFAULT_AVATAR_INERTIA_TENSOR(30.0f, 8.0f, 30.0f); + btCollisionShape* shape = new btCapsuleShape(_radius, 2.0f * _halfHeight); - _rigidBody = new btRigidBody(mass, nullptr, shape, inertia); + _rigidBody = new btRigidBody(DEFAULT_AVATAR_MASS, nullptr, shape, DEFAULT_AVATAR_INERTIA_TENSOR); } else { btCollisionShape* shape = _rigidBody->getCollisionShape(); if (shape) { diff --git a/interface/src/avatar/MyCharacterController.h b/interface/src/avatar/MyCharacterController.h index 39f0f99917..265406bc6f 100644 --- a/interface/src/avatar/MyCharacterController.h +++ b/interface/src/avatar/MyCharacterController.h @@ -21,7 +21,7 @@ class MyAvatar; class MyCharacterController : public CharacterController { public: - MyCharacterController(MyAvatar* avatar); + explicit MyCharacterController(MyAvatar* avatar); ~MyCharacterController (); virtual void updateShapeIfNecessary() override; From 5292e537ea5f5fb21f4669f681e697989c8b391d Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 14 Mar 2016 11:22:01 -0700 Subject: [PATCH 67/77] further unmangle merge --- libraries/entities/src/EntityTree.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index a1b2af08c0..96cb638d1f 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -1025,7 +1025,6 @@ void EntityTree::fixupMissingParents() { bool doMove = false; if (entity->isParentIDValid()) { // this entity's parent was previously not known, and now is. Update its location in the EntityTree... - iter.remove(); doMove = true; } else if (getIsServer() && _avatarIDs.contains(entity->getParentID())) { // this is a child of an avatar, which the entity server will never have From 1f8a55da3abbaec197ab407dc949e396596b1405 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 14 Mar 2016 11:36:44 -0700 Subject: [PATCH 68/77] dynamic is the same as grabbable-by-default --- examples/html/entityProperties.html | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/examples/html/entityProperties.html b/examples/html/entityProperties.html index ae42ea7caf..139d5cef67 100644 --- a/examples/html/entityProperties.html +++ b/examples/html/entityProperties.html @@ -243,12 +243,6 @@ } - function isGrabbableByDefault(properties) { - return properties.type == "Box" || - properties.type == "Sphere" || - properties.dynamic - } - function userDataChanger(groupName, keyName, checkBoxElement, userDataElement, defaultValue) { var properties = {}; var parsedData = {}; @@ -571,7 +565,7 @@ elCollideOtherAvatar.checked = properties.collidesWith.indexOf("otherAvatar") > -1; // boxes and sphere are grabbable by default - elGrabbable.checked = isGrabbableByDefault(properties); + elGrabbable.checked = properties.dynamic; elWantsTrigger.checked = false; elIgnoreIK.checked = false; var parsedUserData = {} @@ -820,7 +814,7 @@ }); elGrabbable.addEventListener('change', function() { - userDataChanger("grabbableKey", "grabbable", elGrabbable, elUserData, isGrabbableByDefault(properties)); + userDataChanger("grabbableKey", "grabbable", elGrabbable, elUserData, properties.dynamic); }); elWantsTrigger.addEventListener('change', function() { userDataChanger("grabbableKey", "wantsTrigger", elWantsTrigger, elUserData, false); From d811c4f6b53ff7abf18fc7539b658aaff0947067 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 14 Mar 2016 11:39:56 -0700 Subject: [PATCH 69/77] dynamic is the same as grabbable-by-default --- examples/html/entityProperties.html | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/html/entityProperties.html b/examples/html/entityProperties.html index 139d5cef67..e3a64da5d4 100644 --- a/examples/html/entityProperties.html +++ b/examples/html/entityProperties.html @@ -564,7 +564,6 @@ elCollideMyAvatar.checked = properties.collidesWith.indexOf("myAvatar") > -1; elCollideOtherAvatar.checked = properties.collidesWith.indexOf("otherAvatar") > -1; - // boxes and sphere are grabbable by default elGrabbable.checked = properties.dynamic; elWantsTrigger.checked = false; elIgnoreIK.checked = false; From e8a03b725fc5ff06042bd9d0c7eec7f6e82fad0d Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 14 Mar 2016 13:03:27 -0700 Subject: [PATCH 70/77] try again on queryAACube --- libraries/shared/src/SpatiallyNestable.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index 10d851ec5a..3392e9c66d 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -781,6 +781,7 @@ void SpatiallyNestable::setQueryAACube(const AACube& queryAACube) { if (queryAACube.getScale() > 0.0f) { _queryAACubeSet = true; } + checkAndAdjustQueryAACube(); } bool SpatiallyNestable::queryAABoxNeedsUpdate() const { From 1a17de6dbbe18f9595309ad1ef0c80b31412b526 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 14 Mar 2016 14:02:25 -0700 Subject: [PATCH 71/77] reduce log spam --- libraries/entities/src/EntityItem.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 3c918a0a77..b79fd7107d 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -515,7 +515,10 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef // we can confidently ignore this packet EntityTreePointer tree = getTree(); if (tree && tree->isDeletedEntity(_id)) { - qDebug() << "Recieved packet for previously deleted entity [" << _id << "] ignoring. (inside " << __FUNCTION__ << ")"; + #ifdef WANT_DEBUG + qDebug() << "Recieved packet for previously deleted entity [" << _id << "] ignoring. " + "(inside " << __FUNCTION__ << ")"; + #endif ignoreServerPacket = true; } From 7858b6b0cd2cc3c52eafed980598905ba41a8816 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 14 Mar 2016 15:02:01 -0700 Subject: [PATCH 72/77] fix for slow start initial value with new randomization --- libraries/networking/src/udt/CongestionControl.cpp | 7 +++---- libraries/networking/src/udt/CongestionControl.h | 9 +++++++-- libraries/networking/src/udt/Connection.cpp | 7 +++++-- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/libraries/networking/src/udt/CongestionControl.cpp b/libraries/networking/src/udt/CongestionControl.cpp index c1feae3911..0f8a9f24f6 100644 --- a/libraries/networking/src/udt/CongestionControl.cpp +++ b/libraries/networking/src/udt/CongestionControl.cpp @@ -34,7 +34,6 @@ void CongestionControl::setPacketSendPeriod(double newSendPeriod) { } DefaultCC::DefaultCC() : - _slowStartLastAck(_sendCurrSeqNum), _lastDecreaseMaxSeq(SequenceNumber {SequenceNumber::MAX }) { _mss = udt::MAX_PACKET_SIZE_WITH_UDP_HEADER; @@ -63,11 +62,11 @@ void DefaultCC::onACK(SequenceNumber ackNum) { if (_slowStart) { // we are in slow start phase - increase the congestion window size by the number of packets just ACKed - _congestionWindowSize += seqlen(_slowStartLastAck, ackNum); + _congestionWindowSize += seqlen(_slowStartLastACK, ackNum); // update the last ACK - _slowStartLastAck = ackNum; - + _slowStartLastACK = ackNum; + // check if we can get out of slow start (is our new congestion window size bigger than the max) if (_congestionWindowSize > _maxCongestionWindowSize) { _slowStart = false; diff --git a/libraries/networking/src/udt/CongestionControl.h b/libraries/networking/src/udt/CongestionControl.h index fa1bf73ecf..5fd784cc20 100644 --- a/libraries/networking/src/udt/CongestionControl.h +++ b/libraries/networking/src/udt/CongestionControl.h @@ -50,6 +50,7 @@ protected: void setMaxCongestionWindowSize(int window) { _maxCongestionWindowSize = window; } void setBandwidth(int bandwidth) { _bandwidth = bandwidth; } void setMaxBandwidth(int maxBandwidth) { _maxBandwidth = maxBandwidth; } + virtual void setInitialSendSequenceNumber(SequenceNumber seqNum) = 0; void setSendCurrentSequenceNumber(SequenceNumber seqNum) { _sendCurrSeqNum = seqNum; } void setReceiveRate(int rate) { _receiveRate = rate; } void setRTT(int rtt) { _rtt = rtt; } @@ -104,14 +105,18 @@ public: virtual void onACK(SequenceNumber ackNum); virtual void onLoss(SequenceNumber rangeStart, SequenceNumber rangeEnd); virtual void onTimeout(); - + +protected: + virtual void setInitialSendSequenceNumber(SequenceNumber seqNum) { _slowStartLastACK = seqNum; } + private: void stopSlowStart(); // stops the slow start on loss or timeout p_high_resolution_clock::time_point _lastRCTime = p_high_resolution_clock::now(); // last rate increase time bool _slowStart { true }; // if in slow start phase - SequenceNumber _slowStartLastAck; // last ACKed seq num + bool _hasSetSlowStartACK { false }; // flag to signal if slow start ACK has been set with handshake sequence number + SequenceNumber _slowStartLastACK; // last ACKed seq num from previous slow start check bool _loss { false }; // if loss happened since last rate increase SequenceNumber _lastDecreaseMaxSeq; // max pkt seq num sent out when last decrease happened double _lastDecreasePeriod { 1 }; // value of _packetSendPeriod when last decrease happened diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index e6a15aa6a0..95afbedb86 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -104,6 +104,9 @@ SendQueue& Connection::getSendQueue() { _sendQueue->setSyncInterval(_synInterval); _sendQueue->setEstimatedTimeout(estimatedTimeout()); _sendQueue->setFlowWindowSize(std::min(_flowWindowSize, (int) _congestionControl->_congestionWindowSize)); + + // give the randomized sequence number to the congestion control object + _congestionControl->setInitialSendSequenceNumber(_sendQueue->getCurrentSequenceNumber()); } return *_sendQueue; @@ -282,7 +285,7 @@ void Connection::sendACK(bool wasCausedBySyncTimeout) { // grab the up to date packet receive speed and estimated bandwidth int32_t packetReceiveSpeed = _receiveWindow.getPacketReceiveSpeed(); int32_t estimatedBandwidth = _receiveWindow.getEstimatedBandwidth(); - + // update those values in our connection stats _stats.recordReceiveRate(packetReceiveSpeed); _stats.recordEstimatedBandwidth(estimatedBandwidth); @@ -541,7 +544,7 @@ void Connection::processACK(std::unique_ptr controlPacket) { // read the ACK sub-sequence number SequenceNumber currentACKSubSequenceNumber; controlPacket->readPrimitive(¤tACKSubSequenceNumber); - + // Check if we need send an ACK2 for this ACK // This will be the case if it has been longer than the sync interval OR // it looks like they haven't received our ACK2 for this ACK From d18f988cba6f67633a9b9034ab1f123bc5527588 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 14 Mar 2016 17:07:35 -0700 Subject: [PATCH 73/77] namechange URCHIN --> ANEMONE --- .../Home/fishTank/createFishTank.js | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/unpublishedScripts/DomainContent/Home/fishTank/createFishTank.js b/unpublishedScripts/DomainContent/Home/fishTank/createFishTank.js index 3c168fc668..07d62643c5 100644 --- a/unpublishedScripts/DomainContent/Home/fishTank/createFishTank.js +++ b/unpublishedScripts/DomainContent/Home/fishTank/createFishTank.js @@ -1,12 +1,12 @@ // // createTank.js -// +// // // created by James b. Pollack @imgntn on 3/9/2016 -// Copyright 2016 High Fidelity, Inc. -// -// Adds a fish tank and base, decorations, particle bubble systems, and a bubble sound. Attaches a script that does fish swimming. -// +// Copyright 2016 High Fidelity, Inc. +// +// Adds a fish tank and base, decorations, particle bubble systems, and a bubble sound. Attaches a script that does fish swimming. +// // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // @@ -76,14 +76,14 @@ var BUBBLE_SOUND_URL = "http://hifi-content.s3.amazonaws.com/DomainContent/Home/ var bubbleSound = SoundCache.getSound(BUBBLE_SOUND_URL); -var URCHIN_FORWARD_OFFSET = TANK_DIMENSIONS.x - 0.35; -var URCHIN_LATERAL_OFFSET = -0.05; -var URCHIN_VERTICAL_OFFSET = -0.12; +var ANEMONE_FORWARD_OFFSET = TANK_DIMENSIONS.x - 0.35; +var ANEMONE_LATERAL_OFFSET = -0.05; +var ANEMONE_VERTICAL_OFFSET = -0.12; -var URCHIN_MODEL_URL = 'http://hifi-content.s3.amazonaws.com/DomainContent/Home/fishTank/anemone.fbx'; -var URCHIN_ANIMATION_URL = 'http://hifi-content.s3.amazonaws.com/DomainContent/Home/fishTank/anemone.fbx'; -var URCHIN_DIMENSIONS = { +var ANEMONE_MODEL_URL = 'http://hifi-content.s3.amazonaws.com/DomainContent/Home/fishTank/anemone.fbx'; +var ANEMONE_ANIMATION_URL = 'http://hifi-content.s3.amazonaws.com/DomainContent/Home/fishTank/anemone.fbx'; +var ANEMONE_DIMENSIONS = { x: 0.4, y: 0.4, z: 0.4 @@ -311,12 +311,12 @@ function createRocks() { } function createUrchin() { - var finalPosition = getOffsetFromTankCenter(URCHIN_VERTICAL_OFFSET, URCHIN_FORWARD_OFFSET, URCHIN_LATERAL_OFFSET); + var finalPosition = getOffsetFromTankCenter(ANEMONE_VERTICAL_OFFSET, ANEMONE_FORWARD_OFFSET, ANEMONE_LATERAL_OFFSET); var properties = { name: 'hifi-home-fishtank-urchin', type: 'Model', - animationURL: URCHIN_ANIMATION_URL, + animationURL: ANEMONE_ANIMATION_URL, animationIsPlaying: true, animationFPS: 15, animationSettings: JSON.stringify({ @@ -326,11 +326,11 @@ function createUrchin() { startAutomatically: true }), parentID: fishTank, - modelURL: URCHIN_MODEL_URL, + modelURL: ANEMONE_MODEL_URL, position: finalPosition, shapeType: 'Sphere', rotation: Quat.fromPitchYawRollDegrees(0, 90, 0), - dimensions: URCHIN_DIMENSIONS + dimensions: ANEMONE_DIMENSIONS } urchin = Entities.addEntity(properties); @@ -467,4 +467,4 @@ function getEntityCustomData(customKey, id, defaultValue) { } else { return defaultValue; } -} \ No newline at end of file +} From cb62af770f414473b1975443125c252bdb182b94 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 14 Mar 2016 17:10:33 -0700 Subject: [PATCH 74/77] namechange urchin --> anemone --- .../DomainContent/Home/fishTank/createFishTank.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/unpublishedScripts/DomainContent/Home/fishTank/createFishTank.js b/unpublishedScripts/DomainContent/Home/fishTank/createFishTank.js index 07d62643c5..1a4c95c622 100644 --- a/unpublishedScripts/DomainContent/Home/fishTank/createFishTank.js +++ b/unpublishedScripts/DomainContent/Home/fishTank/createFishTank.js @@ -12,7 +12,7 @@ // -var fishTank, tankBase, bubbleSystem, secondBubbleSystem, thirdBubbleSystem, innerContainer, bubbleInjector, lowerCorner, upperCorner, urchin, treasure, rocks; +var fishTank, tankBase, bubbleSystem, secondBubbleSystem, thirdBubbleSystem, innerContainer, bubbleInjector, lowerCorner, upperCorner, anemone, treasure, rocks; var CLEANUP = true; var TANK_DIMENSIONS = { @@ -314,7 +314,7 @@ function createUrchin() { var finalPosition = getOffsetFromTankCenter(ANEMONE_VERTICAL_OFFSET, ANEMONE_FORWARD_OFFSET, ANEMONE_LATERAL_OFFSET); var properties = { - name: 'hifi-home-fishtank-urchin', + name: 'hifi-home-fishtank-anemone', type: 'Model', animationURL: ANEMONE_ANIMATION_URL, animationIsPlaying: true, @@ -333,7 +333,7 @@ function createUrchin() { dimensions: ANEMONE_DIMENSIONS } - urchin = Entities.addEntity(properties); + anemone = Entities.addEntity(properties); } @@ -416,7 +416,7 @@ function cleanup() { Entities.deleteEntity(innerContainer); Entities.deleteEntity(lowerCorner); Entities.deleteEntity(upperCorner); - Entities.deleteEntity(urchin); + Entities.deleteEntity(anemone); Entities.deleteEntity(rocks); bubbleInjector.stop(); bubbleInjector = null; From 16a57bda819b7ce62247535cc030fde7b0e0c6ed Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Mon, 14 Mar 2016 17:30:53 -0700 Subject: [PATCH 75/77] SwingTwistConstriant: fix for bad index. --- libraries/animation/src/SwingTwistConstraint.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/animation/src/SwingTwistConstraint.cpp b/libraries/animation/src/SwingTwistConstraint.cpp index 72659ff09d..d6d8c87344 100644 --- a/libraries/animation/src/SwingTwistConstraint.cpp +++ b/libraries/animation/src/SwingTwistConstraint.cpp @@ -249,7 +249,7 @@ void SwingTwistConstraint::setSwingLimits(const std::vector& swungDir int rightIndex = 0; for (int i = 0; i < numLimits; ++i) { float theta = (float)i * deltaTheta; - int leftIndex = (rightIndex - 1) % numLimits; + int leftIndex = (rightIndex - 1 + numLimits) % numLimits; while (rightIndex < numLimits && theta > limits[rightIndex]._theta) { leftIndex = rightIndex++; } From ff0862b5944bc3ce1bc816fc85f1bafe750e6610 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Mon, 14 Mar 2016 14:41:08 -0700 Subject: [PATCH 76/77] Emplace render engine jobs --- libraries/render/src/render/Task.h | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/libraries/render/src/render/Task.h b/libraries/render/src/render/Task.h index 7d74529b64..eabdc99338 100644 --- a/libraries/render/src/render/Task.h +++ b/libraries/render/src/render/Task.h @@ -240,7 +240,9 @@ public: const Varying getInput() const { return _input; } const Varying getOutput() const { return _output; } - Model(const Varying& input, Data data = Data()) : Concept(std::make_shared()), _data(data), _input(input), _output(Output()) { + template + Model(const Varying& input, A&&... args) : + Concept(std::make_shared()), _data(Data(std::forward(args)...)), _input(input), _output(Output()) { applyConfiguration(); } @@ -308,7 +310,10 @@ public: const Varying getInput() const { return _input; } const Varying getOutput() const { return _output; } - Model(const Varying& input, Data data = Data()) : Concept(data._config), _data(data), _input(input), _output(Output()) { + template + Model(const Varying& input, A&&... args) : + Concept(nullptr), _data(Data(std::forward(args)...)), _input(input), _output(Output()) { + _config = _data._config; std::static_pointer_cast(_config)->init(&_data); applyConfiguration(); } @@ -337,9 +342,7 @@ public: // Create a new job in the container's queue; returns the job's output template const Varying addJob(std::string name, const Varying& input, A&&... args) { - _jobs.emplace_back(name, std::make_shared( - input, - typename T::JobModel::Data(std::forward(args)...))); + _jobs.emplace_back(name, std::make_shared(input, std::forward(args)...)); QConfigPointer config = _jobs.back().getConfiguration(); config->setParent(_config.get()); config->setObjectName(name.c_str()); From 8cb602173ad0241d080e38ca484eed063006551e Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 14 Mar 2016 20:54:41 -0700 Subject: [PATCH 77/77] remove the unused member variable --- libraries/networking/src/udt/CongestionControl.h | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/networking/src/udt/CongestionControl.h b/libraries/networking/src/udt/CongestionControl.h index 5fd784cc20..69b7a32d2d 100644 --- a/libraries/networking/src/udt/CongestionControl.h +++ b/libraries/networking/src/udt/CongestionControl.h @@ -115,7 +115,6 @@ private: p_high_resolution_clock::time_point _lastRCTime = p_high_resolution_clock::now(); // last rate increase time bool _slowStart { true }; // if in slow start phase - bool _hasSetSlowStartACK { false }; // flag to signal if slow start ACK has been set with handshake sequence number SequenceNumber _slowStartLastACK; // last ACKed seq num from previous slow start check bool _loss { false }; // if loss happened since last rate increase SequenceNumber _lastDecreaseMaxSeq; // max pkt seq num sent out when last decrease happened