mirror of
https://github.com/id-Software/DOOM-3.git
synced 2026-03-20 17:10:42 +01:00
hello world
This commit is contained in:
1087
neo/game/anim/Anim.cpp
Normal file
1087
neo/game/anim/Anim.cpp
Normal file
File diff suppressed because it is too large
Load Diff
621
neo/game/anim/Anim.h
Normal file
621
neo/game/anim/Anim.h
Normal file
@@ -0,0 +1,621 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 GPL Source Code
|
||||
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
|
||||
|
||||
Doom 3 Source Code 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.
|
||||
|
||||
Doom 3 Source Code 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 Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
#ifndef __ANIM_H__
|
||||
#define __ANIM_H__
|
||||
|
||||
//
|
||||
// animation channels
|
||||
// these can be changed by modmakers and licensees to be whatever they need.
|
||||
const int ANIM_NumAnimChannels = 5;
|
||||
const int ANIM_MaxAnimsPerChannel = 3;
|
||||
const int ANIM_MaxSyncedAnims = 3;
|
||||
|
||||
//
|
||||
// animation channels. make sure to change script/doom_defs.script if you add any channels, or change their order
|
||||
//
|
||||
const int ANIMCHANNEL_ALL = 0;
|
||||
const int ANIMCHANNEL_TORSO = 1;
|
||||
const int ANIMCHANNEL_LEGS = 2;
|
||||
const int ANIMCHANNEL_HEAD = 3;
|
||||
const int ANIMCHANNEL_EYELIDS = 4;
|
||||
|
||||
// for converting from 24 frames per second to milliseconds
|
||||
ID_INLINE int FRAME2MS( int framenum ) {
|
||||
return ( framenum * 1000 ) / 24;
|
||||
}
|
||||
|
||||
class idRenderModel;
|
||||
class idAnimator;
|
||||
class idAnimBlend;
|
||||
class function_t;
|
||||
class idEntity;
|
||||
class idSaveGame;
|
||||
class idRestoreGame;
|
||||
|
||||
typedef struct {
|
||||
int cycleCount; // how many times the anim has wrapped to the begining (0 for clamped anims)
|
||||
int frame1;
|
||||
int frame2;
|
||||
float frontlerp;
|
||||
float backlerp;
|
||||
} frameBlend_t;
|
||||
|
||||
typedef struct {
|
||||
int nameIndex;
|
||||
int parentNum;
|
||||
int animBits;
|
||||
int firstComponent;
|
||||
} jointAnimInfo_t;
|
||||
|
||||
typedef struct {
|
||||
jointHandle_t num;
|
||||
jointHandle_t parentNum;
|
||||
int channel;
|
||||
} jointInfo_t;
|
||||
|
||||
//
|
||||
// joint modifier modes. make sure to change script/doom_defs.script if you add any, or change their order.
|
||||
//
|
||||
typedef enum {
|
||||
JOINTMOD_NONE, // no modification
|
||||
JOINTMOD_LOCAL, // modifies the joint's position or orientation in joint local space
|
||||
JOINTMOD_LOCAL_OVERRIDE, // sets the joint's position or orientation in joint local space
|
||||
JOINTMOD_WORLD, // modifies joint's position or orientation in model space
|
||||
JOINTMOD_WORLD_OVERRIDE // sets the joint's position or orientation in model space
|
||||
} jointModTransform_t;
|
||||
|
||||
typedef struct {
|
||||
jointHandle_t jointnum;
|
||||
idMat3 mat;
|
||||
idVec3 pos;
|
||||
jointModTransform_t transform_pos;
|
||||
jointModTransform_t transform_axis;
|
||||
} jointMod_t;
|
||||
|
||||
#define ANIM_TX BIT( 0 )
|
||||
#define ANIM_TY BIT( 1 )
|
||||
#define ANIM_TZ BIT( 2 )
|
||||
#define ANIM_QX BIT( 3 )
|
||||
#define ANIM_QY BIT( 4 )
|
||||
#define ANIM_QZ BIT( 5 )
|
||||
|
||||
typedef enum {
|
||||
FC_SCRIPTFUNCTION,
|
||||
FC_SCRIPTFUNCTIONOBJECT,
|
||||
FC_EVENTFUNCTION,
|
||||
FC_SOUND,
|
||||
FC_SOUND_VOICE,
|
||||
FC_SOUND_VOICE2,
|
||||
FC_SOUND_BODY,
|
||||
FC_SOUND_BODY2,
|
||||
FC_SOUND_BODY3,
|
||||
FC_SOUND_WEAPON,
|
||||
FC_SOUND_ITEM,
|
||||
FC_SOUND_GLOBAL,
|
||||
FC_SOUND_CHATTER,
|
||||
FC_SKIN,
|
||||
FC_TRIGGER,
|
||||
FC_TRIGGER_SMOKE_PARTICLE,
|
||||
FC_MELEE,
|
||||
FC_DIRECTDAMAGE,
|
||||
FC_BEGINATTACK,
|
||||
FC_ENDATTACK,
|
||||
FC_MUZZLEFLASH,
|
||||
FC_CREATEMISSILE,
|
||||
FC_LAUNCHMISSILE,
|
||||
FC_FIREMISSILEATTARGET,
|
||||
FC_FOOTSTEP,
|
||||
FC_LEFTFOOT,
|
||||
FC_RIGHTFOOT,
|
||||
FC_ENABLE_EYE_FOCUS,
|
||||
FC_DISABLE_EYE_FOCUS,
|
||||
FC_FX,
|
||||
FC_DISABLE_GRAVITY,
|
||||
FC_ENABLE_GRAVITY,
|
||||
FC_JUMP,
|
||||
FC_ENABLE_CLIP,
|
||||
FC_DISABLE_CLIP,
|
||||
FC_ENABLE_WALK_IK,
|
||||
FC_DISABLE_WALK_IK,
|
||||
FC_ENABLE_LEG_IK,
|
||||
FC_DISABLE_LEG_IK,
|
||||
FC_RECORDDEMO,
|
||||
FC_AVIGAME
|
||||
} frameCommandType_t;
|
||||
|
||||
typedef struct {
|
||||
int num;
|
||||
int firstCommand;
|
||||
} frameLookup_t;
|
||||
|
||||
typedef struct {
|
||||
frameCommandType_t type;
|
||||
idStr *string;
|
||||
|
||||
union {
|
||||
const idSoundShader *soundShader;
|
||||
const function_t *function;
|
||||
const idDeclSkin *skin;
|
||||
int index;
|
||||
};
|
||||
} frameCommand_t;
|
||||
|
||||
typedef struct {
|
||||
bool prevent_idle_override : 1;
|
||||
bool random_cycle_start : 1;
|
||||
bool ai_no_turn : 1;
|
||||
bool anim_turn : 1;
|
||||
} animFlags_t;
|
||||
|
||||
|
||||
/*
|
||||
==============================================================================================
|
||||
|
||||
idModelExport
|
||||
|
||||
==============================================================================================
|
||||
*/
|
||||
|
||||
class idModelExport {
|
||||
private:
|
||||
void Reset( void );
|
||||
bool ParseOptions( idLexer &lex );
|
||||
int ParseExportSection( idParser &parser );
|
||||
|
||||
static bool CheckMayaInstall( void );
|
||||
static void LoadMayaDll( void );
|
||||
|
||||
bool ConvertMayaToMD5( void );
|
||||
static bool initialized;
|
||||
|
||||
public:
|
||||
idStr commandLine;
|
||||
idStr src;
|
||||
idStr dest;
|
||||
bool force;
|
||||
|
||||
idModelExport();
|
||||
|
||||
static void Shutdown( void );
|
||||
|
||||
int ExportDefFile( const char *filename );
|
||||
bool ExportModel( const char *model );
|
||||
bool ExportAnim( const char *anim );
|
||||
int ExportModels( const char *pathname, const char *extension );
|
||||
};
|
||||
|
||||
/*
|
||||
==============================================================================================
|
||||
|
||||
idMD5Anim
|
||||
|
||||
==============================================================================================
|
||||
*/
|
||||
|
||||
class idMD5Anim {
|
||||
private:
|
||||
int numFrames;
|
||||
int frameRate;
|
||||
int animLength;
|
||||
int numJoints;
|
||||
int numAnimatedComponents;
|
||||
idList<idBounds> bounds;
|
||||
idList<jointAnimInfo_t> jointInfo;
|
||||
idList<idJointQuat> baseFrame;
|
||||
idList<float> componentFrames;
|
||||
idStr name;
|
||||
idVec3 totaldelta;
|
||||
mutable int ref_count;
|
||||
|
||||
public:
|
||||
idMD5Anim();
|
||||
~idMD5Anim();
|
||||
|
||||
void Free( void );
|
||||
bool Reload( void );
|
||||
size_t Allocated( void ) const;
|
||||
size_t Size( void ) const { return sizeof( *this ) + Allocated(); };
|
||||
bool LoadAnim( const char *filename );
|
||||
|
||||
void IncreaseRefs( void ) const;
|
||||
void DecreaseRefs( void ) const;
|
||||
int NumRefs( void ) const;
|
||||
|
||||
void CheckModelHierarchy( const idRenderModel *model ) const;
|
||||
void GetInterpolatedFrame( frameBlend_t &frame, idJointQuat *joints, const int *index, int numIndexes ) const;
|
||||
void GetSingleFrame( int framenum, idJointQuat *joints, const int *index, int numIndexes ) const;
|
||||
int Length( void ) const;
|
||||
int NumFrames( void ) const;
|
||||
int NumJoints( void ) const;
|
||||
const idVec3 &TotalMovementDelta( void ) const;
|
||||
const char *Name( void ) const;
|
||||
|
||||
void GetFrameBlend( int framenum, frameBlend_t &frame ) const; // frame 1 is first frame
|
||||
void ConvertTimeToFrame( int time, int cyclecount, frameBlend_t &frame ) const;
|
||||
|
||||
void GetOrigin( idVec3 &offset, int currentTime, int cyclecount ) const;
|
||||
void GetOriginRotation( idQuat &rotation, int time, int cyclecount ) const;
|
||||
void GetBounds( idBounds &bounds, int currentTime, int cyclecount ) const;
|
||||
};
|
||||
|
||||
/*
|
||||
==============================================================================================
|
||||
|
||||
idAnim
|
||||
|
||||
==============================================================================================
|
||||
*/
|
||||
|
||||
class idAnim {
|
||||
private:
|
||||
const class idDeclModelDef *modelDef;
|
||||
const idMD5Anim *anims[ ANIM_MaxSyncedAnims ];
|
||||
int numAnims;
|
||||
idStr name;
|
||||
idStr realname;
|
||||
idList<frameLookup_t> frameLookup;
|
||||
idList<frameCommand_t> frameCommands;
|
||||
animFlags_t flags;
|
||||
|
||||
public:
|
||||
idAnim();
|
||||
idAnim( const idDeclModelDef *modelDef, const idAnim *anim );
|
||||
~idAnim();
|
||||
|
||||
void SetAnim( const idDeclModelDef *modelDef, const char *sourcename, const char *animname, int num, const idMD5Anim *md5anims[ ANIM_MaxSyncedAnims ] );
|
||||
const char *Name( void ) const;
|
||||
const char *FullName( void ) const;
|
||||
const idMD5Anim *MD5Anim( int num ) const;
|
||||
const idDeclModelDef *ModelDef( void ) const;
|
||||
int Length( void ) const;
|
||||
int NumFrames( void ) const;
|
||||
int NumAnims( void ) const;
|
||||
const idVec3 &TotalMovementDelta( void ) const;
|
||||
bool GetOrigin( idVec3 &offset, int animNum, int time, int cyclecount ) const;
|
||||
bool GetOriginRotation( idQuat &rotation, int animNum, int currentTime, int cyclecount ) const;
|
||||
bool GetBounds( idBounds &bounds, int animNum, int time, int cyclecount ) const;
|
||||
const char *AddFrameCommand( const class idDeclModelDef *modelDef, int framenum, idLexer &src, const idDict *def );
|
||||
void CallFrameCommands( idEntity *ent, int from, int to ) const;
|
||||
bool HasFrameCommands( void ) const;
|
||||
|
||||
// returns first frame (zero based) that command occurs. returns -1 if not found.
|
||||
int FindFrameForFrameCommand( frameCommandType_t framecommand, const frameCommand_t **command ) const;
|
||||
void SetAnimFlags( const animFlags_t &animflags );
|
||||
const animFlags_t &GetAnimFlags( void ) const;
|
||||
};
|
||||
|
||||
/*
|
||||
==============================================================================================
|
||||
|
||||
idDeclModelDef
|
||||
|
||||
==============================================================================================
|
||||
*/
|
||||
|
||||
class idDeclModelDef : public idDecl {
|
||||
public:
|
||||
idDeclModelDef();
|
||||
~idDeclModelDef();
|
||||
|
||||
virtual size_t Size( void ) const;
|
||||
virtual const char * DefaultDefinition( void ) const;
|
||||
virtual bool Parse( const char *text, const int textLength );
|
||||
virtual void FreeData( void );
|
||||
|
||||
void Touch( void ) const;
|
||||
|
||||
const idDeclSkin * GetDefaultSkin( void ) const;
|
||||
const idJointQuat * GetDefaultPose( void ) const;
|
||||
void SetupJoints( int *numJoints, idJointMat **jointList, idBounds &frameBounds, bool removeOriginOffset ) const;
|
||||
idRenderModel * ModelHandle( void ) const;
|
||||
void GetJointList( const char *jointnames, idList<jointHandle_t> &jointList ) const;
|
||||
const jointInfo_t * FindJoint( const char *name ) const;
|
||||
|
||||
int NumAnims( void ) const;
|
||||
const idAnim * GetAnim( int index ) const;
|
||||
int GetSpecificAnim( const char *name ) const;
|
||||
int GetAnim( const char *name ) const;
|
||||
bool HasAnim( const char *name ) const;
|
||||
const idDeclSkin * GetSkin( void ) const;
|
||||
const char * GetModelName( void ) const;
|
||||
const idList<jointInfo_t> & Joints( void ) const;
|
||||
const int * JointParents( void ) const;
|
||||
int NumJoints( void ) const;
|
||||
const jointInfo_t * GetJoint( int jointHandle ) const;
|
||||
const char * GetJointName( int jointHandle ) const;
|
||||
int NumJointsOnChannel( int channel ) const;
|
||||
const int * GetChannelJoints( int channel ) const;
|
||||
|
||||
const idVec3 & GetVisualOffset( void ) const;
|
||||
|
||||
private:
|
||||
void CopyDecl( const idDeclModelDef *decl );
|
||||
bool ParseAnim( idLexer &src, int numDefaultAnims );
|
||||
|
||||
private:
|
||||
idVec3 offset;
|
||||
idList<jointInfo_t> joints;
|
||||
idList<int> jointParents;
|
||||
idList<int> channelJoints[ ANIM_NumAnimChannels ];
|
||||
idRenderModel * modelHandle;
|
||||
idList<idAnim *> anims;
|
||||
const idDeclSkin * skin;
|
||||
};
|
||||
|
||||
/*
|
||||
==============================================================================================
|
||||
|
||||
idAnimBlend
|
||||
|
||||
==============================================================================================
|
||||
*/
|
||||
|
||||
class idAnimBlend {
|
||||
private:
|
||||
const class idDeclModelDef *modelDef;
|
||||
int starttime;
|
||||
int endtime;
|
||||
int timeOffset;
|
||||
float rate;
|
||||
|
||||
int blendStartTime;
|
||||
int blendDuration;
|
||||
float blendStartValue;
|
||||
float blendEndValue;
|
||||
|
||||
float animWeights[ ANIM_MaxSyncedAnims ];
|
||||
short cycle;
|
||||
short frame;
|
||||
short animNum;
|
||||
bool allowMove;
|
||||
bool allowFrameCommands;
|
||||
|
||||
friend class idAnimator;
|
||||
|
||||
void Reset( const idDeclModelDef *_modelDef );
|
||||
void CallFrameCommands( idEntity *ent, int fromtime, int totime ) const;
|
||||
void SetFrame( const idDeclModelDef *modelDef, int animnum, int frame, int currenttime, int blendtime );
|
||||
void CycleAnim( const idDeclModelDef *modelDef, int animnum, int currenttime, int blendtime );
|
||||
void PlayAnim( const idDeclModelDef *modelDef, int animnum, int currenttime, int blendtime );
|
||||
bool BlendAnim( int currentTime, int channel, int numJoints, idJointQuat *blendFrame, float &blendWeight, bool removeOrigin, bool overrideBlend, bool printInfo ) const;
|
||||
void BlendOrigin( int currentTime, idVec3 &blendPos, float &blendWeight, bool removeOriginOffset ) const;
|
||||
void BlendDelta( int fromtime, int totime, idVec3 &blendDelta, float &blendWeight ) const;
|
||||
void BlendDeltaRotation( int fromtime, int totime, idQuat &blendDelta, float &blendWeight ) const;
|
||||
bool AddBounds( int currentTime, idBounds &bounds, bool removeOriginOffset ) const;
|
||||
|
||||
public:
|
||||
idAnimBlend();
|
||||
void Save( idSaveGame *savefile ) const;
|
||||
void Restore( idRestoreGame *savefile, const idDeclModelDef *modelDef );
|
||||
const char *AnimName( void ) const;
|
||||
const char *AnimFullName( void ) const;
|
||||
float GetWeight( int currenttime ) const;
|
||||
float GetFinalWeight( void ) const;
|
||||
void SetWeight( float newweight, int currenttime, int blendtime );
|
||||
int NumSyncedAnims( void ) const;
|
||||
bool SetSyncedAnimWeight( int num, float weight );
|
||||
void Clear( int currentTime, int clearTime );
|
||||
bool IsDone( int currentTime ) const;
|
||||
bool FrameHasChanged( int currentTime ) const;
|
||||
int GetCycleCount( void ) const;
|
||||
void SetCycleCount( int count );
|
||||
void SetPlaybackRate( int currentTime, float newRate );
|
||||
float GetPlaybackRate( void ) const;
|
||||
void SetStartTime( int startTime );
|
||||
int GetStartTime( void ) const;
|
||||
int GetEndTime( void ) const;
|
||||
int GetFrameNumber( int currenttime ) const;
|
||||
int AnimTime( int currenttime ) const;
|
||||
int NumFrames( void ) const;
|
||||
int Length( void ) const;
|
||||
int PlayLength( void ) const;
|
||||
void AllowMovement( bool allow );
|
||||
void AllowFrameCommands( bool allow );
|
||||
const idAnim *Anim( void ) const;
|
||||
int AnimNum( void ) const;
|
||||
};
|
||||
|
||||
/*
|
||||
==============================================================================================
|
||||
|
||||
idAFPoseJointMod
|
||||
|
||||
==============================================================================================
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
AF_JOINTMOD_AXIS,
|
||||
AF_JOINTMOD_ORIGIN,
|
||||
AF_JOINTMOD_BOTH
|
||||
} AFJointModType_t;
|
||||
|
||||
class idAFPoseJointMod {
|
||||
public:
|
||||
idAFPoseJointMod( void );
|
||||
|
||||
AFJointModType_t mod;
|
||||
idMat3 axis;
|
||||
idVec3 origin;
|
||||
};
|
||||
|
||||
ID_INLINE idAFPoseJointMod::idAFPoseJointMod( void ) {
|
||||
mod = AF_JOINTMOD_AXIS;
|
||||
axis.Identity();
|
||||
origin.Zero();
|
||||
}
|
||||
|
||||
/*
|
||||
==============================================================================================
|
||||
|
||||
idAnimator
|
||||
|
||||
==============================================================================================
|
||||
*/
|
||||
|
||||
class idAnimator {
|
||||
public:
|
||||
idAnimator();
|
||||
~idAnimator();
|
||||
|
||||
size_t Allocated( void ) const;
|
||||
size_t Size( void ) const;
|
||||
|
||||
void Save( idSaveGame *savefile ) const; // archives object for save game file
|
||||
void Restore( idRestoreGame *savefile ); // unarchives object from save game file
|
||||
|
||||
void SetEntity( idEntity *ent );
|
||||
idEntity *GetEntity( void ) const ;
|
||||
void RemoveOriginOffset( bool remove );
|
||||
bool RemoveOrigin( void ) const;
|
||||
|
||||
void GetJointList( const char *jointnames, idList<jointHandle_t> &jointList ) const;
|
||||
|
||||
int NumAnims( void ) const;
|
||||
const idAnim *GetAnim( int index ) const;
|
||||
int GetAnim( const char *name ) const;
|
||||
bool HasAnim( const char *name ) const;
|
||||
|
||||
void ServiceAnims( int fromtime, int totime );
|
||||
bool IsAnimating( int currentTime ) const;
|
||||
|
||||
void GetJoints( int *numJoints, idJointMat **jointsPtr );
|
||||
int NumJoints( void ) const;
|
||||
jointHandle_t GetFirstChild( jointHandle_t jointnum ) const;
|
||||
jointHandle_t GetFirstChild( const char *name ) const;
|
||||
|
||||
idRenderModel *SetModel( const char *modelname );
|
||||
idRenderModel *ModelHandle( void ) const;
|
||||
const idDeclModelDef *ModelDef( void ) const;
|
||||
|
||||
void ForceUpdate( void );
|
||||
void ClearForceUpdate( void );
|
||||
bool CreateFrame( int animtime, bool force );
|
||||
bool FrameHasChanged( int animtime ) const;
|
||||
void GetDelta( int fromtime, int totime, idVec3 &delta ) const;
|
||||
bool GetDeltaRotation( int fromtime, int totime, idMat3 &delta ) const;
|
||||
void GetOrigin( int currentTime, idVec3 &pos ) const;
|
||||
bool GetBounds( int currentTime, idBounds &bounds );
|
||||
|
||||
idAnimBlend *CurrentAnim( int channelNum );
|
||||
void Clear( int channelNum, int currentTime, int cleartime );
|
||||
void SetFrame( int channelNum, int animnum, int frame, int currenttime, int blendtime );
|
||||
void CycleAnim( int channelNum, int animnum, int currenttime, int blendtime );
|
||||
void PlayAnim( int channelNum, int animnum, int currenttime, int blendTime );
|
||||
|
||||
// copies the current anim from fromChannelNum to channelNum.
|
||||
// the copied anim will have frame commands disabled to avoid executing them twice.
|
||||
void SyncAnimChannels( int channelNum, int fromChannelNum, int currenttime, int blendTime );
|
||||
|
||||
void SetJointPos( jointHandle_t jointnum, jointModTransform_t transform_type, const idVec3 &pos );
|
||||
void SetJointAxis( jointHandle_t jointnum, jointModTransform_t transform_type, const idMat3 &mat );
|
||||
void ClearJoint( jointHandle_t jointnum );
|
||||
void ClearAllJoints( void );
|
||||
|
||||
void InitAFPose( void );
|
||||
void SetAFPoseJointMod( const jointHandle_t jointNum, const AFJointModType_t mod, const idMat3 &axis, const idVec3 &origin );
|
||||
void FinishAFPose( int animnum, const idBounds &bounds, const int time );
|
||||
void SetAFPoseBlendWeight( float blendWeight );
|
||||
bool BlendAFPose( idJointQuat *blendFrame ) const;
|
||||
void ClearAFPose( void );
|
||||
|
||||
void ClearAllAnims( int currentTime, int cleartime );
|
||||
|
||||
jointHandle_t GetJointHandle( const char *name ) const;
|
||||
const char * GetJointName( jointHandle_t handle ) const;
|
||||
int GetChannelForJoint( jointHandle_t joint ) const;
|
||||
bool GetJointTransform( jointHandle_t jointHandle, int currenttime, idVec3 &offset, idMat3 &axis );
|
||||
bool GetJointLocalTransform( jointHandle_t jointHandle, int currentTime, idVec3 &offset, idMat3 &axis );
|
||||
|
||||
const animFlags_t GetAnimFlags( int animnum ) const;
|
||||
int NumFrames( int animnum ) const;
|
||||
int NumSyncedAnims( int animnum ) const;
|
||||
const char *AnimName( int animnum ) const;
|
||||
const char *AnimFullName( int animnum ) const;
|
||||
int AnimLength( int animnum ) const;
|
||||
const idVec3 &TotalMovementDelta( int animnum ) const;
|
||||
|
||||
private:
|
||||
void FreeData( void );
|
||||
void PushAnims( int channel, int currentTime, int blendTime );
|
||||
|
||||
private:
|
||||
const idDeclModelDef * modelDef;
|
||||
idEntity * entity;
|
||||
|
||||
idAnimBlend channels[ ANIM_NumAnimChannels ][ ANIM_MaxAnimsPerChannel ];
|
||||
idList<jointMod_t *> jointMods;
|
||||
int numJoints;
|
||||
idJointMat * joints;
|
||||
|
||||
mutable int lastTransformTime; // mutable because the value is updated in CreateFrame
|
||||
mutable bool stoppedAnimatingUpdate;
|
||||
bool removeOriginOffset;
|
||||
bool forceUpdate;
|
||||
|
||||
idBounds frameBounds;
|
||||
|
||||
float AFPoseBlendWeight;
|
||||
idList<int> AFPoseJoints;
|
||||
idList<idAFPoseJointMod> AFPoseJointMods;
|
||||
idList<idJointQuat> AFPoseJointFrame;
|
||||
idBounds AFPoseBounds;
|
||||
int AFPoseTime;
|
||||
};
|
||||
|
||||
/*
|
||||
==============================================================================================
|
||||
|
||||
idAnimManager
|
||||
|
||||
==============================================================================================
|
||||
*/
|
||||
|
||||
class idAnimManager {
|
||||
public:
|
||||
idAnimManager();
|
||||
~idAnimManager();
|
||||
|
||||
static bool forceExport;
|
||||
|
||||
void Shutdown( void );
|
||||
idMD5Anim * GetAnim( const char *name );
|
||||
void ReloadAnims( void );
|
||||
void ListAnims( void ) const;
|
||||
int JointIndex( const char *name );
|
||||
const char * JointName( int index ) const;
|
||||
|
||||
void ClearAnimsInUse( void );
|
||||
void FlushUnusedAnims( void );
|
||||
|
||||
private:
|
||||
idHashTable<idMD5Anim *> animations;
|
||||
idStrList jointnames;
|
||||
idHashIndex jointnamesHash;
|
||||
};
|
||||
|
||||
#endif /* !__ANIM_H__ */
|
||||
5022
neo/game/anim/Anim_Blend.cpp
Normal file
5022
neo/game/anim/Anim_Blend.cpp
Normal file
File diff suppressed because it is too large
Load Diff
562
neo/game/anim/Anim_Import.cpp
Normal file
562
neo/game/anim/Anim_Import.cpp
Normal file
@@ -0,0 +1,562 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 GPL Source Code
|
||||
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
|
||||
|
||||
Doom 3 Source Code 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.
|
||||
|
||||
Doom 3 Source Code 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 Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "../../idlib/precompiled.h"
|
||||
#pragma hdrstop
|
||||
|
||||
#include "../Game_local.h"
|
||||
#include "../../MayaImport/maya_main.h"
|
||||
|
||||
/***********************************************************************
|
||||
|
||||
Maya conversion functions
|
||||
|
||||
***********************************************************************/
|
||||
|
||||
static idStr Maya_Error;
|
||||
|
||||
static exporterInterface_t Maya_ConvertModel = NULL;
|
||||
static exporterShutdown_t Maya_Shutdown = NULL;
|
||||
static int importDLL = 0;
|
||||
|
||||
bool idModelExport::initialized = false;
|
||||
|
||||
/*
|
||||
====================
|
||||
idModelExport::idModelExport
|
||||
====================
|
||||
*/
|
||||
idModelExport::idModelExport() {
|
||||
Reset();
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
idModelExport::Shutdown
|
||||
====================
|
||||
*/
|
||||
void idModelExport::Shutdown( void ) {
|
||||
if ( Maya_Shutdown ) {
|
||||
Maya_Shutdown();
|
||||
}
|
||||
|
||||
if ( importDLL ) {
|
||||
sys->DLL_Unload( importDLL );
|
||||
}
|
||||
|
||||
importDLL = 0;
|
||||
Maya_Shutdown = NULL;
|
||||
Maya_ConvertModel = NULL;
|
||||
Maya_Error.Clear();
|
||||
initialized = false;
|
||||
}
|
||||
|
||||
/*
|
||||
=====================
|
||||
idModelExport::CheckMayaInstall
|
||||
|
||||
Determines if Maya is installed on the user's machine
|
||||
=====================
|
||||
*/
|
||||
bool idModelExport::CheckMayaInstall( void ) {
|
||||
#ifndef _WIN32
|
||||
return false;
|
||||
#elif 0
|
||||
HKEY hKey;
|
||||
long lres, lType;
|
||||
|
||||
lres = RegOpenKey( HKEY_LOCAL_MACHINE, "SOFTWARE\\Alias|Wavefront\\Maya\\4.5\\Setup\\InstallPath", &hKey );
|
||||
|
||||
if ( lres != ERROR_SUCCESS ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
lres = RegQueryValueEx( hKey, "MAYA_INSTALL_LOCATION", NULL, (unsigned long*)&lType, (unsigned char*)NULL, (unsigned long*)NULL );
|
||||
|
||||
RegCloseKey( hKey );
|
||||
|
||||
if ( lres != ERROR_SUCCESS ) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
#else
|
||||
HKEY hKey;
|
||||
long lres;
|
||||
|
||||
// only check the non-version specific key so that we only have to update the maya dll when new versions are released
|
||||
lres = RegOpenKey( HKEY_LOCAL_MACHINE, "SOFTWARE\\Alias|Wavefront\\Maya", &hKey );
|
||||
RegCloseKey( hKey );
|
||||
|
||||
if ( lres != ERROR_SUCCESS ) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
=====================
|
||||
idModelExport::LoadMayaDll
|
||||
|
||||
Checks to see if we can load the Maya export dll
|
||||
=====================
|
||||
*/
|
||||
void idModelExport::LoadMayaDll( void ) {
|
||||
exporterDLLEntry_t dllEntry;
|
||||
char dllPath[ MAX_OSPATH ];
|
||||
|
||||
fileSystem->FindDLL( "MayaImport", dllPath, false );
|
||||
if ( !dllPath[ 0 ] ) {
|
||||
return;
|
||||
}
|
||||
importDLL = sys->DLL_Load( dllPath );
|
||||
if ( !importDLL ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// look up the dll interface functions
|
||||
dllEntry = ( exporterDLLEntry_t )sys->DLL_GetProcAddress( importDLL, "dllEntry" );
|
||||
Maya_ConvertModel = ( exporterInterface_t )sys->DLL_GetProcAddress( importDLL, "Maya_ConvertModel" );
|
||||
Maya_Shutdown = ( exporterShutdown_t )sys->DLL_GetProcAddress( importDLL, "Maya_Shutdown" );
|
||||
if ( !Maya_ConvertModel || !dllEntry || !Maya_Shutdown ) {
|
||||
Maya_ConvertModel = NULL;
|
||||
Maya_Shutdown = NULL;
|
||||
sys->DLL_Unload( importDLL );
|
||||
importDLL = 0;
|
||||
gameLocal.Error( "Invalid interface on export DLL." );
|
||||
return;
|
||||
}
|
||||
|
||||
// initialize the DLL
|
||||
if ( !dllEntry( MD5_VERSION, common, sys ) ) {
|
||||
// init failed
|
||||
Maya_ConvertModel = NULL;
|
||||
Maya_Shutdown = NULL;
|
||||
sys->DLL_Unload( importDLL );
|
||||
importDLL = 0;
|
||||
gameLocal.Error( "Export DLL init failed." );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=====================
|
||||
idModelExport::ConvertMayaToMD5
|
||||
|
||||
Checks if a Maya model should be converted to an MD5, and converts if if the time/date or
|
||||
version number has changed.
|
||||
=====================
|
||||
*/
|
||||
bool idModelExport::ConvertMayaToMD5( void ) {
|
||||
ID_TIME_T
|
||||
sourceTime;
|
||||
ID_TIME_T destTime;
|
||||
int version;
|
||||
idToken cmdLine;
|
||||
idStr path;
|
||||
|
||||
// check if our DLL got loaded
|
||||
if ( initialized && !Maya_ConvertModel ) {
|
||||
Maya_Error = "MayaImport dll not loaded.";
|
||||
return false;
|
||||
}
|
||||
|
||||
// if idAnimManager::forceExport is set then we always reexport Maya models
|
||||
if ( idAnimManager::forceExport ) {
|
||||
force = true;
|
||||
}
|
||||
|
||||
// get the source file's time
|
||||
if ( fileSystem->ReadFile( src, NULL, &sourceTime ) < 0 ) {
|
||||
// source file doesn't exist
|
||||
return true;
|
||||
}
|
||||
|
||||
// get the destination file's time
|
||||
if ( !force && ( fileSystem->ReadFile( dest, NULL, &destTime ) >= 0 ) ) {
|
||||
idParser parser( LEXFL_ALLOWPATHNAMES | LEXFL_NOSTRINGESCAPECHARS );
|
||||
|
||||
parser.LoadFile( dest );
|
||||
|
||||
// read the file version
|
||||
if ( parser.CheckTokenString( MD5_VERSION_STRING ) ) {
|
||||
version = parser.ParseInt();
|
||||
|
||||
// check the command line
|
||||
if ( parser.CheckTokenString( "commandline" ) ) {
|
||||
parser.ReadToken( &cmdLine );
|
||||
|
||||
// check the file time, scale, and version
|
||||
if ( ( destTime >= sourceTime ) && ( version == MD5_VERSION ) && ( cmdLine == commandLine ) ) {
|
||||
// don't convert it
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if this is the first time we've been run, check if Maya is installed and load our DLL
|
||||
if ( !initialized ) {
|
||||
initialized = true;
|
||||
|
||||
if ( !CheckMayaInstall() ) {
|
||||
Maya_Error = "Maya not installed in registry.";
|
||||
return false;
|
||||
}
|
||||
|
||||
LoadMayaDll();
|
||||
|
||||
// check if our DLL got loaded
|
||||
if ( !Maya_ConvertModel ) {
|
||||
Maya_Error = "Could not load MayaImport dll.";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// we need to make sure we have a full path, so convert the filename to an OS path
|
||||
src = fileSystem->RelativePathToOSPath( src );
|
||||
dest = fileSystem->RelativePathToOSPath( dest );
|
||||
|
||||
dest.ExtractFilePath( path );
|
||||
if ( path.Length() ) {
|
||||
fileSystem->CreateOSPath( path );
|
||||
}
|
||||
|
||||
// get the os path in case it needs to create one
|
||||
path = fileSystem->RelativePathToOSPath( "" );
|
||||
|
||||
common->SetRefreshOnPrint( true );
|
||||
Maya_Error = Maya_ConvertModel( path, commandLine );
|
||||
common->SetRefreshOnPrint( false );
|
||||
if ( Maya_Error != "Ok" ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// conversion succeded
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
idModelExport::Reset
|
||||
====================
|
||||
*/
|
||||
void idModelExport::Reset( void ) {
|
||||
force = false;
|
||||
commandLine = "";
|
||||
src = "";
|
||||
dest = "";
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
idModelExport::ExportModel
|
||||
====================
|
||||
*/
|
||||
bool idModelExport::ExportModel( const char *model ) {
|
||||
const char *game = cvarSystem->GetCVarString( "fs_game" );
|
||||
if ( strlen(game) == 0 ) {
|
||||
game = BASE_GAMEDIR;
|
||||
}
|
||||
|
||||
Reset();
|
||||
src = model;
|
||||
dest = model;
|
||||
dest.SetFileExtension( MD5_MESH_EXT );
|
||||
|
||||
sprintf( commandLine, "mesh %s -dest %s -game %s", src.c_str(), dest.c_str(), game );
|
||||
if ( !ConvertMayaToMD5() ) {
|
||||
gameLocal.Printf( "Failed to export '%s' : %s", src.c_str(), Maya_Error.c_str() );
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
idModelExport::ExportAnim
|
||||
====================
|
||||
*/
|
||||
bool idModelExport::ExportAnim( const char *anim ) {
|
||||
const char *game = cvarSystem->GetCVarString( "fs_game" );
|
||||
if ( strlen(game) == 0 ) {
|
||||
game = BASE_GAMEDIR;
|
||||
}
|
||||
|
||||
Reset();
|
||||
src = anim;
|
||||
dest = anim;
|
||||
dest.SetFileExtension( MD5_ANIM_EXT );
|
||||
|
||||
sprintf( commandLine, "anim %s -dest %s -game %s", src.c_str(), dest.c_str(), game );
|
||||
if ( !ConvertMayaToMD5() ) {
|
||||
gameLocal.Printf( "Failed to export '%s' : %s", src.c_str(), Maya_Error.c_str() );
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
idModelExport::ParseOptions
|
||||
====================
|
||||
*/
|
||||
bool idModelExport::ParseOptions( idLexer &lex ) {
|
||||
idToken token;
|
||||
idStr destdir;
|
||||
idStr sourcedir;
|
||||
|
||||
if ( !lex.ReadToken( &token ) ) {
|
||||
lex.Error( "Expected filename" );
|
||||
return false;
|
||||
}
|
||||
|
||||
src = token;
|
||||
dest = token;
|
||||
|
||||
while( lex.ReadToken( &token ) ) {
|
||||
if ( token == "-" ) {
|
||||
if ( !lex.ReadToken( &token ) ) {
|
||||
lex.Error( "Expecting option" );
|
||||
return false;
|
||||
}
|
||||
if ( token == "sourcedir" ) {
|
||||
if ( !lex.ReadToken( &token ) ) {
|
||||
lex.Error( "Missing pathname after -sourcedir" );
|
||||
return false;
|
||||
}
|
||||
sourcedir = token;
|
||||
} else if ( token == "destdir" ) {
|
||||
if ( !lex.ReadToken( &token ) ) {
|
||||
lex.Error( "Missing pathname after -destdir" );
|
||||
return false;
|
||||
}
|
||||
destdir = token;
|
||||
} else if ( token == "dest" ) {
|
||||
if ( !lex.ReadToken( &token ) ) {
|
||||
lex.Error( "Missing filename after -dest" );
|
||||
return false;
|
||||
}
|
||||
dest = token;
|
||||
} else {
|
||||
commandLine += va( " -%s", token.c_str() );
|
||||
}
|
||||
} else {
|
||||
commandLine += va( " %s", token.c_str() );
|
||||
}
|
||||
}
|
||||
|
||||
if ( sourcedir.Length() ) {
|
||||
src.StripPath();
|
||||
sourcedir.BackSlashesToSlashes();
|
||||
sprintf( src, "%s/%s", sourcedir.c_str(), src.c_str() );
|
||||
}
|
||||
|
||||
if ( destdir.Length() ) {
|
||||
dest.StripPath();
|
||||
destdir.BackSlashesToSlashes();
|
||||
sprintf( dest, "%s/%s", destdir.c_str(), dest.c_str() );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
idModelExport::ParseExportSection
|
||||
====================
|
||||
*/
|
||||
int idModelExport::ParseExportSection( idParser &parser ) {
|
||||
idToken command;
|
||||
idToken token;
|
||||
idStr defaultCommands;
|
||||
idLexer lex;
|
||||
idStr temp;
|
||||
idStr parms;
|
||||
int count;
|
||||
|
||||
// only export sections that match our export mask
|
||||
if ( g_exportMask.GetString()[ 0 ] ) {
|
||||
if ( parser.CheckTokenString( "{" ) ) {
|
||||
parser.SkipBracedSection( false );
|
||||
return 0;
|
||||
}
|
||||
|
||||
parser.ReadToken( &token );
|
||||
if ( token.Icmp( g_exportMask.GetString() ) ) {
|
||||
parser.SkipBracedSection();
|
||||
return 0;
|
||||
}
|
||||
parser.ExpectTokenString( "{" );
|
||||
} else if ( !parser.CheckTokenString( "{" ) ) {
|
||||
// skip the export mask
|
||||
parser.ReadToken( &token );
|
||||
parser.ExpectTokenString( "{" );
|
||||
}
|
||||
|
||||
count = 0;
|
||||
|
||||
lex.SetFlags( LEXFL_NOSTRINGCONCAT | LEXFL_ALLOWPATHNAMES | LEXFL_ALLOWMULTICHARLITERALS | LEXFL_ALLOWBACKSLASHSTRINGCONCAT );
|
||||
|
||||
while( 1 ) {
|
||||
|
||||
if ( !parser.ReadToken( &command ) ) {
|
||||
parser.Error( "Unexpoected end-of-file" );
|
||||
break;
|
||||
}
|
||||
|
||||
if ( command == "}" ) {
|
||||
break;
|
||||
}
|
||||
|
||||
if ( command == "options" ) {
|
||||
parser.ParseRestOfLine( defaultCommands );
|
||||
} else if ( command == "addoptions" ) {
|
||||
parser.ParseRestOfLine( temp );
|
||||
defaultCommands += " ";
|
||||
defaultCommands += temp;
|
||||
} else if ( ( command == "mesh" ) || ( command == "anim" ) || ( command == "camera" ) ) {
|
||||
if ( !parser.ReadToken( &token ) ) {
|
||||
parser.Error( "Expected filename" );
|
||||
}
|
||||
|
||||
temp = token;
|
||||
parser.ParseRestOfLine( parms );
|
||||
|
||||
if ( defaultCommands.Length() ) {
|
||||
sprintf( temp, "%s %s", temp.c_str(), defaultCommands.c_str() );
|
||||
}
|
||||
|
||||
if ( parms.Length() ) {
|
||||
sprintf( temp, "%s %s", temp.c_str(), parms.c_str() );
|
||||
}
|
||||
|
||||
lex.LoadMemory( temp, temp.Length(), parser.GetFileName() );
|
||||
|
||||
Reset();
|
||||
if ( ParseOptions( lex ) ) {
|
||||
const char *game = cvarSystem->GetCVarString( "fs_game" );
|
||||
if ( strlen(game) == 0 ) {
|
||||
game = BASE_GAMEDIR;
|
||||
}
|
||||
|
||||
if ( command == "mesh" ) {
|
||||
dest.SetFileExtension( MD5_MESH_EXT );
|
||||
} else if ( command == "anim" ) {
|
||||
dest.SetFileExtension( MD5_ANIM_EXT );
|
||||
} else if ( command == "camera" ) {
|
||||
dest.SetFileExtension( MD5_CAMERA_EXT );
|
||||
} else {
|
||||
dest.SetFileExtension( command );
|
||||
}
|
||||
idStr back = commandLine;
|
||||
sprintf( commandLine, "%s %s -dest %s -game %s%s", command.c_str(), src.c_str(), dest.c_str(), game, commandLine.c_str() );
|
||||
if ( ConvertMayaToMD5() ) {
|
||||
count++;
|
||||
} else {
|
||||
parser.Warning( "Failed to export '%s' : %s", src.c_str(), Maya_Error.c_str() );
|
||||
}
|
||||
}
|
||||
lex.FreeSource();
|
||||
} else {
|
||||
parser.Error( "Unknown token: %s", command.c_str() );
|
||||
parser.SkipBracedSection( false );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idModelExport::ExportDefFile
|
||||
================
|
||||
*/
|
||||
int idModelExport::ExportDefFile( const char *filename ) {
|
||||
idParser parser( LEXFL_NOSTRINGCONCAT | LEXFL_ALLOWPATHNAMES | LEXFL_ALLOWMULTICHARLITERALS | LEXFL_ALLOWBACKSLASHSTRINGCONCAT );
|
||||
idToken token;
|
||||
int count;
|
||||
|
||||
count = 0;
|
||||
|
||||
if ( !parser.LoadFile( filename ) ) {
|
||||
gameLocal.Printf( "Could not load '%s'\n", filename );
|
||||
return 0;
|
||||
}
|
||||
|
||||
while( parser.ReadToken( &token ) ) {
|
||||
if ( token == "export" ) {
|
||||
count += ParseExportSection( parser );
|
||||
} else {
|
||||
parser.ReadToken( &token );
|
||||
parser.SkipBracedSection();
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idModelExport::ExportModels
|
||||
================
|
||||
*/
|
||||
int idModelExport::ExportModels( const char *pathname, const char *extension ) {
|
||||
int count;
|
||||
|
||||
count = 0;
|
||||
|
||||
idFileList *files;
|
||||
int i;
|
||||
|
||||
if ( !CheckMayaInstall() ) {
|
||||
// if Maya isn't installed, don't bother checking if we have anims to export
|
||||
return 0;
|
||||
}
|
||||
|
||||
gameLocal.Printf( "--------- Exporting models --------\n" );
|
||||
if ( !g_exportMask.GetString()[ 0 ] ) {
|
||||
gameLocal.Printf( " Export mask: '%s'\n", g_exportMask.GetString() );
|
||||
}
|
||||
|
||||
count = 0;
|
||||
|
||||
files = fileSystem->ListFiles( pathname, extension );
|
||||
for( i = 0; i < files->GetNumFiles(); i++ ) {
|
||||
count += ExportDefFile( va( "%s/%s", pathname, files->GetFile( i ) ) );
|
||||
}
|
||||
fileSystem->FreeFileList( files );
|
||||
|
||||
gameLocal.Printf( "...%d models exported.\n", count );
|
||||
gameLocal.Printf( "-----------------------------------\n" );
|
||||
|
||||
return count;
|
||||
}
|
||||
924
neo/game/anim/Anim_Testmodel.cpp
Normal file
924
neo/game/anim/Anim_Testmodel.cpp
Normal file
@@ -0,0 +1,924 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 GPL Source Code
|
||||
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
|
||||
|
||||
Doom 3 Source Code 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.
|
||||
|
||||
Doom 3 Source Code 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 Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
/*
|
||||
=============================================================================
|
||||
|
||||
MODEL TESTING
|
||||
|
||||
Model viewing can begin with either "testmodel <modelname>"
|
||||
|
||||
The names must be the full pathname after the basedir, like
|
||||
"models/weapons/v_launch/tris.md3" or "players/male/tris.md3"
|
||||
|
||||
Extension will default to ".ase" if not specified.
|
||||
|
||||
Testmodel will create a fake entity 100 units in front of the current view
|
||||
position, directly facing the viewer. It will remain immobile, so you can
|
||||
move around it to view it from different angles.
|
||||
|
||||
g_testModelRotate
|
||||
g_testModelAnimate
|
||||
g_testModelBlend
|
||||
|
||||
=============================================================================
|
||||
*/
|
||||
|
||||
#include "../../idlib/precompiled.h"
|
||||
#pragma hdrstop
|
||||
|
||||
#include "../Game_local.h"
|
||||
|
||||
CLASS_DECLARATION( idAnimatedEntity, idTestModel )
|
||||
EVENT( EV_FootstepLeft, idTestModel::Event_Footstep )
|
||||
EVENT( EV_FootstepRight, idTestModel::Event_Footstep )
|
||||
END_CLASS
|
||||
|
||||
/*
|
||||
================
|
||||
idTestModel::idTestModel
|
||||
================
|
||||
*/
|
||||
idTestModel::idTestModel() {
|
||||
head = NULL;
|
||||
headAnimator = NULL;
|
||||
anim = 0;
|
||||
headAnim = 0;
|
||||
starttime = 0;
|
||||
animtime = 0;
|
||||
mode = 0;
|
||||
frame = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idTestModel::Save
|
||||
================
|
||||
*/
|
||||
void idTestModel::Save( idSaveGame *savefile ) {
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idTestModel::Restore
|
||||
================
|
||||
*/
|
||||
void idTestModel::Restore( idRestoreGame *savefile ) {
|
||||
// FIXME: one day we may actually want to save/restore test models, but for now we'll just delete them
|
||||
delete this;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idTestModel::Spawn
|
||||
================
|
||||
*/
|
||||
void idTestModel::Spawn( void ) {
|
||||
idVec3 size;
|
||||
idBounds bounds;
|
||||
const char *headModel;
|
||||
jointHandle_t joint;
|
||||
idStr jointName;
|
||||
idVec3 origin, modelOffset;
|
||||
idMat3 axis;
|
||||
const idKeyValue *kv;
|
||||
copyJoints_t copyJoint;
|
||||
|
||||
if ( renderEntity.hModel && renderEntity.hModel->IsDefaultModel() && !animator.ModelDef() ) {
|
||||
gameLocal.Warning( "Unable to create testmodel for '%s' : model defaulted", spawnArgs.GetString( "model" ) );
|
||||
PostEventMS( &EV_Remove, 0 );
|
||||
return;
|
||||
}
|
||||
|
||||
mode = g_testModelAnimate.GetInteger();
|
||||
animator.RemoveOriginOffset( g_testModelAnimate.GetInteger() == 1 );
|
||||
|
||||
physicsObj.SetSelf( this );
|
||||
physicsObj.SetOrigin( GetPhysics()->GetOrigin() );
|
||||
physicsObj.SetAxis( GetPhysics()->GetAxis() );
|
||||
|
||||
if ( spawnArgs.GetVector( "mins", NULL, bounds[0] ) ) {
|
||||
spawnArgs.GetVector( "maxs", NULL, bounds[1] );
|
||||
physicsObj.SetClipBox( bounds, 1.0f );
|
||||
physicsObj.SetContents( 0 );
|
||||
} else if ( spawnArgs.GetVector( "size", NULL, size ) ) {
|
||||
bounds[ 0 ].Set( size.x * -0.5f, size.y * -0.5f, 0.0f );
|
||||
bounds[ 1 ].Set( size.x * 0.5f, size.y * 0.5f, size.z );
|
||||
physicsObj.SetClipBox( bounds, 1.0f );
|
||||
physicsObj.SetContents( 0 );
|
||||
}
|
||||
|
||||
spawnArgs.GetVector( "offsetModel", "0 0 0", modelOffset );
|
||||
|
||||
// add the head model if it has one
|
||||
headModel = spawnArgs.GetString( "def_head", "" );
|
||||
if ( headModel[ 0 ] ) {
|
||||
jointName = spawnArgs.GetString( "head_joint" );
|
||||
joint = animator.GetJointHandle( jointName );
|
||||
if ( joint == INVALID_JOINT ) {
|
||||
gameLocal.Warning( "Joint '%s' not found for 'head_joint'", jointName.c_str() );
|
||||
} else {
|
||||
// copy any sounds in case we have frame commands on the head
|
||||
idDict args;
|
||||
const idKeyValue *sndKV = spawnArgs.MatchPrefix( "snd_", NULL );
|
||||
while( sndKV ) {
|
||||
args.Set( sndKV->GetKey(), sndKV->GetValue() );
|
||||
sndKV = spawnArgs.MatchPrefix( "snd_", sndKV );
|
||||
}
|
||||
|
||||
head = gameLocal.SpawnEntityType( idAnimatedEntity::Type, &args );
|
||||
animator.GetJointTransform( joint, gameLocal.time, origin, axis );
|
||||
origin = GetPhysics()->GetOrigin() + ( origin + modelOffset ) * GetPhysics()->GetAxis();
|
||||
head.GetEntity()->SetModel( headModel );
|
||||
head.GetEntity()->SetOrigin( origin );
|
||||
head.GetEntity()->SetAxis( GetPhysics()->GetAxis() );
|
||||
head.GetEntity()->BindToJoint( this, animator.GetJointName( joint ), true );
|
||||
|
||||
headAnimator = head.GetEntity()->GetAnimator();
|
||||
|
||||
// set up the list of joints to copy to the head
|
||||
for( kv = spawnArgs.MatchPrefix( "copy_joint", NULL ); kv != NULL; kv = spawnArgs.MatchPrefix( "copy_joint", kv ) ) {
|
||||
jointName = kv->GetKey();
|
||||
|
||||
if ( jointName.StripLeadingOnce( "copy_joint_world " ) ) {
|
||||
copyJoint.mod = JOINTMOD_WORLD_OVERRIDE;
|
||||
} else {
|
||||
jointName.StripLeadingOnce( "copy_joint " );
|
||||
copyJoint.mod = JOINTMOD_LOCAL_OVERRIDE;
|
||||
}
|
||||
|
||||
copyJoint.from = animator.GetJointHandle( jointName );
|
||||
if ( copyJoint.from == INVALID_JOINT ) {
|
||||
gameLocal.Warning( "Unknown copy_joint '%s'", jointName.c_str() );
|
||||
continue;
|
||||
}
|
||||
|
||||
copyJoint.to = headAnimator->GetJointHandle( jointName );
|
||||
if ( copyJoint.to == INVALID_JOINT ) {
|
||||
gameLocal.Warning( "Unknown copy_joint '%s' on head", jointName.c_str() );
|
||||
continue;
|
||||
}
|
||||
|
||||
copyJoints.Append( copyJoint );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// start any shader effects based off of the spawn time
|
||||
renderEntity.shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( gameLocal.time );
|
||||
|
||||
SetPhysics( &physicsObj );
|
||||
|
||||
gameLocal.Printf( "Added testmodel at origin = '%s', angles = '%s'\n", GetPhysics()->GetOrigin().ToString(), GetPhysics()->GetAxis().ToAngles().ToString() );
|
||||
BecomeActive( TH_THINK );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idTestModel::~idTestModel
|
||||
================
|
||||
*/
|
||||
idTestModel::~idTestModel() {
|
||||
StopSound( SND_CHANNEL_ANY, false );
|
||||
if ( renderEntity.hModel ) {
|
||||
gameLocal.Printf( "Removing testmodel %s\n", renderEntity.hModel->Name() );
|
||||
} else {
|
||||
gameLocal.Printf( "Removing testmodel\n" );
|
||||
}
|
||||
if ( gameLocal.testmodel == this ) {
|
||||
gameLocal.testmodel = NULL;
|
||||
}
|
||||
if ( head.GetEntity() ) {
|
||||
head.GetEntity()->StopSound( SND_CHANNEL_ANY, false );
|
||||
head.GetEntity()->PostEventMS( &EV_Remove, 0 );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
idTestModel::Event_Footstep
|
||||
===============
|
||||
*/
|
||||
void idTestModel::Event_Footstep( void ) {
|
||||
StartSound( "snd_footstep", SND_CHANNEL_BODY, 0, false, NULL );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idTestModel::ShouldConstructScriptObjectAtSpawn
|
||||
|
||||
Called during idEntity::Spawn to see if it should construct the script object or not.
|
||||
Overridden by subclasses that need to spawn the script object themselves.
|
||||
================
|
||||
*/
|
||||
bool idTestModel::ShouldConstructScriptObjectAtSpawn( void ) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idTestModel::Think
|
||||
================
|
||||
*/
|
||||
void idTestModel::Think( void ) {
|
||||
idVec3 pos;
|
||||
idMat3 axis;
|
||||
idAngles ang;
|
||||
int i;
|
||||
|
||||
if ( thinkFlags & TH_THINK ) {
|
||||
if ( anim && ( gameLocal.testmodel == this ) && ( mode != g_testModelAnimate.GetInteger() ) ) {
|
||||
StopSound( SND_CHANNEL_ANY, false );
|
||||
if ( head.GetEntity() ) {
|
||||
head.GetEntity()->StopSound( SND_CHANNEL_ANY, false );
|
||||
}
|
||||
switch( g_testModelAnimate.GetInteger() ) {
|
||||
default:
|
||||
case 0:
|
||||
// cycle anim with origin reset
|
||||
if ( animator.NumFrames( anim ) <= 1 ) {
|
||||
// single frame animations end immediately, so just cycle it since it's the same result
|
||||
animator.CycleAnim( ANIMCHANNEL_ALL, anim, gameLocal.time, FRAME2MS( g_testModelBlend.GetInteger() ) );
|
||||
if ( headAnim ) {
|
||||
headAnimator->CycleAnim( ANIMCHANNEL_ALL, headAnim, gameLocal.time, FRAME2MS( g_testModelBlend.GetInteger() ) );
|
||||
}
|
||||
} else {
|
||||
animator.PlayAnim( ANIMCHANNEL_ALL, anim, gameLocal.time, FRAME2MS( g_testModelBlend.GetInteger() ) );
|
||||
if ( headAnim ) {
|
||||
headAnimator->PlayAnim( ANIMCHANNEL_ALL, headAnim, gameLocal.time, FRAME2MS( g_testModelBlend.GetInteger() ) );
|
||||
if ( headAnimator->AnimLength( headAnim ) > animator.AnimLength( anim ) ) {
|
||||
// loop the body anim when the head anim is longer
|
||||
animator.CurrentAnim( ANIMCHANNEL_ALL )->SetCycleCount( -1 );
|
||||
}
|
||||
}
|
||||
}
|
||||
animator.RemoveOriginOffset( false );
|
||||
break;
|
||||
|
||||
case 1:
|
||||
// cycle anim with fixed origin
|
||||
animator.CycleAnim( ANIMCHANNEL_ALL, anim, gameLocal.time, FRAME2MS( g_testModelBlend.GetInteger() ) );
|
||||
animator.RemoveOriginOffset( true );
|
||||
if ( headAnim ) {
|
||||
headAnimator->CycleAnim( ANIMCHANNEL_ALL, headAnim, gameLocal.time, FRAME2MS( g_testModelBlend.GetInteger() ) );
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
// cycle anim with continuous origin
|
||||
animator.CycleAnim( ANIMCHANNEL_ALL, anim, gameLocal.time, FRAME2MS( g_testModelBlend.GetInteger() ) );
|
||||
animator.RemoveOriginOffset( false );
|
||||
if ( headAnim ) {
|
||||
headAnimator->CycleAnim( ANIMCHANNEL_ALL, headAnim, gameLocal.time, FRAME2MS( g_testModelBlend.GetInteger() ) );
|
||||
}
|
||||
break;
|
||||
|
||||
case 3:
|
||||
// frame by frame with continuous origin
|
||||
animator.SetFrame( ANIMCHANNEL_ALL, anim, frame, gameLocal.time, FRAME2MS( g_testModelBlend.GetInteger() ) );
|
||||
animator.RemoveOriginOffset( false );
|
||||
if ( headAnim ) {
|
||||
headAnimator->SetFrame( ANIMCHANNEL_ALL, headAnim, frame, gameLocal.time, FRAME2MS( g_testModelBlend.GetInteger() ) );
|
||||
}
|
||||
break;
|
||||
|
||||
case 4:
|
||||
// play anim once
|
||||
animator.PlayAnim( ANIMCHANNEL_ALL, anim, gameLocal.time, FRAME2MS( g_testModelBlend.GetInteger() ) );
|
||||
animator.RemoveOriginOffset( false );
|
||||
if ( headAnim ) {
|
||||
headAnimator->PlayAnim( ANIMCHANNEL_ALL, headAnim, gameLocal.time, FRAME2MS( g_testModelBlend.GetInteger() ) );
|
||||
}
|
||||
break;
|
||||
|
||||
case 5:
|
||||
// frame by frame with fixed origin
|
||||
animator.SetFrame( ANIMCHANNEL_ALL, anim, frame, gameLocal.time, FRAME2MS( g_testModelBlend.GetInteger() ) );
|
||||
animator.RemoveOriginOffset( true );
|
||||
if ( headAnim ) {
|
||||
headAnimator->SetFrame( ANIMCHANNEL_ALL, headAnim, frame, gameLocal.time, FRAME2MS( g_testModelBlend.GetInteger() ) );
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
mode = g_testModelAnimate.GetInteger();
|
||||
}
|
||||
|
||||
if ( ( mode == 0 ) && ( gameLocal.time >= starttime + animtime ) ) {
|
||||
starttime = gameLocal.time;
|
||||
StopSound( SND_CHANNEL_ANY, false );
|
||||
animator.PlayAnim( ANIMCHANNEL_ALL, anim, gameLocal.time, FRAME2MS( g_testModelBlend.GetInteger() ) );
|
||||
if ( headAnim ) {
|
||||
headAnimator->PlayAnim( ANIMCHANNEL_ALL, headAnim, gameLocal.time, FRAME2MS( g_testModelBlend.GetInteger() ) );
|
||||
if ( headAnimator->AnimLength( headAnim ) > animator.AnimLength( anim ) ) {
|
||||
// loop the body anim when the head anim is longer
|
||||
animator.CurrentAnim( ANIMCHANNEL_ALL )->SetCycleCount( -1 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( headAnimator ) {
|
||||
// copy the animation from the body to the head
|
||||
for( i = 0; i < copyJoints.Num(); i++ ) {
|
||||
if ( copyJoints[ i ].mod == JOINTMOD_WORLD_OVERRIDE ) {
|
||||
idMat3 mat = head.GetEntity()->GetPhysics()->GetAxis().Transpose();
|
||||
GetJointWorldTransform( copyJoints[ i ].from, gameLocal.time, pos, axis );
|
||||
pos -= head.GetEntity()->GetPhysics()->GetOrigin();
|
||||
headAnimator->SetJointPos( copyJoints[ i ].to, copyJoints[ i ].mod, pos * mat );
|
||||
headAnimator->SetJointAxis( copyJoints[ i ].to, copyJoints[ i ].mod, axis * mat );
|
||||
} else {
|
||||
animator.GetJointLocalTransform( copyJoints[ i ].from, gameLocal.time, pos, axis );
|
||||
headAnimator->SetJointPos( copyJoints[ i ].to, copyJoints[ i ].mod, pos );
|
||||
headAnimator->SetJointAxis( copyJoints[ i ].to, copyJoints[ i ].mod, axis );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// update rotation
|
||||
RunPhysics();
|
||||
|
||||
physicsObj.GetAngles( ang );
|
||||
physicsObj.SetAngularExtrapolation( extrapolation_t(EXTRAPOLATION_LINEAR|EXTRAPOLATION_NOSTOP), gameLocal.time, 0, ang, idAngles( 0, g_testModelRotate.GetFloat() * 360.0f / 60.0f, 0 ), ang_zero );
|
||||
|
||||
idClipModel *clip = physicsObj.GetClipModel();
|
||||
if ( clip && animator.ModelDef() ) {
|
||||
idVec3 neworigin;
|
||||
idMat3 axis;
|
||||
jointHandle_t joint;
|
||||
|
||||
joint = animator.GetJointHandle( "origin" );
|
||||
animator.GetJointTransform( joint, gameLocal.time, neworigin, axis );
|
||||
neworigin = ( ( neworigin - animator.ModelDef()->GetVisualOffset() ) * physicsObj.GetAxis() ) + GetPhysics()->GetOrigin();
|
||||
clip->Link( gameLocal.clip, this, 0, neworigin, clip->GetAxis() );
|
||||
}
|
||||
}
|
||||
|
||||
UpdateAnimation();
|
||||
Present();
|
||||
|
||||
if ( ( gameLocal.testmodel == this ) && g_showTestModelFrame.GetInteger() && anim ) {
|
||||
gameLocal.Printf( "^5 Anim: ^7%s ^5Frame: ^7%d/%d Time: %.3f\n", animator.AnimFullName( anim ), animator.CurrentAnim( ANIMCHANNEL_ALL )->GetFrameNumber( gameLocal.time ),
|
||||
animator.CurrentAnim( ANIMCHANNEL_ALL )->NumFrames(), MS2SEC( gameLocal.time - animator.CurrentAnim( ANIMCHANNEL_ALL )->GetStartTime() ) );
|
||||
if ( headAnim ) {
|
||||
gameLocal.Printf( "^5 Head: ^7%s ^5Frame: ^7%d/%d Time: %.3f\n\n", headAnimator->AnimFullName( headAnim ), headAnimator->CurrentAnim( ANIMCHANNEL_ALL )->GetFrameNumber( gameLocal.time ),
|
||||
headAnimator->CurrentAnim( ANIMCHANNEL_ALL )->NumFrames(), MS2SEC( gameLocal.time - headAnimator->CurrentAnim( ANIMCHANNEL_ALL )->GetStartTime() ) );
|
||||
} else {
|
||||
gameLocal.Printf( "\n\n" );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idTestModel::NextAnim
|
||||
================
|
||||
*/
|
||||
void idTestModel::NextAnim( const idCmdArgs &args ) {
|
||||
if ( !animator.NumAnims() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
anim++;
|
||||
if ( anim >= animator.NumAnims() ) {
|
||||
// anim 0 is no anim
|
||||
anim = 1;
|
||||
}
|
||||
|
||||
starttime = gameLocal.time;
|
||||
animtime = animator.AnimLength( anim );
|
||||
animname = animator.AnimFullName( anim );
|
||||
headAnim = 0;
|
||||
if ( headAnimator ) {
|
||||
headAnimator->ClearAllAnims( gameLocal.time, 0 );
|
||||
headAnim = headAnimator->GetAnim( animname );
|
||||
if ( !headAnim ) {
|
||||
headAnim = headAnimator->GetAnim( "idle" );
|
||||
}
|
||||
|
||||
if ( headAnim && ( headAnimator->AnimLength( headAnim ) > animtime ) ) {
|
||||
animtime = headAnimator->AnimLength( headAnim );
|
||||
}
|
||||
}
|
||||
|
||||
gameLocal.Printf( "anim '%s', %d.%03d seconds, %d frames\n", animname.c_str(), animator.AnimLength( anim ) / 1000, animator.AnimLength( anim ) % 1000, animator.NumFrames( anim ) );
|
||||
if ( headAnim ) {
|
||||
gameLocal.Printf( "head '%s', %d.%03d seconds, %d frames\n", headAnimator->AnimFullName( headAnim ), headAnimator->AnimLength( headAnim ) / 1000, headAnimator->AnimLength( headAnim ) % 1000, headAnimator->NumFrames( headAnim ) );
|
||||
}
|
||||
|
||||
// reset the anim
|
||||
mode = -1;
|
||||
frame = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idTestModel::PrevAnim
|
||||
================
|
||||
*/
|
||||
void idTestModel::PrevAnim( const idCmdArgs &args ) {
|
||||
if ( !animator.NumAnims() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
headAnim = 0;
|
||||
anim--;
|
||||
if ( anim < 0 ) {
|
||||
anim = animator.NumAnims() - 1;
|
||||
}
|
||||
|
||||
starttime = gameLocal.time;
|
||||
animtime = animator.AnimLength( anim );
|
||||
animname = animator.AnimFullName( anim );
|
||||
headAnim = 0;
|
||||
if ( headAnimator ) {
|
||||
headAnimator->ClearAllAnims( gameLocal.time, 0 );
|
||||
headAnim = headAnimator->GetAnim( animname );
|
||||
if ( !headAnim ) {
|
||||
headAnim = headAnimator->GetAnim( "idle" );
|
||||
}
|
||||
|
||||
if ( headAnim && ( headAnimator->AnimLength( headAnim ) > animtime ) ) {
|
||||
animtime = headAnimator->AnimLength( headAnim );
|
||||
}
|
||||
}
|
||||
|
||||
gameLocal.Printf( "anim '%s', %d.%03d seconds, %d frames\n", animname.c_str(), animator.AnimLength( anim ) / 1000, animator.AnimLength( anim ) % 1000, animator.NumFrames( anim ) );
|
||||
if ( headAnim ) {
|
||||
gameLocal.Printf( "head '%s', %d.%03d seconds, %d frames\n", headAnimator->AnimFullName( headAnim ), headAnimator->AnimLength( headAnim ) / 1000, headAnimator->AnimLength( headAnim ) % 1000, headAnimator->NumFrames( headAnim ) );
|
||||
}
|
||||
|
||||
// reset the anim
|
||||
mode = -1;
|
||||
frame = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idTestModel::NextFrame
|
||||
================
|
||||
*/
|
||||
void idTestModel::NextFrame( const idCmdArgs &args ) {
|
||||
if ( !anim || ( ( g_testModelAnimate.GetInteger() != 3 ) && ( g_testModelAnimate.GetInteger() != 5 ) ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
frame++;
|
||||
if ( frame > animator.NumFrames( anim ) ) {
|
||||
frame = 1;
|
||||
}
|
||||
|
||||
gameLocal.Printf( "^5 Anim: ^7%s\n^5Frame: ^7%d/%d\n\n", animator.AnimFullName( anim ), frame, animator.NumFrames( anim ) );
|
||||
|
||||
// reset the anim
|
||||
mode = -1;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idTestModel::PrevFrame
|
||||
================
|
||||
*/
|
||||
void idTestModel::PrevFrame( const idCmdArgs &args ) {
|
||||
if ( !anim || ( ( g_testModelAnimate.GetInteger() != 3 ) && ( g_testModelAnimate.GetInteger() != 5 ) ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
frame--;
|
||||
if ( frame < 1 ) {
|
||||
frame = animator.NumFrames( anim );
|
||||
}
|
||||
|
||||
gameLocal.Printf( "^5 Anim: ^7%s\n^5Frame: ^7%d/%d\n\n", animator.AnimFullName( anim ), frame, animator.NumFrames( anim ) );
|
||||
|
||||
// reset the anim
|
||||
mode = -1;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idTestModel::TestAnim
|
||||
================
|
||||
*/
|
||||
void idTestModel::TestAnim( const idCmdArgs &args ) {
|
||||
idStr name;
|
||||
int animNum;
|
||||
const idAnim *newanim;
|
||||
|
||||
if ( args.Argc() < 2 ) {
|
||||
gameLocal.Printf( "usage: testanim <animname>\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
newanim = NULL;
|
||||
|
||||
name = args.Argv( 1 );
|
||||
#if 0
|
||||
if ( strstr( name, ".ma" ) || strstr( name, ".mb" ) ) {
|
||||
const idMD5Anim *md5anims[ ANIM_MaxSyncedAnims ];
|
||||
idModelExport exporter;
|
||||
exporter.ExportAnim( name );
|
||||
name.SetFileExtension( MD5_ANIM_EXT );
|
||||
md5anims[ 0 ] = animationLib.GetAnim( name );
|
||||
if ( md5anims[ 0 ] ) {
|
||||
customAnim.SetAnim( animator.ModelDef(), name, name, 1, md5anims );
|
||||
newanim = &customAnim;
|
||||
}
|
||||
} else {
|
||||
animNum = animator.GetAnim( name );
|
||||
}
|
||||
#else
|
||||
animNum = animator.GetAnim( name );
|
||||
#endif
|
||||
|
||||
if ( !animNum ) {
|
||||
gameLocal.Printf( "Animation '%s' not found.\n", name.c_str() );
|
||||
return;
|
||||
}
|
||||
|
||||
anim = animNum;
|
||||
starttime = gameLocal.time;
|
||||
animtime = animator.AnimLength( anim );
|
||||
headAnim = 0;
|
||||
if ( headAnimator ) {
|
||||
headAnimator->ClearAllAnims( gameLocal.time, 0 );
|
||||
headAnim = headAnimator->GetAnim( animname );
|
||||
if ( !headAnim ) {
|
||||
headAnim = headAnimator->GetAnim( "idle" );
|
||||
if ( !headAnim ) {
|
||||
gameLocal.Printf( "Missing 'idle' anim for head.\n" );
|
||||
}
|
||||
}
|
||||
|
||||
if ( headAnim && ( headAnimator->AnimLength( headAnim ) > animtime ) ) {
|
||||
animtime = headAnimator->AnimLength( headAnim );
|
||||
}
|
||||
}
|
||||
|
||||
animname = name;
|
||||
gameLocal.Printf( "anim '%s', %d.%03d seconds, %d frames\n", animname.c_str(), animator.AnimLength( anim ) / 1000, animator.AnimLength( anim ) % 1000, animator.NumFrames( anim ) );
|
||||
|
||||
// reset the anim
|
||||
mode = -1;
|
||||
}
|
||||
|
||||
/*
|
||||
=====================
|
||||
idTestModel::BlendAnim
|
||||
=====================
|
||||
*/
|
||||
void idTestModel::BlendAnim( const idCmdArgs &args ) {
|
||||
int anim1;
|
||||
int anim2;
|
||||
|
||||
if ( args.Argc() < 4 ) {
|
||||
gameLocal.Printf( "usage: testblend <anim1> <anim2> <frames>\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
anim1 = gameLocal.testmodel->animator.GetAnim( args.Argv( 1 ) );
|
||||
if ( !anim1 ) {
|
||||
gameLocal.Printf( "Animation '%s' not found.\n", args.Argv( 1 ) );
|
||||
return;
|
||||
}
|
||||
|
||||
anim2 = gameLocal.testmodel->animator.GetAnim( args.Argv( 2 ) );
|
||||
if ( !anim2 ) {
|
||||
gameLocal.Printf( "Animation '%s' not found.\n", args.Argv( 2 ) );
|
||||
return;
|
||||
}
|
||||
|
||||
animname = args.Argv( 2 );
|
||||
animator.CycleAnim( ANIMCHANNEL_ALL, anim1, gameLocal.time, 0 );
|
||||
animator.CycleAnim( ANIMCHANNEL_ALL, anim2, gameLocal.time, FRAME2MS( atoi( args.Argv( 3 ) ) ) );
|
||||
|
||||
anim = anim2;
|
||||
headAnim = 0;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
|
||||
Testmodel console commands
|
||||
|
||||
***********************************************************************/
|
||||
|
||||
/*
|
||||
=================
|
||||
idTestModel::KeepTestModel_f
|
||||
|
||||
Makes the current test model permanent, allowing you to place
|
||||
multiple test models
|
||||
=================
|
||||
*/
|
||||
void idTestModel::KeepTestModel_f( const idCmdArgs &args ) {
|
||||
if ( !gameLocal.testmodel ) {
|
||||
gameLocal.Printf( "No active testModel.\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
gameLocal.Printf( "modelDef %p kept\n", gameLocal.testmodel->renderEntity.hModel );
|
||||
|
||||
gameLocal.testmodel = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
idTestModel::TestSkin_f
|
||||
|
||||
Sets a skin on an existing testModel
|
||||
=================
|
||||
*/
|
||||
void idTestModel::TestSkin_f( const idCmdArgs &args ) {
|
||||
idVec3 offset;
|
||||
idStr name;
|
||||
idPlayer * player;
|
||||
idDict dict;
|
||||
|
||||
player = gameLocal.GetLocalPlayer();
|
||||
if ( !player || !gameLocal.CheatsOk() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// delete the testModel if active
|
||||
if ( !gameLocal.testmodel ) {
|
||||
common->Printf( "No active testModel\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( args.Argc() < 2 ) {
|
||||
common->Printf( "removing testSkin.\n" );
|
||||
gameLocal.testmodel->SetSkin( NULL );
|
||||
return;
|
||||
}
|
||||
|
||||
name = args.Argv( 1 );
|
||||
gameLocal.testmodel->SetSkin( declManager->FindSkin( name ) );
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
idTestModel::TestShaderParm_f
|
||||
|
||||
Sets a shaderParm on an existing testModel
|
||||
=================
|
||||
*/
|
||||
void idTestModel::TestShaderParm_f( const idCmdArgs &args ) {
|
||||
idVec3 offset;
|
||||
idStr name;
|
||||
idPlayer * player;
|
||||
idDict dict;
|
||||
|
||||
player = gameLocal.GetLocalPlayer();
|
||||
if ( !player || !gameLocal.CheatsOk() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// delete the testModel if active
|
||||
if ( !gameLocal.testmodel ) {
|
||||
common->Printf( "No active testModel\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( args.Argc() != 3 ) {
|
||||
common->Printf( "USAGE: testShaderParm <parmNum> <float | \"time\">\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
int parm = atoi( args.Argv( 1 ) );
|
||||
if ( parm < 0 || parm >= MAX_ENTITY_SHADER_PARMS ) {
|
||||
common->Printf( "parmNum %i out of range\n", parm );
|
||||
return;
|
||||
}
|
||||
|
||||
float value;
|
||||
if ( !idStr::Icmp( args.Argv( 2 ), "time" ) ) {
|
||||
value = gameLocal.time * -0.001;
|
||||
} else {
|
||||
value = atof( args.Argv( 2 ) );
|
||||
}
|
||||
|
||||
gameLocal.testmodel->SetShaderParm( parm, value );
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
idTestModel::TestModel_f
|
||||
|
||||
Creates a static modelDef in front of the current position, which
|
||||
can then be moved around
|
||||
=================
|
||||
*/
|
||||
void idTestModel::TestModel_f( const idCmdArgs &args ) {
|
||||
idVec3 offset;
|
||||
idStr name;
|
||||
idPlayer * player;
|
||||
const idDict * entityDef;
|
||||
idDict dict;
|
||||
|
||||
player = gameLocal.GetLocalPlayer();
|
||||
if ( !player || !gameLocal.CheatsOk() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// delete the testModel if active
|
||||
if ( gameLocal.testmodel ) {
|
||||
delete gameLocal.testmodel;
|
||||
gameLocal.testmodel = NULL;
|
||||
}
|
||||
|
||||
if ( args.Argc() < 2 ) {
|
||||
return;
|
||||
}
|
||||
|
||||
name = args.Argv( 1 );
|
||||
|
||||
entityDef = gameLocal.FindEntityDefDict( name, false );
|
||||
if ( entityDef ) {
|
||||
dict = *entityDef;
|
||||
} else {
|
||||
if ( declManager->FindType( DECL_MODELDEF, name, false ) ) {
|
||||
dict.Set( "model", name );
|
||||
} else {
|
||||
// allow map models with underscore prefixes to be tested during development
|
||||
// without appending an ase
|
||||
if ( name[ 0 ] != '_' ) {
|
||||
name.DefaultFileExtension( ".ase" );
|
||||
}
|
||||
|
||||
if ( strstr( name, ".ma" ) || strstr( name, ".mb" ) ) {
|
||||
idModelExport exporter;
|
||||
exporter.ExportModel( name );
|
||||
name.SetFileExtension( MD5_MESH_EXT );
|
||||
}
|
||||
|
||||
if ( !renderModelManager->CheckModel( name ) ) {
|
||||
gameLocal.Printf( "Can't register model\n" );
|
||||
return;
|
||||
}
|
||||
dict.Set( "model", name );
|
||||
}
|
||||
}
|
||||
|
||||
offset = player->GetPhysics()->GetOrigin() + player->viewAngles.ToForward() * 100.0f;
|
||||
|
||||
dict.Set( "origin", offset.ToString() );
|
||||
dict.Set( "angle", va( "%f", player->viewAngles.yaw + 180.0f ) );
|
||||
gameLocal.testmodel = ( idTestModel * )gameLocal.SpawnEntityType( idTestModel::Type, &dict );
|
||||
gameLocal.testmodel->renderEntity.shaderParms[SHADERPARM_TIMEOFFSET] = -MS2SEC( gameLocal.time );
|
||||
}
|
||||
|
||||
/*
|
||||
=====================
|
||||
idTestModel::ArgCompletion_TestModel
|
||||
=====================
|
||||
*/
|
||||
void idTestModel::ArgCompletion_TestModel( const idCmdArgs &args, void(*callback)( const char *s ) ) {
|
||||
int i, num;
|
||||
|
||||
num = declManager->GetNumDecls( DECL_ENTITYDEF );
|
||||
for ( i = 0; i < num; i++ ) {
|
||||
callback( idStr( args.Argv( 0 ) ) + " " + declManager->DeclByIndex( DECL_ENTITYDEF, i , false )->GetName() );
|
||||
}
|
||||
num = declManager->GetNumDecls( DECL_MODELDEF );
|
||||
for ( i = 0; i < num; i++ ) {
|
||||
callback( idStr( args.Argv( 0 ) ) + " " + declManager->DeclByIndex( DECL_MODELDEF, i , false )->GetName() );
|
||||
}
|
||||
cmdSystem->ArgCompletion_FolderExtension( args, callback, "models/", false, ".lwo", ".ase", ".md5mesh", ".ma", ".mb", NULL );
|
||||
}
|
||||
|
||||
/*
|
||||
=====================
|
||||
idTestModel::TestParticleStopTime_f
|
||||
=====================
|
||||
*/
|
||||
void idTestModel::TestParticleStopTime_f( const idCmdArgs &args ) {
|
||||
if ( !gameLocal.testmodel ) {
|
||||
gameLocal.Printf( "No testModel active.\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
gameLocal.testmodel->renderEntity.shaderParms[SHADERPARM_PARTICLE_STOPTIME] = MS2SEC( gameLocal.time );
|
||||
gameLocal.testmodel->UpdateVisuals();
|
||||
}
|
||||
|
||||
/*
|
||||
=====================
|
||||
idTestModel::TestAnim_f
|
||||
=====================
|
||||
*/
|
||||
void idTestModel::TestAnim_f( const idCmdArgs &args ) {
|
||||
if ( !gameLocal.testmodel ) {
|
||||
gameLocal.Printf( "No testModel active.\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
gameLocal.testmodel->TestAnim( args );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=====================
|
||||
idTestModel::ArgCompletion_TestAnim
|
||||
=====================
|
||||
*/
|
||||
void idTestModel::ArgCompletion_TestAnim( const idCmdArgs &args, void(*callback)( const char *s ) ) {
|
||||
if ( gameLocal.testmodel ) {
|
||||
idAnimator *animator = gameLocal.testmodel->GetAnimator();
|
||||
for( int i = 0; i < animator->NumAnims(); i++ ) {
|
||||
callback( va( "%s %s", args.Argv( 0 ), animator->AnimFullName( i ) ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=====================
|
||||
idTestModel::TestBlend_f
|
||||
=====================
|
||||
*/
|
||||
void idTestModel::TestBlend_f( const idCmdArgs &args ) {
|
||||
if ( !gameLocal.testmodel ) {
|
||||
gameLocal.Printf( "No testModel active.\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
gameLocal.testmodel->BlendAnim( args );
|
||||
}
|
||||
|
||||
/*
|
||||
=====================
|
||||
idTestModel::TestModelNextAnim_f
|
||||
=====================
|
||||
*/
|
||||
void idTestModel::TestModelNextAnim_f( const idCmdArgs &args ) {
|
||||
if ( !gameLocal.testmodel ) {
|
||||
gameLocal.Printf( "No testModel active.\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
gameLocal.testmodel->NextAnim( args );
|
||||
}
|
||||
|
||||
/*
|
||||
=====================
|
||||
idTestModel::TestModelPrevAnim_f
|
||||
=====================
|
||||
*/
|
||||
void idTestModel::TestModelPrevAnim_f( const idCmdArgs &args ) {
|
||||
if ( !gameLocal.testmodel ) {
|
||||
gameLocal.Printf( "No testModel active.\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
gameLocal.testmodel->PrevAnim( args );
|
||||
}
|
||||
|
||||
/*
|
||||
=====================
|
||||
idTestModel::TestModelNextFrame_f
|
||||
=====================
|
||||
*/
|
||||
void idTestModel::TestModelNextFrame_f( const idCmdArgs &args ) {
|
||||
if ( !gameLocal.testmodel ) {
|
||||
gameLocal.Printf( "No testModel active.\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
gameLocal.testmodel->NextFrame( args );
|
||||
}
|
||||
|
||||
/*
|
||||
=====================
|
||||
idTestModel::TestModelPrevFrame_f
|
||||
=====================
|
||||
*/
|
||||
void idTestModel::TestModelPrevFrame_f( const idCmdArgs &args ) {
|
||||
if ( !gameLocal.testmodel ) {
|
||||
gameLocal.Printf( "No testModel active.\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
gameLocal.testmodel->PrevFrame( args );
|
||||
}
|
||||
95
neo/game/anim/Anim_Testmodel.h
Normal file
95
neo/game/anim/Anim_Testmodel.h
Normal file
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 GPL Source Code
|
||||
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
|
||||
|
||||
Doom 3 Source Code 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.
|
||||
|
||||
Doom 3 Source Code 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 Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#ifndef __ANIM_TESTMODEL_H__
|
||||
#define __ANIM_TESTMODEL_H__
|
||||
|
||||
/*
|
||||
==============================================================================================
|
||||
|
||||
idTestModel
|
||||
|
||||
==============================================================================================
|
||||
*/
|
||||
|
||||
class idTestModel : public idAnimatedEntity {
|
||||
public:
|
||||
CLASS_PROTOTYPE( idTestModel );
|
||||
|
||||
idTestModel();
|
||||
~idTestModel();
|
||||
|
||||
void Save( idSaveGame *savefile );
|
||||
void Restore( idRestoreGame *savefile );
|
||||
|
||||
void Spawn( void );
|
||||
|
||||
virtual bool ShouldConstructScriptObjectAtSpawn( void ) const;
|
||||
|
||||
void NextAnim( const idCmdArgs &args );
|
||||
void PrevAnim( const idCmdArgs &args );
|
||||
void NextFrame( const idCmdArgs &args );
|
||||
void PrevFrame( const idCmdArgs &args );
|
||||
void TestAnim( const idCmdArgs &args );
|
||||
void BlendAnim( const idCmdArgs &args );
|
||||
|
||||
static void KeepTestModel_f( const idCmdArgs &args );
|
||||
static void TestModel_f( const idCmdArgs &args );
|
||||
static void ArgCompletion_TestModel( const idCmdArgs &args, void(*callback)( const char *s ) );
|
||||
static void TestSkin_f( const idCmdArgs &args );
|
||||
static void TestShaderParm_f( const idCmdArgs &args );
|
||||
static void TestParticleStopTime_f( const idCmdArgs &args );
|
||||
static void TestAnim_f( const idCmdArgs &args );
|
||||
static void ArgCompletion_TestAnim( const idCmdArgs &args, void(*callback)( const char *s ) );
|
||||
static void TestBlend_f( const idCmdArgs &args );
|
||||
static void TestModelNextAnim_f( const idCmdArgs &args );
|
||||
static void TestModelPrevAnim_f( const idCmdArgs &args );
|
||||
static void TestModelNextFrame_f( const idCmdArgs &args );
|
||||
static void TestModelPrevFrame_f( const idCmdArgs &args );
|
||||
|
||||
private:
|
||||
idEntityPtr<idEntity> head;
|
||||
idAnimator *headAnimator;
|
||||
idAnim customAnim;
|
||||
idPhysics_Parametric physicsObj;
|
||||
idStr animname;
|
||||
int anim;
|
||||
int headAnim;
|
||||
int mode;
|
||||
int frame;
|
||||
int starttime;
|
||||
int animtime;
|
||||
|
||||
idList<copyJoints_t> copyJoints;
|
||||
|
||||
virtual void Think( void );
|
||||
|
||||
void Event_Footstep( void );
|
||||
};
|
||||
|
||||
#endif /* !__ANIM_TESTMODEL_H__*/
|
||||
Reference in New Issue
Block a user