Files
SingularityViewer/indra/llcharacter/llkeyframemotion.h
2019-03-09 01:51:50 -06:00

581 lines
18 KiB
C++

/**
* @file llkeyframemotion.h
* @brief Implementation of LLKeframeMotion class.
*
* $LicenseInfo:firstyear=2001&license=viewergpl$
*
* Copyright (c) 2001-2009, Linden Research, Inc.
* AICachedPointer and AICachedPointPtr copyright (c) 2013, Aleric Inglewood.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
*
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*/
#ifndef LL_LLKEYFRAMEMOTION_H
#define LL_LLKEYFRAMEMOTION_H
//-----------------------------------------------------------------------------
// Header files
//-----------------------------------------------------------------------------
#include <string>
#include "llassetstorage.h"
#include "llbboxlocal.h"
#include "llhandmotion.h"
#include "lljointstate.h"
#include "llmotion.h"
#include "llquaternion.h"
#include "v3dmath.h"
#include "v3math.h"
#include "llbvhconsts.h"
#include <boost/intrusive_ptr.hpp>
class LLKeyframeDataCache;
class LLVFS;
class LLDataPacker;
class LLMotionController;
#define MIN_REQUIRED_PIXEL_AREA_KEYFRAME (40.f)
#define MAX_CHAIN_LENGTH (4)
const S32 KEYFRAME_MOTION_VERSION = 1;
const S32 KEYFRAME_MOTION_SUBVERSION = 0;
//-----------------------------------------------------------------------------
// <singu>
template<typename KEY, typename T>
class AICachedPointer;
template<typename KEY, typename T>
void intrusive_ptr_add_ref(AICachedPointer<KEY, T> const* p);
template<typename KEY, typename T>
void intrusive_ptr_release(AICachedPointer<KEY, T> const* p);
template<typename KEY, typename T>
class AICachedPointer
{
public:
typedef std::set<AICachedPointer<KEY, T> > container_type;
private:
KEY mKey; // The unique key.
LLPointer<T> mData; // The actual data pointer.
container_type* mCache; // Pointer to the underlaying cache.
mutable int mRefCount; // Number of AICachedPointerPtr's pointing to this object.
public:
// Construct a NULL pointer. This is needed when adding a new entry to a std::set, it is always first default constructed.
AICachedPointer(void) : mCache(NULL) { }
// Copy constructor. This is needed to replace the std::set inserted instance with its actual value.
AICachedPointer(AICachedPointer const& cptr) : mKey(cptr.mKey), mData(cptr.mData), mCache(cptr.mCache), mRefCount(0) { }
// Construct a AICachedPointer that points to 'ptr' with key 'key'.
AICachedPointer(KEY const& key, T* ptr, container_type* cache) : mKey(key), mData(ptr), mCache(cache), mRefCount(-1) { }
// Construct a temporary NULL pointer that can be used in a search for a key.
AICachedPointer(KEY const& key) : mKey(key), mCache(NULL) { }
// Accessors for key and data.
KEY const& key(void) const { return mKey; }
T const* get(void) const { return mData.get(); }
T* get(void) { return mData.get(); }
// Order only by key.
friend bool operator<(AICachedPointer const& cp1, AICachedPointer const& cp2) { return cp1.mKey < cp2.mKey; }
private:
friend void intrusive_ptr_add_ref<>(AICachedPointer<KEY, T> const* p);
friend void intrusive_ptr_release<>(AICachedPointer<KEY, T> const* p);
private:
AICachedPointer& operator=(AICachedPointer const&);
};
template<typename KEY, typename T>
void intrusive_ptr_add_ref(AICachedPointer<KEY, T> const* p)
{
llassert(p->mCache);
if (p->mCache)
{
p->mRefCount++;
}
}
template<typename KEY, typename T>
void intrusive_ptr_release(AICachedPointer<KEY, T> const* p)
{
llassert(p->mCache);
if (p->mCache)
{
if (--p->mRefCount == 0)
{
p->mCache->erase(p->mKey);
}
}
}
template<typename KEY, typename T>
class AICachedPointerPtr
{
private:
boost::intrusive_ptr<AICachedPointer<KEY, T> const> mPtr;
static int sCnt;
public:
AICachedPointerPtr(void) { ++sCnt; }
AICachedPointerPtr(AICachedPointerPtr const& cpp) : mPtr(cpp.mPtr) { ++sCnt; }
AICachedPointerPtr(AICachedPointer<KEY, T> const* cp) : mPtr(cp) { ++sCnt; }
~AICachedPointerPtr() { --sCnt; }
typedef boost::intrusive_ptr<AICachedPointer<KEY, T> const> const AICachedPointerPtr<KEY, T>::* const bool_type;
operator bool_type() const { return mPtr ? &AICachedPointerPtr<KEY, T>::mPtr : NULL; }
T const* operator->() const { return mPtr->get(); }
T* operator->() { return const_cast<AICachedPointer<KEY, T>&>(*mPtr).get(); }
T const& operator*() const { return *mPtr->get(); }
T& operator*() { return *const_cast<AICachedPointer<KEY, T>&>(*mPtr).get(); }
AICachedPointerPtr& operator=(AICachedPointerPtr const& cpp) { mPtr = cpp.mPtr; return *this; }
};
template<typename KEY, typename T>
int AICachedPointerPtr<KEY, T>::sCnt;
// </singu>
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// class LLKeyframeMotion
//-----------------------------------------------------------------------------
class LLKeyframeMotion :
public LLMotion
{
friend class LLKeyframeDataCache;
public:
// Constructor
LLKeyframeMotion(const LLUUID &id, LLMotionController* controller);
// Destructor
virtual ~LLKeyframeMotion();
private:
// private helper functions to wrap some asserts
LLPointer<LLJointState>& getJointState(U32 index);
LLJoint* getJoint(U32 index);
public:
//-------------------------------------------------------------------------
// functions to support MotionController and MotionRegistry
//-------------------------------------------------------------------------
// static constructor
// all subclasses must implement such a function and register it
static LLMotion* create(LLUUID const& id, LLMotionController* controller);
public:
//-------------------------------------------------------------------------
// animation callbacks to be implemented by subclasses
//-------------------------------------------------------------------------
// motions must specify whether or not they loop
virtual BOOL getLoop() {
if (mJointMotionList) return mJointMotionList->mLoop;
else return FALSE;
}
// motions must report their total duration
virtual F32 getDuration() {
if (mJointMotionList) return mJointMotionList->mDuration;
else return 0.f;
}
// motions must report their "ease in" duration
virtual F32 getEaseInDuration() {
if (mJointMotionList) return mJointMotionList->mEaseInDuration;
else return 0.f;
}
// motions must report their "ease out" duration.
virtual F32 getEaseOutDuration() {
if (mJointMotionList) return mJointMotionList->mEaseOutDuration;
else return 0.f;
}
// motions must report their priority
virtual LLJoint::JointPriority getPriority() {
if (mJointMotionList) return mJointMotionList->mBasePriority;
else return LLJoint::LOW_PRIORITY;
}
virtual LLMotionBlendType getBlendType() { return NORMAL_BLEND; }
// called to determine when a motion should be activated/deactivated based on avatar pixel coverage
virtual F32 getMinPixelArea() { return MIN_REQUIRED_PIXEL_AREA_KEYFRAME; }
// run-time (post constructor) initialization,
// called after parameters have been set
// must return true to indicate success and be available for activation
virtual LLMotionInitStatus onInitialize(LLCharacter *character);
// called when a motion is activated
// must return TRUE to indicate success, or else
// it will be deactivated
virtual BOOL onActivate();
// called per time step
// must return TRUE while it is active, and
// must return FALSE when the motion is completed.
virtual BOOL onUpdate(F32 time, U8* joint_mask);
// called when a motion is deactivated
virtual void onDeactivate();
virtual void setStopTime(F32 time);
static void setVFS(LLVFS* vfs) { sVFS = vfs; }
static void onLoadComplete(LLVFS *vfs,
const LLUUID& asset_uuid,
LLAssetType::EType type,
void* user_data, S32 status, LLExtStat ext_status);
public:
U32 getFileSize();
BOOL serialize(LLDataPacker& dp) const;
BOOL deserialize(LLDataPacker& dp, const LLUUID& asset_id);
BOOL isLoaded() { return !!mJointMotionList; }
// setters for modifying a keyframe animation
void setLoop(BOOL loop);
F32 getLoopIn() {
return (mJointMotionList) ? mJointMotionList->mLoopInPoint : 0.f;
}
F32 getLoopOut() {
return (mJointMotionList) ? mJointMotionList->mLoopOutPoint : 0.f;
}
void setLoopIn(F32 in_point);
void setLoopOut(F32 out_point);
void setHandPose(LLHandMotion::eHandPose pose) {
if (mJointMotionList) mJointMotionList->mHandPose = pose;
}
LLHandMotion::eHandPose getHandPose() {
return (mJointMotionList) ? mJointMotionList->mHandPose : LLHandMotion::HAND_POSE_RELAXED;
}
void setPriority(S32 priority);
void setEmote(const LLUUID& emote_id);
void setEaseIn(F32 ease_in);
void setEaseOut(F32 ease_in);
F32 getLastUpdateTime() { return mLastLoopedTime; }
const LLBBoxLocal& getPelvisBBox();
static void flushKeyframeCache();
protected:
//-------------------------------------------------------------------------
// JointConstraintSharedData
//-------------------------------------------------------------------------
class JointConstraintSharedData
{
public:
JointConstraintSharedData() :
mChainLength(0),
mEaseInStartTime(0.f),
mEaseInStopTime(0.f),
mEaseOutStartTime(0.f),
mEaseOutStopTime(0.f),
mUseTargetOffset(FALSE),
mConstraintType(CONSTRAINT_TYPE_POINT),
mConstraintTargetType(CONSTRAINT_TARGET_TYPE_BODY),
mSourceConstraintVolume(0),
mTargetConstraintVolume(0),
mJointStateIndices(NULL)
{ };
~JointConstraintSharedData() { delete [] mJointStateIndices; }
S32 mSourceConstraintVolume;
LLVector3 mSourceConstraintOffset;
S32 mTargetConstraintVolume;
LLVector3 mTargetConstraintOffset;
LLVector3 mTargetConstraintDir;
S32 mChainLength;
S32* mJointStateIndices;
F32 mEaseInStartTime;
F32 mEaseInStopTime;
F32 mEaseOutStartTime;
F32 mEaseOutStopTime;
BOOL mUseTargetOffset;
EConstraintType mConstraintType;
EConstraintTargetType mConstraintTargetType;
};
//-----------------------------------------------------------------------------
// JointConstraint()
//-----------------------------------------------------------------------------
class JointConstraint
{
public:
JointConstraint(JointConstraintSharedData* shared_data);
~JointConstraint();
JointConstraintSharedData* mSharedData;
F32 mWeight;
F32 mTotalLength;
LLVector3 mPositions[MAX_CHAIN_LENGTH];
F32 mJointLengths[MAX_CHAIN_LENGTH];
F32 mJointLengthFractions[MAX_CHAIN_LENGTH];
BOOL mActive;
LLVector3d mGroundPos;
LLVector3 mGroundNorm;
LLJoint* mSourceVolume;
LLJoint* mTargetVolume;
F32 mFixupDistanceRMS;
};
void applyKeyframes(F32 time);
void applyConstraints(F32 time, U8* joint_mask);
void activateConstraint(JointConstraint* constraintp);
void initializeConstraint(JointConstraint* constraint);
void deactivateConstraint(JointConstraint *constraintp);
void applyConstraint(JointConstraint* constraintp, F32 time, U8* joint_mask);
BOOL setupPose();
public:
enum AssetStatus { ASSET_LOADED, ASSET_FETCHED, ASSET_NEEDS_FETCH, ASSET_FETCH_FAILED, ASSET_UNDEFINED };
enum InterpolationType { IT_STEP, IT_LINEAR, IT_SPLINE };
//-------------------------------------------------------------------------
// ScaleKey
//-------------------------------------------------------------------------
class ScaleKey
{
public:
ScaleKey() { mTime = 0.0f; }
ScaleKey(F32 time, const LLVector3 &scale) { mTime = time; mScale = scale; }
F32 mTime;
LLVector3 mScale;
};
//-------------------------------------------------------------------------
// RotationKey
//-------------------------------------------------------------------------
class RotationKey
{
public:
RotationKey() { mTime = 0.0f; }
RotationKey(F32 time, const LLQuaternion &rotation) { mTime = time; mRotation = rotation; }
F32 mTime;
LLQuaternion mRotation;
};
//-------------------------------------------------------------------------
// PositionKey
//-------------------------------------------------------------------------
class PositionKey
{
public:
PositionKey() { mTime = 0.0f; }
PositionKey(F32 time, const LLVector3 &position) { mTime = time; mPosition = position; }
F32 mTime;
LLVector3 mPosition;
};
//-------------------------------------------------------------------------
// ScaleCurve
//-------------------------------------------------------------------------
class ScaleCurve
{
public:
ScaleCurve();
~ScaleCurve();
LLVector3 getValue(F32 time, F32 duration);
LLVector3 interp(F32 u, ScaleKey& before, ScaleKey& after);
InterpolationType mInterpolationType;
S32 mNumKeys;
typedef std::map<F32, ScaleKey> key_map_t;
key_map_t mKeys;
ScaleKey mLoopInKey;
ScaleKey mLoopOutKey;
};
//-------------------------------------------------------------------------
// RotationCurve
//-------------------------------------------------------------------------
class RotationCurve
{
public:
RotationCurve();
~RotationCurve();
LLQuaternion getValue(F32 time, F32 duration);
LLQuaternion interp(F32 u, RotationKey& before, RotationKey& after);
InterpolationType mInterpolationType;
S32 mNumKeys;
typedef std::map<F32, RotationKey> key_map_t;
key_map_t mKeys;
RotationKey mLoopInKey;
RotationKey mLoopOutKey;
};
//-------------------------------------------------------------------------
// PositionCurve
//-------------------------------------------------------------------------
class PositionCurve
{
public:
PositionCurve();
~PositionCurve();
LLVector3 getValue(F32 time, F32 duration);
LLVector3 interp(F32 u, PositionKey& before, PositionKey& after);
InterpolationType mInterpolationType;
S32 mNumKeys;
typedef std::map<F32, PositionKey> key_map_t;
key_map_t mKeys;
PositionKey mLoopInKey;
PositionKey mLoopOutKey;
};
//-------------------------------------------------------------------------
// JointMotion
//-------------------------------------------------------------------------
class JointMotion
{
public:
PositionCurve mPositionCurve;
RotationCurve mRotationCurve;
ScaleCurve mScaleCurve;
std::string mJointName;
U32 mUsage;
LLJoint::JointPriority mPriority;
void update(LLJointState* joint_state, F32 time, F32 duration);
};
//-------------------------------------------------------------------------
// JointMotionList
//-------------------------------------------------------------------------
class JointMotionList : public LLRefCount
{
public:
std::vector<JointMotion*> mJointMotionArray;
F32 mDuration;
BOOL mLoop;
F32 mLoopInPoint;
F32 mLoopOutPoint;
F32 mEaseInDuration;
F32 mEaseOutDuration;
LLJoint::JointPriority mBasePriority;
LLHandMotion::eHandPose mHandPose;
LLJoint::JointPriority mMaxPriority;
typedef std::list<JointConstraintSharedData*> constraint_list_t;
constraint_list_t mConstraints;
LLBBoxLocal mPelvisBBox;
// mEmoteName is a facial motion, but it's necessary to appear here so that it's cached.
// TODO: LLKeyframeDataCache::getKeyframeData should probably return a class containing
// JointMotionList and mEmoteName, see LLKeyframeMotion::onInitialize.
std::string mEmoteName;
public:
JointMotionList();
~JointMotionList();
U32 dumpDiagInfo(bool silent = false) const;
JointMotion* getJointMotion(U32 index) const { llassert(index < mJointMotionArray.size()); return mJointMotionArray[index]; }
U32 getNumJointMotions() const { return mJointMotionArray.size(); }
};
// Singu: Type of a pointer to the cached pointer (in LLKeyframeDataCache::sKeyframeDataMap) to a JointMotionList object.
typedef AICachedPointerPtr<LLUUID, JointMotionList> JointMotionListPtr;
protected:
static LLVFS* sVFS;
//-------------------------------------------------------------------------
// Member Data
//-------------------------------------------------------------------------
JointMotionListPtr mJointMotionList; // singu: automatically clean up cache entry when destructed.
std::vector<LLPointer<LLJointState> > mJointStates;
LLJoint* mPelvisp;
LLCharacter* mCharacter;
typedef std::list<JointConstraint*> constraint_list_t;
constraint_list_t mConstraints;
U32 mLastSkeletonSerialNum;
F32 mLastUpdateTime;
F32 mLastLoopedTime;
AssetStatus mAssetStatus;
};
class LLKeyframeDataCache
{
private:
friend class LLKeyframeMotion;
LLKeyframeDataCache(){};
~LLKeyframeDataCache();
public:
typedef AICachedPointer<LLUUID, LLKeyframeMotion::JointMotionList>::container_type keyframe_data_map_t; // singu: add automatic cache cleanup.
static keyframe_data_map_t sKeyframeDataMap;
//<singu>
static LLKeyframeMotion::JointMotionListPtr createKeyframeData(LLUUID const& id); // id may not exist.
static LLKeyframeMotion::JointMotionListPtr getKeyframeData(LLUUID const& id); // id may or may not exists. Returns a NULL pointer when it doesn't exist.
//</singu>
static void removeKeyframeData(const LLUUID& id);
//print out diagnostic info
static void dumpDiagInfo(int quiet = 0); // singu: added param 'quiet'.
static void clear();
};
#endif // LL_LLKEYFRAMEMOTION_H