Also, split getReactions() API into two calls * getTriggerReactions() - lists all reactions that can be triggered with MyAvatar.triggerReaction(). * getBeginReactions() - lists all reactions that can be used with MyAvatar.beginReaction() and MyAvatar.endReaction().
Unified · Split
| @@ -125,16 +125,25 @@ QString userRecenterModelToString(MyAvatar::SitStandModelType model) { · 124 unmodified lines | ||
| 125 | 125 | } |
| 126 | 126 | } |
| 127 | 127 | |
| 128 | −static const QStringList REACTION_NAMES = { | |
| 128 | +static const QStringList TRIGGER_REACTION_NAMES = { | |
| 129 | 129 | QString("positive"), |
| 130 | − QString("negative"), | |
| 130 | + QString("negative") | |
| 131 | +}; | |
| 132 | + | |
| 133 | +static const QStringList BEGIN_END_REACTION_NAMES = { | |
| 131 | 134 | QString("raiseHand"), |
| 132 | 135 | QString("applaud"), |
| 133 | 136 | QString("point") |
| 134 | 137 | }; |
| 135 | 138 | |
| 136 | −static int reactionNameToIndex(const QString& reactionName) { | |
| 137 | − return REACTION_NAMES.indexOf(reactionName); | |
| 139 | +static int triggerReactionNameToIndex(const QString& reactionName) { | |
| 140 | + assert(NUM_AVATAR_TRIGGER_REACTIONS == TRIGGER_REACTION_NAMES.size()); | |
| 141 | + return TRIGGER_REACTION_NAMES.indexOf(reactionName); | |
| 142 | +} | |
| 143 | + | |
| 144 | +static int beginEndReactionNameToIndex(const QString& reactionName) { | |
| 145 | + assert(NUM_AVATAR_BEGIN_END_REACTIONS == TRIGGER_REACTION_NAMES.size()); | |
| 146 | + return BEGIN_END_REACTION_NAMES.indexOf(reactionName); | |
| 138 | 147 | } |
| 139 | 148 | |
| 140 | 149 | MyAvatar::MyAvatar(QThread* thread) : |
| @@ -5824,13 +5833,17 @@ void MyAvatar::setModelScale(float scale) { · 5683 unmodified lines | ||
| 5824 | 5833 | } |
| 5825 | 5834 | } |
| 5826 | 5835 | |
| 5827 | −QStringList MyAvatar::getReactions() const { | |
| 5828 | − return REACTION_NAMES; | |
| 5836 | +QStringList MyAvatar::getBeginEndReactions() const { | |
| 5837 | + return BEGIN_END_REACTION_NAMES; | |
| 5838 | +} | |
| 5839 | + | |
| 5840 | +QStringList MyAvatar::getTriggerReactions() const { | |
| 5841 | + return TRIGGER_REACTION_NAMES; | |
| 5829 | 5842 | } |
| 5830 | 5843 | |
| 5831 | 5844 | bool MyAvatar::triggerReaction(QString reactionName) { |
| 5832 | − int reactionIndex = reactionNameToIndex(reactionName); | |
| 5833 | − if (reactionIndex >= 0 && reactionIndex < (int)NUM_AVATAR_REACTIONS) { | |
| 5845 | + int reactionIndex = triggerReactionNameToIndex(reactionName); | |
| 5846 | + if (reactionIndex >= 0 && reactionIndex < (int)NUM_AVATAR_TRIGGER_REACTIONS) { | |
| 5834 | 5847 | std::lock_guard<std::mutex> guard(_reactionLock); |
| 5835 | 5848 | _reactionTriggers[reactionIndex] = true; |
| 5836 | 5849 | return true; |
| @@ -5839,8 +5852,8 @@ bool MyAvatar::triggerReaction(QString reactionName) { · 2 unmodified lines | ||
| 5839 | 5852 | } |
| 5840 | 5853 | |
| 5841 | 5854 | bool MyAvatar::beginReaction(QString reactionName) { |
| 5842 | − int reactionIndex = reactionNameToIndex(reactionName); | |
| 5843 | − if (reactionIndex >= 0 && reactionIndex < (int)NUM_AVATAR_REACTIONS) { | |
| 5855 | + int reactionIndex = beginEndReactionNameToIndex(reactionName); | |
| 5856 | + if (reactionIndex >= 0 && reactionIndex < (int)NUM_AVATAR_BEGIN_END_REACTIONS) { | |
| 5844 | 5857 | std::lock_guard<std::mutex> guard(_reactionLock); |
| 5845 | 5858 | _reactionEnabledRefCounts[reactionIndex]++; |
| 5846 | 5859 | return true; |
| @@ -5849,8 +5862,8 @@ bool MyAvatar::beginReaction(QString reactionName) { · 2 unmodified lines | ||
| 5849 | 5862 | } |
| 5850 | 5863 | |
| 5851 | 5864 | bool MyAvatar::endReaction(QString reactionName) { |
| 5852 | − int reactionIndex = reactionNameToIndex(reactionName); | |
| 5853 | − if (reactionIndex >= 0 && reactionIndex < (int)NUM_AVATAR_REACTIONS) { | |
| 5865 | + int reactionIndex = beginEndReactionNameToIndex(reactionName); | |
| 5866 | + if (reactionIndex >= 0 && reactionIndex < (int)NUM_AVATAR_BEGIN_END_REACTIONS) { | |
| 5854 | 5867 | std::lock_guard<std::mutex> guard(_reactionLock); |
| 5855 | 5868 | _reactionEnabledRefCounts[reactionIndex]--; |
| 5856 | 5869 | return true; |
| @@ -5860,12 +5873,17 @@ bool MyAvatar::endReaction(QString reactionName) { · 3 unmodified lines | ||
| 5860 | 5873 | |
| 5861 | 5874 | void MyAvatar::updateRigControllerParameters(Rig::ControllerParameters& params) { |
| 5862 | 5875 | std::lock_guard<std::mutex> guard(_reactionLock); |
| 5863 | − for (int i = 0; i < NUM_AVATAR_REACTIONS; i++) { | |
| 5864 | 5876 | |
| 5877 | + for (int i = 0; i < TRIGGER_REACTION_NAMES.size(); i++) { | |
| 5878 | + params.reactionTriggers[i] = _reactionTriggers[i]; | |
| 5879 | + } | |
| 5880 | + | |
| 5881 | + for (int i = 0; i < BEGIN_END_REACTION_NAMES.size(); i++) { | |
| 5865 | 5882 | // copy current state into params. |
| 5866 | 5883 | params.reactionEnabledFlags[i] = _reactionEnabledRefCounts[i] > 0; |
| 5867 | − params.reactionTriggers[i] = _reactionTriggers[i]; | |
| 5884 | + } | |
| 5868 | 5885 | |
| 5886 | + for (int i = 0; i < TRIGGER_REACTION_NAMES.size(); i++) { | |
| 5869 | 5887 | // clear reaction triggers here as well |
| 5870 | 5888 | _reactionTriggers[i] = false; |
| 5871 | 5889 | } |
| @@ -2213,13 +2213,23 @@ public slots: · 2212 unmodified lines | ||
| 2213 | 2213 | virtual void setModelScale(float scale) override; |
| 2214 | 2214 | |
| 2215 | 2215 | /**jsdoc |
| 2216 | − * MyAvatar.getReactions | |
| 2216 | + * MyAvatar.getTriggerReactions | |
| 2217 | + * Returns a list of reactions names that can be triggered using MyAvatar.triggerReaction(). | |
| 2217 | 2218 | * @returns {string[]} Array of reaction names. |
| 2218 | 2219 | */ |
| 2219 | − QStringList getReactions() const; | |
| 2220 | + QStringList getTriggerReactions() const; | |
| 2221 | + | |
| 2222 | + | |
| 2223 | + /**jsdoc | |
| 2224 | + * MyAvatar.getBeginReactions | |
| 2225 | + * Returns a list of reactions names that can be enabled using MyAvatar.beginReaction() and MyAvatar.endReaction(). | |
| 2226 | + * @returns {string[]} Array of reaction names. | |
| 2227 | + */ | |
| 2228 | + QStringList getBeginEndReactions() const; | |
| 2220 | 2229 | |
| 2221 | 2230 | /**jsdoc |
| 2222 | 2231 | * MyAvatar.triggerReaction |
| 2232 | + * Plays the given reaction on the avatar, once the reaction is complete it will automatically complete. Only reaction names returned from MyAvatar.getTriggerReactions() are available. | |
| 2223 | 2233 | * @param {string} reactionName - reaction name |
| 2224 | 2234 | * @returns {bool} false if the given reaction is not supported. |
| 2225 | 2235 | */ |
| @@ -2227,6 +2237,9 @@ public slots: · 1 unmodified line | ||
| 2227 | 2237 | |
| 2228 | 2238 | /**jsdoc |
| 2229 | 2239 | * MyAvatar.beginReaction |
| 2240 | + * Plays the given reaction on the avatar. The avatar will continue to play the reaction until stopped via the MyAvatar.endReaction() call or superseeded by another reaction. | |
| 2241 | + * Only reaction names returned from MyAvatar.getBeginEndReactions() are available. | |
| 2242 | + * NOTE: the caller is responsible for calling the corresponding MyAvatar.endReaction(), otherwise the avatar might become stuck in the reaction forever. | |
| 2230 | 2243 | * @param {string} reactionName - reaction name |
| 2231 | 2244 | * @returns {bool} false if the given reaction is not supported. |
| 2232 | 2245 | */ |
| @@ -2234,6 +2247,7 @@ public slots: · 1 unmodified line | ||
| 2234 | 2247 | |
| 2235 | 2248 | /**jsdoc |
| 2236 | 2249 | * MyAvatar.endReaction |
| 2250 | + * Used to stop a given reaction that was started via MyAvatar.beginReaction(). | |
| 2237 | 2251 | * @param {string} reactionName - reaction name |
| 2238 | 2252 | * @returns {bool} false if the given reaction is not supported. |
| 2239 | 2253 | */ |
| @@ -2872,8 +2886,9 @@ private: · 632 unmodified lines | ||
| 2872 | 2886 | QScriptEngine* _scriptEngine { nullptr }; |
| 2873 | 2887 | bool _needToSaveAvatarEntitySettings { false }; |
| 2874 | 2888 | |
| 2875 | − int _reactionEnabledRefCounts[NUM_AVATAR_REACTIONS] { 0, 0, 0, 0, 0 }; | |
| 2876 | − bool _reactionTriggers[NUM_AVATAR_REACTIONS] { false, false, false, false, false }; | |
| 2889 | + bool _reactionTriggers[NUM_AVATAR_TRIGGER_REACTIONS] { false, false }; | |
| 2890 | + int _reactionEnabledRefCounts[NUM_AVATAR_BEGIN_END_REACTIONS] { 0, 0, 0 }; | |
| 2891 | + | |
| 2877 | 2892 | mutable std::mutex _reactionLock; |
| 2878 | 2893 | }; |
| 2879 | 2894 | |
| @@ -95,6 +95,15 @@ const AnimPoseVec& AnimStateMachine::evaluate(const AnimVariantMap& animVars, co · 94 unmodified lines | ||
| 95 | 95 | return _poses; |
| 96 | 96 | } |
| 97 | 97 | |
| 98 | +const QString& AnimStateMachine::getCurrentStateID() const { | |
| 99 | + if (_currentState) { | |
| 100 | + return _currentState->getID(); | |
| 101 | + } else { | |
| 102 | + static QString emptyString; | |
| 103 | + return emptyString; | |
| 104 | + } | |
| 105 | +} | |
| 106 | + | |
| 98 | 107 | void AnimStateMachine::setCurrentState(State::Pointer state) { |
| 99 | 108 | _previousState = _currentState ? _currentState : state; |
| 100 | 109 | _currentState = state; |
| @@ -116,6 +116,7 @@ public: · 115 unmodified lines | ||
| 116 | 116 | virtual const AnimPoseVec& evaluate(const AnimVariantMap& animVars, const AnimContext& context, float dt, AnimVariantMap& triggersOut) override; |
| 117 | 117 | |
| 118 | 118 | void setCurrentStateVar(QString& currentStateVar) { _currentStateVar = currentStateVar; } |
| 119 | + const QString& getCurrentStateID() const; | |
| 119 | 120 | |
| 120 | 121 | protected: |
| 121 | 122 | |
| @@ -29,6 +29,7 @@ · 28 unmodified lines | ||
| 29 | 29 | #include "AnimInverseKinematics.h" |
| 30 | 30 | #include "AnimOverlay.h" |
| 31 | 31 | #include "AnimSkeleton.h" |
| 32 | +#include "AnimStateMachine.h" | |
| 32 | 33 | #include "AnimUtil.h" |
| 33 | 34 | #include "AvatarConstants.h" |
| 34 | 35 | #include "IKTarget.h" |
| @@ -1906,28 +1907,7 @@ void Rig::updateFeet(bool leftFootEnabled, bool rightFootEnabled, bool headEnabl · 1871 unmodified lines | ||
| 1906 | 1907 | |
| 1907 | 1908 | void Rig::updateReactions(const ControllerParameters& params) { |
| 1908 | 1909 | |
| 1909 | − // enable/disable animVars | |
| 1910 | − bool enabled = params.reactionEnabledFlags[AVATAR_REACTION_POSITIVE]; | |
| 1911 | − _animVars.set("reactionPositiveEnabled", enabled); | |
| 1912 | − _animVars.set("reactionPositiveDisabled", !enabled); | |
| 1913 | − | |
| 1914 | − enabled = params.reactionEnabledFlags[AVATAR_REACTION_NEGATIVE]; | |
| 1915 | − _animVars.set("reactionNegativeEnabled", enabled); | |
| 1916 | − _animVars.set("reactionNegativeDisabled", !enabled); | |
| 1917 | − | |
| 1918 | − enabled = params.reactionEnabledFlags[AVATAR_REACTION_RAISE_HAND]; | |
| 1919 | − _animVars.set("reactionRaiseHandEnabled", enabled); | |
| 1920 | − _animVars.set("reactionRaiseHandDisabled", !enabled); | |
| 1921 | − | |
| 1922 | − enabled = params.reactionEnabledFlags[AVATAR_REACTION_APPLAUD]; | |
| 1923 | − _animVars.set("reactionApplaudEnabled", enabled); | |
| 1924 | − _animVars.set("reactionApplaudDisabled", !enabled); | |
| 1925 | − | |
| 1926 | − enabled = params.reactionEnabledFlags[AVATAR_REACTION_POINT]; | |
| 1927 | − _animVars.set("reactionPointEnabled", enabled); | |
| 1928 | − _animVars.set("reactionPointDisabled", !enabled); | |
| 1929 | − | |
| 1930 | − // trigger animVars | |
| 1910 | + // trigger reactions | |
| 1931 | 1911 | if (params.reactionTriggers[AVATAR_REACTION_POSITIVE]) { |
| 1932 | 1912 | _animVars.set("reactionPositiveTrigger", true); |
| 1933 | 1913 | } else { |
| @@ -1940,22 +1920,33 @@ void Rig::updateReactions(const ControllerParameters& params) { · 6 unmodified lines | ||
| 1940 | 1920 | _animVars.set("reactionNegativeTrigger", false); |
| 1941 | 1921 | } |
| 1942 | 1922 | |
| 1943 | − if (params.reactionTriggers[AVATAR_REACTION_RAISE_HAND]) { | |
| 1944 | − _animVars.set("reactionRaiseHandTrigger", true); | |
| 1945 | − } else { | |
| 1946 | − _animVars.set("reactionRaiseHandTrigger", false); | |
| 1947 | − } | |
| 1923 | + // begin end reactions | |
| 1924 | + bool enabled = params.reactionEnabledFlags[AVATAR_REACTION_RAISE_HAND]; | |
| 1925 | + _animVars.set("reactionRaiseHandEnabled", enabled); | |
| 1926 | + _animVars.set("reactionRaiseHandDisabled", !enabled); | |
| 1948 | 1927 | |
| 1949 | − if (params.reactionTriggers[AVATAR_REACTION_APPLAUD]) { | |
| 1950 | − _animVars.set("reactionApplaudTrigger", true); | |
| 1951 | − } else { | |
| 1952 | − _animVars.set("reactionApplaudTrigger", false); | |
| 1953 | − } | |
| 1928 | + enabled = params.reactionEnabledFlags[AVATAR_REACTION_APPLAUD]; | |
| 1929 | + _animVars.set("reactionApplaudEnabled", enabled); | |
| 1930 | + _animVars.set("reactionApplaudDisabled", !enabled); | |
| 1954 | 1931 | |
| 1955 | − if (params.reactionTriggers[AVATAR_REACTION_POINT]) { | |
| 1956 | − _animVars.set("reactionPointTrigger", true); | |
| 1957 | − } else { | |
| 1958 | − _animVars.set("reactionPointTrigger", false); | |
| 1932 | + enabled = params.reactionEnabledFlags[AVATAR_REACTION_POINT]; | |
| 1933 | + _animVars.set("reactionPointEnabled", enabled); | |
| 1934 | + _animVars.set("reactionPointDisabled", !enabled); | |
| 1935 | + | |
| 1936 | + // determine if we should ramp off IK | |
| 1937 | + if (_enableInverseKinematics) { | |
| 1938 | + bool reactionPlaying = false; | |
| 1939 | + std::shared_ptr<AnimStateMachine> mainStateMachine = std::dynamic_pointer_cast<AnimStateMachine>(_animNode->findByName("mainStateMachine")); | |
| 1940 | + std::shared_ptr<AnimStateMachine> idleStateMachine = std::dynamic_pointer_cast<AnimStateMachine>(_animNode->findByName("idle")); | |
| 1941 | + if (mainStateMachine && mainStateMachine->getCurrentStateID() == "idle" && idleStateMachine) { | |
| 1942 | + reactionPlaying = idleStateMachine->getCurrentStateID().startsWith("reaction"); | |
| 1943 | + } | |
| 1944 | + | |
| 1945 | + bool hipsEnabled = params.primaryControllerFlags[PrimaryControllerType_Hips] & (uint8_t)ControllerFlags::Enabled; | |
| 1946 | + if (reactionPlaying && !hipsEnabled) { | |
| 1947 | + // disable head IK while reaction is playing, but only in "desktop" mode. | |
| 1948 | + _animVars.set("headType", (int)IKTarget::Type::Unknown); | |
| 1949 | + } | |
| 1959 | 1950 | } |
| 1960 | 1951 | } |
| 1961 | 1952 | |
| @@ -88,8 +88,8 @@ public: · 87 unmodified lines | ||
| 88 | 88 | AnimPose secondaryControllerPoses[NumSecondaryControllerTypes]; // rig space |
| 89 | 89 | uint8_t secondaryControllerFlags[NumSecondaryControllerTypes]; |
| 90 | 90 | bool isTalking; |
| 91 | − bool reactionEnabledFlags[NUM_AVATAR_REACTIONS]; | |
| 92 | − bool reactionTriggers[NUM_AVATAR_REACTIONS]; | |
| 91 | + bool reactionEnabledFlags[NUM_AVATAR_BEGIN_END_REACTIONS]; | |
| 92 | + bool reactionTriggers[NUM_AVATAR_TRIGGER_REACTIONS]; | |
| 93 | 93 | HFMJointShapeInfo hipsShapeInfo; |
| 94 | 94 | HFMJointShapeInfo spineShapeInfo; |
| 95 | 95 | HFMJointShapeInfo spine1ShapeInfo; |
| @@ -106,13 +106,17 @@ static const float AVATAR_WALK_SPEED_SCALAR = 1.0f; · 105 unmodified lines | ||
| 106 | 106 | static const float AVATAR_DESKTOP_SPRINT_SPEED_SCALAR = 3.0f; |
| 107 | 107 | static const float AVATAR_HMD_SPRINT_SPEED_SCALAR = 2.0f; |
| 108 | 108 | |
| 109 | −enum AvatarReaction { | |
| 109 | +enum AvatarTriggerReaction { | |
| 110 | 110 | AVATAR_REACTION_POSITIVE = 0, |
| 111 | 111 | AVATAR_REACTION_NEGATIVE, |
| 112 | + NUM_AVATAR_TRIGGER_REACTIONS | |
| 113 | +}; | |
| 114 | + | |
| 115 | +enum AvatarBeginEndReaction { | |
| 112 | 116 | AVATAR_REACTION_RAISE_HAND, |
| 113 | 117 | AVATAR_REACTION_APPLAUD, |
| 114 | 118 | AVATAR_REACTION_POINT, |
| 115 | − NUM_AVATAR_REACTIONS | |
| 119 | + NUM_AVATAR_BEGIN_END_REACTIONS | |
| 116 | 120 | }; |
| 117 | 121 | |
| 118 | 122 | #endif // hifi_AvatarConstants_h |