/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
/** \file plArmatureMod.h
A modifier which manages multi-channel animation and has a physical body.
Designed for avatars; also good for vehicles, creatures, etc.
*/
// PLARMATUREMOD
//
// An armature is an object with both a physical presence (physics behavior) and articulated animated parts.
// (The parts are not themselves physical)
// An avatar is a type of armature, as is a critter, and anything else that moves around.
//
// This modifier combines multi-channel animation with blending (inherited from plAGMasterMod)
// with convenience functions for moving a physical body around and some specialized animation support
#ifndef plArmatureMod_inc
#define plArmatureMod_inc
#include "plAGMasterMod.h"
// other local
#include "plAvDefs.h"
#include "../pnSceneObject/plSimulationInterface.h"
#include "hsMatrix44.h"
#include "../plNetCommon/plNetCommon.h"
#include
/////////////////////////////////////////////////////////////////////////////////////////
//
// FORWARDS
//
/////////////////////////////////////////////////////////////////////////////////////////
class hsQuat;
class plMatrixChannel;
class plAGModifier;
class plAGMasterMod;
class plAGChannel;
class plClothingOutfit;
class plClothingSDLModifier;
class plAvatarSDLModifier;
class plMatrixDelayedCorrectionApplicator;
class plMatrixDifferenceApp;
class plDebugText;
class plArmatureEffectsMgr;
class plAvBoneMap; // below
class plDrawable;
class plControlEventMsg;
class plAvatarInputStateMsg;
class plLayerLinkAnimation;
class plPipeline;
class plArmatureBrain;
class plArmatureUpdateMsg;
class plPhysicalControllerCore;
typedef std::vector plKeyVector;
typedef std::vector plBrainStack;
class plArmatureModBase : public plAGMasterMod
{
public:
plArmatureModBase();
virtual ~plArmatureModBase();
CLASSNAME_REGISTER( plArmatureModBase );
GETINTERFACE_ANY( plArmatureModBase, plAGMasterMod );
virtual hsBool MsgReceive(plMessage* msg);
virtual void AddTarget(plSceneObject* so);
virtual void RemoveTarget(plSceneObject* so);
virtual hsBool IEval(double secs, hsScalar del, UInt32 dirty);
virtual void Read(hsStream *stream, hsResMgr *mgr);
virtual void Write(hsStream *stream, hsResMgr *mgr);
plMatrixDifferenceApp *GetRootAnimator() { return fRootAnimator; }
plPhysicalControllerCore* GetController() const { return fController; }
plKey GetWorldKey() const;
virtual hsBool ValidatePhysics();
virtual hsBool ValidateMesh();
virtual void PushBrain(plArmatureBrain *brain);
virtual void PopBrain();
plArmatureBrain *GetCurrentBrain() const;
plDrawable *FindDrawable() const;
virtual void LeaveAge();
virtual hsBool IsFinal();
// LOD stuff
void AdjustLOD(); // see if we need to switch to a different resolution
hsBool SetLOD(int newLOD); // switch to a different resolution
void RefreshTree(); // Resend an LOD update to all our nodes (for when geometry changes)
int AppendMeshKey(plKey meshKey);
int AppendBoneVec(plKeyVector *boneVec);
UInt8 GetNumLOD() const;
// A collection of reasons (flags) that things might be disabled. When all flags are gone
// The object is re-enabled.
enum
{
kDisableReasonUnknown = 0x0001,
kDisableReasonRelRegion = 0x0002,
kDisableReasonLinking = 0x0004,
kDisableReasonCCR = 0x0008,
kDisableReasonVehicle = 0x0010,
kDisableReasonGenericBrain = 0x0020,
};
void EnablePhysics(hsBool status, UInt16 reason = kDisableReasonUnknown);
void EnablePhysicsKinematic(hsBool status);
void EnableDrawing(hsBool status, UInt16 reason = kDisableReasonUnknown);
hsBool IsPhysicsEnabled() { return fDisabledPhysics == 0; }
hsBool IsDrawEnabled() { return fDisabledDraw == 0; }
static void AddressMessageToDescendants(const plCoordinateInterface * CI, plMessage *msg);
static void EnableDrawingTree(const plSceneObject *object, hsBool status);
static int fMinLOD; // throttle for lowest-indexed LOD
static double fLODDistance; // Distance for first LOD switch 2nd is 2x this distance (for now)
protected:
virtual void IFinalize();
virtual void ICustomizeApplicator();
void IEnableBones(int lod, hsBool enable);
// Some of these flags are only needed by derived classes, but I just want
// the one waitFlags variable.
enum
{
kNeedMesh = 0x01,
kNeedPhysics = 0x02,
kNeedAudio = 0x04,
kNeedCamera = 0x08,
kNeedSpawn = 0x10,
kNeedApplicator = 0x20,
kNeedBrainActivation = 0x40,
};
UInt16 fWaitFlags;
int fCurLOD;
plPhysicalControllerCore* fController;
plKeyVector fMeshKeys;
plBrainStack fBrains;
plMatrixDifferenceApp *fRootAnimator;
std::vector fUnusedBones;
UInt16 fDisabledPhysics;
UInt16 fDisabledDraw;
};
class plArmatureMod : public plArmatureModBase
{
friend class plHBehavior;
friend class plAvatarSDLModifier;
friend class plAvatarPhysicalSDLModifier;
friend class plClothingSDLModifier;
friend class plAvOneShotLinkTask;
public:
plArmatureMod();
virtual ~plArmatureMod();
CLASSNAME_REGISTER( plArmatureMod );
GETINTERFACE_ANY( plArmatureMod, plArmatureModBase );
virtual hsBool MsgReceive(plMessage* msg);
virtual void AddTarget(plSceneObject* so);
virtual void RemoveTarget(plSceneObject* so);
virtual hsBool IEval(double secs, hsScalar del, UInt32 dirty);
virtual void Read(hsStream *stream, hsResMgr *mgr);
virtual void Write(hsStream *stream, hsResMgr *mgr);
virtual hsBool ValidatePhysics();
virtual hsBool ValidateMesh();
// Get or set the position of the avatar in simulation space. Set any
// arguments you don't care about to nil.
void SetPositionAndRotationSim(const hsPoint3* position, const hsQuat* rotation);
void GetPositionAndRotationSim(hsPoint3* position, hsQuat* rotation);
hsBool IsLocalAvatar();
hsBool IsLocalAI();
virtual const plSceneObject *FindBone(const char * name) const;
virtual const plSceneObject *FindBone(UInt32 id) const; // use an id from an appropriate taxonomy, such as plAvBrainHuman::BoneID
virtual void AddBoneMapping(UInt32 id, const plSceneObject *bone);
plAGModifier *GetRootAGMod();
plAGAnim *FindCustomAnim(const char *baseName) const;
virtual void Spawn(double timeNow);
virtual void SpawnAt(int which, double timeNow);
virtual void EnterAge(hsBool reSpawn);
virtual void LeaveAge();
virtual void PanicLink(hsBool playLinkOutAnim = true);
virtual void PersonalLink();
virtual bool ToggleDontPanicLinkFlag() { fDontPanicLink = fDontPanicLink ? false : true; return fDontPanicLink; }
int GetBrainCount();
plArmatureBrain *GetNextBrain(plArmatureBrain *brain);
plArmatureBrain *GetBrain(int index) { if(index <= fBrains.size()) return fBrains.at(index); else return nil; }
plArmatureBrain *FindBrainByClass(UInt32 classID) const;
void TurnToPoint(hsPoint3 &point);
void SuspendInput();
void ResumeInput();
UInt8 IsInputSuspended() { return fSuspendInputCount; }
void IProcessQueuedInput();
void PreserveInputState();
void RestoreInputState();
hsBool GetInputFlag(int f) const;
void SetInputFlag(int which, hsBool status);
void ClearInputFlags(bool saveAlwaysRun, bool clearBackup);
hsBool HasMovementFlag() const; // Is any *movement* input flag on?
hsScalar GetTurnStrength() const;
hsScalar GetKeyTurnStrength() const;
hsScalar GetAnalogTurnStrength() const;
void SetReverseFBOnIdle(bool val);
hsBool IsFBReversed();
bool ForwardKeyDown() const;
bool BackwardKeyDown() const;
bool StrafeLeftKeyDown() const;
bool StrafeRightKeyDown() const;
bool StrafeKeyDown() const;
bool FastKeyDown() const;
bool TurnLeftKeyDown() const;
bool TurnRightKeyDown() const;
bool JumpKeyDown() const;
bool ExitModeKeyDown() const;
void SetForwardKeyDown();
void SetBackwardKeyDown();
void SetStrafeLeftKeyDown(bool on = true);
void SetStrafeRightKeyDown(bool on = true);
void SetFastKeyDown();
void SetTurnLeftKeyDown(bool status = true);
void SetTurnRightKeyDown(bool status = true);
void SetJumpKeyDown();
void DebugDumpMoveKeys(int &x, int &y, int lineHeight, char *strBuf, plDebugText &debugTxt);
void GetMoveKeyString(char *buff);
void SynchIfLocal(double timeNow, int force); // Just physical state
void SynchInputState(UInt32 rcvID = kInvalidPlayerID);
hsBool DirtySynchState(const char* SDLStateName, UInt32 synchFlags );
hsBool DirtyPhysicalSynchState(UInt32 synchFlags);
plClothingOutfit *GetClothingOutfit() const { return fClothingOutfit; }
plClothingSDLModifier *GetClothingSDLMod() const { return fClothingSDLMod; }
const plSceneObject *GetClothingSO(UInt8 lod) const;
plArmatureEffectsMgr *GetArmatureEffects() const { return fEffects; }
enum
{
kWalk,
kRun,
kTurn,
kImpact,
kSwim,
};
const char *plArmatureMod::GetAnimRootName(const char *name);
Int8 AnimNameToIndex(const char *name);
void SetBodyType(int type) { fBodyType = type; }
int GetBodyType(int type) { return fBodyType; }
int GetCurrentGenericType();
bool FindMatchingGenericBrain(const char *names[], int count);
char *MakeAnimationName(const char * baseName) const;
char *GetRootName();
void SetRootName(const char *name);
int RefreshDebugDisplay();
void DumpToDebugDisplay(int &x, int &y, int lineHeight, char *strBuf, plDebugText &debugTxt);
void SetDebugState(hsBool state) { fDebugOn = (state != 0); }
bool GetDebugState() { return fDebugOn; }
virtual void RefreshTree() {}
hsBool IsInStealthMode() const;
int GetStealthLevel() const { return fStealthLevel; }
bool IsOpaque();
bool IsMidLink();
hsBool ConsumeJump(); // returns true if the jump keypress was available to consume
void SendBehaviorNotify(UInt32 type, hsBool start = true) { IFireBehaviorNotify(type,start); }
// Discovered a bug which makes these values horribly out of scale. So we do the rescale
// in the Get/Set functions for backwards compatability.
static void SetMouseTurnSensitivity(hsScalar val) { fMouseTurnSensitivity = val / 150.f; }
static hsScalar GetMouseTurnSensitivity() { return fMouseTurnSensitivity * 150.f; }
static void SetSpawnPointOverride( const char *overrideObjName );
static void WindowActivate(bool active);
void SetFollowerParticleSystemSO(plSceneObject *follower);
plSceneObject *GetFollowerParticleSystemSO();
void RegisterForBehaviorNotify(plKey key);
void UnRegisterForBehaviorNotify(plKey key);
const hsBitVector& GetRelRegionCareAbout() const { return fRegionsICareAbout; }
const hsBitVector& GetRelRegionImIn() const { return fRegionsImIn; }
bool IsKILowestLevel();
int GetKILevel();
void SetLinkInAnim(const char *animName);
plKey GetLinkInAnimKey() const;
enum
{
kSwapTargetShadow,
kMaxSwapType
};
enum
{
kBoneBaseMale = 0,
kBoneBaseFemale,
kBoneBaseCritter, // AI controlled avatar
kBoneBaseActor, // human controlled, non human avatar
kMaxBoneBase
};
enum
{
kAvatarLOSGround,
kAvatarLOSSwimSurface,
};
plMatrixDelayedCorrectionApplicator *fBoneRootAnimator;
static const hsScalar kAvatarInputSynchThreshold;
static hsBool fClickToTurn;
static const char *BoneStrings[];
void SetPhysicalDims(hsScalar height, hsScalar width) { fPhysHeight = height; fPhysWidth = width; }
void SetBodyAgeName(const char* ageName) {if (ageName) fBodyAgeName = ageName; else fBodyAgeName = "";}
void SetBodyFootstepSoundPage(const char* pageName) {if (pageName) fBodyFootstepSoundPage = pageName; else fBodyFootstepSoundPage = "";}
void SetAnimationPrefix(const char* prefix) {if (prefix) fAnimationPrefix = prefix; else fAnimationPrefix = "";}
const char* GetUserStr() {return fUserStr.c_str();}
protected:
void IInitDefaults();
virtual void IFinalize();
virtual void ICustomizeApplicator();
virtual void ISetupMarkerCallbacks(plATCAnim *anim, plAnimTimeConvert *atc);
void NetworkSynch(double timeNow, int force = 0);
hsBool IHandleControlMsg(plControlEventMsg* pMsg);
void IFireBehaviorNotify(UInt32 type, hsBool behaviorStart = true);
void IHandleInputStateMsg(plAvatarInputStateMsg *msg);
void ILinkToPersonalAge();
int IFindSpawnOverride(void);
void ISetTransparentDrawOrder(bool val);
plLayerLinkAnimation *IFindLayerLinkAnim();
char *fRootName; // the name of the player root (from the max file)
hsBitVector fMoveFlags; // which keys/buttons are currently pressed
hsBitVector fMoveFlagsBackup; // a copy of fMoveFlags
typedef std::vector CtrlMessageVec;
CtrlMessageVec fQueuedCtrlMessages; // input messages we haven't processed
hsScalar fMouseFrameTurnStrength; // Sum turnage from mouse delta messages since last eval.
plKey fFootSoundSOKey; // The Scene Object we attach to targets for footstep sounds
plKey fLinkSoundSOKey; // Same thing for linking... wwwwawAWAWAwawa...
plKey fLinkInAnimKey; // Set when we link out, this is the anim to play (backwards) when we link in.
static hsScalar fMouseTurnSensitivity;
plArmatureUpdateMsg *fUpdateMsg;
// Trying to be a good lad here and align all our bools and UInt8s...
bool fMidLink; // We're in between a LeaveAge and an EnterAge
bool fAlreadyPanicLinking; // Cleared when you enter an age. Prevents spamming the server with panic link requests.
bool fUnconsumedJump; // We've pressed the jump key, but haven't jumped yet
bool fReverseFBOnIdle; // see set/getters for comments
bool fPendingSynch;
bool fDebugOn;
bool fOpaque;
UInt8 fSuspendInputCount;
UInt8 fStealthMode;
int fStealthLevel; // you are invisible to other players/CCRs of lower stealthLevel
double fLastInputSynch;
plAGModifier * fRootAGMod;
plAvBoneMap * fBoneMap; // uses id codes to look up bones. set up by the brain as needed.
double fLastSynch;
int fBodyType;
plClothingOutfit *fClothingOutfit;
plClothingSDLModifier *fClothingSDLMod;
plAvatarSDLModifier *fAvatarSDLMod;
plAvatarPhysicalSDLModifier *fAvatarPhysicalSDLMod;
hsTArray fClothToSOMap;
plArmatureEffectsMgr *fEffects;
plSceneObject *fFollowerParticleSystemSO;
static char *fSpawnPointOverride;
// These vectors are used with relevance regions for culling out other objects
hsBitVector fRegionsImIn;
hsBitVector fRegionsICareAbout;
hsBitVector fOldRegionsImIn;
hsBitVector fOldRegionsICareAbout;
hsTArray fNotifyKeys;
// Extra info for creating our special physical at runtime
float fPhysHeight;
float fPhysWidth;
bool fDontPanicLink;
// strings for animations, age names, footstep sounds, etc
std::string fBodyAgeName;
std::string fBodyFootstepSoundPage;
std::string fAnimationPrefix;
// user-defined string assigned to this avatar
std::string fUserStr;
};
// PLARMATURELOD
// This class has been phased into plArmatureModBase. It's left behind
// for backwards compatability.
class plArmatureLODMod : public plArmatureMod
{
public:
// tors
plArmatureLODMod();
plArmatureLODMod(const char * root_name);
virtual ~plArmatureLODMod();
CLASSNAME_REGISTER( plArmatureLODMod );
GETINTERFACE_ANY( plArmatureLODMod, plArmatureMod );
virtual void Read(hsStream *stream, hsResMgr *mgr);
virtual void Write(hsStream *stream, hsResMgr *mgr);
};
class plAvBoneMap
{
public:
plAvBoneMap();
virtual ~plAvBoneMap();
const plSceneObject * FindBone(UInt32 boneID); // you probably want to use plAvBrainHuman::BoneID;
void AddBoneMapping(UInt32 boneID, const plSceneObject *SO);
protected:
class BoneMapImp; // forward declaration to keep the header clean: see .cpp for implementation
BoneMapImp *fImp; // the thing that actually holds our map
};
#define TWO_PI (hsScalarPI * 2)
#endif plArmatureMod_inc