From db955d894f6bd64980e7b458e35c8887d9442a72 Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Tue, 6 Oct 2015 14:52:53 -0700 Subject: [PATCH 01/14] Align avatar body to head on reset. --- interface/src/avatar/MyAvatar.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 9654305d70..82a2231a61 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -141,6 +141,7 @@ QByteArray MyAvatar::toByteArray(bool cullSmallChanges, bool sendAll) { void MyAvatar::reset() { _skeletonModel.reset(); + float headYaw = getHead()->getBaseYaw(); // degrees getHead()->reset(); _targetVelocity = glm::vec3(0.0f); @@ -148,6 +149,7 @@ void MyAvatar::reset() { // Reset the pitch and roll components of the avatar's orientation, preserve yaw direction glm::vec3 eulers = safeEulerAngles(getOrientation()); eulers.x = 0.0f; + eulers.y += headYaw; // align body with head eulers.z = 0.0f; setOrientation(glm::quat(eulers)); From 2dabe69341e234aaba12904b72c7402390ea8100 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Tue, 6 Oct 2015 20:30:16 -0700 Subject: [PATCH 02/14] When HMD is at rest, re-center the body under the avatar. This should help the case when a user avatar is stuck in an uncomfortable pose for a long period of time. If they stop moving their head, the body should recenter itself and appear more natural. Added an AtRestDetector class. That tracks the average and variance of both position and rotation (quaternion logarithms), then detects when the variance falls under a threshold. Also, renamed variables with the straighting prefix to straightening. --- interface/src/avatar/MyAvatar.cpp | 35 +++++++++++---------- interface/src/avatar/MyAvatar.h | 6 ++-- libraries/shared/src/AtRestDetector.cpp | 41 +++++++++++++++++++++++++ libraries/shared/src/AtRestDetector.h | 34 ++++++++++++++++++++ 4 files changed, 98 insertions(+), 18 deletions(-) create mode 100644 libraries/shared/src/AtRestDetector.cpp create mode 100644 libraries/shared/src/AtRestDetector.h diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 0105d1b648..371ce549e6 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -111,7 +111,8 @@ MyAvatar::MyAvatar(RigPointer rig) : _goToOrientation(), _rig(rig), _prevShouldDrawHead(true), - _audioListenerMode(FROM_HEAD) + _audioListenerMode(FROM_HEAD), + _hmdAtRestDetector(glm::vec3(0), glm::quat()) { for (int i = 0; i < MAX_DRIVE_KEYS; i++) { _driveKeys[i] = 0.0f; @@ -311,37 +312,39 @@ void MyAvatar::updateFromHMDSensorMatrix(const glm::mat4& hmdSensorMatrix) { _hmdSensorPosition = extractTranslation(hmdSensorMatrix); _hmdSensorOrientation = glm::quat_cast(hmdSensorMatrix); - const float STRAIGHTING_LEAN_DURATION = 0.5f; // seconds + bool hmdIsAtRest = _hmdAtRestDetector.update(deltaTime, _hmdSensorPosition, _hmdSensorOrientation); + + const float STRAIGHTENING_LEAN_DURATION = 0.5f; // seconds // define a vertical capsule - const float STRAIGHTING_LEAN_CAPSULE_RADIUS = 0.2f; // meters - const float STRAIGHTING_LEAN_CAPSULE_LENGTH = 0.05f; // length of the cylinder part of the capsule in meters. + const float STRAIGHTENING_LEAN_CAPSULE_RADIUS = 0.2f; // meters + const float STRAIGHTENING_LEAN_CAPSULE_LENGTH = 0.05f; // length of the cylinder part of the capsule in meters. auto newBodySensorMatrix = deriveBodyFromHMDSensor(); glm::vec3 diff = extractTranslation(newBodySensorMatrix) - extractTranslation(_bodySensorMatrix); - if (!_straightingLean && capsuleCheck(diff, STRAIGHTING_LEAN_CAPSULE_LENGTH, STRAIGHTING_LEAN_CAPSULE_RADIUS)) { + if (!_straighteningLean && (capsuleCheck(diff, STRAIGHTENING_LEAN_CAPSULE_LENGTH, STRAIGHTENING_LEAN_CAPSULE_RADIUS) || hmdIsAtRest)) { // begin homing toward derived body position. - _straightingLean = true; - _straightingLeanAlpha = 0.0f; + _straighteningLean = true; + _straighteningLeanAlpha = 0.0f; - } else if (_straightingLean) { + } else if (_straighteningLean) { auto newBodySensorMatrix = deriveBodyFromHMDSensor(); auto worldBodyMatrix = _sensorToWorldMatrix * newBodySensorMatrix; glm::vec3 worldBodyPos = extractTranslation(worldBodyMatrix); glm::quat worldBodyRot = glm::normalize(glm::quat_cast(worldBodyMatrix)); - _straightingLeanAlpha += (1.0f / STRAIGHTING_LEAN_DURATION) * deltaTime; + _straighteningLeanAlpha += (1.0f / STRAIGHTENING_LEAN_DURATION) * deltaTime; - if (_straightingLeanAlpha >= 1.0f) { - _straightingLean = false; + if (_straighteningLeanAlpha >= 1.0f) { + _straighteningLean = false; nextAttitude(worldBodyPos, worldBodyRot); _bodySensorMatrix = newBodySensorMatrix; } else { // interp position toward the desired pos - glm::vec3 pos = lerp(getPosition(), worldBodyPos, _straightingLeanAlpha); - glm::quat rot = glm::normalize(safeMix(getOrientation(), worldBodyRot, _straightingLeanAlpha)); + glm::vec3 pos = lerp(getPosition(), worldBodyPos, _straighteningLeanAlpha); + glm::quat rot = glm::normalize(safeMix(getOrientation(), worldBodyRot, _straighteningLeanAlpha)); nextAttitude(pos, rot); // interp sensor matrix toward desired @@ -349,13 +352,13 @@ void MyAvatar::updateFromHMDSensorMatrix(const glm::mat4& hmdSensorMatrix) { glm::quat nextBodyRot = glm::normalize(glm::quat_cast(newBodySensorMatrix)); glm::vec3 prevBodyPos = extractTranslation(_bodySensorMatrix); glm::quat prevBodyRot = glm::normalize(glm::quat_cast(_bodySensorMatrix)); - pos = lerp(prevBodyPos, nextBodyPos, _straightingLeanAlpha); - rot = glm::normalize(safeMix(prevBodyRot, nextBodyRot, _straightingLeanAlpha)); + pos = lerp(prevBodyPos, nextBodyPos, _straighteningLeanAlpha); + rot = glm::normalize(safeMix(prevBodyRot, nextBodyRot, _straighteningLeanAlpha)); _bodySensorMatrix = createMatFromQuatAndPos(rot, pos); } } } -// + // best called at end of main loop, just before rendering. // update sensor to world matrix from current body position and hmd sensor. // This is so the correct camera can be used for rendering. diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 5d87737dd7..202079b405 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -17,6 +17,7 @@ #include #include "Avatar.h" +#include "AtRestDetector.h" class ModelItemID; @@ -363,10 +364,11 @@ private: glm::vec3 _customListenPosition; glm::quat _customListenOrientation; - bool _straightingLean = false; - float _straightingLeanAlpha = 0.0f; + bool _straighteningLean = false; + float _straighteningLeanAlpha = 0.0f; quint64 _lastUpdateFromHMDTime = usecTimestampNow(); + AtRestDetector _hmdAtRestDetector; }; QScriptValue audioListenModeToScriptValue(QScriptEngine* engine, const AudioListenerMode& audioListenerMode); diff --git a/libraries/shared/src/AtRestDetector.cpp b/libraries/shared/src/AtRestDetector.cpp new file mode 100644 index 0000000000..5e623a005c --- /dev/null +++ b/libraries/shared/src/AtRestDetector.cpp @@ -0,0 +1,41 @@ +#include "AtRestDetector.h" +#include "SharedLogging.h" + +AtRestDetector::AtRestDetector(const glm::vec3& startPosition, const glm::quat& startRotation) { + reset(startPosition, startRotation); +} + +void AtRestDetector::reset(const glm::vec3& startPosition, const glm::quat& startRotation) { + _positionAverage = startPosition; + _positionVariance = 0.0f; + + glm::quat ql = glm::log(startRotation); + _quatLogAverage = glm::vec3(ql.x, ql.y, ql.z); + _quatLogVariance = 0.0f; +} + +bool AtRestDetector::update(float dt, const glm::vec3& position, const glm::quat& rotation) { + const float TAU = 1.0f; + float delta = glm::min(dt / TAU, 1.0f); + + // keep a running average of position. + _positionAverage = position * delta + _positionAverage * (1 - delta); + + // keep a running average of position variances. + glm::vec3 dx = position - _positionAverage; + _positionVariance = glm::dot(dx, dx) * delta + _positionVariance * (1 - delta); + + // keep a running average of quaternion logarithms. + glm::quat quatLogAsQuat = glm::log(rotation); + glm::vec3 quatLog(quatLogAsQuat.x, quatLogAsQuat.y, quatLogAsQuat.z); + _quatLogAverage = quatLog * delta + _quatLogAverage * (1 - delta); + + // keep a running average of quatLog variances. + glm::vec3 dql = quatLog - _quatLogAverage; + _quatLogVariance = glm::dot(dql, dql) * delta + _quatLogVariance * (1 - delta); + + const float POSITION_VARIANCE_THRESHOLD = 0.001f; + const float QUAT_LOG_VARIANCE_THRESHOLD = 0.00002f; + + return _positionVariance < POSITION_VARIANCE_THRESHOLD && _quatLogVariance < QUAT_LOG_VARIANCE_THRESHOLD; +} diff --git a/libraries/shared/src/AtRestDetector.h b/libraries/shared/src/AtRestDetector.h new file mode 100644 index 0000000000..d82e54a692 --- /dev/null +++ b/libraries/shared/src/AtRestDetector.h @@ -0,0 +1,34 @@ +// +// AtRestDetector.h +// libraries/shared/src +// +// Created by Anthony Thibault on 10/6/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 +// + +#ifndef hifi_AtRestDetector_h +#define hifi_AtRestDetector_h + +#include +#include + +class AtRestDetector { +public: + AtRestDetector(const glm::vec3& startPosition, const glm::quat& startRotation); + void reset(const glm::vec3& startPosition, const glm::quat& startRotation); + + // returns true if object is at rest, dt in assumed to be seconds. + bool update(float dt, const glm::vec3& position, const glm::quat& startRotation); + +protected: + glm::vec3 _positionAverage; + float _positionVariance; + + glm::vec3 _quatLogAverage; + float _quatLogVariance; +}; + +#endif From 1fc305ca6b6e2426754c62cc39f3a95e4be72a7c Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Tue, 6 Oct 2015 20:51:53 -0700 Subject: [PATCH 03/14] Update HMD-derived avatar stuff during reset, update position under head, and remove unused vars. --- interface/src/avatar/MyAvatar.cpp | 24 ++++++++++++++++-------- interface/src/avatar/MyAvatar.h | 3 --- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 82a2231a61..68eeca429a 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -78,12 +78,10 @@ const float MyAvatar::ZOOM_DEFAULT = 1.5f; MyAvatar::MyAvatar(RigPointer rig) : Avatar(rig), - _gravity(0.0f, 0.0f, 0.0f), _wasPushing(false), _isPushing(false), _isBraking(false), _boomLength(ZOOM_DEFAULT), - _trapDuration(0.0f), _thrust(0.0f), _keyboardMotorVelocity(0.0f), _keyboardMotorTimescale(DEFAULT_KEYBOARD_MOTOR_TIMESCALE), @@ -142,16 +140,11 @@ QByteArray MyAvatar::toByteArray(bool cullSmallChanges, bool sendAll) { void MyAvatar::reset() { _skeletonModel.reset(); float headYaw = getHead()->getBaseYaw(); // degrees - getHead()->reset(); - - _targetVelocity = glm::vec3(0.0f); - setThrust(glm::vec3(0.0f)); // Reset the pitch and roll components of the avatar's orientation, preserve yaw direction glm::vec3 eulers = safeEulerAngles(getOrientation()); eulers.x = 0.0f; - eulers.y += headYaw; // align body with head + eulers.y += glm::radians(headYaw); // align body with head eulers.z = 0.0f; - setOrientation(glm::quat(eulers)); // This should be simpler when we have only graph animations always on. bool isRig = _rig->getEnableRig(); @@ -160,6 +153,21 @@ void MyAvatar::reset() { qApp->setRawAvatarUpdateThreading(false); _rig->disableHands = true; setEnableRigAnimations(true); + + _wasPushing = _isPushing = _isBraking = _billboardValid = _goToPending = _straightingLean = false; + getHead()->reset(); + _targetVelocity = glm::vec3(0.0f); + setThrust(glm::vec3(0.0f)); + auto worldBodyMatrix = _sensorToWorldMatrix * _bodySensorMatrix; // Assuming these are in sync and current... + setPosition(extractTranslation(worldBodyMatrix)); // ...positions body under head. + setOrientation(glm::quat(eulers)); // Not from worldBodyMatrix, in case it is NOT in sync and current. + // Make sure we have current sensor data. + _hmdSensorMatrix = qApp->getHMDSensorPose(); + _hmdSensorPosition = extractTranslation(_hmdSensorMatrix); + _hmdSensorOrientation = extractRotation(_hmdSensorMatrix); + _bodySensorMatrix = deriveBodyFromHMDSensor(); // Based on new HMD position and yaw (no x/z rotation), in sensor space. + updateSensorToWorldMatrix(); // Uses updated position/orientation and _bodySensorMatrix changes + _skeletonModel.simulate(0.1f); // non-zero setEnableRigAnimations(false); _skeletonModel.simulate(0.1f); diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 5d87737dd7..9f9027f905 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -282,8 +282,6 @@ private: // results are in sensor space glm::mat4 deriveBodyFromHMDSensor() const; - glm::vec3 _gravity; - float _driveKeys[MAX_DRIVE_KEYS]; bool _wasPushing; bool _isPushing; @@ -291,7 +289,6 @@ private: float _boomLength; - float _trapDuration; // seconds that avatar has been trapped by collisions glm::vec3 _thrust; // impulse accumulator for outside sources glm::vec3 _keyboardMotorVelocity; // target local-frame velocity of avatar (keyboard) From 652376db8a529578da77b845dbc5ba2821b085bf Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Thu, 8 Oct 2015 21:44:45 -0700 Subject: [PATCH 04/14] Kill the stuff we can't do yet. --- interface/src/avatar/MyAvatar.cpp | 40 +++++++++++++++++++------------ 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 3b8f99ab19..88dc00d53c 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -140,35 +140,45 @@ QByteArray MyAvatar::toByteArray(bool cullSmallChanges, bool sendAll) { } void MyAvatar::reset() { - _skeletonModel.reset(); - float headYaw = getHead()->getBaseYaw(); // degrees - // Reset the pitch and roll components of the avatar's orientation, preserve yaw direction - glm::vec3 eulers = safeEulerAngles(getOrientation()); - eulers.x = 0.0f; - eulers.y += glm::radians(headYaw); // align body with head - eulers.z = 0.0f; - + // Gather animation mode... // This should be simpler when we have only graph animations always on. bool isRig = _rig->getEnableRig(); // seting rig animation to true, below, will clear the graph animation menu item, so grab it now. bool isGraph = _rig->getEnableAnimGraph() || Menu::getInstance()->isOptionChecked(MenuOption::EnableAnimGraph); + // ... and get to sane configuration where other activity won't bother us. qApp->setRawAvatarUpdateThreading(false); _rig->disableHands = true; setEnableRigAnimations(true); + // Reset dynamic state. _wasPushing = _isPushing = _isBraking = _billboardValid = _goToPending = _straightingLean = false; + _skeletonModel.reset(); getHead()->reset(); _targetVelocity = glm::vec3(0.0f); setThrust(glm::vec3(0.0f)); - auto worldBodyMatrix = _sensorToWorldMatrix * _bodySensorMatrix; // Assuming these are in sync and current... - setPosition(extractTranslation(worldBodyMatrix)); // ...positions body under head. - setOrientation(glm::quat(eulers)); // Not from worldBodyMatrix, in case it is NOT in sync and current. - // Make sure we have current sensor data. + + // Get fresh data, in case we're really slow and out of wack. _hmdSensorMatrix = qApp->getHMDSensorPose(); _hmdSensorPosition = extractTranslation(_hmdSensorMatrix); - _hmdSensorOrientation = extractRotation(_hmdSensorMatrix); - _bodySensorMatrix = deriveBodyFromHMDSensor(); // Based on new HMD position and yaw (no x/z rotation), in sensor space. - updateSensorToWorldMatrix(); // Uses updated position/orientation and _bodySensorMatrix changes + _hmdSensorOrientation = glm::quat_cast(_hmdSensorMatrix); + + // Reset body position/orientation under the head. + auto newBodySensorMatrix = deriveBodyFromHMDSensor(); // Based on current cached HMD position/rotation.. + auto worldBodyMatrix = _sensorToWorldMatrix * newBodySensorMatrix; + glm::vec3 worldBodyPos = extractTranslation(worldBodyMatrix); + glm::quat worldBodyRot = glm::normalize(glm::quat_cast(worldBodyMatrix)); + + // FIXME: Hack to retain the previous behavior wrt height. + // I'd like to make the body match head height, but that will have to wait for separate PR. + worldBodyPos.y = getPosition().y; + + setPosition(worldBodyPos); + setOrientation(worldBodyRot); + // If there is any discrepency between positioning and the head (as there is in initial deriveBodyFromHMDSensor), + // we can make that right by setting _bodySensorMatrix = newBodySensorMatrix. + // However, doing so will make the head want to point to the previous body orientation, as cached above. + //_bodySensorMatrix = newBodySensorMatrix; + //updateSensorToWorldMatrix(); // Uses updated position/orientation and _bodySensorMatrix changes _skeletonModel.simulate(0.1f); // non-zero setEnableRigAnimations(false); From f1babb7fa04ad881228acf40f7c824283b215d16 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 8 Oct 2015 17:35:48 -0700 Subject: [PATCH 05/14] Fix bug in OctreeInboundPacketProcessor where node can be null --- .../src/octree/OctreeInboundPacketProcessor.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/assignment-client/src/octree/OctreeInboundPacketProcessor.cpp b/assignment-client/src/octree/OctreeInboundPacketProcessor.cpp index cb94990037..92c08152f7 100644 --- a/assignment-client/src/octree/OctreeInboundPacketProcessor.cpp +++ b/assignment-client/src/octree/OctreeInboundPacketProcessor.cpp @@ -261,6 +261,12 @@ int OctreeInboundPacketProcessor::sendNackPackets() { } const SharedNodePointer& destinationNode = DependencyManager::get()->nodeWithUUID(nodeUUID); + // If the node no longer exists, wait until the ReceivedPacketProcessor has cleaned up the node + // to remove it from our stats list. + // FIXME Is it safe to clean it up here before ReceivedPacketProcess has? + if (!destinationNode) { + continue; + } // retrieve sequence number stats of node, prune its missing set SequenceNumberStats& sequenceNumberStats = nodeStats.getIncomingEditSequenceNumberStats(); From 4dddb508a8917796ae058d03cd0f4bdf4712e19e Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 8 Oct 2015 17:36:01 -0700 Subject: [PATCH 06/14] Fix _packets not being cleaned up in ReceivedPacketProcessor --- libraries/networking/src/ReceivedPacketProcessor.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/networking/src/ReceivedPacketProcessor.cpp b/libraries/networking/src/ReceivedPacketProcessor.cpp index cc516bdbbd..f92a82cf0d 100644 --- a/libraries/networking/src/ReceivedPacketProcessor.cpp +++ b/libraries/networking/src/ReceivedPacketProcessor.cpp @@ -88,6 +88,7 @@ bool ReceivedPacketProcessor::process() { void ReceivedPacketProcessor::nodeKilled(SharedNodePointer node) { lock(); + _packets.remove_if([&](const NodeSharedPacketPair& pair) { return pair.first == node; }); _nodePacketCounts.remove(node->getUUID()); unlock(); } From 21e9d30bbe282f3971cd0bd5bd4b9758479ccfa8 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 9 Oct 2015 09:58:32 -0700 Subject: [PATCH 07/14] Move qdeclare/qregister calls to their respective class header --- libraries/networking/src/udt/Packet.cpp | 2 ++ libraries/networking/src/udt/Packet.h | 4 +++- libraries/networking/src/udt/PacketList.cpp | 2 ++ libraries/networking/src/udt/PacketList.h | 2 ++ libraries/networking/src/udt/Socket.cpp | 6 ------ 5 files changed, 9 insertions(+), 7 deletions(-) diff --git a/libraries/networking/src/udt/Packet.cpp b/libraries/networking/src/udt/Packet.cpp index d06ff9707e..e068727e6f 100644 --- a/libraries/networking/src/udt/Packet.cpp +++ b/libraries/networking/src/udt/Packet.cpp @@ -13,6 +13,8 @@ using namespace udt; +static int packetMetaTypeId = qRegisterMetaType("Packet*"); + int Packet::localHeaderSize(bool isPartOfMessage) { return sizeof(Packet::SequenceNumberAndBitField) + (isPartOfMessage ? sizeof(Packet::MessageNumberAndBitField) + sizeof(MessagePartNumber) : 0); diff --git a/libraries/networking/src/udt/Packet.h b/libraries/networking/src/udt/Packet.h index 24b9144672..02d2c3d9bd 100644 --- a/libraries/networking/src/udt/Packet.h +++ b/libraries/networking/src/udt/Packet.h @@ -88,7 +88,9 @@ private: mutable PacketPosition _packetPosition { PacketPosition::ONLY }; mutable MessagePartNumber _messagePartNumber { 0 }; }; - + } // namespace udt +Q_DECLARE_METATYPE(udt::Packet*); + #endif // hifi_Packet_h diff --git a/libraries/networking/src/udt/PacketList.cpp b/libraries/networking/src/udt/PacketList.cpp index 09d8628a1c..332603a8b9 100644 --- a/libraries/networking/src/udt/PacketList.cpp +++ b/libraries/networking/src/udt/PacketList.cpp @@ -15,6 +15,8 @@ using namespace udt; +static int packetListMetaTypeId = qRegisterMetaType("PacketList*"); + std::unique_ptr PacketList::create(PacketType packetType, QByteArray extendedHeader, bool isReliable, bool isOrdered) { auto packetList = std::unique_ptr(new PacketList(packetType, extendedHeader, diff --git a/libraries/networking/src/udt/PacketList.h b/libraries/networking/src/udt/PacketList.h index 5337094d1f..a6bee9f5eb 100644 --- a/libraries/networking/src/udt/PacketList.h +++ b/libraries/networking/src/udt/PacketList.h @@ -118,4 +118,6 @@ template std::unique_ptr PacketList::takeFront() { } +Q_DECLARE_METATYPE(udt::PacketList*); + #endif // hifi_PacketList_h diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index bc34c6e294..6d4a834879 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -24,16 +24,10 @@ using namespace udt; -Q_DECLARE_METATYPE(Packet*); -Q_DECLARE_METATYPE(PacketList*); - Socket::Socket(QObject* parent) : QObject(parent), _synTimer(new QTimer(this)) { - qRegisterMetaType("Packet*"); - qRegisterMetaType("PacketList*"); - connect(&_udpSocket, &QUdpSocket::readyRead, this, &Socket::readPendingDatagrams); // make sure our synchronization method is called every SYN interval From 36aaffce43891cd50b490d9ead43c86e2089cb80 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 9 Oct 2015 10:01:53 -0700 Subject: [PATCH 08/14] Revert "Fix _packets not being cleaned up in ReceivedPacketProcessor" This reverts commit 4dddb508a8917796ae058d03cd0f4bdf4712e19e. --- libraries/networking/src/ReceivedPacketProcessor.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/networking/src/ReceivedPacketProcessor.cpp b/libraries/networking/src/ReceivedPacketProcessor.cpp index f92a82cf0d..cc516bdbbd 100644 --- a/libraries/networking/src/ReceivedPacketProcessor.cpp +++ b/libraries/networking/src/ReceivedPacketProcessor.cpp @@ -88,7 +88,6 @@ bool ReceivedPacketProcessor::process() { void ReceivedPacketProcessor::nodeKilled(SharedNodePointer node) { lock(); - _packets.remove_if([&](const NodeSharedPacketPair& pair) { return pair.first == node; }); _nodePacketCounts.remove(node->getUUID()); unlock(); } From 58f9830a94e1456b08d98cd37e661b1531b8a9bf Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 9 Oct 2015 10:04:35 -0700 Subject: [PATCH 09/14] fix for re-send timeout in SendQueue --- libraries/networking/src/udt/Connection.cpp | 1 + libraries/networking/src/udt/SendQueue.cpp | 3 ++- libraries/networking/src/udt/SendQueue.h | 2 ++ 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 96d73676f0..639b2990ec 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -91,6 +91,7 @@ SendQueue& Connection::getSendQueue() { // set defaults on the send queue from our congestion control object and estimatedTimeout() _sendQueue->setPacketSendPeriod(_congestionControl->_packetSendPeriod); + _sendQueue->setSyncInterval(_synInterval); _sendQueue->setEstimatedTimeout(estimatedTimeout()); _sendQueue->setFlowWindowSize(std::min(_flowWindowSize, (int) _congestionControl->_congestionWindowSize)); } diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index 01175d0a94..fd11b0f41e 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -439,7 +439,8 @@ bool SendQueue::isInactive(bool sentAPacket) { } else { // We think the client is still waiting for data (based on the sequence number gap) // Let's wait either for a response from the client or until the estimated timeout - auto waitDuration = std::chrono::microseconds(_estimatedTimeout); + // (plus the sync interval to allow the client to respond) has elapsed + auto waitDuration = std::chrono::microseconds(_estimatedTimeout + _syncInterval); // use our condition_variable_any to wait auto cvStatus = _emptyCondition.wait_for(locker, waitDuration); diff --git a/libraries/networking/src/udt/SendQueue.h b/libraries/networking/src/udt/SendQueue.h index 96de12a971..3fe4006139 100644 --- a/libraries/networking/src/udt/SendQueue.h +++ b/libraries/networking/src/udt/SendQueue.h @@ -63,6 +63,7 @@ public: void setPacketSendPeriod(int newPeriod) { _packetSendPeriod = newPeriod; } void setEstimatedTimeout(int estimatedTimeout) { _estimatedTimeout = estimatedTimeout; } + void setSyncInterval(int syncInterval) { _syncInterval = syncInterval; } public slots: void stop(); @@ -114,6 +115,7 @@ private: std::atomic _state { State::NotStarted }; std::atomic _estimatedTimeout { 0 }; // Estimated timeout, set from CC + std::atomic _syncInterval { udt::DEFAULT_SYN_INTERVAL_USECS }; // Sync interval, set from CC std::atomic _timeoutExpiryCount { 0 }; // The number of times the timeout has expired without response from client std::atomic _lastReceiverResponse { 0 }; // Timestamp for the last time we got new data from the receiver (ACK/NAK) From c02df56cebcd7d0a56cbeacc2731883c89cd6527 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 9 Oct 2015 13:15:13 -0700 Subject: [PATCH 10/14] Fix uninitialized pointer in AssetResourceRequest --- libraries/networking/src/AssetResourceRequest.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/AssetResourceRequest.h b/libraries/networking/src/AssetResourceRequest.h index aee26a5d5a..0024426be0 100644 --- a/libraries/networking/src/AssetResourceRequest.h +++ b/libraries/networking/src/AssetResourceRequest.h @@ -30,7 +30,7 @@ private slots: void onDownloadProgress(qint64 bytesReceived, qint64 bytesTotal); private: - AssetRequest* _assetRequest; + AssetRequest* _assetRequest { nullptr }; }; #endif From cba8b0962d8f616fc123bf8ae132cc6f54cf462c Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 9 Oct 2015 13:29:59 -0700 Subject: [PATCH 11/14] Fix warnings --- libraries/gpu/src/gpu/GLBackendTexture.cpp | 2 -- .../input-plugins/src/input-plugins/SixenseManager.cpp | 6 +++--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/libraries/gpu/src/gpu/GLBackendTexture.cpp b/libraries/gpu/src/gpu/GLBackendTexture.cpp index b72fadafa0..71c5a83331 100755 --- a/libraries/gpu/src/gpu/GLBackendTexture.cpp +++ b/libraries/gpu/src/gpu/GLBackendTexture.cpp @@ -339,8 +339,6 @@ GLBackend::GLTexture* GLBackend::syncGPUObject(const Texture& texture) { GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(texture.getTexelFormat(), srcFormat); - auto semantic = texture.getTexelFormat().getSemantic(); - glTexImage2D(GL_TEXTURE_2D, 0, texelFormat.internalFormat, texture.getWidth(), texture.getHeight(), 0, texelFormat.format, texelFormat.type, bytes); diff --git a/libraries/input-plugins/src/input-plugins/SixenseManager.cpp b/libraries/input-plugins/src/input-plugins/SixenseManager.cpp index bc64ec4ccc..f542e63668 100644 --- a/libraries/input-plugins/src/input-plugins/SixenseManager.cpp +++ b/libraries/input-plugins/src/input-plugins/SixenseManager.cpp @@ -68,10 +68,10 @@ const float DEFAULT_REACH_LENGTH = 1.5f; SixenseManager::SixenseManager() : InputDevice("Hydra"), -#ifdef __APPLE__ - _sixenseLibrary(NULL), -#endif _reachLength(DEFAULT_REACH_LENGTH), +#ifdef __APPLE__ + _sixenseLibrary(nullptr), +#endif _hydrasConnected(false) { } From 0c489e3afd6e93ff3170022e27514a02b9def1dc Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Fri, 9 Oct 2015 14:46:05 -0700 Subject: [PATCH 12/14] MyAvatar: Rename new instance variable after merge. --- 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 a02fd4fee1..22816e9001 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -152,7 +152,7 @@ void MyAvatar::reset() { setEnableRigAnimations(true); // Reset dynamic state. - _wasPushing = _isPushing = _isBraking = _billboardValid = _goToPending = _straightingLean = false; + _wasPushing = _isPushing = _isBraking = _billboardValid = _goToPending = _straighteningLean = false; _skeletonModel.reset(); getHead()->reset(); _targetVelocity = glm::vec3(0.0f); From 4661b49e3d03b446d34d0ff5ae737c878cd53803 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Fri, 9 Oct 2015 14:57:24 -0700 Subject: [PATCH 13/14] fix regressions introduced by deciding not to call setEntityCustomData --- unpublishedScripts/hiddenEntityReset.js | 6 +++--- unpublishedScripts/masterReset.js | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/unpublishedScripts/hiddenEntityReset.js b/unpublishedScripts/hiddenEntityReset.js index 9b443fc1ae..d480c0ac74 100644 --- a/unpublishedScripts/hiddenEntityReset.js +++ b/unpublishedScripts/hiddenEntityReset.js @@ -979,7 +979,7 @@ resetMe: { resetMe: true, }, - grabbaleKey: { + grabbableKey: { grabbable: false } }) @@ -1165,7 +1165,7 @@ resetMe: true, }, grabbableKey: { - grabbale: false + grabbable: false } }) }); @@ -1207,7 +1207,7 @@ resetMe: { resetMe: true, }, - grabbaleKey: { + grabbableKey: { grabbable: false } }) diff --git a/unpublishedScripts/masterReset.js b/unpublishedScripts/masterReset.js index 6b4a2528cf..693e2eb28b 100644 --- a/unpublishedScripts/masterReset.js +++ b/unpublishedScripts/masterReset.js @@ -946,7 +946,7 @@ MasterReset = function() { resetMe: { resetMe: true, }, - grabbaleKey: { + grabbableKey: { grabbable: false } }) @@ -1132,7 +1132,7 @@ MasterReset = function() { resetMe: true, }, grabbableKey: { - grabbale: false + grabbable: false } }) }); @@ -1174,7 +1174,7 @@ MasterReset = function() { resetMe: { resetMe: true, }, - grabbaleKey: { + grabbableKey: { grabbable: false } }) From 1dfafec5afaf765fa7b44485efee9888aacbfc75 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Fri, 9 Oct 2015 15:46:54 -0700 Subject: [PATCH 14/14] Prototyping controller refactoring --- libraries/controllers/CMakeLists.txt | 14 ++ .../src/controllers/ControllerMapping.cpp | 190 ++++++++++++++++++ 2 files changed, 204 insertions(+) create mode 100644 libraries/controllers/CMakeLists.txt create mode 100644 libraries/controllers/src/controllers/ControllerMapping.cpp diff --git a/libraries/controllers/CMakeLists.txt b/libraries/controllers/CMakeLists.txt new file mode 100644 index 0000000000..fbabbe1463 --- /dev/null +++ b/libraries/controllers/CMakeLists.txt @@ -0,0 +1,14 @@ +set(TARGET_NAME controllers) + +# set a default root dir for each of our optional externals if it was not passed +setup_hifi_library(Script) + +# use setup_hifi_library macro to setup our project and link appropriate Qt modules +link_hifi_libraries(shared plugins input-plugins) + +GroupSources("src/controllers") + +add_dependency_external_projects(glm) +find_package(GLM REQUIRED) +target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS}) + diff --git a/libraries/controllers/src/controllers/ControllerMapping.cpp b/libraries/controllers/src/controllers/ControllerMapping.cpp new file mode 100644 index 0000000000..59f8789d31 --- /dev/null +++ b/libraries/controllers/src/controllers/ControllerMapping.cpp @@ -0,0 +1,190 @@ +#include +#include + +#include +#include + +extern float currentTime(); + +namespace Controllers { + + /* + * Encapsulates a particular input / output, + * i.e. Hydra.Button0, Standard.X, Action.Yaw + */ + class Endpoint { + public: + virtual float value() = 0; + virtual void apply(float newValue, float oldValue, const Endpoint& source) = 0; + }; + + using EndpointList = std::list; + + const EndpointList& getHardwareEndpoints(); + + // Ex: xbox.RY, xbox.A .... + class HardwareEndpoint : public Endpoint { + public: + virtual float value() override { + // ... + } + + virtual void apply(float newValue, float oldValue, const Endpoint& source) override { + // Default does nothing, but in theory this could be something like vibration + // mapping.from(xbox.X).to(xbox.Vibrate) + } + }; + + class VirtualEndpoint : public Endpoint { + public: + virtual void apply(float newValue) { + if (newValue != _lastValue) { + _lastValue = newValue; + } + } + + virtual float value() { + return _lastValue; + } + + float _lastValue; + }; + + /* + * A function which provides input + */ + class FunctionEndpoint : public Endpoint { + public: + + virtual float value() override { + float now = currentTime(); + float delta = now - _lastCalled; + float result = _inputFunction.call(_object, QScriptValue(delta)).toNumber(); + _lastCalled = now; + return result; + } + + virtual void apply(float newValue, float oldValue, const Endpoint& source) override { + if (newValue != oldValue) { + //_outputFunction.call(newValue, oldValue, source); + } + } + + float _lastValue{ NAN }; + float _lastCalled{ 0 }; + QScriptValue _outputFunction; + QScriptValue _inputFunction; + QScriptValue _object; + }; + + + // Encapsulates part of a filter chain + class Filter { + public: + virtual float apply(float newValue, float oldValue) = 0; + }; + + class ScaleFilter : public Filter { + public: + virtual float apply(float newValue, float oldValue) { + return newValue * _scale; + } + + float _scale{ 1.0 }; + }; + + class PulseFilter : public Filter { + public: + virtual float apply(float newValue, float oldValue) { + // ??? + } + + float _lastEmitValue{ 0 }; + float _lastEmitTime{ 0 }; + float _interval{ -1.0f }; + }; + + using FilterList = std::list; + + /* + * encapsulates a source, destination and filters to apply + */ + class Route { + public: + Endpoint* _source; + Endpoint* _destination; + FilterList _filters; + }; + + using ValueMap = std::map; + + class Mapping { + public: + // List of routes + using List = std::list; + // Map of source channels to route lists + using Map = std::map; + + Map _channelMappings; + ValueMap _lastValues; + }; + + class MappingsStack { + std::list _stack; + ValueMap _lastValues; + + void update() { + EndpointList hardwareInputs = getHardwareEndpoints(); + ValueMap currentValues; + + for (auto input : hardwareInputs) { + currentValues[input] = input->value(); + } + + // Now process the current values for each level of the stack + for (auto& mapping : _stack) { + update(mapping, currentValues); + } + + _lastValues = currentValues; + } + + void update(Mapping& mapping, ValueMap& values) { + ValueMap updates; + EndpointList consumedEndpoints; + for (const auto& entry : values) { + Endpoint* endpoint = entry.first; + if (!mapping._channelMappings.count(endpoint)) { + continue; + } + + const Mapping::List& routes = mapping._channelMappings[endpoint]; + consumedEndpoints.push_back(endpoint); + for (const auto& route : routes) { + float lastValue = 0; + if (mapping._lastValues.count(endpoint)) { + lastValue = mapping._lastValues[endpoint]; + } + float value = entry.second; + for (const auto& filter : route._filters) { + value = filter->apply(value, lastValue); + } + updates[route._destination] = value; + } + } + + // Update the last seen values + mapping._lastValues = values; + + // Remove all the consumed inputs + for (auto endpoint : consumedEndpoints) { + values.erase(endpoint); + } + + // Add all the updates (may restore some of the consumed data if a passthrough was created (i.e. source == dest) + for (const auto& entry : updates) { + values[entry.first] = entry.second; + } + } + }; +}