2013-04-04 14:52:42 +00:00
// leave this as first line for PCH reasons...
//
# ifndef __Q_SHARED_H
# include "../game/q_shared.h"
# endif
# if !defined(TR_LOCAL_H)
# include "../renderer/tr_local.h"
# endif
# if !defined(_QCOMMON_H_)
# include "../qcommon/qcommon.h"
# endif
# include "../renderer/MatComp.h"
# if !defined(G2_H_INC)
# include "G2.h"
# endif
# include "G2_local.h"
//=====================================================================================================================
// Bone List handling routines - so entities can override bone info on a bone by bone level, and also interrogate this info
// Given a bone name, see if that bone is already in our bone list - note the model_t pointer that gets passed in here MUST point at the
// gla file, not the glm file type.
int G2_Find_Bone ( const model_t * mod , boneInfo_v & blist , const char * boneName )
{
int i ;
mdxaSkel_t * skel ;
mdxaSkelOffsets_t * offsets ;
offsets = ( mdxaSkelOffsets_t * ) ( ( byte * ) mod - > mdxa + sizeof ( mdxaHeader_t ) ) ;
skel = ( mdxaSkel_t * ) ( ( byte * ) mod - > mdxa + sizeof ( mdxaHeader_t ) + offsets - > offsets [ 0 ] ) ;
// look through entire list
for ( i = 0 ; i < blist . size ( ) ; i + + )
{
// if this bone entry has no info in it, bounce over it
if ( blist [ i ] . boneNumber = = - 1 )
{
continue ;
}
// figure out what skeletal info structure this bone entry is looking at
skel = ( mdxaSkel_t * ) ( ( byte * ) mod - > mdxa + sizeof ( mdxaHeader_t ) + offsets - > offsets [ blist [ i ] . boneNumber ] ) ;
// if name is the same, we found it
if ( ! stricmp ( skel - > name , boneName ) )
{
return i ;
}
}
// didn't find it
return - 1 ;
}
// we need to add a bone to the list - find a free one and see if we can find a corresponding bone in the gla file
int G2_Add_Bone ( const model_t * mod , boneInfo_v & blist , const char * boneName )
{
int i , x ;
mdxaSkel_t * skel ;
mdxaSkelOffsets_t * offsets ;
boneInfo_t tempBone ;
offsets = ( mdxaSkelOffsets_t * ) ( ( byte * ) mod - > mdxa + sizeof ( mdxaHeader_t ) ) ;
// walk the entire list of bones in the gla file for this model and see if any match the name of the bone we want to find
for ( x = 0 ; x < mod - > mdxa - > numBones ; x + + )
{
skel = ( mdxaSkel_t * ) ( ( byte * ) mod - > mdxa + sizeof ( mdxaHeader_t ) + offsets - > offsets [ x ] ) ;
// if name is the same, we found it
if ( ! stricmp ( skel - > name , boneName ) )
{
break ;
}
}
// check to see we did actually make a match with a bone in the model
if ( x = = mod - > mdxa - > numBones )
{
// didn't find it? Error
assert ( 0 ) ;
return - 1 ;
}
// look through entire list - see if it's already there first
for ( i = 0 ; i < blist . size ( ) ; i + + )
{
// if this bone entry has info in it, bounce over it
if ( blist [ i ] . boneNumber ! = - 1 )
{
skel = ( mdxaSkel_t * ) ( ( byte * ) mod - > mdxa + sizeof ( mdxaHeader_t ) + offsets - > offsets [ blist [ i ] . boneNumber ] ) ;
// if name is the same, we found it
if ( ! stricmp ( skel - > name , boneName ) )
{
return i ;
}
}
else
{
// if we found an entry that had a -1 for the bonenumber, then we hit a bone slot that was empty
blist [ i ] . boneNumber = x ;
blist [ i ] . flags = 0 ;
return i ;
}
}
// ok, we didn't find an existing bone of that name, or an empty slot. Lets add an entry
tempBone . boneNumber = x ;
tempBone . flags = 0 ;
blist . push_back ( tempBone ) ;
return blist . size ( ) - 1 ;
}
// Given a model handle, and a bone name, we want to remove this bone from the bone override list
qboolean G2_Remove_Bone_Index ( boneInfo_v & blist , int index )
{
// did we find it?
if ( index ! = - 1 )
{
// check the flags first - if it's still being used Do NOT remove it
if ( ! blist [ index ] . flags )
{
// set this bone to not used
blist [ index ] . boneNumber = - 1 ;
int newSize = blist . size ( ) ;
// now look through the list from the back and see if there is a block of -1's we can resize off the end of the list
for ( int i = blist . size ( ) - 1 ; i > - 1 ; i - - )
{
if ( blist [ i ] . boneNumber = = - 1 )
{
newSize = i ;
}
// once we hit one that isn't a -1, we are done.
else
{
break ;
}
}
// do we need to resize?
if ( newSize ! = blist . size ( ) )
{
// yes, so lets do it
blist . resize ( newSize ) ;
}
return qtrue ;
}
}
// assert(0);
// no
return qfalse ;
}
// given a bone number, see if there is an override bone in the bone list
int G2_Find_Bone_In_List ( boneInfo_v & blist , const int boneNum )
{
int i ;
// look through entire list
for ( i = 0 ; i < blist . size ( ) ; i + + )
{
if ( blist [ i ] . boneNumber = = boneNum )
{
return i ;
}
}
return - 1 ;
}
// given a model, bonelist and bonename, lets stop an anim if it's playing.
qboolean G2_Stop_Bone_Index ( boneInfo_v & blist , int index , int flags )
{
// did we find it?
if ( index ! = - 1 )
{
blist [ index ] . flags & = ~ ( flags ) ;
// try and remove this bone if we can
return G2_Remove_Bone_Index ( blist , index ) ;
}
assert ( 0 ) ;
return qfalse ;
}
// generate a matrix for a given bone given some new angles for it.
void G2_Generate_Matrix ( const model_t * mod , boneInfo_v & blist , int index , const float * angles , int flags ,
const Eorientations up , const Eorientations left , const Eorientations forward )
{
mdxaSkel_t * skel ;
mdxaSkelOffsets_t * offsets ;
mdxaBone_t temp1 ;
mdxaBone_t permutation ;
mdxaBone_t * boneOverride = & blist [ index ] . matrix ;
vec3_t newAngles ;
if ( flags & ( BONE_ANGLES_PREMULT | BONE_ANGLES_POSTMULT ) )
{
// build us a matrix out of the angles we are fed - but swap y and z because of wacky Quake setup
vec3_t newAngles ;
// determine what axis newAngles Yaw should revolve around
switch ( up )
{
case NEGATIVE_X :
newAngles [ 1 ] = angles [ 2 ] + 180 ;
break ;
case POSITIVE_X :
newAngles [ 1 ] = angles [ 2 ] ;
break ;
case NEGATIVE_Y :
newAngles [ 1 ] = angles [ 0 ] ;
break ;
case POSITIVE_Y :
newAngles [ 1 ] = angles [ 0 ] ;
break ;
case NEGATIVE_Z :
newAngles [ 1 ] = angles [ 1 ] + 180 ;
break ;
case POSITIVE_Z :
newAngles [ 1 ] = angles [ 1 ] ;
break ;
}
// determine what axis newAngles pitch should revolve around
switch ( left )
{
case NEGATIVE_X :
newAngles [ 0 ] = angles [ 2 ] ;
break ;
case POSITIVE_X :
newAngles [ 0 ] = angles [ 2 ] + 180 ;
break ;
case NEGATIVE_Y :
newAngles [ 0 ] = angles [ 0 ] ;
break ;
case POSITIVE_Y :
newAngles [ 0 ] = angles [ 0 ] + 180 ;
break ;
case NEGATIVE_Z :
newAngles [ 0 ] = angles [ 1 ] ;
break ;
case POSITIVE_Z :
newAngles [ 0 ] = angles [ 1 ] ;
break ;
}
// determine what axis newAngles Roll should revolve around
switch ( forward )
{
case NEGATIVE_X :
newAngles [ 2 ] = angles [ 2 ] ;
break ;
case POSITIVE_X :
newAngles [ 2 ] = angles [ 2 ] ;
break ;
case NEGATIVE_Y :
newAngles [ 2 ] = angles [ 0 ] ;
break ;
case POSITIVE_Y :
newAngles [ 2 ] = angles [ 0 ] + 180 ;
break ;
case NEGATIVE_Z :
newAngles [ 2 ] = angles [ 1 ] ;
break ;
case POSITIVE_Z :
newAngles [ 2 ] = angles [ 1 ] + 180 ;
break ;
}
Create_Matrix ( newAngles , boneOverride ) ;
// figure out where the bone hirearchy info is
offsets = ( mdxaSkelOffsets_t * ) ( ( byte * ) mod - > mdxa + sizeof ( mdxaHeader_t ) ) ;
skel = ( mdxaSkel_t * ) ( ( byte * ) mod - > mdxa + sizeof ( mdxaHeader_t ) + offsets - > offsets [ blist [ index ] . boneNumber ] ) ;
Multiply_3x4Matrix ( & temp1 , boneOverride , & skel - > BasePoseMatInv ) ;
Multiply_3x4Matrix ( boneOverride , & skel - > BasePoseMat , & temp1 ) ;
}
else
{
VectorCopy ( angles , newAngles ) ;
// why I should need do this Fuck alone knows. But I do.
if ( left = = POSITIVE_Y )
{
newAngles [ 0 ] + = 180 ;
}
Create_Matrix ( newAngles , & temp1 ) ;
permutation . matrix [ 0 ] [ 0 ] = permutation . matrix [ 0 ] [ 1 ] = permutation . matrix [ 0 ] [ 2 ] = permutation . matrix [ 0 ] [ 3 ] = 0 ;
permutation . matrix [ 1 ] [ 0 ] = permutation . matrix [ 1 ] [ 1 ] = permutation . matrix [ 1 ] [ 2 ] = permutation . matrix [ 1 ] [ 3 ] = 0 ;
permutation . matrix [ 2 ] [ 0 ] = permutation . matrix [ 2 ] [ 1 ] = permutation . matrix [ 2 ] [ 2 ] = permutation . matrix [ 2 ] [ 3 ] = 0 ;
// determine what axis newAngles Yaw should revolve around
switch ( forward )
{
case NEGATIVE_X :
permutation . matrix [ 0 ] [ 0 ] = - 1 ; // works
break ;
case POSITIVE_X :
permutation . matrix [ 0 ] [ 0 ] = 1 ; // works
break ;
case NEGATIVE_Y :
permutation . matrix [ 1 ] [ 0 ] = - 1 ;
break ;
case POSITIVE_Y :
permutation . matrix [ 1 ] [ 0 ] = 1 ;
break ;
case NEGATIVE_Z :
permutation . matrix [ 2 ] [ 0 ] = - 1 ;
break ;
case POSITIVE_Z :
permutation . matrix [ 2 ] [ 0 ] = 1 ;
break ;
}
// determine what axis newAngles pitch should revolve around
switch ( left )
{
case NEGATIVE_X :
permutation . matrix [ 0 ] [ 1 ] = - 1 ;
break ;
case POSITIVE_X :
permutation . matrix [ 0 ] [ 1 ] = 1 ;
break ;
case NEGATIVE_Y :
permutation . matrix [ 1 ] [ 1 ] = - 1 ; // works
break ;
case POSITIVE_Y :
permutation . matrix [ 1 ] [ 1 ] = 1 ; // works
break ;
case NEGATIVE_Z :
permutation . matrix [ 2 ] [ 1 ] = - 1 ;
break ;
case POSITIVE_Z :
permutation . matrix [ 2 ] [ 1 ] = 1 ;
break ;
}
// determine what axis newAngles Roll should revolve around
switch ( up )
{
case NEGATIVE_X :
permutation . matrix [ 0 ] [ 2 ] = - 1 ;
break ;
case POSITIVE_X :
permutation . matrix [ 0 ] [ 2 ] = 1 ;
break ;
case NEGATIVE_Y :
permutation . matrix [ 1 ] [ 2 ] = - 1 ;
break ;
case POSITIVE_Y :
permutation . matrix [ 1 ] [ 2 ] = 1 ;
break ;
case NEGATIVE_Z :
permutation . matrix [ 2 ] [ 2 ] = - 1 ; // works
break ;
case POSITIVE_Z :
permutation . matrix [ 2 ] [ 2 ] = 1 ; // works
break ;
}
Multiply_3x4Matrix ( boneOverride , & temp1 , & permutation ) ;
}
// keep a copy of the matrix in the newmatrix which is actually what we use
memcpy ( & blist [ index ] . newMatrix , & blist [ index ] . matrix , sizeof ( mdxaBone_t ) ) ;
}
//=========================================================================================
//// Public Bone Routines
// Given a model handle, and a bone name, we want to remove this bone from the bone override list
qboolean G2_Remove_Bone ( const char * fileName , boneInfo_v & blist , const char * boneName )
{
model_t * mod_m = R_GetModelByHandle ( RE_RegisterModel ( fileName ) ) ;
model_t * mod_a = R_GetModelByHandle ( mod_m - > mdxm - > animIndex ) ;
int index = G2_Find_Bone ( mod_a , blist , boneName ) ;
return G2_Remove_Bone_Index ( blist , index ) ;
}
2013-04-04 18:24:26 +00:00
# define DEBUG_PCJ (0)
2013-04-04 14:52:42 +00:00
// Given a model handle, and a bone name, we want to set angles specifically for overriding
qboolean G2_Set_Bone_Angles_Index ( boneInfo_v & blist , const int index ,
const float * angles , const int flags , const Eorientations yaw ,
const Eorientations pitch , const Eorientations roll , qhandle_t * modelList ,
const int modelIndex , const int blendTime , const int currentTime )
{
if ( ( index > = blist . size ( ) ) | | ( blist [ index ] . boneNumber = = - 1 ) )
{
// we are attempting to set a bone override that doesn't exist
assert ( 0 ) ;
return qfalse ;
}
if ( flags & ( BONE_ANGLES_PREMULT | BONE_ANGLES_POSTMULT ) )
{
// you CANNOT call this with an index with these kinds of bone overrides - we need the model details for these kinds of bone angle overrides
assert ( 0 ) ;
return qfalse ;
}
// yes, so set the angles and flags correctly
blist [ index ] . flags & = ~ ( BONE_ANGLES_TOTAL ) ;
blist [ index ] . flags | = flags ;
blist [ index ] . boneBlendStart = currentTime ;
blist [ index ] . boneBlendTime = blendTime ;
2013-04-04 18:24:26 +00:00
# if DEBUG_PCJ
OutputDebugString ( va ( " PCJ %2d %6d (%6.2f,%6.2f,%6.2f) %d %d %d %d \n " , index , currentTime , angles [ 0 ] , angles [ 1 ] , angles [ 2 ] , yaw , pitch , roll , flags ) ) ;
# endif
2013-04-04 14:52:42 +00:00
G2_Generate_Matrix ( NULL , blist , index , angles , flags , yaw , pitch , roll ) ;
return qtrue ;
}
// Given a model handle, and a bone name, we want to set angles specifically for overriding
qboolean G2_Set_Bone_Angles ( const char * fileName , boneInfo_v & blist , const char * boneName , const float * angles ,
const int flags , const Eorientations up , const Eorientations left , const Eorientations forward ,
qhandle_t * modelList , const int modelIndex , const int blendTime , const int currentTime )
{
model_t * mod_m ;
if ( ! fileName [ 0 ] )
{
mod_m = R_GetModelByHandle ( modelList [ modelIndex ] ) ;
}
else
{
mod_m = R_GetModelByHandle ( RE_RegisterModel ( fileName ) ) ;
}
model_t * mod_a = R_GetModelByHandle ( mod_m - > mdxm - > animIndex ) ;
int index = G2_Find_Bone ( mod_a , blist , boneName ) ;
// did we find it?
if ( index ! = - 1 )
{
// yes, so set the angles and flags correctly
blist [ index ] . flags & = ~ ( BONE_ANGLES_TOTAL ) ;
blist [ index ] . flags | = flags ;
blist [ index ] . boneBlendStart = currentTime ;
blist [ index ] . boneBlendTime = blendTime ;
2013-04-04 18:24:26 +00:00
# if DEBUG_PCJ
OutputDebugString ( va ( " %2d %6d (%6.2f,%6.2f,%6.2f) %d %d %d %d \n " , index , currentTime , angles [ 0 ] , angles [ 1 ] , angles [ 2 ] , up , left , forward , flags ) ) ;
# endif
2013-04-04 14:52:42 +00:00
G2_Generate_Matrix ( mod_a , blist , index , angles , flags , up , left , forward ) ;
return qtrue ;
}
// no - lets try and add this bone in
index = G2_Add_Bone ( mod_a , blist , boneName ) ;
// did we find a free one?
if ( index ! = - 1 )
{
// yes, so set the angles and flags correctly
blist [ index ] . flags & = ~ ( BONE_ANGLES_TOTAL ) ;
blist [ index ] . flags | = flags ;
blist [ index ] . boneBlendStart = currentTime ;
blist [ index ] . boneBlendTime = blendTime ;
2013-04-04 18:24:26 +00:00
# if DEBUG_PCJ
OutputDebugString ( va ( " %2d %6d (%6.2f,%6.2f,%6.2f) %d %d %d %d \n " , index , currentTime , angles [ 0 ] , angles [ 1 ] , angles [ 2 ] , up , left , forward , flags ) ) ;
# endif
2013-04-04 14:52:42 +00:00
G2_Generate_Matrix ( mod_a , blist , index , angles , flags , up , left , forward ) ;
return qtrue ;
}
assert ( 0 ) ;
// no
return qfalse ;
}
// Given a model handle, and a bone name, we want to set angles specifically for overriding - using a matrix directly
qboolean G2_Set_Bone_Angles_Matrix_Index ( boneInfo_v & blist , const int index ,
const mdxaBone_t & matrix , const int flags , qhandle_t * modelList ,
const int modelIndex , const int blendTime , const int currentTime )
{
if ( ( index > = blist . size ( ) ) | | ( blist [ index ] . boneNumber = = - 1 ) )
{
// we are attempting to set a bone override that doesn't exist
assert ( 0 ) ;
return qfalse ;
}
// yes, so set the angles and flags correctly
blist [ index ] . flags & = ~ ( BONE_ANGLES_TOTAL ) ;
blist [ index ] . flags | = flags ;
blist [ index ] . boneBlendStart = currentTime ;
blist [ index ] . boneBlendTime = blendTime ;
memcpy ( & blist [ index ] . matrix , & matrix , sizeof ( mdxaBone_t ) ) ;
memcpy ( & blist [ index ] . newMatrix , & matrix , sizeof ( mdxaBone_t ) ) ;
return qtrue ;
}
// Given a model handle, and a bone name, we want to set angles specifically for overriding - using a matrix directly
qboolean G2_Set_Bone_Angles_Matrix ( const char * fileName , boneInfo_v & blist , const char * boneName , const mdxaBone_t & matrix ,
const int flags , qhandle_t * modelList , const int modelIndex , const int blendTime , const int currentTime )
{
model_t * mod_m ;
if ( ! fileName [ 0 ] )
{
mod_m = R_GetModelByHandle ( modelList [ modelIndex ] ) ;
}
else
{
mod_m = R_GetModelByHandle ( RE_RegisterModel ( fileName ) ) ;
}
model_t * mod_a = R_GetModelByHandle ( mod_m - > mdxm - > animIndex ) ;
int index = G2_Find_Bone ( mod_a , blist , boneName ) ;
// did we find it?
if ( index ! = - 1 )
{
// yes, so set the angles and flags correctly
blist [ index ] . flags & = ~ ( BONE_ANGLES_TOTAL ) ;
blist [ index ] . flags | = flags ;
memcpy ( & blist [ index ] . matrix , & matrix , sizeof ( mdxaBone_t ) ) ;
memcpy ( & blist [ index ] . newMatrix , & matrix , sizeof ( mdxaBone_t ) ) ;
return qtrue ;
}
// no - lets try and add this bone in
index = G2_Add_Bone ( mod_a , blist , boneName ) ;
// did we find a free one?
if ( index ! = - 1 )
{
// yes, so set the angles and flags correctly
blist [ index ] . flags & = ~ ( BONE_ANGLES_TOTAL ) ;
blist [ index ] . flags | = flags ;
memcpy ( & blist [ index ] . matrix , & matrix , sizeof ( mdxaBone_t ) ) ;
memcpy ( & blist [ index ] . newMatrix , & matrix , sizeof ( mdxaBone_t ) ) ;
return qtrue ;
}
assert ( 0 ) ;
// no
return qfalse ;
}
2013-04-04 18:24:26 +00:00
# define DEBUG_G2_TIMING (0)
2013-04-04 14:52:42 +00:00
// given a model, bone name, a bonelist, a start/end frame number, a anim speed and some anim flags, set up or modify an existing bone entry for a new set of anims
2013-04-04 18:24:26 +00:00
qboolean G2_Set_Bone_Anim_Index (
boneInfo_v & blist ,
const int index ,
const int startFrame ,
const int endFrame ,
const int flags ,
const float animSpeed ,
const int currentTime ,
const float setFrame ,
const int blendTime )
2013-04-04 14:52:42 +00:00
{
int modFlags = flags ;
if ( ( index > = blist . size ( ) ) | | ( blist [ index ] . boneNumber = = - 1 ) )
{
// we are attempting to set a bone override that doesn't exist
assert ( 0 ) ;
return qfalse ;
}
if ( setFrame ! = - 1 )
{
assert ( ( setFrame > = startFrame ) & & ( setFrame < = endFrame ) ) ;
}
2013-04-04 18:24:26 +00:00
if ( flags & BONE_ANIM_BLEND )
{
float currentFrame , animSpeed ;
int startFrame , endFrame , flags ;
// figure out where we are now
if ( G2_Get_Bone_Anim_Index ( blist , index , currentTime , & currentFrame , & startFrame , & endFrame , & flags , & animSpeed , NULL , 0 ) )
2013-04-04 14:52:42 +00:00
{
2013-04-04 18:24:26 +00:00
if ( blist [ index ] . blendStart = = currentTime ) //we're replacing a blend in progress which hasn't started
2013-04-04 14:52:42 +00:00
{
// set the amount of time it's going to take to blend this anim with the last frame of the last one
blist [ index ] . blendTime = blendTime ;
}
else
{
2013-04-04 18:24:26 +00:00
if ( animSpeed < 0.0f )
{
blist [ index ] . blendFrame = floor ( currentFrame ) ;
blist [ index ] . blendLerpFrame = floor ( currentFrame ) ;
}
else
{
blist [ index ] . blendFrame = currentFrame ;
blist [ index ] . blendLerpFrame = currentFrame + 1 ;
// cope with if the lerp frame is actually off the end of the anim
if ( blist [ index ] . blendFrame > = endFrame )
{
// we only want to lerp with the first frame of the anim if we are looping
if ( blist [ index ] . flags & BONE_ANIM_OVERRIDE_LOOP )
{
blist [ index ] . blendFrame = startFrame ;
}
// if we intend to end this anim or freeze after this, then just keep on the last frame
else
{
// assert(endFrame>0);
if ( endFrame < = 0 )
{
blist [ index ] . blendLerpFrame = 0 ;
}
else
{
blist [ index ] . blendFrame = endFrame - 1 ;
}
}
}
// cope with if the lerp frame is actually off the end of the anim
if ( blist [ index ] . blendLerpFrame > = endFrame )
{
// we only want to lerp with the first frame of the anim if we are looping
if ( blist [ index ] . flags & BONE_ANIM_OVERRIDE_LOOP )
{
blist [ index ] . blendLerpFrame = startFrame ;
}
// if we intend to end this anim or freeze after this, then just keep on the last frame
else
{
// assert(endFrame>0);
if ( endFrame < = 0 )
{
blist [ index ] . blendLerpFrame = 0 ;
}
else
{
blist [ index ] . blendLerpFrame = endFrame - 1 ;
}
}
}
}
// set the amount of time it's going to take to blend this anim with the last frame of the last one
blist [ index ] . blendTime = blendTime ;
blist [ index ] . blendStart = currentTime ;
2013-04-04 14:52:42 +00:00
}
}
2013-04-04 18:24:26 +00:00
// hmm, we weren't animating on this bone. In which case disable the blend
2013-04-04 14:52:42 +00:00
else
{
blist [ index ] . blendFrame = blist [ index ] . blendLerpFrame = 0 ;
2013-04-04 18:24:26 +00:00
blist [ index ] . blendTime = 0 ;
modFlags & = ~ ( BONE_ANIM_BLEND ) ;
2013-04-04 14:52:42 +00:00
}
2013-04-04 18:24:26 +00:00
}
else
{
blist [ index ] . blendFrame = blist [ index ] . blendLerpFrame = 0 ;
blist [ index ] . blendTime = blist [ index ] . blendStart = 0 ;
// we aren't blending, so remove the option to do so
modFlags & = ~ BONE_ANIM_BLEND ;
}
// yes, so set the anim data and flags correctly
blist [ index ] . endFrame = endFrame ;
blist [ index ] . startFrame = startFrame ;
blist [ index ] . animSpeed = animSpeed ;
blist [ index ] . pauseTime = 0 ;
// start up the animation:)
if ( setFrame ! = - 1 )
{
blist [ index ] . lastTime = blist [ index ] . startTime = ( currentTime - ( ( ( setFrame - ( float ) startFrame ) * 50.0 ) / animSpeed ) ) ;
}
else
{
blist [ index ] . lastTime = blist [ index ] . startTime = currentTime ;
}
blist [ index ] . flags & = ~ ( BONE_ANIM_TOTAL ) ;
blist [ index ] . flags | = modFlags ;
2013-04-04 14:52:42 +00:00
2013-04-04 18:24:26 +00:00
# if DEBUG_G2_TIMING
if ( index = = 2 )
{
const boneInfo_t & bone = blist [ index ] ;
char mess [ 1000 ] ;
if ( bone . flags & BONE_ANIM_BLEND )
2013-04-04 14:52:42 +00:00
{
2013-04-04 18:24:26 +00:00
sprintf ( mess , " sab[%2d] %5d %5d (%5d-%5d) %4.2f %4x bt(%5d-%5d) %7.2f %5d \n " ,
index ,
currentTime ,
bone . startTime ,
bone . startFrame ,
bone . endFrame ,
bone . animSpeed ,
bone . flags ,
bone . blendStart ,
bone . blendStart + bone . blendTime ,
bone . blendFrame ,
bone . blendLerpFrame
) ;
2013-04-04 14:52:42 +00:00
}
else
{
2013-04-04 18:24:26 +00:00
sprintf ( mess , " saa[%2d] %5d %5d (%5d-%5d) %4.2f %4x \n " ,
index ,
currentTime ,
bone . startTime ,
bone . startFrame ,
bone . endFrame ,
bone . animSpeed ,
bone . flags
) ;
2013-04-04 14:52:42 +00:00
}
2013-04-04 18:24:26 +00:00
OutputDebugString ( mess ) ;
}
# endif
2013-04-04 14:52:42 +00:00
2013-04-04 18:24:26 +00:00
return qtrue ;
2013-04-04 14:52:42 +00:00
}
// given a model, bone name, a bonelist, a start/end frame number, a anim speed and some anim flags, set up or modify an existing bone entry for a new set of anims
2013-04-04 18:24:26 +00:00
qboolean G2_Set_Bone_Anim ( const char * fileName ,
boneInfo_v & blist ,
const char * boneName ,
const int startFrame ,
const int endFrame ,
const int flags ,
const float animSpeed ,
const int currentTime ,
const float setFrame ,
const int blendTime )
2013-04-04 14:52:42 +00:00
{
model_t * mod_m = R_GetModelByHandle ( RE_RegisterModel ( fileName ) ) ;
model_t * mod_a = R_GetModelByHandle ( mod_m - > mdxm - > animIndex ) ;
int index = G2_Find_Bone ( mod_a , blist , boneName ) ;
2013-04-04 18:24:26 +00:00
if ( index = = - 1 )
2013-04-04 14:52:42 +00:00
{
2013-04-04 18:24:26 +00:00
index = G2_Add_Bone ( mod_a , blist , boneName ) ;
2013-04-04 14:52:42 +00:00
}
if ( index ! = - 1 )
{
2013-04-04 18:24:26 +00:00
return G2_Set_Bone_Anim_Index ( blist , index , startFrame , endFrame , flags , animSpeed , currentTime , setFrame , blendTime ) ;
2013-04-04 14:52:42 +00:00
}
return qfalse ;
}
qboolean G2_Get_Bone_Anim_Range ( const char * fileName , boneInfo_v & blist , const char * boneName , int * startFrame , int * endFrame )
{
model_t * mod_m = R_GetModelByHandle ( RE_RegisterModel ( fileName ) ) ;
model_t * mod_a = R_GetModelByHandle ( mod_m - > mdxm - > animIndex ) ;
int index = G2_Find_Bone ( mod_a , blist , boneName ) ;
// did we find it?
if ( index ! = - 1 )
{
// are we an animating bone?
if ( blist [ index ] . flags & ( BONE_ANIM_OVERRIDE_LOOP | BONE_ANIM_OVERRIDE ) )
{
* startFrame = blist [ index ] . startFrame ;
* endFrame = blist [ index ] . endFrame ;
return qtrue ;
}
}
return qfalse ;
}
// given a model, bonelist and bonename, return the current frame, startframe and endframe of the current animation
// NOTE if we aren't running an animation, then qfalse is returned
qboolean G2_Get_Bone_Anim_Index ( boneInfo_v & blist , const int index , const int currentTime ,
float * currentFrame , int * startFrame , int * endFrame , int * flags , float * retAnimSpeed , qhandle_t * modelList , int modelIndex )
{
// did we find it?
if ( ( index ! = - 1 ) & & ! ( ( index > = blist . size ( ) ) | | ( blist [ index ] . boneNumber = = - 1 ) ) )
{
// are we an animating bone?
if ( blist [ index ] . flags & ( BONE_ANIM_OVERRIDE_LOOP | BONE_ANIM_OVERRIDE ) )
{
// yes - add in animation speed to current frame
float animSpeed = blist [ index ] . animSpeed ;
float time = ( currentTime - blist [ index ] . startTime ) / 50.0f ;
float mendFrame = ( float ) blist [ index ] . endFrame ;
// are we a paused anim?
if ( blist [ index ] . pauseTime )
{
time = ( blist [ index ] . pauseTime - blist [ index ] . startTime ) / 50.0f ;
}
2013-04-04 18:24:26 +00:00
if ( time < 0 )
{
time = 0 ;
}
2013-04-04 14:52:42 +00:00
float newFrame_g = blist [ index ] . startFrame + ( time * animSpeed ) ;
* currentFrame = newFrame_g ;
int animSize = blist [ index ] . endFrame - blist [ index ] . startFrame ;
// we are supposed to be animating right?
if ( animSize )
{
// did we run off the end?
2013-04-04 18:24:26 +00:00
if ( ( ( animSpeed > 0.0f ) & & ( newFrame_g > mendFrame - 1 ) ) | |
( ( animSpeed < 0.0f ) & & ( newFrame_g < mendFrame + 1 ) ) )
2013-04-04 14:52:42 +00:00
{
// yep - decide what to do
if ( blist [ index ] . flags & BONE_ANIM_OVERRIDE_LOOP )
{
if ( animSpeed < 0.0f )
{
2013-04-04 18:24:26 +00:00
if ( newFrame_g < = mendFrame + 1 )
2013-04-04 14:52:42 +00:00
{
2013-04-04 18:24:26 +00:00
newFrame_g = mendFrame + fmod ( newFrame_g - mendFrame , animSize ) - animSize ;
2013-04-04 14:52:42 +00:00
}
}
else
{
2013-04-04 18:24:26 +00:00
if ( newFrame_g > = mendFrame )
2013-04-04 14:52:42 +00:00
{
2013-04-04 18:24:26 +00:00
newFrame_g = mendFrame + fmod ( newFrame_g - mendFrame , animSize ) - animSize ;
2013-04-04 14:52:42 +00:00
}
}
* currentFrame = newFrame_g ;
}
else
{
// nope, we ran off the end of the current anim
if ( blist [ index ] . flags & BONE_ANIM_OVERRIDE_FREEZE )
{
if ( animSpeed > 0.0f )
{
* currentFrame = blist [ index ] . endFrame - 1 ;
}
else
{
* currentFrame = blist [ index ] . endFrame + 1 ;
}
}
else
{
2013-04-04 18:24:26 +00:00
* currentFrame = 0 ;
2013-04-04 14:52:42 +00:00
}
}
}
}
else
{
* currentFrame = blist [ index ] . startFrame ;
}
* startFrame = blist [ index ] . startFrame ;
* endFrame = blist [ index ] . endFrame ;
* flags = blist [ index ] . flags ;
* retAnimSpeed = animSpeed ;
return qtrue ;
}
}
2013-04-04 18:24:26 +00:00
* startFrame = 0 ;
* endFrame = 1 ;
* currentFrame = 0 ;
* flags = 0 ;
* retAnimSpeed = 1.0f ;
2013-04-04 14:52:42 +00:00
return qfalse ;
}
// given a model, bonelist and bonename, return the current frame, startframe and endframe of the current animation
// NOTE if we aren't running an animation, then qfalse is returned
qboolean G2_Get_Bone_Anim ( const char * fileName , boneInfo_v & blist , const char * boneName , const int currentTime ,
float * currentFrame , int * startFrame , int * endFrame , int * flags , float * retAnimSpeed , qhandle_t * modelList , int modelIndex )
{
model_t * mod_m ;
if ( ! fileName [ 0 ] )
{
mod_m = R_GetModelByHandle ( modelList [ modelIndex ] ) ;
}
else
{
mod_m = R_GetModelByHandle ( RE_RegisterModel ( fileName ) ) ;
}
model_t * mod_a = R_GetModelByHandle ( mod_m - > mdxm - > animIndex ) ;
int index = G2_Find_Bone ( mod_a , blist , boneName ) ;
// did we find it?
if ( index ! = - 1 )
{
// are we an animating bone?
if ( blist [ index ] . flags & ( BONE_ANIM_OVERRIDE_LOOP | BONE_ANIM_OVERRIDE ) )
{
// yes - add in animation speed to current frame
float animSpeed = blist [ index ] . animSpeed ;
float time = ( currentTime - blist [ index ] . startTime ) / 50.0f ;
float mendFrame = ( float ) blist [ index ] . endFrame ;
// are we a paused anim?
if ( blist [ index ] . pauseTime )
{
time = ( blist [ index ] . pauseTime - blist [ index ] . startTime ) / 50.0f ;
}
2013-04-04 18:24:26 +00:00
if ( time < 0 )
{
time = 0 ;
}
2013-04-04 14:52:42 +00:00
float newFrame_g = blist [ index ] . startFrame + ( time * animSpeed ) ;
* currentFrame = newFrame_g ;
int animSize = blist [ index ] . endFrame - blist [ index ] . startFrame ;
// we are supposed to be animating right?
if ( animSize )
{
// did we run off the end?
2013-04-04 18:24:26 +00:00
if ( ( ( animSpeed > 0.0f ) & & ( newFrame_g > mendFrame - 1 ) ) | |
( ( animSpeed < 0.0f ) & & ( newFrame_g < mendFrame + 1 ) ) )
2013-04-04 14:52:42 +00:00
{
// yep - decide what to do
if ( blist [ index ] . flags & BONE_ANIM_OVERRIDE_LOOP )
{
// get our new animation frame back within the bounds of the animation set
if ( animSpeed < 0.0f )
{
2013-04-04 18:24:26 +00:00
if ( newFrame_g < = mendFrame + 1 )
2013-04-04 14:52:42 +00:00
{
2013-04-04 18:24:26 +00:00
newFrame_g = mendFrame + fmod ( newFrame_g - mendFrame , animSize ) - animSize ;
2013-04-04 14:52:42 +00:00
}
}
else
{
2013-04-04 18:24:26 +00:00
if ( newFrame_g > = mendFrame )
2013-04-04 14:52:42 +00:00
{
2013-04-04 18:24:26 +00:00
newFrame_g = mendFrame + fmod ( newFrame_g - mendFrame , animSize ) - animSize ;
2013-04-04 14:52:42 +00:00
}
}
* currentFrame = newFrame_g ;
}
else
{
// nope, we ran off the end of the current anim
if ( blist [ index ] . flags & BONE_ANIM_OVERRIDE_FREEZE )
{
if ( animSpeed > 0.0f )
{
* currentFrame = blist [ index ] . endFrame - 1 ;
}
else
{
* currentFrame = blist [ index ] . endFrame + 1 ;
}
}
else
{
2013-04-04 18:24:26 +00:00
* currentFrame = 0 ;
2013-04-04 14:52:42 +00:00
}
}
}
}
else
{
* currentFrame = blist [ index ] . startFrame ;
}
* startFrame = blist [ index ] . startFrame ;
* endFrame = blist [ index ] . endFrame ;
* flags = blist [ index ] . flags ;
* retAnimSpeed = animSpeed ;
return qtrue ;
}
}
2013-04-04 18:24:26 +00:00
* startFrame = 0 ;
* endFrame = 1 ;
* currentFrame = 0 ;
* flags = 0 ; //hmmmm this used to be -1
* retAnimSpeed = 1.0f ;
2013-04-04 14:52:42 +00:00
return qfalse ;
}
// given a model, bonelist and bonename, lets pause an anim if it's playing.
qboolean G2_Pause_Bone_Anim ( const char * fileName , boneInfo_v & blist , const char * boneName , const int currentTime )
{
model_t * mod_m = R_GetModelByHandle ( RE_RegisterModel ( fileName ) ) ;
model_t * mod_a = R_GetModelByHandle ( mod_m - > mdxm - > animIndex ) ;
int index = G2_Find_Bone ( mod_a , blist , boneName ) ;
// did we find it?
if ( index ! = - 1 )
{
// are we pausing or un pausing?
if ( blist [ index ] . pauseTime )
{
int startFrame , endFrame , flags ;
float currentFrame , animSpeed ;
// figure out what frame we are on now
G2_Get_Bone_Anim ( fileName , blist , boneName , blist [ index ] . pauseTime , & currentFrame , & startFrame , & endFrame , & flags , & animSpeed , NULL , 0 ) ;
// reset start time so we are actually on this frame right now
G2_Set_Bone_Anim ( fileName , blist , boneName , startFrame , endFrame , flags , animSpeed , currentTime , currentFrame , 0 ) ;
// no pausing anymore
blist [ index ] . pauseTime = 0 ;
}
// ahh, just pausing, the easy bit
else
{
blist [ index ] . pauseTime = currentTime ;
}
return qtrue ;
}
assert ( 0 ) ;
return qfalse ;
}
qboolean G2_IsPaused ( const char * fileName , boneInfo_v & blist , const char * boneName )
{
model_t * mod_m = R_GetModelByHandle ( RE_RegisterModel ( fileName ) ) ;
model_t * mod_a = R_GetModelByHandle ( mod_m - > mdxm - > animIndex ) ;
int index = G2_Find_Bone ( mod_a , blist , boneName ) ;
// did we find it?
if ( index ! = - 1 )
{
// are we paused?
if ( blist [ index ] . pauseTime )
{
// yup. paused.
return qtrue ;
}
return qfalse ;
}
return qfalse ;
}
// given a model, bonelist and bonename, lets stop an anim if it's playing.
qboolean G2_Stop_Bone_Anim_Index ( boneInfo_v & blist , const int index )
{
if ( ( index > = blist . size ( ) ) | | ( blist [ index ] . boneNumber = = - 1 ) )
{
// we are attempting to set a bone override that doesn't exist
assert ( 0 ) ;
return qfalse ;
}
blist [ index ] . flags & = ~ ( BONE_ANIM_TOTAL ) ;
// try and remove this bone if we can
return G2_Remove_Bone_Index ( blist , index ) ;
}
// given a model, bonelist and bonename, lets stop an anim if it's playing.
qboolean G2_Stop_Bone_Anim ( const char * fileName , boneInfo_v & blist , const char * boneName )
{
model_t * mod_m = R_GetModelByHandle ( RE_RegisterModel ( fileName ) ) ;
model_t * mod_a = R_GetModelByHandle ( mod_m - > mdxm - > animIndex ) ;
int index = G2_Find_Bone ( mod_a , blist , boneName ) ;
// did we find it?
if ( index ! = - 1 )
{
blist [ index ] . flags & = ~ ( BONE_ANIM_TOTAL ) ;
// try and remove this bone if we can
return G2_Remove_Bone_Index ( blist , index ) ;
}
assert ( 0 ) ;
return qfalse ;
}
// given a model, bonelist and bonename, lets stop an anim if it's playing.
qboolean G2_Stop_Bone_Angles_Index ( boneInfo_v & blist , const int index )
{
if ( ( index > = blist . size ( ) ) | | ( blist [ index ] . boneNumber = = - 1 ) )
{
// we are attempting to set a bone override that doesn't exist
assert ( 0 ) ;
return qfalse ;
}
blist [ index ] . flags & = ~ ( BONE_ANGLES_TOTAL ) ;
// try and remove this bone if we can
return G2_Remove_Bone_Index ( blist , index ) ;
}
// given a model, bonelist and bonename, lets stop an anim if it's playing.
qboolean G2_Stop_Bone_Angles ( const char * fileName , boneInfo_v & blist , const char * boneName )
{
model_t * mod_m = R_GetModelByHandle ( RE_RegisterModel ( fileName ) ) ;
model_t * mod_a = R_GetModelByHandle ( mod_m - > mdxm - > animIndex ) ;
int index = G2_Find_Bone ( mod_a , blist , boneName ) ;
// did we find it?
if ( index ! = - 1 )
{
blist [ index ] . flags & = ~ ( BONE_ANGLES_TOTAL ) ;
// try and remove this bone if we can
return G2_Remove_Bone_Index ( blist , index ) ;
}
assert ( 0 ) ;
return qfalse ;
}
// actually walk the bone list and update each and every bone if we have ended an animation for them.
void G2_Animate_Bone_List ( CGhoul2Info_v & ghoul2 , const int currentTime , const int index )
{
int i ;
boneInfo_v & blist = ghoul2 [ index ] . mBlist ;
// look through entire list
for ( i = 0 ; i < blist . size ( ) ; i + + )
{
// we we a valid bone override?
if ( blist [ i ] . boneNumber ! = - 1 )
{
// are we animating?
if ( blist [ i ] . flags & ( BONE_ANIM_OVERRIDE_LOOP | BONE_ANIM_OVERRIDE ) )
{
// yes - add in animation speed to current frame
float animSpeed = blist [ i ] . animSpeed ;
float endFrame = ( float ) blist [ i ] . endFrame ;
float time = ( currentTime - blist [ i ] . startTime ) / 50.0f ;
// are we a paused anim?
if ( blist [ i ] . pauseTime )
{
time = ( blist [ i ] . pauseTime - blist [ i ] . startTime ) / 50.0f ;
}
2013-04-04 18:24:26 +00:00
if ( time < 0.0f )
{
time = 0.0f ;
}
2013-04-04 14:52:42 +00:00
float newFrame_g = blist [ i ] . startFrame + ( time * animSpeed ) ;
int animSize = endFrame - blist [ i ] . startFrame ;
// we are supposed to be animating right?
if ( animSize )
{
// did we run off the end?
2013-04-04 18:24:26 +00:00
if ( ( ( animSpeed > 0.0f ) & & ( newFrame_g > endFrame - 1 ) ) | |
( ( animSpeed < 0.0f ) & & ( newFrame_g < endFrame + 1 ) ) )
2013-04-04 14:52:42 +00:00
{
// yep - decide what to do
if ( blist [ i ] . flags & BONE_ANIM_OVERRIDE_LOOP )
{
// get our new animation frame back within the bounds of the animation set
if ( animSpeed < 0.0f )
{
2013-04-04 18:24:26 +00:00
if ( newFrame_g < = endFrame + 1 )
2013-04-04 14:52:42 +00:00
{
2013-04-04 18:24:26 +00:00
newFrame_g = endFrame + fmod ( newFrame_g - endFrame , animSize ) - animSize ;
2013-04-04 14:52:42 +00:00
}
}
else
{
2013-04-04 18:24:26 +00:00
if ( newFrame_g > = endFrame )
2013-04-04 14:52:42 +00:00
{
2013-04-04 18:24:26 +00:00
newFrame_g = endFrame + fmod ( newFrame_g - endFrame , animSize ) - animSize ;
2013-04-04 14:52:42 +00:00
}
}
// figure out new start time
float frameTime = newFrame_g - blist [ i ] . startFrame ;
blist [ i ] . startTime = currentTime - ( int ) ( ( frameTime / animSpeed ) * 50.0f ) ;
2013-04-04 18:24:26 +00:00
if ( blist [ i ] . startTime > currentTime )
{
blist [ i ] . startTime = currentTime ;
}
2013-04-04 14:52:42 +00:00
assert ( blist [ i ] . startTime < = currentTime ) ;
blist [ i ] . lastTime = blist [ i ] . startTime ;
}
else
{
2013-04-04 18:24:26 +00:00
if ( ( blist [ i ] . flags & BONE_ANIM_OVERRIDE_FREEZE ) ! = BONE_ANIM_OVERRIDE_FREEZE )
2013-04-04 14:52:42 +00:00
{
// nope, just stop it. And remove the bone if possible
G2_Stop_Bone_Index ( blist , i , ( BONE_ANIM_TOTAL ) ) ;
}
}
}
}
}
}
}
}
// set the bone list to all unused so the bone transformation routine ignores it.
void G2_Init_Bone_List ( boneInfo_v & blist )
{
blist . clear ( ) ;
}
void G2_RemoveRedundantBoneOverrides ( boneInfo_v & blist , int * activeBones )
{
int i ;
// walk the surface list, removing surface overrides or generated surfaces that are pointing at surfaces that aren't active anymore
for ( i = 0 ; i < blist . size ( ) ; i + + )
{
if ( blist [ i ] . boneNumber ! = - 1 )
{
if ( ! activeBones [ blist [ i ] . boneNumber ] )
{
blist [ i ] . flags = 0 ;
G2_Remove_Bone_Index ( blist , i ) ;
}
}
}
}
int G2_Get_Bone_Index ( CGhoul2Info * ghoul2 , const char * boneName )
{
model_t * mod_m = R_GetModelByHandle ( RE_RegisterModel ( ghoul2 - > mFileName ) ) ;
model_t * mod_a = R_GetModelByHandle ( mod_m - > mdxm - > animIndex ) ;
return ( G2_Find_Bone ( mod_a , ghoul2 - > mBlist , boneName ) ) ;
}