diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index d0eaea8f23..2f7ae62e2e 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -237,6 +237,7 @@ void Avatar::simulate(float deltaTime) { measureMotionDerivatives(deltaTime); simulateAttachments(deltaTime); + updatePalms(); } bool Avatar::isLookingAtMe(AvatarSharedPointer avatar) const { @@ -1155,34 +1156,24 @@ void Avatar::rebuildCollisionShape() { } } +// thread-safe glm::vec3 Avatar::getLeftPalmPosition() { - glm::vec3 leftHandPosition; - getSkeletonModel().getLeftHandPosition(leftHandPosition); - glm::quat leftRotation; - getSkeletonModel().getJointRotationInWorldFrame(getSkeletonModel().getLeftHandJointIndex(), leftRotation); - leftHandPosition += HAND_TO_PALM_OFFSET * glm::inverse(leftRotation); - return leftHandPosition; + return _leftPalmPositionCache.get(); } +// thread-safe glm::quat Avatar::getLeftPalmRotation() { - glm::quat leftRotation; - getSkeletonModel().getJointRotationInWorldFrame(getSkeletonModel().getLeftHandJointIndex(), leftRotation); - return leftRotation; + return _leftPalmRotationCache.get(); } +// thread-safe glm::vec3 Avatar::getRightPalmPosition() { - glm::vec3 rightHandPosition; - getSkeletonModel().getRightHandPosition(rightHandPosition); - glm::quat rightRotation; - getSkeletonModel().getJointRotationInWorldFrame(getSkeletonModel().getRightHandJointIndex(), rightRotation); - rightHandPosition += HAND_TO_PALM_OFFSET * glm::inverse(rightRotation); - return rightHandPosition; + return _rightPalmPositionCache.get(); } +// thread-safe glm::quat Avatar::getRightPalmRotation() { - glm::quat rightRotation; - getSkeletonModel().getJointRotationInWorldFrame(getSkeletonModel().getRightHandJointIndex(), rightRotation); - return rightRotation; + return _rightPalmRotationCache.get(); } void Avatar::setPosition(const glm::vec3& position) { @@ -1194,3 +1185,24 @@ void Avatar::setOrientation(const glm::quat& orientation) { AvatarData::setOrientation(orientation); updateAttitude(); } + +void Avatar::updatePalms() { + + // get palm rotations + glm::quat leftPalmRotation, rightPalmRotation; + getSkeletonModel().getJointRotationInWorldFrame(getSkeletonModel().getLeftHandJointIndex(), leftPalmRotation); + getSkeletonModel().getJointRotationInWorldFrame(getSkeletonModel().getRightHandJointIndex(), rightPalmRotation); + + // get palm positions + glm::vec3 leftPalmPosition, rightPalmPosition; + getSkeletonModel().getLeftHandPosition(leftPalmPosition); + getSkeletonModel().getRightHandPosition(rightPalmPosition); + leftPalmPosition += HAND_TO_PALM_OFFSET * glm::inverse(leftPalmRotation); + rightPalmPosition += HAND_TO_PALM_OFFSET * glm::inverse(rightPalmRotation); + + // update thread-safe caches + _leftPalmRotationCache.set(leftPalmRotation); + _rightPalmRotationCache.set(rightPalmRotation); + _leftPalmPositionCache.set(leftPalmPosition); + _rightPalmPositionCache.set(rightPalmPosition); +} diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index 8f89027d2f..576327db3b 100644 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -27,6 +27,7 @@ #include "SkeletonModel.h" #include "world.h" #include "Rig.h" +#include namespace render { template <> const ItemKey payloadGetKey(const AvatarSharedPointer& avatar); @@ -227,8 +228,15 @@ protected: virtual void updateJointMappings() override; + virtual void updatePalms(); + render::ItemID _renderItemID; + ThreadSafeValueCache _leftPalmPositionCache { glm::vec3() }; + ThreadSafeValueCache _leftPalmRotationCache { glm::quat() }; + ThreadSafeValueCache _rightPalmPositionCache { glm::vec3() }; + ThreadSafeValueCache _rightPalmRotationCache { glm::quat() }; + private: bool _initialized; NetworkTexturePointer _billboardTexture; diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 000cd75784..60e35b4b52 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -417,6 +417,8 @@ void MyAvatar::updateSensorToWorldMatrix() { // position when driven from the head. glm::mat4 desiredMat = createMatFromQuatAndPos(getOrientation(), getPosition()); _sensorToWorldMatrix = desiredMat * glm::inverse(_bodySensorMatrix); + + lateUpdatePalms(); } // Update avatar head rotation with sensor data @@ -1839,3 +1841,8 @@ QScriptValue audioListenModeToScriptValue(QScriptEngine* engine, const AudioList void audioListenModeFromScriptValue(const QScriptValue& object, AudioListenerMode& audioListenerMode) { audioListenerMode = (AudioListenerMode)object.toUInt16(); } + + +void MyAvatar::lateUpdatePalms() { + Avatar::updatePalms(); +} diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 1a5753d0a5..44823c9913 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -311,12 +311,14 @@ private: void setVisibleInSceneIfReady(Model* model, render::ScenePointer scene, bool visiblity); - PalmData getActivePalmData(int palmIndex) const; - // derive avatar body position and orientation from the current HMD Sensor location. // results are in HMD frame glm::mat4 deriveBodyFromHMDSensor() const; + virtual void updatePalms() override {} + void lateUpdatePalms(); + + float _driveKeys[MAX_DRIVE_KEYS]; bool _wasPushing; bool _isPushing; diff --git a/libraries/shared/src/ThreadSafeValueCache.h b/libraries/shared/src/ThreadSafeValueCache.h new file mode 100644 index 0000000000..e4e78ca3d7 --- /dev/null +++ b/libraries/shared/src/ThreadSafeValueCache.h @@ -0,0 +1,49 @@ +// +// ThreadSafeValueCache.h +// interface/src/avatar +// +// Copyright 2012 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_ThreadSafeValueCache_h +#define hifi_ThreadSafeValueCache_h + +#include + +// Helper class for for sharing a value type between threads. +// It allows many threads to get or set a value atomically. +// This provides cache semantics, any get will return the last set value. +// +// For example: This can be used to copy values between C++ code running on the application thread +// and JavaScript which is running on a different thread. + +template +class ThreadSafeValueCache { +public: + ThreadSafeValueCache(const T& v) : _value { v } {} + + // returns atomic copy of the cached value. + T get() const { + std::lock_guard guard(_mutex); + return _value; + } + + // will reflect copy of value into the cache. + void set(const T& v) { + std::lock_guard guard(_mutex); + _value = v; + } + +private: + mutable std::mutex _mutex; + T _value; + + // no copies + ThreadSafeValueCache(const ThreadSafeValueCache&) = delete; + ThreadSafeValueCache& operator=(const ThreadSafeValueCache&) = delete; +}; + +#endif // #define hifi_ThreadSafeValueCache_h