2013-04-04 22:35:38 +00:00
// leave this as first line for PCH reasons...
//
//Anything above this #include will be ignored by the compiler
# include "../qcommon/exe_headers.h"
# if !defined(TR_LOCAL_H)
# include "../renderer/tr_local.h"
# endif
# include "../renderer/matcomp.h"
# if !defined(G2_H_INC)
# include "G2.h"
# endif
# include "G2_local.h"
//rww - RAGDOLL_BEGIN
# ifndef __linux__
# include <float.h>
# else
# include <math.h>
# define _isnan isnan
# endif
# include "G2_gore.h"
//#define RAG_TRACE_DEBUG_LINES
# include "../client/client.h" //while this is all "shared" code, there are some places where we want to make cgame callbacks (for ragdoll) only if the cgvm exists
//rww - RAGDOLL_END
//=====================================================================================================================
// 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 ;
//rww - RAGDOLL_BEGIN
memset ( & tempBone , 0 , sizeof ( tempBone ) ) ;
//rww - RAGDOLL_END
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);
# ifdef _DEBUG
Com_Printf ( " WARNING: Failed to add bone %s \n " , boneName ) ;
# endif
# ifdef _RAG_PRINT_TEST
Com_Printf ( " WARNING: Failed to add bone %s \n " , boneName ) ;
# endif
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 ;
}
}
# ifdef _RAG_PRINT_TEST
Com_Printf ( " New bone added for %s \n " , boneName ) ;
# endif
// 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 )
{
if ( index ! = - 1 )
{
if ( blist [ index ] . flags & BONE_ANGLES_RAGDOLL )
{
return qtrue ; // don't accept any calls on ragdoll bones
}
}
// 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 ;
unsigned 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 ( CGhoul2Info * ghlInfo , boneInfo_v & blist , const char * boneName )
{
int index ;
assert ( ghlInfo - > animModel ) ;
index = G2_Find_Bone ( ghlInfo - > animModel , blist , boneName ) ;
return G2_Remove_Bone_Index ( blist , index ) ;
}
# define DEBUG_PCJ (0)
// 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 ( index ! = - 1 )
{
if ( blist [ index ] . flags & BONE_ANGLES_RAGDOLL )
{
return qtrue ; // don't accept any calls on ragdoll bones
}
}
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 ;
# 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
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 ( CGhoul2Info * ghlInfo , 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 ;
model_t * mod_a ;
mod_m = ( model_t * ) ghlInfo - > currentModel ;
mod_a = ( model_t * ) ghlInfo - > animModel ;
int index = G2_Find_Bone ( mod_a , blist , boneName ) ;
// did we find it?
if ( index ! = - 1 )
{
if ( blist [ index ] . flags & BONE_ANGLES_RAGDOLL )
{
return qtrue ; // don't accept any calls on ragdoll bones
}
// 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 ;
# 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
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 ;
# 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
G2_Generate_Matrix ( mod_a , blist , index , angles , flags , up , left , forward ) ;
return qtrue ;
}
// assert(0);
//Jeese, we don't need an assert here too. There's already a warning in G2_Add_Bone if it fails.
// 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 ;
}
if ( index ! = - 1 )
{
if ( blist [ index ] . flags & BONE_ANGLES_RAGDOLL )
{
return qtrue ; // don't accept any calls on ragdoll bones
}
}
// 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 ) ;
if ( index ! = - 1 )
{
if ( blist [ index ] . flags & BONE_ANGLES_RAGDOLL )
{
return qtrue ; // don't accept any calls on ragdoll bones
}
}
// 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 ;
}
# define DEBUG_G2_TIMING (0)
// 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
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 ,
const int numFrames )
{
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 ( index ! = - 1 )
{
if ( blist [ index ] . flags & BONE_ANGLES_RAGDOLL )
{
return qtrue ; // don't accept any calls on ragdoll bones
}
2013-04-04 23:21:13 +00:00
//mark it for needing a transform for the cached trace transform stuff
blist [ index ] . flags | = BONE_NEED_TRANSFORM ;
2013-04-04 22:35:38 +00:00
}
if ( setFrame ! = - 1 )
{
assert ( ( setFrame > = startFrame ) & & ( setFrame < = endFrame ) ) ;
}
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 , numFrames ) )
{
if ( blist [ index ] . blendStart = = currentTime ) //we're replacing a blend in progress which hasn't started
{
// 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
{
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 ;
}
}
// hmm, we weren't animating on this bone. In which case disable the blend
else
{
blist [ index ] . blendFrame = blist [ index ] . blendLerpFrame = 0 ;
blist [ index ] . blendTime = 0 ;
modFlags & = ~ ( BONE_ANIM_BLEND ) ;
}
}
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 ) ;
if ( blist [ index ] . flags < 0 )
{
blist [ index ] . flags = 0 ;
}
blist [ index ] . flags | = modFlags ;
# if DEBUG_G2_TIMING
if ( index = = 2 )
{
const boneInfo_t & bone = blist [ index ] ;
char mess [ 1000 ] ;
if ( bone . flags & BONE_ANIM_BLEND )
{
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
) ;
}
else
{
sprintf ( mess , " saa[%2d] %5d %5d (%5d-%5d) %4.2f %4x \n " ,
index ,
currentTime ,
bone . startTime ,
bone . startFrame ,
bone . endFrame ,
bone . animSpeed ,
bone . flags
) ;
}
OutputDebugString ( mess ) ;
}
# endif
return qtrue ;
}
// 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
qboolean G2_Set_Bone_Anim ( CGhoul2Info * ghlInfo ,
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 )
{
model_t * mod_a = ( model_t * ) ghlInfo - > animModel ;
int index = G2_Find_Bone ( mod_a , blist , boneName ) ;
if ( index = = - 1 )
{
index = G2_Add_Bone ( mod_a , blist , boneName ) ;
}
if ( index ! = - 1 )
{
if ( blist [ index ] . flags & BONE_ANGLES_RAGDOLL )
{
return qtrue ; // don't accept any calls on ragdoll bones
}
}
if ( index ! = - 1 )
{
return G2_Set_Bone_Anim_Index ( blist , index , startFrame , endFrame , flags , animSpeed , currentTime , setFrame , blendTime , ghlInfo - > aHeader - > numFrames ) ;
}
return qfalse ;
}
qboolean G2_Get_Bone_Anim_Range ( CGhoul2Info * ghlInfo , boneInfo_v & blist , const char * boneName , int * startFrame , int * endFrame )
{
model_t * mod_a = ( model_t * ) ghlInfo - > animModel ;
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
void G2_TimingModel ( boneInfo_t & bone , int currentTime , int numFramesInFile , int & currentFrame , int & newFrame , float & lerp ) ;
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 numFrames )
{
// did we find it?
if ( ( index > = 0 ) & & ! ( ( index > = blist . size ( ) ) | | ( blist [ index ] . boneNumber = = - 1 ) ) )
{
// are we an animating bone?
if ( blist [ index ] . flags & ( BONE_ANIM_OVERRIDE_LOOP | BONE_ANIM_OVERRIDE ) )
{
int lcurrentFrame , newFrame ;
float lerp ;
G2_TimingModel ( blist [ index ] , currentTime , numFrames , lcurrentFrame , newFrame , lerp ) ;
* currentFrame = float ( lcurrentFrame ) + lerp ;
* startFrame = blist [ index ] . startFrame ;
* endFrame = blist [ index ] . endFrame ;
* flags = blist [ index ] . flags ;
* retAnimSpeed = blist [ index ] . animSpeed ;
return qtrue ;
}
}
* startFrame = 0 ;
* endFrame = 1 ;
* currentFrame = 0.0f ;
* flags = 0 ;
* retAnimSpeed = 0.0f ;
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 ( CGhoul2Info * ghlInfo , 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_a = ( model_t * ) ghlInfo - > animModel ;
int index = G2_Find_Bone ( mod_a , blist , boneName ) ;
if ( index = = - 1 )
{
index = G2_Add_Bone ( mod_a , blist , boneName ) ;
if ( index = = - 1 )
{
return qfalse ;
}
}
assert ( ghlInfo - > aHeader ) ;
if ( G2_Get_Bone_Anim_Index ( blist , index , currentTime , currentFrame , startFrame , endFrame , flags , retAnimSpeed , modelList , ghlInfo - > aHeader - > numFrames ) )
{
assert ( * startFrame > = 0 & & * startFrame < ghlInfo - > aHeader - > numFrames ) ;
assert ( * endFrame > 0 & & * endFrame < = ghlInfo - > aHeader - > numFrames ) ;
assert ( * currentFrame > = 0.0f & & ( ( int ) ( * currentFrame ) ) < ghlInfo - > aHeader - > numFrames ) ;
return qtrue ;
}
return qfalse ;
}
// given a model, bonelist and bonename, lets pause an anim if it's playing.
qboolean G2_Pause_Bone_Anim ( CGhoul2Info * ghlInfo , boneInfo_v & blist , const char * boneName , const int currentTime )
{
model_t * mod_a = ( model_t * ) ghlInfo - > animModel ;
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 ( ghlInfo , 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 ( ghlInfo , 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 ;
}
if ( time < 0.0f )
{
time = 0.0f ;
}
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?
if ( ( ( animSpeed > 0.0f ) & & ( newFrame_g > endFrame - 1 ) ) | |
( ( animSpeed < 0.0f ) & & ( newFrame_g < endFrame + 1 ) ) )
{
// 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 )
{
if ( newFrame_g < = endFrame + 1 )
{
newFrame_g = endFrame + fmod ( newFrame_g - endFrame , animSize ) - animSize ;
}
}
else
{
if ( newFrame_g > = endFrame )
{
newFrame_g = endFrame + fmod ( newFrame_g - endFrame , animSize ) - animSize ;
}
}
// figure out new start time
float frameTime = newFrame_g - blist [ i ] . startFrame ;
blist [ i ] . startTime = currentTime - ( int ) ( ( frameTime / animSpeed ) * 50.0f ) ;
if ( blist [ i ] . startTime > currentTime )
{
blist [ i ] . startTime = currentTime ;
}
assert ( blist [ i ] . startTime < = currentTime ) ;
blist [ i ] . lastTime = blist [ i ] . startTime ;
}
else
{
if ( ( blist [ i ] . flags & BONE_ANIM_OVERRIDE_FREEZE ) ! = BONE_ANIM_OVERRIDE_FREEZE )
{
// nope, just stop it. And remove the bone if possible
G2_Stop_Bone_Index ( blist , i , ( BONE_ANIM_TOTAL ) ) ;
}
}
}
}
}
}
}
}
//rww - RAGDOLL_BEGIN
/*
rag stuff
*/
static void G2_RagDollSolve ( CGhoul2Info_v & ghoul2V , int g2Index , float decay , int frameNum , const vec3_t currentOrg , bool LimitAngles , CRagDollUpdateParams * params = NULL ) ;
static void G2_RagDollCurrentPosition ( CGhoul2Info_v & ghoul2V , int g2Index , int frameNum , const vec3_t angles , const vec3_t position , const vec3_t scale ) ;
static bool G2_RagDollSettlePositionNumeroTrois ( CGhoul2Info_v & ghoul2V , const vec3_t currentOrg , CRagDollUpdateParams * params , int curTime ) ;
static bool G2_RagDollSetup ( CGhoul2Info & ghoul2 , int frameNum , bool resetOrigin , const vec3_t origin , bool anyRendered ) ;
void G2_GetBoneBasepose ( CGhoul2Info & ghoul2 , int boneNum , mdxaBone_t * & retBasepose , mdxaBone_t * & retBaseposeInv ) ;
int G2_GetBoneDependents ( CGhoul2Info & ghoul2 , int boneNum , int * tempDependents , int maxDep ) ;
void G2_GetBoneMatrixLow ( CGhoul2Info & ghoul2 , int boneNum , const vec3_t scale , mdxaBone_t & retMatrix , mdxaBone_t * & retBasepose , mdxaBone_t * & retBaseposeInv ) ;
int G2_GetParentBoneMatrixLow ( CGhoul2Info & ghoul2 , int boneNum , const vec3_t scale , mdxaBone_t & retMatrix , mdxaBone_t * & retBasepose , mdxaBone_t * & retBaseposeInv ) ;
bool G2_WasBoneRendered ( CGhoul2Info & ghoul2 , int boneNum ) ;
# define MAX_BONES_RAG (256)
struct SRagEffector
{
vec3_t currentOrigin ;
vec3_t desiredDirection ;
vec3_t desiredOrigin ;
float radius ;
float weight ;
} ;
# define RAG_MASK (CONTENTS_SOLID|CONTENTS_TERRAIN) //|CONTENTS_SHOTCLIP|CONTENTS_TERRAIN//(/*MASK_SOLID|*/CONTENTS_SOLID|CONTENTS_PLAYERCLIP|CONTENTS_SHOTCLIP|CONTENTS_TERRAIN|CONTENTS_BODY)
extern cvar_t * broadsword ;
extern cvar_t * broadsword_kickbones ;
extern cvar_t * broadsword_kickorigin ;
extern cvar_t * broadsword_dontstopanim ;
extern cvar_t * broadsword_waitforshot ;
extern cvar_t * broadsword_playflop ;
extern cvar_t * broadsword_effcorr ;
extern cvar_t * broadsword_ragtobase ;
extern cvar_t * broadsword_dircap ;
extern cvar_t * broadsword_extra1 ;
extern cvar_t * broadsword_extra2 ;
# define RAG_PCJ (0x00001)
# define RAG_PCJ_POST_MULT (0x00002) // has the pcj flag as well
# define RAG_PCJ_MODEL_ROOT (0x00004) // has the pcj flag as well
# define RAG_PCJ_PELVIS (0x00008) // has the pcj flag and POST_MULT as well
# define RAG_EFFECTOR (0x00100)
# define RAG_WAS_NOT_RENDERED (0x01000) // not particularily reliable, more of a hint
# define RAG_WAS_EVER_RENDERED (0x02000) // not particularily reliable, more of a hint
# define RAG_BONE_LIGHTWEIGHT (0x04000) //used to indicate a bone's velocity treatment
# define RAG_PCJ_IK_CONTROLLED (0x08000) //controlled from IK move input
# define RAG_UNSNAPPABLE (0x10000) //cannot be broken out of constraints ever
// thiese flags are on the model and correspond to...
//#define GHOUL2_RESERVED_FOR_RAGDOLL 0x0ff0 // these are not defined here for dependecies sake
# define GHOUL2_RAG_STARTED 0x0010 // we are actually a ragdoll
# define GHOUL2_RAG_PENDING 0x0100 // got start death anim but not end death anim
# define GHOUL2_RAG_DONE 0x0200 // got end death anim
# define GHOUL2_RAG_COLLISION_DURING_DEATH 0x0400 // ever have gotten a collision (da) event
# define GHOUL2_RAG_COLLISION_SLIDE 0x0800 // ever have gotten a collision (slide) event
# define GHOUL2_RAG_FORCESOLVE 0x1000 //api-override, determine if ragdoll should be forced to continue solving even if it thinks it is settled
//#define flrand Q_flrand
static mdxaBone_t * ragBasepose [ MAX_BONES_RAG ] ;
static mdxaBone_t * ragBaseposeInv [ MAX_BONES_RAG ] ;
static mdxaBone_t ragBones [ MAX_BONES_RAG ] ;
static SRagEffector ragEffectors [ MAX_BONES_RAG ] ;
static boneInfo_t * ragBoneData [ MAX_BONES_RAG ] ;
static int tempDependents [ MAX_BONES_RAG ] ;
static int ragBlistIndex [ MAX_BONES_RAG ] ;
static int numRags ;
static vec3_t ragBoneMins ;
static vec3_t ragBoneMaxs ;
static vec3_t ragBoneCM ;
static bool haveDesiredPelvisOffset = false ;
static vec3_t desiredPelvisOffset ; // this is for the root
static float ragOriginChange = 0.0f ;
static vec3_t ragOriginChangeDir ;
//debug
static vec3_t handPos = { 0 , 0 , 0 } ;
static vec3_t handPos2 = { 0 , 0 , 0 } ;
enum ERagState
{
ERS_DYNAMIC ,
ERS_SETTLING ,
ERS_SETTLED
} ;
static int ragState ;
static vector < boneInfo_t * > rag ; // once we get the dependents precomputed this can be local
static void G2_Generate_MatrixRag (
// caution this must not be called before the whole skeleton is "remembered"
boneInfo_v & blist ,
int index )
{
boneInfo_t & bone = blist [ index ] ; //.sent;
memcpy ( & bone . matrix , & bone . ragOverrideMatrix , sizeof ( mdxaBone_t ) ) ;
# ifdef _DEBUG
int i , j ;
for ( i = 0 ; i < 3 ; i + + )
{
for ( j = 0 ; j < 4 ; j + + )
{
assert ( ! _isnan ( bone . matrix . matrix [ i ] [ j ] ) ) ;
}
}
# endif // _DEBUG
memcpy ( & blist [ index ] . newMatrix , & bone . matrix , sizeof ( mdxaBone_t ) ) ;
}
int G2_Find_Bone_Rag ( CGhoul2Info * ghlInfo , boneInfo_v & blist , const char * boneName )
{
int i ;
mdxaSkel_t * skel ;
mdxaSkelOffsets_t * offsets ;
offsets = ( mdxaSkelOffsets_t * ) ( ( byte * ) ghlInfo - > aHeader + sizeof ( mdxaHeader_t ) ) ;
skel = ( mdxaSkel_t * ) ( ( byte * ) ghlInfo - > aHeader + sizeof ( mdxaHeader_t ) + offsets - > offsets [ 0 ] ) ;
/*
model_t * currentModel ;
model_t * animModel ;
mdxaHeader_t * aHeader ;
currentModel = R_GetModelByHandle ( RE_RegisterModel ( ghlInfo - > mFileName ) ) ;
assert ( currentModel ) ;
animModel = R_GetModelByHandle ( currentModel - > mdxm - > animIndex ) ;
assert ( animModel ) ;
aHeader = animModel - > mdxa ;
assert ( aHeader ) ;
offsets = ( mdxaSkelOffsets_t * ) ( ( byte * ) aHeader + sizeof ( mdxaHeader_t ) ) ;
skel = ( mdxaSkel_t * ) ( ( byte * ) aHeader + 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 * ) ghlInfo - > aHeader + sizeof ( mdxaHeader_t ) + offsets - > offsets [ blist [ i ] . boneNumber ] ) ;
//skel = (mdxaSkel_t *)((byte *)aHeader + sizeof(mdxaHeader_t) + offsets->offsets[blist[i].boneNumber]);
// if name is the same, we found it
if ( ! stricmp ( skel - > name , boneName ) )
{
return i ;
}
}
# if _DEBUG
// G2_Bone_Not_Found(boneName,ghlInfo->mFileName);
# endif
// didn't find it
return - 1 ;
}
static int G2_Set_Bone_Rag ( const mdxaHeader_t * mod_a ,
boneInfo_v & blist ,
const char * boneName ,
CGhoul2Info & ghoul2 ,
const vec3_t scale ,
const vec3_t origin )
{
// do not change the state of the skeleton here
int index = G2_Find_Bone_Rag ( & ghoul2 , blist , boneName ) ;
if ( index = = - 1 )
{
index = G2_Add_Bone ( ghoul2 . animModel , blist , boneName ) ;
}
if ( index ! = - 1 )
{
boneInfo_t & bone = blist [ index ] ;
VectorCopy ( origin , bone . extraVec1 ) ;
G2_GetBoneMatrixLow ( ghoul2 , bone . boneNumber , scale , bone . originalTrueBoneMatrix , bone . basepose , bone . baseposeInv ) ;
// bone.parentRawBoneIndex=G2_GetParentBoneMatrixLow(ghoul2,bone.boneNumber,scale,bone.parentTrueBoneMatrix,bone.baseposeParent,bone.baseposeInvParent);
assert ( ! _isnan ( bone . originalTrueBoneMatrix . matrix [ 1 ] [ 1 ] ) ) ;
assert ( ! _isnan ( bone . originalTrueBoneMatrix . matrix [ 1 ] [ 3 ] ) ) ;
bone . originalOrigin [ 0 ] = bone . originalTrueBoneMatrix . matrix [ 0 ] [ 3 ] ;
bone . originalOrigin [ 1 ] = bone . originalTrueBoneMatrix . matrix [ 1 ] [ 3 ] ;
bone . originalOrigin [ 2 ] = bone . originalTrueBoneMatrix . matrix [ 2 ] [ 3 ] ;
}
return index ;
}
static int G2_Set_Bone_Angles_Rag (
CGhoul2Info & ghoul2 ,
const mdxaHeader_t * mod_a ,
boneInfo_v & blist ,
const char * boneName ,
const int flags ,
const float radius ,
const vec3_t angleMin = 0 ,
const vec3_t angleMax = 0 ,
const int blendTime = 500 )
{
int index = G2_Find_Bone_Rag ( & ghoul2 , blist , boneName ) ;
if ( index = = - 1 )
{
index = G2_Add_Bone ( ghoul2 . animModel , blist , boneName ) ;
}
if ( index ! = - 1 )
{
boneInfo_t & bone = blist [ index ] ;
bone . flags & = ~ ( BONE_ANGLES_TOTAL ) ;
bone . flags | = BONE_ANGLES_RAGDOLL ;
if ( flags & RAG_PCJ )
{
if ( flags & RAG_PCJ_POST_MULT )
{
bone . flags | = BONE_ANGLES_POSTMULT ;
}
else if ( flags & RAG_PCJ_MODEL_ROOT )
{
bone . flags | = BONE_ANGLES_PREMULT ;
// bone.flags |= BONE_ANGLES_POSTMULT;
}
else
{
assert ( ! " Invalid RAG PCJ \n " ) ;
}
}
bone . ragStartTime = G2API_GetTime ( 0 ) ;
bone . boneBlendStart = bone . ragStartTime ;
bone . boneBlendTime = blendTime ;
bone . radius = radius ;
bone . weight = 1.0f ;
//init the others to valid values
bone . epGravFactor = 0 ;
VectorClear ( bone . epVelocity ) ;
bone . solidCount = 0 ;
bone . physicsSettled = false ;
bone . snapped = false ;
bone . parentBoneIndex = - 1 ;
bone . offsetRotation = 0.0f ;
bone . overGradSpeed = 0.0f ;
VectorClear ( bone . overGoalSpot ) ;
bone . hasOverGoal = false ;
bone . hasAnimFrameMatrix = - 1 ;
// bone.weight=pow(radius,1.7f); //cubed was too harsh
// bone.weight=radius*radius*radius;
if ( angleMin & & angleMax )
{
VectorCopy ( angleMin , bone . minAngles ) ;
VectorCopy ( angleMax , bone . maxAngles ) ;
}
else
{
VectorCopy ( bone . currentAngles , bone . minAngles ) ; // I guess this isn't a rag pcj then
VectorCopy ( bone . currentAngles , bone . maxAngles ) ;
}
if ( ! bone . lastTimeUpdated )
{
static mdxaBone_t id =
{
1.0f , 0.0f , 0.0f , 0.0f ,
0.0f , 1.0f , 0.0f , 0.0f ,
0.0f , 0.0f , 1.0f , 0.0f
} ;
memcpy ( & bone . ragOverrideMatrix , & id , sizeof ( mdxaBone_t ) ) ;
VectorClear ( bone . anglesOffset ) ;
VectorClear ( bone . positionOffset ) ;
VectorClear ( bone . velocityEffector ) ; // this is actually a velocity now
VectorClear ( bone . velocityRoot ) ; // this is actually a velocity now
VectorClear ( bone . lastPosition ) ;
VectorClear ( bone . lastShotDir ) ;
bone . lastContents = 0 ;
// if this is non-zero, we are in a dynamic state
bone . firstCollisionTime = bone . ragStartTime ;
// if this is non-zero, we are in a settling state
bone . restTime = 0 ;
// if they are both zero, we are in a settled state
bone . firstTime = 0 ;
bone . RagFlags = flags ;
bone . DependentRagIndexMask = 0 ;
G2_Generate_MatrixRag ( blist , index ) ; // set everything to th id
#if 0
VectorClear ( bone . currentAngles ) ;
// VectorAdd(bone.minAngles,bone.maxAngles,bone.currentAngles);
// VectorScale(bone.currentAngles,0.5f,bone.currentAngles);
# else
{
if (
( flags & RAG_PCJ_MODEL_ROOT ) | |
( flags & RAG_PCJ_PELVIS ) | |
! ( flags & RAG_PCJ ) )
{
VectorClear ( bone . currentAngles ) ;
}
else
{
int k ;
for ( k = 0 ; k < 3 ; k + + )
{
float scalar = flrand ( - 1.0f , 1.0f ) ;
scalar * = flrand ( - 1.0f , 1.0f ) * flrand ( - 1.0f , 1.0f ) ;
// this is a heavily central distribution
// center it on .5 (and make it small)
scalar * = 0.5f ;
scalar + = 0.5f ;
bone . currentAngles [ k ] = ( bone . minAngles [ k ] - bone . maxAngles [ k ] ) * scalar + bone . maxAngles [ k ] ;
}
}
}
// VectorClear(bone.currentAngles);
# endif
VectorCopy ( bone . currentAngles , bone . lastAngles ) ;
}
}
return index ;
}
class CRagDollParams ;
const mdxaHeader_t * G2_GetModA ( CGhoul2Info & ghoul2 ) ;
static void G2_RagDollMatchPosition ( )
{
haveDesiredPelvisOffset = false ;
int i ;
for ( i = 0 ; i < numRags ; i + + )
{
boneInfo_t & bone = * ragBoneData [ i ] ;
SRagEffector & e = ragEffectors [ i ] ;
vec3_t & desiredPos = e . desiredOrigin ; // we will save this
if ( 0 & & ( bone . RagFlags & RAG_PCJ_PELVIS ) )
{
// just move to quake origin
VectorCopy ( bone . originalOrigin , desiredPos ) ;
VectorSubtract ( desiredPos , e . currentOrigin , desiredPelvisOffset ) ; // last arg is dest
haveDesiredPelvisOffset = true ;
VectorCopy ( e . currentOrigin , bone . lastPosition ) ; // last arg is dest
continue ;
}
if ( ! ( bone . RagFlags & RAG_EFFECTOR ) )
{
continue ;
}
VectorCopy ( bone . originalOrigin , desiredPos ) ;
VectorSubtract ( desiredPos , e . currentOrigin , e . desiredDirection ) ;
VectorCopy ( e . currentOrigin , bone . lastPosition ) ; // last arg is dest
}
}
qboolean G2_Set_Bone_Anim_No_BS ( CGhoul2Info & ghoul2 , const mdxaHeader_t * mod , boneInfo_v & blist , const char * boneName , const int argStartFrame ,
const int argEndFrame , const int flags , const float animSpeed , const int currentTime , const float setFrame ,
const int blendTime , const int creationID , bool resetBonemap = true )
{
int index = G2_Find_Bone_Rag ( & ghoul2 , blist , boneName ) ;
int modFlags = flags ;
int startFrame = argStartFrame ;
int endFrame = argEndFrame ;
if ( index ! = - 1 )
{
blist [ index ] . blendFrame = blist [ index ] . blendLerpFrame = 0 ;
blist [ index ] . blendTime = blist [ index ] . blendStart = 0 ;
modFlags & = ~ ( BONE_ANIM_BLEND ) ;
blist [ index ] . endFrame = endFrame ;
blist [ index ] . startFrame = startFrame ;
blist [ index ] . animSpeed = animSpeed ;
blist [ index ] . pauseTime = 0 ;
// blist[index].boneMap = NULL;
// blist[index].lastTime = blist[index].startTime = (currentTime - (((setFrame - (float)startFrame) * 50.0)/ animSpeed));
blist [ index ] . flags & = ~ ( BONE_ANIM_TOTAL ) ;
blist [ index ] . flags | = modFlags ;
return qtrue ;
}
index = G2_Add_Bone ( ghoul2 . animModel , blist , boneName ) ;
if ( index ! = - 1 )
{
blist [ index ] . blendFrame = blist [ index ] . blendLerpFrame = 0 ;
blist [ index ] . blendTime = 0 ;
modFlags & = ~ ( BONE_ANIM_BLEND ) ;
blist [ index ] . endFrame = endFrame ;
blist [ index ] . startFrame = startFrame ;
blist [ index ] . animSpeed = animSpeed ;
blist [ index ] . pauseTime = 0 ;
// blist[index].boneMap = NULL;
// blist[index].lastTime = blist[index].startTime = (currentTime - (((setFrame - (float)startFrame) * 50.0f)/ animSpeed));
blist [ index ] . flags & = ~ ( BONE_ANIM_TOTAL ) ;
blist [ index ] . flags | = modFlags ;
return qtrue ;
}
assert ( 0 ) ;
return qfalse ;
}
void G2_ResetRagDoll ( CGhoul2Info_v & ghoul2V )
{
int model ;
for ( model = 0 ; model < ghoul2V . size ( ) ; model + + )
{
if ( ghoul2V [ model ] . mModelindex ! = - 1 )
{
break ;
}
}
if ( model = = ghoul2V . size ( ) )
{
return ;
}
CGhoul2Info & ghoul2 = ghoul2V [ model ] ;
if ( ! ( ghoul2 . mFlags & GHOUL2_RAG_STARTED ) )
{ //no use in doing anything if we aren't ragging
return ;
}
boneInfo_v & blist = ghoul2 . mBlist ;
# if 1
//Eh, screw it. Ragdoll does a lot of terrible things to the bones that probably aren't directly reversible, so just reset it all.
G2_Init_Bone_List ( blist ) ;
# else //The anims on every bone are messed up too, as are the angles. There's not really any way to get back to a normal state, so just clear the list
//and let them re-set their anims/angles gameside.
int i = 0 ;
while ( i < blist . size ( ) )
{
boneInfo_t & bone = blist [ i ] ;
if ( bone . boneNumber ! = - 1 & & ( bone . flags & BONE_ANGLES_RAGDOLL ) )
{
bone . flags & = ~ BONE_ANGLES_RAGDOLL ;
bone . flags & = ~ BONE_ANGLES_IK ;
bone . RagFlags = 0 ;
bone . lastTimeUpdated = 0 ;
VectorClear ( bone . currentAngles ) ;
bone . ragStartTime = 0 ;
}
i + + ;
}
# endif
ghoul2 . mFlags & = ~ ( GHOUL2_RAG_PENDING | GHOUL2_RAG_DONE | GHOUL2_RAG_STARTED ) ;
}
void G2_SetRagDoll ( CGhoul2Info_v & ghoul2V , CRagDollParams * parms )
{
if ( parms )
{
parms - > CallRagDollBegin = qfalse ;
}
if ( ! broadsword | | ! broadsword - > integer | | ! parms )
{
return ;
}
int model ;
for ( model = 0 ; model < ghoul2V . size ( ) ; model + + )
{
if ( ghoul2V [ model ] . mModelindex ! = - 1 )
{
break ;
}
}
if ( model = = ghoul2V . size ( ) )
{
return ;
}
CGhoul2Info & ghoul2 = ghoul2V [ model ] ;
const mdxaHeader_t * mod_a = G2_GetModA ( ghoul2 ) ;
if ( ! mod_a )
{
return ;
}
int curTime = G2API_GetTime ( 0 ) ;
boneInfo_v & blist = ghoul2 . mBlist ;
int index = G2_Find_Bone_Rag ( & ghoul2 , blist , " model_root " ) ;
# ifndef DEDICATED
switch ( parms - > RagPhase )
{
case CRagDollParams : : ERagPhase : : RP_START_DEATH_ANIM :
ghoul2 . mFlags | = GHOUL2_RAG_PENDING ;
return ; /// not doing anything with this yet
break ;
case CRagDollParams : : ERagPhase : : RP_END_DEATH_ANIM :
ghoul2 . mFlags | = GHOUL2_RAG_PENDING | GHOUL2_RAG_DONE ;
if ( broadsword_waitforshot & &
broadsword_waitforshot - > integer )
{
if ( broadsword_waitforshot - > integer = = 2 )
{
if ( ! ( ghoul2 . mFlags & ( GHOUL2_RAG_COLLISION_DURING_DEATH | GHOUL2_RAG_COLLISION_SLIDE ) ) )
{
//nothing was encountered, lets just wait for the first shot
return ; // we ain't starting yet
}
}
else
{
return ; // we ain't starting yet
}
}
break ;
case CRagDollParams : : ERagPhase : : RP_DEATH_COLLISION :
if ( parms - > collisionType )
{
ghoul2 . mFlags | = GHOUL2_RAG_COLLISION_SLIDE ;
}
else
{
ghoul2 . mFlags | = GHOUL2_RAG_COLLISION_DURING_DEATH ;
}
if ( broadsword_dontstopanim & & broadsword_waitforshot & &
( broadsword_dontstopanim - > integer | | broadsword_waitforshot - > integer )
)
{
if ( ! ( ghoul2 . mFlags & GHOUL2_RAG_DONE ) )
{
return ; // we ain't starting yet
}
}
break ;
case CRagDollParams : : ERagPhase : : RP_CORPSE_SHOT :
if ( broadsword_kickorigin & &
broadsword_kickorigin - > integer )
{
if ( index > = 0 & & index < blist . size ( ) )
{
boneInfo_t & bone = blist [ index ] ;
if ( bone . boneNumber > = 0 )
{
if ( bone . flags & BONE_ANGLES_RAGDOLL )
{
//rww - Would need ent pointer here. But.. since this is SW, we aren't even having corpse shooting anyway I'd imagine.
/*
float magicFactor14 = 8.0f ; //64.0f; // kick strength
if ( parms - > fShotStrength )
{ //if there is a shot strength, use it instead
magicFactor14 = parms - > fShotStrength ;
}
parms - > me - > s . pos . trType = TR_GRAVITY ;
parms - > me - > s . pos . trDelta [ 0 ] + = bone . lastShotDir [ 0 ] * magicFactor14 ;
parms - > me - > s . pos . trDelta [ 1 ] + = bone . lastShotDir [ 1 ] * magicFactor14 ;
//parms->me->s.pos.trDelta[2] = fabsf(bone.lastShotDir[2])*magicFactor14;
//rww - The vertical portion of this doesn't seem to work very well
//I am just leaving it whatever it is for now, because my velocity scaling
//only works on x and y and the gravity stuff for NPCs is a bit unpleasent
//trying to change/work with
assert ( ! _isnan ( bone . lastShotDir [ 1 ] ) ) ;
*/
}
}
}
}
break ;
case CRagDollParams : : ERagPhase : : RP_GET_PELVIS_OFFSET :
if ( parms - > RagPhase = = CRagDollParams : : ERagPhase : : RP_GET_PELVIS_OFFSET )
{
VectorClear ( parms - > pelvisAnglesOffset ) ;
VectorClear ( parms - > pelvisPositionOffset ) ;
}
// intentional lack of a break
case CRagDollParams : : ERagPhase : : RP_SET_PELVIS_OFFSET :
if ( index > = 0 & & index < blist . size ( ) )
{
boneInfo_t & bone = blist [ index ] ;
if ( bone . boneNumber > = 0 )
{
if ( bone . flags & BONE_ANGLES_RAGDOLL )
{
if ( parms - > RagPhase = = CRagDollParams : : ERagPhase : : RP_GET_PELVIS_OFFSET )
{
VectorCopy ( bone . anglesOffset , parms - > pelvisAnglesOffset ) ;
VectorCopy ( bone . positionOffset , parms - > pelvisPositionOffset ) ;
}
else
{
VectorCopy ( parms - > pelvisAnglesOffset , bone . anglesOffset ) ;
VectorCopy ( parms - > pelvisPositionOffset , bone . positionOffset ) ;
}
}
}
}
return ;
break ;
case CRagDollParams : : ERagPhase : : RP_DISABLE_EFFECTORS :
// not doing anything with this yet
return ;
break ;
default :
assert ( 0 ) ;
return ;
break ;
}
# endif //!DEDICATED
if ( ghoul2 . mFlags & GHOUL2_RAG_STARTED )
{
// only going to begin ragdoll once, everything else depends on what happens to the origin
return ;
}
#if 0
if ( index > = 0 )
{
OutputDebugString ( va ( " death %d %d \n " , blist [ index ] . startFrame , blist [ index ] . endFrame ) ) ;
}
# endif
ghoul2 . mFlags | = GHOUL2_RAG_PENDING | GHOUL2_RAG_DONE | GHOUL2_RAG_STARTED ; // well anyway we are going live
parms - > CallRagDollBegin = qtrue ;
G2_GenerateWorldMatrix ( parms - > angles , parms - > position ) ;
G2_ConstructGhoulSkeleton ( ghoul2V , curTime , false , parms - > scale ) ;
G2_Set_Bone_Rag ( mod_a , blist , " model_root " , ghoul2 , parms - > scale , parms - > position ) ;
G2_Set_Bone_Rag ( mod_a , blist , " pelvis " , ghoul2 , parms - > scale , parms - > position ) ;
G2_Set_Bone_Rag ( mod_a , blist , " lower_lumbar " , ghoul2 , parms - > scale , parms - > position ) ;
G2_Set_Bone_Rag ( mod_a , blist , " upper_lumbar " , ghoul2 , parms - > scale , parms - > position ) ;
G2_Set_Bone_Rag ( mod_a , blist , " thoracic " , ghoul2 , parms - > scale , parms - > position ) ;
G2_Set_Bone_Rag ( mod_a , blist , " cranium " , ghoul2 , parms - > scale , parms - > position ) ;
G2_Set_Bone_Rag ( mod_a , blist , " rhumerus " , ghoul2 , parms - > scale , parms - > position ) ;
G2_Set_Bone_Rag ( mod_a , blist , " lhumerus " , ghoul2 , parms - > scale , parms - > position ) ;
G2_Set_Bone_Rag ( mod_a , blist , " rradius " , ghoul2 , parms - > scale , parms - > position ) ;
G2_Set_Bone_Rag ( mod_a , blist , " lradius " , ghoul2 , parms - > scale , parms - > position ) ;
G2_Set_Bone_Rag ( mod_a , blist , " rfemurYZ " , ghoul2 , parms - > scale , parms - > position ) ;
G2_Set_Bone_Rag ( mod_a , blist , " lfemurYZ " , ghoul2 , parms - > scale , parms - > position ) ;
G2_Set_Bone_Rag ( mod_a , blist , " rtibia " , ghoul2 , parms - > scale , parms - > position ) ;
G2_Set_Bone_Rag ( mod_a , blist , " ltibia " , ghoul2 , parms - > scale , parms - > position ) ;
G2_Set_Bone_Rag ( mod_a , blist , " rhand " , ghoul2 , parms - > scale , parms - > position ) ;
G2_Set_Bone_Rag ( mod_a , blist , " lhand " , ghoul2 , parms - > scale , parms - > position ) ;
//G2_Set_Bone_Rag(mod_a,blist,"rtarsal",ghoul2,parms->scale,parms->position);
//G2_Set_Bone_Rag(mod_a,blist,"ltarsal",ghoul2,parms->scale,parms->position);
G2_Set_Bone_Rag ( mod_a , blist , " rtalus " , ghoul2 , parms - > scale , parms - > position ) ;
G2_Set_Bone_Rag ( mod_a , blist , " ltalus " , ghoul2 , parms - > scale , parms - > position ) ;
G2_Set_Bone_Rag ( mod_a , blist , " rradiusX " , ghoul2 , parms - > scale , parms - > position ) ;
G2_Set_Bone_Rag ( mod_a , blist , " lradiusX " , ghoul2 , parms - > scale , parms - > position ) ;
G2_Set_Bone_Rag ( mod_a , blist , " rfemurX " , ghoul2 , parms - > scale , parms - > position ) ;
G2_Set_Bone_Rag ( mod_a , blist , " lfemurX " , ghoul2 , parms - > scale , parms - > position ) ;
G2_Set_Bone_Rag ( mod_a , blist , " ceyebrow " , ghoul2 , parms - > scale , parms - > position ) ;
//int startFrame = 3665, endFrame = 3665+1;
int startFrame = parms - > startFrame , endFrame = parms - > endFrame ;
G2_Set_Bone_Anim_No_BS ( ghoul2 , mod_a , blist , " upper_lumbar " , startFrame , endFrame - 1 ,
BONE_ANIM_OVERRIDE_FREEZE | BONE_ANIM_BLEND ,
1.0f , curTime , float ( startFrame ) , 150 , 0 , true ) ;
G2_Set_Bone_Anim_No_BS ( ghoul2 , mod_a , blist , " lower_lumbar " , startFrame , endFrame - 1 ,
BONE_ANIM_OVERRIDE_FREEZE | BONE_ANIM_BLEND ,
1.0f , curTime , float ( startFrame ) , 150 , 0 , true ) ;
G2_Set_Bone_Anim_No_BS ( ghoul2 , mod_a , blist , " Motion " , startFrame , endFrame - 1 ,
BONE_ANIM_OVERRIDE_FREEZE | BONE_ANIM_BLEND ,
1.0f , curTime , float ( startFrame ) , 150 , 0 , true ) ;
// G2_Set_Bone_Anim_No_BS(ghoul2, mod_a,blist,"model_root",startFrame,endFrame-1,
// BONE_ANIM_OVERRIDE_FREEZE|BONE_ANIM_BLEND,
// 1.0f,curTime,float(startFrame),150,0,true);
G2_Set_Bone_Anim_No_BS ( ghoul2 , mod_a , blist , " lfemurYZ " , startFrame , endFrame - 1 ,
BONE_ANIM_OVERRIDE_FREEZE | BONE_ANIM_BLEND ,
1.0f , curTime , float ( startFrame ) , 150 , 0 , true ) ;
G2_Set_Bone_Anim_No_BS ( ghoul2 , mod_a , blist , " rfemurYZ " , startFrame , endFrame - 1 ,
BONE_ANIM_OVERRIDE_FREEZE | BONE_ANIM_BLEND ,
1.0f , curTime , float ( startFrame ) , 150 , 0 , true ) ;
G2_Set_Bone_Anim_No_BS ( ghoul2 , mod_a , blist , " rhumerus " , startFrame , endFrame - 1 ,
BONE_ANIM_OVERRIDE_FREEZE | BONE_ANIM_BLEND ,
1.0f , curTime , float ( startFrame ) , 150 , 0 , true ) ;
G2_Set_Bone_Anim_No_BS ( ghoul2 , mod_a , blist , " lhumerus " , startFrame , endFrame - 1 ,
BONE_ANIM_OVERRIDE_FREEZE | BONE_ANIM_BLEND ,
1.0f , curTime , float ( startFrame ) , 150 , 0 , true ) ;
// should already be set G2_GenerateWorldMatrix(parms->angles, parms->position);
G2_ConstructGhoulSkeleton ( ghoul2V , curTime , false , parms - > scale ) ;
static const float fRadScale = 0.3f ; //0.5f;
vec3_t pcjMin , pcjMax ;
VectorSet ( pcjMin , - 90.0f , - 45.0f , - 45.0f ) ;
VectorSet ( pcjMax , 90.0f , 45.0f , 45.0f ) ;
G2_Set_Bone_Angles_Rag ( ghoul2 , mod_a , blist , " model_root " , RAG_PCJ_MODEL_ROOT | RAG_PCJ | RAG_UNSNAPPABLE , 10.0f * fRadScale , pcjMin , pcjMax , 100 ) ;
VectorSet ( pcjMin , - 45.0f , - 45.0f , - 45.0f ) ;
VectorSet ( pcjMax , 45.0f , 45.0f , 45.0f ) ;
G2_Set_Bone_Angles_Rag ( ghoul2 , mod_a , blist , " pelvis " , RAG_PCJ_PELVIS | RAG_PCJ | RAG_PCJ_POST_MULT | RAG_UNSNAPPABLE , 10.0f * fRadScale , pcjMin , pcjMax , 100 ) ;
# if 1
// new base anim, unconscious flop
int pcjflags = RAG_PCJ | RAG_PCJ_POST_MULT ; //|RAG_EFFECTOR;
VectorSet ( pcjMin , - 15.0f , - 15.0f , - 15.0f ) ;
VectorSet ( pcjMax , 15.0f , 15.0f , 15.0f ) ;
G2_Set_Bone_Angles_Rag ( ghoul2 , mod_a , blist , " lower_lumbar " , pcjflags | RAG_UNSNAPPABLE , 10.0f * fRadScale , pcjMin , pcjMax , 500 ) ;
G2_Set_Bone_Angles_Rag ( ghoul2 , mod_a , blist , " upper_lumbar " , pcjflags | RAG_UNSNAPPABLE , 10.0f * fRadScale , pcjMin , pcjMax , 500 ) ;
VectorSet ( pcjMin , - 25.0f , - 25.0f , - 25.0f ) ;
VectorSet ( pcjMax , 25.0f , 25.0f , 25.0f ) ;
G2_Set_Bone_Angles_Rag ( ghoul2 , mod_a , blist , " thoracic " , pcjflags | RAG_EFFECTOR | RAG_UNSNAPPABLE , 12.0f * fRadScale , pcjMin , pcjMax , 500 ) ;
VectorSet ( pcjMin , - 10.0f , - 10.0f , - 90.0f ) ;
VectorSet ( pcjMax , 10.0f , 10.0f , 90.0f ) ;
G2_Set_Bone_Angles_Rag ( ghoul2 , mod_a , blist , " cranium " , pcjflags | RAG_BONE_LIGHTWEIGHT | RAG_UNSNAPPABLE , 6.0f * fRadScale , pcjMin , pcjMax , 500 ) ;
static const float sFactLeg = 1.0f ;
static const float sFactArm = 1.0f ;
static const float sRadArm = 1.0f ;
static const float sRadLeg = 1.0f ;
VectorSet ( pcjMin , - 100.0f , - 40.0f , - 15.0f ) ;
VectorSet ( pcjMax , - 15.0f , 80.0f , 15.0f ) ;
VectorScale ( pcjMin , sFactArm , pcjMin ) ;
VectorScale ( pcjMax , sFactArm , pcjMax ) ;
G2_Set_Bone_Angles_Rag ( ghoul2 , mod_a , blist , " rhumerus " , pcjflags | RAG_BONE_LIGHTWEIGHT | RAG_UNSNAPPABLE , ( 4.0f * sRadArm ) * fRadScale , pcjMin , pcjMax , 500 ) ;
VectorSet ( pcjMin , - 50.0f , - 80.0f , - 15.0f ) ;
VectorSet ( pcjMax , 15.0f , 40.0f , 15.0f ) ;
VectorScale ( pcjMin , sFactArm , pcjMin ) ;
VectorScale ( pcjMax , sFactArm , pcjMax ) ;
G2_Set_Bone_Angles_Rag ( ghoul2 , mod_a , blist , " lhumerus " , pcjflags | RAG_BONE_LIGHTWEIGHT | RAG_UNSNAPPABLE , ( 4.0f * sRadArm ) * fRadScale , pcjMin , pcjMax , 500 ) ;
VectorSet ( pcjMin , - 25.0f , - 20.0f , - 20.0f ) ;
VectorSet ( pcjMax , 90.0f , 20.0f , - 20.0f ) ;
VectorScale ( pcjMin , sFactArm , pcjMin ) ;
VectorScale ( pcjMax , sFactArm , pcjMax ) ;
G2_Set_Bone_Angles_Rag ( ghoul2 , mod_a , blist , " rradius " , pcjflags | RAG_BONE_LIGHTWEIGHT , ( 3.0f * sRadArm ) * fRadScale , pcjMin , pcjMax , 500 ) ;
VectorSet ( pcjMin , - 90.0f , - 20.0f , - 20.0f ) ;
VectorSet ( pcjMax , 30.0f , 20.0f , - 20.0f ) ;
VectorScale ( pcjMin , sFactArm , pcjMin ) ;
VectorScale ( pcjMax , sFactArm , pcjMax ) ;
G2_Set_Bone_Angles_Rag ( ghoul2 , mod_a , blist , " lradius " , pcjflags | RAG_BONE_LIGHTWEIGHT , ( 3.0f * sRadArm ) * fRadScale , pcjMin , pcjMax , 500 ) ;
VectorSet ( pcjMin , - 80.0f , - 50.0f , - 20.0f ) ;
VectorSet ( pcjMax , 30.0f , 5.0f , 20.0f ) ;
VectorScale ( pcjMin , sFactLeg , pcjMin ) ;
VectorScale ( pcjMax , sFactLeg , pcjMax ) ;
G2_Set_Bone_Angles_Rag ( ghoul2 , mod_a , blist , " rfemurYZ " , pcjflags | RAG_BONE_LIGHTWEIGHT , ( 6.0f * sRadLeg ) * fRadScale , pcjMin , pcjMax , 500 ) ;
VectorSet ( pcjMin , - 60.0f , - 5.0f , - 20.0f ) ;
VectorSet ( pcjMax , 50.0f , 50.0f , 20.0f ) ;
VectorScale ( pcjMin , sFactLeg , pcjMin ) ;
VectorScale ( pcjMax , sFactLeg , pcjMax ) ;
G2_Set_Bone_Angles_Rag ( ghoul2 , mod_a , blist , " lfemurYZ " , pcjflags | RAG_BONE_LIGHTWEIGHT , ( 6.0f * sRadLeg ) * fRadScale , pcjMin , pcjMax , 500 ) ;
VectorSet ( pcjMin , - 20.0f , - 15.0f , - 15.0f ) ;
VectorSet ( pcjMax , 100.0f , 15.0f , 15.0f ) ;
VectorScale ( pcjMin , sFactLeg , pcjMin ) ;
VectorScale ( pcjMax , sFactLeg , pcjMax ) ;
G2_Set_Bone_Angles_Rag ( ghoul2 , mod_a , blist , " rtibia " , pcjflags | RAG_EFFECTOR | RAG_BONE_LIGHTWEIGHT , ( 4.0f * sRadLeg ) * fRadScale , pcjMin , pcjMax , 500 ) ;
VectorSet ( pcjMin , 20.0f , - 15.0f , - 15.0f ) ;
VectorSet ( pcjMax , 100.0f , 15.0f , 15.0f ) ;
VectorScale ( pcjMin , sFactLeg , pcjMin ) ;
VectorScale ( pcjMax , sFactLeg , pcjMax ) ;
G2_Set_Bone_Angles_Rag ( ghoul2 , mod_a , blist , " ltibia " , pcjflags | RAG_EFFECTOR | RAG_BONE_LIGHTWEIGHT , ( 4.0f * sRadLeg ) * fRadScale , pcjMin , pcjMax , 500 ) ;
# else
// old base anim
int pcjflags = RAG_PCJ | RAG_PCJ_POST_MULT | RAG_EFFECTOR ;
VectorSet ( pcjMin , - 15.0f , - 15.0f , - 15.0f ) ;
VectorSet ( pcjMax , 45.0f , 15.0f , 15.0f ) ;
G2_Set_Bone_Angles_Rag ( ghoul2 , mod_a , blist , " lower_lumbar " , pcjflags , 10.0f , pcjMin , pcjMax , 500 ) ;
G2_Set_Bone_Angles_Rag ( ghoul2 , mod_a , blist , " upper_lumbar " , pcjflags , 10.0f , pcjMin , pcjMax , 500 ) ;
VectorSet ( pcjMin , - 45.0f , - 45.0f , - 45.0f ) ;
VectorSet ( pcjMax , 45.0f , 45.0f , 45.0f ) ;
G2_Set_Bone_Angles_Rag ( ghoul2 , mod_a , blist , " thoracic " , pcjflags , 10.0f , pcjMin , pcjMax , 500 ) ;
VectorSet ( pcjMin , - 10.0f , - 10.0f , - 90.0f ) ;
VectorSet ( pcjMax , 10.0f , 10.0f , 90.0f ) ;
G2_Set_Bone_Angles_Rag ( ghoul2 , mod_a , blist , " cranium " , pcjflags | RAG_BONE_LIGHTWEIGHT , 6.0f , pcjMin , pcjMax , 500 ) ;
//VectorSet(pcjMin,-45.0f,-90.0f,-100.0f);
VectorSet ( pcjMin , - 180.0f , - 180.0f , - 100.0f ) ;
//VectorSet(pcjMax,60.0f,60.0f,45.0f);
VectorSet ( pcjMax , 180.0f , 180.0f , 45.0f ) ;
G2_Set_Bone_Angles_Rag ( ghoul2 , mod_a , blist , " rhumerus " , pcjflags | RAG_BONE_LIGHTWEIGHT , 4.0f , pcjMin , pcjMax , 500 ) ;
//VectorSet(pcjMin,-45.0f,-60.0f,-45.0f);
VectorSet ( pcjMin , - 180.0f , - 180.0f , - 100.0f ) ;
//VectorSet(pcjMax,60.0f,90.0f,100.0f);
VectorSet ( pcjMax , 180.0f , 180.0f , 100.0f ) ;
G2_Set_Bone_Angles_Rag ( ghoul2 , mod_a , blist , " lhumerus " , pcjflags | RAG_BONE_LIGHTWEIGHT , 4.0f , pcjMin , pcjMax , 500 ) ;
//-120/120
VectorSet ( pcjMin , - 120.0f , - 20.0f , - 20.0f ) ;
VectorSet ( pcjMax , 50.0f , 20.0f , - 20.0f ) ;
G2_Set_Bone_Angles_Rag ( ghoul2 , mod_a , blist , " rradius " , pcjflags | RAG_BONE_LIGHTWEIGHT , 3.0f , pcjMin , pcjMax , 500 ) ;
VectorSet ( pcjMin , - 120.0f , - 20.0f , - 20.0f ) ;
VectorSet ( pcjMax , 5.0f , 20.0f , - 20.0f ) ;
G2_Set_Bone_Angles_Rag ( ghoul2 , mod_a , blist , " lradius " , pcjflags | RAG_BONE_LIGHTWEIGHT , 3.0f , pcjMin , pcjMax , 500 ) ;
VectorSet ( pcjMin , - 90.0f , - 50.0f , - 20.0f ) ;
VectorSet ( pcjMax , 50.0f , 20.0f , 20.0f ) ;
G2_Set_Bone_Angles_Rag ( ghoul2 , mod_a , blist , " rfemurYZ " , pcjflags | RAG_BONE_LIGHTWEIGHT , 6.0f , pcjMin , pcjMax , 500 ) ;
VectorSet ( pcjMin , - 90.0f , - 20.0f , - 20.0f ) ;
VectorSet ( pcjMax , 50.0f , 50.0f , 20.0f ) ;
G2_Set_Bone_Angles_Rag ( ghoul2 , mod_a , blist , " lfemurYZ " , pcjflags | RAG_BONE_LIGHTWEIGHT , 6.0f , pcjMin , pcjMax , 500 ) ;
//120
VectorSet ( pcjMin , - 20.0f , - 15.0f , - 15.0f ) ;
VectorSet ( pcjMax , 120.0f , 15.0f , 15.0f ) ;
G2_Set_Bone_Angles_Rag ( ghoul2 , mod_a , blist , " rtibia " , pcjflags | RAG_EFFECTOR | RAG_BONE_LIGHTWEIGHT , 4.0f , pcjMin , pcjMax , 500 ) ;
VectorSet ( pcjMin , 20.0f , - 15.0f , - 15.0f ) ;
VectorSet ( pcjMax , 120.0f , 15.0f , 15.0f ) ;
G2_Set_Bone_Angles_Rag ( ghoul2 , mod_a , blist , " ltibia " , pcjflags | RAG_EFFECTOR | RAG_BONE_LIGHTWEIGHT , 4.0f , pcjMin , pcjMax , 500 ) ;
# endif
float sRadEArm = 1.2f ;
float sRadELeg = 1.2f ;
// int rhand=
G2_Set_Bone_Angles_Rag ( ghoul2 , mod_a , blist , " rhand " , RAG_EFFECTOR | RAG_BONE_LIGHTWEIGHT , ( 6.0f * sRadEArm ) * fRadScale ) ;
G2_Set_Bone_Angles_Rag ( ghoul2 , mod_a , blist , " lhand " , RAG_EFFECTOR | RAG_BONE_LIGHTWEIGHT , ( 6.0f * sRadEArm ) * fRadScale ) ;
//G2_Set_Bone_Angles_Rag(ghoul2, mod_a,blist,"rtarsal",RAG_EFFECTOR|RAG_BONE_LIGHTWEIGHT,(4.0f*sRadELeg)*fRadScale);
//G2_Set_Bone_Angles_Rag(ghoul2, mod_a,blist,"ltarsal",RAG_EFFECTOR|RAG_BONE_LIGHTWEIGHT,(4.0f*sRadELeg)*fRadScale);
// G2_Set_Bone_Angles_Rag(ghoul2, mod_a,blist,"rtibia",RAG_EFFECTOR|RAG_BONE_LIGHTWEIGHT,(4.0f*sRadELeg)*fRadScale);
// G2_Set_Bone_Angles_Rag(ghoul2, mod_a,blist,"ltibia",RAG_EFFECTOR|RAG_BONE_LIGHTWEIGHT,(4.0f*sRadELeg)*fRadScale);
G2_Set_Bone_Angles_Rag ( ghoul2 , mod_a , blist , " rtalus " , RAG_EFFECTOR | RAG_BONE_LIGHTWEIGHT , ( 4.0f * sRadELeg ) * fRadScale ) ;
G2_Set_Bone_Angles_Rag ( ghoul2 , mod_a , blist , " ltalus " , RAG_EFFECTOR | RAG_BONE_LIGHTWEIGHT , ( 4.0f * sRadELeg ) * fRadScale ) ;
G2_Set_Bone_Angles_Rag ( ghoul2 , mod_a , blist , " rradiusX " , RAG_EFFECTOR | RAG_BONE_LIGHTWEIGHT , ( 6.0f * sRadEArm ) * fRadScale ) ;
G2_Set_Bone_Angles_Rag ( ghoul2 , mod_a , blist , " lradiusX " , RAG_EFFECTOR | RAG_BONE_LIGHTWEIGHT , ( 6.0f * sRadEArm ) * fRadScale ) ;
G2_Set_Bone_Angles_Rag ( ghoul2 , mod_a , blist , " rfemurX " , RAG_EFFECTOR | RAG_BONE_LIGHTWEIGHT , ( 10.0f * sRadELeg ) * fRadScale ) ;
G2_Set_Bone_Angles_Rag ( ghoul2 , mod_a , blist , " lfemurX " , RAG_EFFECTOR | RAG_BONE_LIGHTWEIGHT , ( 10.0f * sRadELeg ) * fRadScale ) ;
//G2_Set_Bone_Angles_Rag(ghoul2, mod_a,blist,"ceyebrow",RAG_EFFECTOR|RAG_BONE_LIGHTWEIGHT,10.0f*fRadScale);
G2_Set_Bone_Angles_Rag ( ghoul2 , mod_a , blist , " ceyebrow " , RAG_EFFECTOR | RAG_BONE_LIGHTWEIGHT , 5.0f ) ;
//match the currrent animation
if ( ! G2_RagDollSetup ( ghoul2 , curTime , true , parms - > position , false ) )
{
assert ( ! " failed to add any rag bones " ) ;
return ;
}
G2_RagDollCurrentPosition ( ghoul2V , model , curTime , parms - > angles , parms - > position , parms - > scale ) ;
#if 0
if ( rhand > 0 )
{
boneInfo_t & bone = blist [ rhand ] ;
SRagEffector & e = ragEffectors [ bone . ragIndex ] ;
VectorCopy ( bone . originalOrigin , handPos ) ;
VectorCopy ( e . currentOrigin , handPos2 ) ;
}
# endif
int k ;
CRagDollUpdateParams fparms ;
VectorCopy ( parms - > position , fparms . position ) ;
VectorCopy ( parms - > angles , fparms . angles ) ;
VectorCopy ( parms - > scale , fparms . scale ) ;
VectorClear ( fparms . velocity ) ;
fparms . me = parms - > me ;
fparms . settleFrame = parms - > endFrame ;
//Guess I don't need to do this, do I?
G2_ConstructGhoulSkeleton ( ghoul2V , curTime , false , parms - > scale ) ;
vec3_t dPos ;
VectorCopy ( parms - > position , dPos ) ;
# ifdef _OLD_STYLE_SETTLE
dPos [ 2 ] - = 6 ;
# endif
for ( k = 0 ; k < /*10*/ 20 ; k + + )
{
G2_RagDollSettlePositionNumeroTrois ( ghoul2V , dPos , & fparms , curTime ) ;
G2_RagDollCurrentPosition ( ghoul2V , model , curTime , parms - > angles , dPos , parms - > scale ) ;
G2_RagDollMatchPosition ( ) ;
G2_RagDollSolve ( ghoul2V , model , 1.0f * ( 1.0f - k / 40.0f ) , curTime , dPos , false ) ;
}
}
void G2_SetRagDollBullet ( CGhoul2Info & ghoul2 , const vec3_t rayStart , const vec3_t hit )
{
if ( ! broadsword | | ! broadsword - > integer )
{
return ;
}
vec3_t shotDir ;
VectorSubtract ( hit , rayStart , shotDir ) ;
float len = VectorLength ( shotDir ) ;
if ( len < 1.0f )
{
return ;
}
float lenr = 1.0f / len ;
shotDir [ 0 ] * = lenr ;
shotDir [ 1 ] * = lenr ;
shotDir [ 2 ] * = lenr ;
bool firstOne = false ;
if ( broadsword_kickbones & & broadsword_kickbones - > integer )
{
int i ;
int magicFactor13 = 150.0f ; // squared radius multiplier for shot effects
boneInfo_v & blist = ghoul2 . mBlist ;
for ( i = blist . size ( ) - 1 ; i > = 0 ; i - - )
{
boneInfo_t & bone = blist [ i ] ;
if ( ( bone . flags & BONE_ANGLES_TOTAL ) )
{
if ( bone . flags & BONE_ANGLES_RAGDOLL )
{
if ( ! firstOne )
{
firstOne = true ;
#if 0
int curTime = G2API_GetTime ( 0 ) ;
const mdxaHeader_t * mod_a = G2_GetModA ( ghoul2 ) ;
int startFrame = 0 , endFrame = 0 ;
# if 1
TheGhoul2Wraith ( ) - > GetAnimFrames ( ghoul2 . mID , " unconsciousdeadflop01 " , startFrame , endFrame ) ;
if ( startFrame = = - 1 & & endFrame = = - 1 )
{ //A bad thing happened! Just use the hardcoded numbers even though they could be wrong.
startFrame = 3573 ;
endFrame = 3583 ;
assert ( 0 ) ;
}
G2_Set_Bone_Anim_No_BS ( mod_a , blist , " upper_lumbar " , startFrame , endFrame - 1 ,
BONE_ANIM_OVERRIDE_FREEZE | BONE_ANIM_BLEND ,
1.0f , curTime , float ( startFrame ) , 75 , 0 , true ) ;
G2_Set_Bone_Anim_No_BS ( mod_a , blist , " lfemurYZ " , startFrame , endFrame - 1 ,
BONE_ANIM_OVERRIDE_FREEZE | BONE_ANIM_BLEND ,
1.0f , curTime , float ( startFrame ) , 75 , 0 , true ) ;
G2_Set_Bone_Anim_No_BS ( mod_a , blist , " rfemurYZ " , startFrame , endFrame - 1 ,
BONE_ANIM_OVERRIDE_FREEZE | BONE_ANIM_BLEND ,
1.0f , curTime , float ( startFrame ) , 75 , 0 , true ) ;
# else
TheGhoul2Wraith ( ) - > GetAnimFrames ( ghoul2 . mID , " backdeadflop01 " , startFrame , endFrame ) ;
if ( startFrame = = - 1 & & endFrame = = - 1 )
{ //A bad thing happened! Just use the hardcoded numbers even though they could be wrong.
startFrame = 3581 ;
endFrame = 3592 ;
assert ( 0 ) ;
}
G2_Set_Bone_Anim_No_BS ( mod_a , blist , " upper_lumbar " , endFrame , startFrame + 1 ,
BONE_ANIM_OVERRIDE_FREEZE ,
- 1.0f , curTime , float ( endFrame - 1 ) , 50 , 0 , true ) ;
G2_Set_Bone_Anim_No_BS ( mod_a , blist , " lfemurYZ " , endFrame , startFrame + 1 ,
BONE_ANIM_OVERRIDE_FREEZE ,
- 1.0f , curTime , float ( endFrame - 1 ) , 50 , 0 , true ) ;
G2_Set_Bone_Anim_No_BS ( mod_a , blist , " rfemurYZ " , endFrame , startFrame + 1 ,
BONE_ANIM_OVERRIDE_FREEZE ,
- 1.0f , curTime , float ( endFrame - 1 ) , 50 , 0 , true ) ;
# endif
# endif
}
VectorCopy ( shotDir , bone . lastShotDir ) ;
vec3_t dir ;
VectorSubtract ( bone . lastPosition , hit , dir ) ;
len = VectorLength ( dir ) ;
if ( len < 1.0f )
{
len = 1.0f ;
}
lenr = 1.0f / len ;
float effect = lenr ;
effect * = magicFactor13 * effect ; // this is cubed, one of them is absorbed by the next calc
bone . velocityEffector [ 0 ] = shotDir [ 0 ] * ( effect + flrand ( 0.0f , 0.05f ) ) ;
bone . velocityEffector [ 1 ] = shotDir [ 1 ] * ( effect + flrand ( 0.0f , 0.05f ) ) ;
bone . velocityEffector [ 2 ] = fabs ( shotDir [ 2 ] ) * ( effect + flrand ( 0.0f , 0.05f ) ) ;
// bone.velocityEffector[0]=shotDir[0]*(effect+flrand(0.0f,0.05f))*flrand(-0.1f,3.0f);
// bone.velocityEffector[1]=shotDir[1]*(effect+flrand(0.0f,0.05f))*flrand(-0.1f,3.0f);
// bone.velocityEffector[2]=fabs(shotDir[2])*(effect+flrand(0.0f,0.05f))*flrand(-0.1f,3.0f);
assert ( ! _isnan ( shotDir [ 2 ] ) ) ;
// bone.currentAngles[0]+=flrand(-10.0f*lenr,10.0f*lenr);
// bone.currentAngles[1]+=flrand(-10.0f*lenr,10.0f*lenr);
// bone.currentAngles[2]+=flrand(-10.0f*lenr,10.0f*lenr);
// bone.lastAngles[0]+=flrand(-10.0f*lenr,10.0f*lenr);
// bone.lastAngles[1]+=flrand(-10.0f*lenr,10.0f*lenr);
// bone.lastAngles[2]+=flrand(-10.0f*lenr,10.0f*lenr);
// go dynamic
bone . firstCollisionTime = G2API_GetTime ( 0 ) ;
// bone.firstCollisionTime=0;
bone . restTime = 0 ;
}
}
}
}
}
static float G2_RagSetState ( CGhoul2Info & ghoul2 , boneInfo_t & bone , int frameNum , const vec3_t origin , bool & resetOrigin )
{
ragOriginChange = DistanceSquared ( origin , bone . extraVec1 ) ;
VectorSubtract ( origin , bone . extraVec1 , ragOriginChangeDir ) ;
float decay = 1.0f ;
int dynamicTime = 1000 ;
int settleTime = 1000 ;
if ( ghoul2 . mFlags & GHOUL2_RAG_FORCESOLVE )
{
ragState = ERS_DYNAMIC ;
if ( frameNum > bone . firstCollisionTime + dynamicTime )
{
VectorCopy ( origin , bone . extraVec1 ) ;
if ( ragOriginChange > 15.0f )
{ //if we moved, or if this bone is still in solid
bone . firstCollisionTime = frameNum ;
}
else
{
// settle out
bone . firstCollisionTime = 0 ;
bone . restTime = frameNum ;
ragState = ERS_SETTLING ;
}
}
}
else if ( bone . firstCollisionTime > 0 )
{
ragState = ERS_DYNAMIC ;
if ( frameNum > bone . firstCollisionTime + dynamicTime )
{
VectorCopy ( origin , bone . extraVec1 ) ;
if ( ragOriginChange > 15.0f )
{ //if we moved, or if this bone is still in solid
bone . firstCollisionTime = frameNum ;
}
else
{
// settle out
bone . firstCollisionTime = 0 ;
bone . restTime = frameNum ;
ragState = ERS_SETTLING ;
}
}
//decay=0.0f;
}
else if ( bone . restTime > 0 )
{
decay = 1.0f - ( frameNum - bone . restTime ) / float ( dynamicTime ) ;
if ( decay < 0.0f )
{
decay = 0.0f ;
}
if ( decay > 1.0f )
{
decay = 1.0f ;
}
float magicFactor8 = 1.0f ; // Power for decay
decay = pow ( decay , magicFactor8 ) ;
ragState = ERS_SETTLING ;
if ( frameNum > bone . restTime + settleTime )
{
VectorCopy ( origin , bone . extraVec1 ) ;
if ( ragOriginChange > 15.0f )
{
bone . restTime = frameNum ;
}
else
{
// stop
bone . restTime = 0 ;
ragState = ERS_SETTLED ;
}
}
//decay=0.0f;
}
else
{
if ( bone . RagFlags & RAG_PCJ_IK_CONTROLLED )
{
bone . firstCollisionTime = frameNum ;
ragState = ERS_DYNAMIC ;
}
else if ( ragOriginChange > 15.0f )
{
bone . firstCollisionTime = frameNum ;
ragState = ERS_DYNAMIC ;
}
else
{
ragState = ERS_SETTLED ;
}
decay = 0.0f ;
}
// ragState=ERS_SETTLED;
// decay=0.0f;
return decay ;
}
static bool G2_RagDollSetup ( CGhoul2Info & ghoul2 , int frameNum , bool resetOrigin , const vec3_t origin , bool anyRendered )
{
int i ;
int minSurvivingBone = 10000 ;
int minSurvivingBoneAt = - 1 ;
int minSurvivingBoneAlt = 10000 ;
int minSurvivingBoneAtAlt = - 1 ;
assert ( ghoul2 . mFileName [ 0 ] ) ;
boneInfo_v & blist = ghoul2 . mBlist ;
rag . clear ( ) ;
int numRendered = 0 ;
int numNotRendered = 0 ;
int pelvisAt = - 1 ;
for ( i = 0 ; i < blist . size ( ) ; i + + )
{
boneInfo_t & bone = blist [ i ] ;
if ( bone . boneNumber > = 0 )
{
assert ( bone . boneNumber < MAX_BONES_RAG ) ;
if ( ( bone . flags & BONE_ANGLES_RAGDOLL ) | | ( bone . flags & BONE_ANGLES_IK ) )
{
//rww - this was (!anyRendered) before. Isn't that wrong? (if anyRendered, then wasRendered should be true)
bool wasRendered =
( ! anyRendered ) | | // offscreeen or something
G2_WasBoneRendered ( ghoul2 , bone . boneNumber ) ;
if ( ! wasRendered )
{
bone . RagFlags | = RAG_WAS_NOT_RENDERED ;
numNotRendered + + ;
}
else
{
bone . RagFlags & = ~ RAG_WAS_NOT_RENDERED ;
bone . RagFlags | = RAG_WAS_EVER_RENDERED ;
numRendered + + ;
}
if ( bone . RagFlags & RAG_PCJ_PELVIS )
{
pelvisAt = i ;
}
else if ( bone . RagFlags & RAG_PCJ_MODEL_ROOT )
{
}
else if ( wasRendered & & ( bone . RagFlags & RAG_PCJ ) )
{
if ( minSurvivingBone > bone . boneNumber )
{
minSurvivingBone = bone . boneNumber ;
minSurvivingBoneAt = i ;
}
}
else if ( wasRendered )
{
if ( minSurvivingBoneAlt > bone . boneNumber )
{
minSurvivingBoneAlt = bone . boneNumber ;
minSurvivingBoneAtAlt = i ;
}
}
if (
anyRendered & &
( bone . RagFlags & RAG_WAS_EVER_RENDERED ) & &
! ( bone . RagFlags & RAG_PCJ_MODEL_ROOT ) & &
! ( bone . RagFlags & RAG_PCJ_PELVIS ) & &
! wasRendered & &
( bone . RagFlags & RAG_EFFECTOR )
)
{
// this thing was rendered in the past, but wasn't now, although other bones were, lets get rid of it
// bone.flags &= ~BONE_ANGLES_RAGDOLL;
// bone.RagFlags = 0;
//OutputDebugString(va("Deleted Effector %d\n",i));
// continue;
}
if ( rag . size ( ) < bone . boneNumber + 1 )
{
rag . resize ( bone . boneNumber + 1 , 0 ) ;
}
rag [ bone . boneNumber ] = & bone ;
ragBlistIndex [ bone . boneNumber ] = i ;
bone . lastTimeUpdated = frameNum ;
if ( resetOrigin )
{
VectorCopy ( origin , bone . extraVec1 ) ; // this is only done incase a limb is removed
}
}
}
}
#if 0
if ( numRendered < 5 ) // I think this is a limb
{
//OutputDebugString(va("limb %3d/%3d (r,N).\n",numRendered,numNotRendered));
if ( minSurvivingBoneAt < 0 )
{
// pelvis is gone, but we have no remaining pcj's
// just find any remain rag effector
minSurvivingBoneAt = minSurvivingBoneAtAlt ;
}
if (
minSurvivingBoneAt > = 0 & &
pelvisAt > = 0 )
{
{
// remove the pelvis as a rag
boneInfo_t & bone = blist [ minSurvivingBoneAt ] ;
bone . flags & = ~ BONE_ANGLES_RAGDOLL ;
bone . RagFlags = 0 ;
}
{
// the root-est bone is now our "pelvis
boneInfo_t & bone = blist [ minSurvivingBoneAt ] ;
VectorSet ( bone . minAngles , - 14500.0f , - 14500.0f , - 14500.0f ) ;
VectorSet ( bone . maxAngles , 14500.0f , 14500.0f , 14500.0f ) ;
bone . RagFlags | = RAG_PCJ_PELVIS | RAG_PCJ ; // this guy is our new "pelvis"
bone . flags | = BONE_ANGLES_POSTMULT ;
bone . ragStartTime = G2API_GetTime ( 0 ) ;
}
}
}
# endif
numRags = 0 ;
int ragStartTime = 0 ;
for ( i = 0 ; i < rag . size ( ) ; i + + )
{
if ( rag [ i ] )
{
boneInfo_t & bone = * rag [ i ] ;
assert ( bone . boneNumber > = 0 ) ;
assert ( numRags < MAX_BONES_RAG ) ;
ragStartTime = bone . ragStartTime ;
bone . ragIndex = numRags ;
ragBoneData [ numRags ] = & bone ;
ragEffectors [ numRags ] . radius = bone . radius ;
ragEffectors [ numRags ] . weight = bone . weight ;
G2_GetBoneBasepose ( ghoul2 , bone . boneNumber , bone . basepose , bone . baseposeInv ) ;
numRags + + ;
}
}
if ( ! numRags )
{
return false ;
}
return true ;
}
static void G2_RagDoll ( CGhoul2Info_v & ghoul2V , int g2Index , CRagDollUpdateParams * params , int curTime )
{
int i ;
if ( ! broadsword | | ! broadsword - > integer )
{
return ;
}
if ( ! params )
{
assert ( 0 ) ;
return ;
}
vec3_t dPos ;
VectorCopy ( params - > position , dPos ) ;
# ifdef _OLD_STYLE_SETTLE
dPos [ 2 ] - = 6 ;
# endif
// params->DebugLine(handPos,handPos2,false);
int frameNum = G2API_GetTime ( 0 ) ;
CGhoul2Info & ghoul2 = ghoul2V [ g2Index ] ;
assert ( ghoul2 . mFileName [ 0 ] ) ;
boneInfo_v & blist = ghoul2 . mBlist ;
// hack for freezing ragdoll (no idea if it works)
#if 0
if ( 0 )
{
// we gotta hack this to basically freeze the timers
for ( i = 0 ; i < blist . size ( ) ; i + + )
{
boneInfo_t & bone = blist [ i ] ;
if ( bone . boneNumber > = 0 )
{
assert ( bone . boneNumber < MAX_BONES_RAG ) ;
if ( bone . flags & BONE_ANGLES_RAGDOLL )
{
bone . ragStartTime + = 50 ;
if ( bone . firstTime )
{
bone . firstTime + = 50 ;
}
if ( bone . firstCollisionTime )
{
bone . firstCollisionTime + = 50 ;
}
if ( bone . restTime )
{
bone . restTime + = 50 ;
}
}
}
}
return ;
}
# endif
float decay = 1.0f ;
bool resetOrigin = false ;
bool anyRendered = false ;
// this loop checks for settled
for ( i = 0 ; i < blist . size ( ) ; i + + )
{
boneInfo_t & bone = blist [ i ] ;
if ( bone . boneNumber > = 0 )
{
assert ( bone . boneNumber < MAX_BONES_RAG ) ;
if ( bone . flags & BONE_ANGLES_RAGDOLL )
{
// check for state transitions
decay = G2_RagSetState ( ghoul2 , bone , frameNum , dPos , resetOrigin ) ; // set the current state
if ( ragState = = ERS_SETTLED )
{
#if 0
bool noneInSolid = true ;
//first iterate through and make sure no bones are still in solid a lot
for ( int j = 0 ; j < blist . size ( ) ; j + + )
{
boneInfo_t & bone2 = blist [ j ] ;
if ( bone2 . boneNumber > = 0 & & bone2 . solidCount > 8 )
{
noneInSolid = false ;
break ;
}
}
if ( noneInSolid )
{ //we're settled then
params - > RagDollSettled ( ) ;
return ;
}
else
{
continue ;
}
# else
params - > RagDollSettled ( ) ;
return ;
# endif
}
if ( G2_WasBoneRendered ( ghoul2 , bone . boneNumber ) )
{
anyRendered = true ;
break ;
}
}
}
}
//int iters=(ragState==ERS_DYNAMIC)?2:1;
int iters = ( ragState = = ERS_DYNAMIC ) ? 4 : 2 ;
bool kicked = false ;
if ( ragOriginChangeDir [ 2 ] < - 100.0f )
{
kicked = true ;
//iters*=8;
iters * = 2 ; //rww - changed to this.. it was getting up to around 600 traces at times before (which is insane)
}
if ( iters )
{
if ( ! G2_RagDollSetup ( ghoul2 , frameNum , resetOrigin , dPos , anyRendered ) )
{
return ;
}
// ok, now our data structures are compact and set up in topological order
for ( i = 0 ; i < iters ; i + + )
{
G2_RagDollCurrentPosition ( ghoul2V , g2Index , frameNum , params - > angles , dPos , params - > scale ) ;
if ( G2_RagDollSettlePositionNumeroTrois ( ghoul2V , dPos , params , curTime ) )
{
#if 0
//effectors are start solid alot, so this was pretty extreme
if ( ! kicked & & iters < 4 )
{
kicked = true ;
//iters*=4;
iters * = 2 ;
}
# endif
}
//params->position[2] += 16;
G2_RagDollSolve ( ghoul2V , g2Index , decay * 2.0f , frameNum , dPos , true , params ) ;
}
}
if ( params - > me ! = ENTITYNUM_NONE )
{
#if 0
vec3_t worldMins , worldMaxs ;
worldMins [ 0 ] = params - > position [ 0 ] - 17 ;
worldMins [ 1 ] = params - > position [ 1 ] - 17 ;
worldMins [ 2 ] = params - > position [ 2 ] ;
worldMaxs [ 0 ] = params - > position [ 0 ] + 17 ;
worldMaxs [ 1 ] = params - > position [ 1 ] + 17 ;
worldMaxs [ 2 ] = params - > position [ 2 ] ;
//OutputDebugString(va("%f \n",worldMins[2]));
// params->DebugLine(worldMins,worldMaxs,true);
# endif
G2_RagDollCurrentPosition ( ghoul2V , g2Index , frameNum , params - > angles , params - > position , params - > scale ) ;
// SV_UnlinkEntity(params->me);
// params->me->SetMins(BB_SHOOTING_SIZE,ragBoneMins);
// params->me->SetMaxs(BB_SHOOTING_SIZE,ragBoneMaxs);
// SV_LinkEntity(params->me);
}
}
# ifdef _DEBUG
# define _DEBUG_BONE_NAMES
# endif
static inline char * G2_Get_Bone_Name ( CGhoul2Info * ghlInfo , boneInfo_v & blist , int boneNum )
{
int i ;
mdxaSkel_t * skel ;
mdxaSkelOffsets_t * offsets ;
offsets = ( mdxaSkelOffsets_t * ) ( ( byte * ) ghlInfo - > aHeader + sizeof ( mdxaHeader_t ) ) ;
skel = ( mdxaSkel_t * ) ( ( byte * ) ghlInfo - > aHeader + 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 ! = boneNum )
{
continue ;
}
// figure out what skeletal info structure this bone entry is looking at
skel = ( mdxaSkel_t * ) ( ( byte * ) ghlInfo - > aHeader + sizeof ( mdxaHeader_t ) + offsets - > offsets [ blist [ i ] . boneNumber ] ) ;
return skel - > name ;
}
// didn't find it
return " BONE_NOT_FOUND " ;
}
char * G2_GetBoneNameFromSkel ( CGhoul2Info & ghoul2 , int boneNum ) ;
static void G2_RagDollCurrentPosition ( CGhoul2Info_v & ghoul2V , int g2Index , int frameNum , const vec3_t angles , const vec3_t position , const vec3_t scale )
{
CGhoul2Info & ghoul2 = ghoul2V [ g2Index ] ;
assert ( ghoul2 . mFileName [ 0 ] ) ;
//OutputDebugString(va("angles %f %f %f\n",angles[0],angles[1],angles[2]));
G2_GenerateWorldMatrix ( angles , position ) ;
G2_ConstructGhoulSkeleton ( ghoul2V , frameNum , false , scale ) ;
float totalWt = 0.0f ;
int i ;
for ( i = 0 ; i < numRags ; i + + )
{
boneInfo_t & bone = * ragBoneData [ i ] ;
G2_GetBoneMatrixLow ( ghoul2 , bone . boneNumber , scale , ragBones [ i ] , ragBasepose [ i ] , ragBaseposeInv [ i ] ) ;
# ifdef _DEBUG_BONE_NAMES
char * debugBoneName = G2_Get_Bone_Name ( & ghoul2 , ghoul2 . mBlist , bone . boneNumber ) ;
assert ( debugBoneName ) ;
# endif
int k ;
//float cmweight=ragEffectors[numRags].weight;
float cmweight = 1.0f ;
for ( k = 0 ; k < 3 ; k + + )
{
ragEffectors [ i ] . currentOrigin [ k ] = ragBones [ i ] . matrix [ k ] [ 3 ] ;
assert ( ! _isnan ( ragEffectors [ i ] . currentOrigin [ k ] ) ) ;
if ( ! i )
{
// set mins, maxs and cm
ragBoneCM [ k ] = ragEffectors [ i ] . currentOrigin [ k ] * cmweight ;
ragBoneMaxs [ k ] = ragEffectors [ i ] . currentOrigin [ k ] ;
ragBoneMins [ k ] = ragEffectors [ i ] . currentOrigin [ k ] ;
}
else
{
ragBoneCM [ k ] + = ragEffectors [ i ] . currentOrigin [ k ] * ragEffectors [ i ] . weight ;
if ( ragEffectors [ i ] . currentOrigin [ k ] > ragBoneMaxs [ k ] )
{
ragBoneMaxs [ k ] = ragEffectors [ i ] . currentOrigin [ k ] ;
}
if ( ragEffectors [ i ] . currentOrigin [ k ] < ragBoneMins [ k ] )
{
ragBoneMins [ k ] = ragEffectors [ i ] . currentOrigin [ k ] ;
}
}
}
totalWt + = cmweight ;
}
assert ( totalWt > 0.0f ) ;
int k ;
{
float wtInv = 1.0f / totalWt ;
for ( k = 0 ; k < 3 ; k + + )
{
ragBoneMaxs [ k ] - = position [ k ] ;
ragBoneMins [ k ] - = position [ k ] ;
ragBoneMaxs [ k ] + = 10.0f ;
ragBoneMins [ k ] - = 10.0f ;
ragBoneCM [ k ] * = wtInv ;
ragBoneCM [ k ] = ragEffectors [ 0 ] . currentOrigin [ k ] ; // use the pelvis
}
}
}
# ifdef _DEBUG
int ragTraceTime = 0 ;
int ragSSCount = 0 ;
int ragTraceCount = 0 ;
# endif
void Rag_Trace ( trace_t * results , const vec3_t start , const vec3_t mins , const vec3_t maxs , const vec3_t end , const int passEntityNum , const int contentmask , const EG2_Collision eG2TraceType , const int useLod )
{
# ifdef _DEBUG
int ragPreTrace = Sys_Milliseconds ( ) ;
# endif
# ifndef DEDICATED
if ( cgvm )
{
ragCallbackTraceLine_t * callData = ( ragCallbackTraceLine_t * ) cl . mSharedMemory ;
VectorCopy ( start , callData - > start ) ;
VectorCopy ( end , callData - > end ) ;
VectorCopy ( mins , callData - > mins ) ;
VectorCopy ( maxs , callData - > maxs ) ;
callData - > ignore = passEntityNum ;
callData - > mask = contentmask ;
VM_Call ( cgvm , CG_RAG_CALLBACK , RAG_CALLBACK_TRACELINE ) ;
* results = callData - > tr ;
}
else
# endif // !DEDICATED
{
results - > entityNum = ENTITYNUM_NONE ;
//SV_Trace(results, start, mins, maxs, end, passEntityNum, contentmask, eG2TraceType, useLod);
CM_BoxTrace ( results , start , end , mins , maxs , 0 , contentmask , 0 ) ;
results - > entityNum = results - > fraction ! = 1.0 ? ENTITYNUM_WORLD : ENTITYNUM_NONE ;
}
# ifdef _DEBUG
int ragPostTrace = Sys_Milliseconds ( ) ;
ragTraceTime + = ( ragPostTrace - ragPreTrace ) ;
if ( results - > startsolid )
{
ragSSCount + + ;
}
ragTraceCount + + ;
# endif
}
//run advanced physics on each bone indivudually
//an adaption of my "exphys" custom game physics model
# define MAX_GRAVITY_PULL 256 //512
static inline bool G2_BoneOnGround ( const vec3_t org , const vec3_t mins , const vec3_t maxs , const int ignoreNum )
{
trace_t tr ;
vec3_t gSpot ;
VectorCopy ( org , gSpot ) ;
gSpot [ 2 ] - = 1.0f ; //seems reasonable to me
Rag_Trace ( & tr , org , mins , maxs , gSpot , ignoreNum , RAG_MASK , G2_NOCOLLIDE , 0 ) ;
if ( tr . fraction ! = 1.0f & & ! tr . startsolid & & ! tr . allsolid )
{ //not in solid, and hit something. Guess it's ground.
return true ;
}
return false ;
}
static inline bool G2_ApplyRealBonePhysics ( boneInfo_t & bone , SRagEffector & e , CRagDollUpdateParams * params , vec3_t goalSpot , const vec3_t testMins , const vec3_t testMaxs ,
const float gravity , const float mass , const float bounce )
{
trace_t tr ;
vec3_t projectedOrigin ;
vec3_t vNorm ;
vec3_t ground ;
float velScaling = 0.1f ;
float vTotal = 0.0f ;
bool boneOnGround = false ;
assert ( mass < = 1.0f & & mass > = 0.01f ) ;
if ( bone . physicsSettled )
{ //then we have no need to continue
return true ;
}
if ( gravity )
{ //factor it in before we do anything.
VectorCopy ( e . currentOrigin , ground ) ;
ground [ 2 ] - = 1.0f ;
Rag_Trace ( & tr , e . currentOrigin , testMins , testMaxs , ground , params - > me , RAG_MASK , G2_NOCOLLIDE , 0 ) ;
if ( tr . entityNum = = ENTITYNUM_NONE )
{
boneOnGround = false ;
}
else
{
boneOnGround = true ;
}
if ( ! boneOnGround )
{
if ( ! params - > velocity [ 2 ] )
{ //only increase gravitational pull once the actual entity is still
bone . epGravFactor + = gravity ;
}
if ( bone . epGravFactor > MAX_GRAVITY_PULL )
{ //cap it off if needed
bone . epGravFactor = MAX_GRAVITY_PULL ;
}
bone . epVelocity [ 2 ] - = bone . epGravFactor ;
}
else
{ //if we're sitting on something then reset the gravity factor.
bone . epGravFactor = 0 ;
}
}
else
{
boneOnGround = G2_BoneOnGround ( e . currentOrigin , testMins , testMaxs , params - > me ) ;
}
if ( ! bone . epVelocity [ 0 ] & & ! bone . epVelocity [ 1 ] & & ! bone . epVelocity [ 2 ] )
{ //nothing to do if we have no velocity even after gravity.
VectorCopy ( e . currentOrigin , goalSpot ) ;
return true ;
}
//get the projected origin based on velocity.
VectorMA ( e . currentOrigin , velScaling , bone . epVelocity , projectedOrigin ) ;
//scale it down based on mass
VectorScale ( bone . epVelocity , 1.0f - mass , bone . epVelocity ) ;
VectorCopy ( bone . epVelocity , vNorm ) ;
vTotal = VectorNormalize ( vNorm ) ;
if ( vTotal < 1 & & boneOnGround )
{ //we've pretty much stopped moving anyway, just clear it out then.
VectorClear ( bone . epVelocity ) ;
bone . epGravFactor = 0 ;
VectorCopy ( e . currentOrigin , goalSpot ) ;
return true ;
}
Rag_Trace ( & tr , e . currentOrigin , testMins , testMaxs , projectedOrigin , params - > me , RAG_MASK , G2_NOCOLLIDE , 0 ) ;
if ( tr . startsolid | | tr . allsolid )
{ //can't go anywhere from here
return false ;
}
//Go ahead and set it to the trace endpoint regardless of what it hit
VectorCopy ( tr . endpos , goalSpot ) ;
if ( tr . fraction = = 1.0f )
{ //Nothing was in the way.
return true ;
}
if ( bounce )
{
vTotal * = bounce ; //scale it by bounce
VectorScale ( tr . plane . normal , vTotal , vNorm ) ; //scale the trace plane normal by the bounce factor
if ( vNorm [ 2 ] > 0 )
{
bone . epGravFactor - = vNorm [ 2 ] * ( 1.0f - mass ) ; //The lighter it is the more gravity will be reduced by bouncing vertically.
if ( bone . epGravFactor < 0 )
{
bone . epGravFactor = 0 ;
}
}
VectorAdd ( bone . epVelocity , vNorm , bone . epVelocity ) ; //add it into the existing velocity.
//I suppose it could be sort of neat to make a game callback here to actual do stuff
//when bones slam into things. But it could be slow too.
/*
if ( tr . entityNum ! = ENTITYNUM_NONE & & ent - > touch )
{ //then call the touch function
ent - > touch ( ent , & g_entities [ tr . entityNum ] , & tr ) ;
}
*/
}
else
{ //if no bounce, kill when it hits something.
bone . epVelocity [ 0 ] = 0 ;
bone . epVelocity [ 1 ] = 0 ;
if ( ! gravity )
{
bone . epVelocity [ 2 ] = 0 ;
}
}
return true ;
}
# ifdef _DEBUG_BONE_NAMES
static inline void G2_RagDebugBox ( vec3_t mins , vec3_t maxs , int duration )
{
# ifdef DEDICATED
return ;
# else
if ( ! cgvm )
{
return ;
}
ragCallbackDebugBox_t * callData = ( ragCallbackDebugBox_t * ) cl . mSharedMemory ;
callData - > duration = duration ;
VectorCopy ( mins , callData - > mins ) ;
VectorCopy ( maxs , callData - > maxs ) ;
VM_Call ( cgvm , CG_RAG_CALLBACK , RAG_CALLBACK_DEBUGBOX ) ;
# endif
}
static inline void G2_RagDebugLine ( vec3_t start , vec3_t end , int time , int color , int radius )
{
# ifdef DEDICATED
return ;
# else
if ( ! cgvm )
{
return ;
}
ragCallbackDebugLine_t * callData = ( ragCallbackDebugLine_t * ) cl . mSharedMemory ;
VectorCopy ( start , callData - > start ) ;
VectorCopy ( end , callData - > end ) ;
callData - > time = time ;
callData - > color = color ;
callData - > radius = radius ;
VM_Call ( cgvm , CG_RAG_CALLBACK , RAG_CALLBACK_DEBUGLINE ) ;
# endif // !DEDICATED
}
# endif
# ifdef _OLD_STYLE_SETTLE
static bool G2_RagDollSettlePositionNumeroTrois ( CGhoul2Info_v & ghoul2V , const vec3_t currentOrg , CRagDollUpdateParams * params , int curTime )
{
haveDesiredPelvisOffset = false ;
vec3_t desiredPos ;
int i ;
assert ( params ) ;
//assert(params->me); //no longer valid, because me is an index!
int ignoreNum = params - > me ;
bool anyStartSolid = false ;
vec3_t groundSpot = { 0 , 0 , 0 } ;
// lets find the floor at our quake origin
{
vec3_t testStart ;
VectorCopy ( currentOrg , testStart ) ; //last arg is dest
vec3_t testEnd ;
VectorCopy ( testStart , testEnd ) ; //last arg is dest
testEnd [ 2 ] - = 200.0f ;
vec3_t testMins ;
vec3_t testMaxs ;
VectorSet ( testMins , - 10 , - 10 , - 10 ) ;
VectorSet ( testMaxs , 10 , 10 , 10 ) ;
{
trace_t tr ;
assert ( ! _isnan ( testStart [ 1 ] ) ) ;
assert ( ! _isnan ( testEnd [ 1 ] ) ) ;
assert ( ! _isnan ( testMins [ 1 ] ) ) ;
assert ( ! _isnan ( testMaxs [ 1 ] ) ) ;
Rag_Trace ( & tr , testStart , testMins , testMaxs , testEnd , ignoreNum , RAG_MASK , G2_NOCOLLIDE , 0 /*SV_TRACE_NO_PLAYER*/ ) ;
if ( tr . entityNum = = 0 )
{
VectorAdvance ( testStart , .5f , testEnd , tr . endpos ) ;
}
if ( tr . startsolid )
{
//hmmm, punt
VectorCopy ( currentOrg , groundSpot ) ; //last arg is dest
groundSpot [ 2 ] - = 30.0f ;
}
else
{
VectorCopy ( tr . endpos , groundSpot ) ; //last arg is dest
}
}
}
for ( i = 0 ; i < numRags ; i + + )
{
boneInfo_t & bone = * ragBoneData [ i ] ;
SRagEffector & e = ragEffectors [ i ] ;
if ( bone . RagFlags & RAG_PCJ_PELVIS )
{
// just move to quake origin
VectorCopy ( currentOrg , desiredPos ) ;
//desiredPos[2]-=35.0f;
desiredPos [ 2 ] - = 20.0f ;
//old deathflop desiredPos[2]-=40.0f;
VectorSubtract ( desiredPos , e . currentOrigin , desiredPelvisOffset ) ; // last arg is dest
haveDesiredPelvisOffset = true ;
VectorCopy ( e . currentOrigin , bone . lastPosition ) ; // last arg is dest
continue ;
}
if ( ! ( bone . RagFlags & RAG_EFFECTOR ) )
{
continue ;
}
vec3_t testMins ;
vec3_t testMaxs ;
VectorSet ( testMins , - e . radius , - e . radius , - e . radius ) ;
VectorSet ( testMaxs , e . radius , e . radius , e . radius ) ;
// first we will see if we are start solid
// if so, we are gonna run some bonus iterations
bool iAmStartSolid = false ;
vec3_t testStart ;
VectorCopy ( e . currentOrigin , testStart ) ; //last arg is dest
testStart [ 2 ] + = 12.0f ; // we are no so concerned with minor penetration
vec3_t testEnd ;
VectorCopy ( testStart , testEnd ) ; //last arg is dest
testEnd [ 2 ] - = 8.0f ;
assert ( ! _isnan ( testStart [ 1 ] ) ) ;
assert ( ! _isnan ( testEnd [ 1 ] ) ) ;
assert ( ! _isnan ( testMins [ 1 ] ) ) ;
assert ( ! _isnan ( testMaxs [ 1 ] ) ) ;
float vertEffectorTraceFraction = 0.0f ;
{
trace_t tr ;
Rag_Trace ( & tr , testStart , testMins , testMaxs , testEnd , ignoreNum , RAG_MASK , G2_NOCOLLIDE , 0 ) ;
if ( tr . entityNum = = 0 )
{
VectorAdvance ( testStart , .5f , testEnd , tr . endpos ) ;
}
if ( tr . startsolid )
{
// above the origin, so lets try lower
if ( e . currentOrigin [ 2 ] > groundSpot [ 2 ] )
{
testStart [ 2 ] = groundSpot [ 2 ] + ( e . radius - 10.0f ) ;
}
else
{
// lets try higher
testStart [ 2 ] = groundSpot [ 2 ] + 8.0f ;
Rag_Trace ( & tr , testStart , testMins , testMaxs , testEnd , ignoreNum , RAG_MASK , G2_NOCOLLIDE , 0 ) ;
if ( tr . entityNum = = 0 )
{
VectorAdvance ( testStart , .5f , testEnd , tr . endpos ) ;
}
}
}
if ( tr . startsolid )
{
iAmStartSolid = true ;
anyStartSolid = true ;
// above the origin, so lets slide away
if ( e . currentOrigin [ 2 ] > groundSpot [ 2 ] )
{
if ( params )
{
//SRagDollEffectorCollision args(e.currentOrigin,tr);
//params->EffectorCollision(args);
# ifndef DEDICATED
if ( cgvm )
{ //make a callback and see if the cgame wants to help us out
ragCallbackBoneInSolid_t * callData = ( ragCallbackBoneInSolid_t * ) cl . mSharedMemory ;
VectorCopy ( e . currentOrigin , callData - > bonePos ) ;
callData - > entNum = params - > me ;
callData - > solidCount = bone . solidCount ;
VM_Call ( cgvm , CG_RAG_CALLBACK , RAG_CALLBACK_BONEINSOLID ) ;
}
# endif
}
}
else
{
//harumph, we are really screwed
}
}
else
{
vertEffectorTraceFraction = tr . fraction ;
if ( params & &
vertEffectorTraceFraction < .95f & &
fabsf ( tr . plane . normal [ 2 ] ) < .707f )
{
//SRagDollEffectorCollision args(e.currentOrigin,tr);
//args.useTracePlane=true;
//params->EffectorCollision(args);
# ifndef DEDICATED
if ( cgvm )
{ //make a callback and see if the cgame wants to help us out
ragCallbackBoneInSolid_t * callData = ( ragCallbackBoneInSolid_t * ) cl . mSharedMemory ;
VectorCopy ( e . currentOrigin , callData - > bonePos ) ;
callData - > entNum = params - > me ;
callData - > solidCount = bone . solidCount ;
VM_Call ( cgvm , CG_RAG_CALLBACK , RAG_CALLBACK_BONEINSOLID ) ;
}
# endif
}
}
}
vec3_t effectorGroundSpot ;
VectorAdvance ( testStart , vertEffectorTraceFraction , testEnd , effectorGroundSpot ) ; // VA(a,t,b,c)-> c := (1-t)a+tb
// trace from the quake origin horzontally to the effector
// gonna choose the maximum of the ground spot or the effector location
// and clamp it to be roughly in the bbox
VectorCopy ( groundSpot , testStart ) ; //last arg is dest
if ( iAmStartSolid )
{
// we don't have a meaningful ground spot
VectorCopy ( e . currentOrigin , testEnd ) ; //last arg is dest
bone . solidCount + + ;
}
else
{
VectorCopy ( effectorGroundSpot , testEnd ) ; //last arg is dest
bone . solidCount = 0 ;
}
assert ( ! _isnan ( testStart [ 1 ] ) ) ;
assert ( ! _isnan ( testEnd [ 1 ] ) ) ;
assert ( ! _isnan ( testMins [ 1 ] ) ) ;
assert ( ! _isnan ( testMaxs [ 1 ] ) ) ;
float ztest ;
if ( testEnd [ 2 ] > testStart [ 2 ] )
{
ztest = testEnd [ 2 ] ;
}
else
{
ztest = testStart [ 2 ] ;
}
if ( ztest < currentOrg [ 2 ] - 30.0f )
{
ztest = currentOrg [ 2 ] - 30.0f ;
}
if ( ztest < currentOrg [ 2 ] + 10.0f )
{
ztest = currentOrg [ 2 ] + 10.0f ;
}
testStart [ 2 ] = ztest ;
testEnd [ 2 ] = ztest ;
float magicFactor44 = 1.0f ; // going to trace a bit longer, this also serves as an expansion parameter
VectorAdvance ( testStart , magicFactor44 , testEnd , testEnd ) ; // VA(a,t,b,c)-> c := (1-t)a+tb
float horzontalTraceFraction = 0.0f ;
vec3_t HorizontalHitSpot = { 0 , 0 , 0 } ;
{
trace_t tr ;
Rag_Trace ( & tr , testStart , testMins , testMaxs , testEnd , ignoreNum , RAG_MASK , G2_NOCOLLIDE , 0 ) ;
if ( tr . entityNum = = 0 )
{
VectorAdvance ( testStart , .5f , testEnd , tr . endpos ) ;
}
horzontalTraceFraction = tr . fraction ;
if ( tr . startsolid )
{
horzontalTraceFraction = 1.0f ;
// punt
VectorCopy ( e . currentOrigin , HorizontalHitSpot ) ;
}
else
{
VectorCopy ( tr . endpos , HorizontalHitSpot ) ;
int magicFactor46 = 0.98f ; // shorten percetage to make sure we can go down along a wall
//float magicFactor46=0.98f; // shorten percetage to make sure we can go down along a wall
//rww - An..int?
VectorAdvance ( tr . endpos , magicFactor46 , testStart , HorizontalHitSpot ) ; // VA(a,t,b,c)-> c := (1-t)a+tb
// roughly speaking this is a wall
if ( horzontalTraceFraction < 0.9f )
{
// roughly speaking this is a wall
if ( fabsf ( tr . plane . normal [ 2 ] ) < 0.7f )
{
//SRagDollEffectorCollision args(e.currentOrigin,tr);
//args.useTracePlane=true;
//params->EffectorCollision(args);
# ifndef DEDICATED
if ( cgvm )
{ //make a callback and see if the cgame wants to help us out
ragCallbackBoneInSolid_t * callData = ( ragCallbackBoneInSolid_t * ) cl . mSharedMemory ;
VectorCopy ( e . currentOrigin , callData - > bonePos ) ;
callData - > entNum = params - > me ;
callData - > solidCount = bone . solidCount ;
VM_Call ( cgvm , CG_RAG_CALLBACK , RAG_CALLBACK_BONEINSOLID ) ;
}
# endif
}
}
else if ( ! iAmStartSolid & &
effectorGroundSpot [ 2 ] < groundSpot [ 2 ] - 8.0f )
{
// this is a situation where we have something dangling below the pelvis, we want to find the plane going downhill away from the origin
// for various reasons, without this correction the body will actually move away from places it can fall off.
//gotta run the trace backwards to get a plane
{
trace_t tr ;
VectorCopy ( effectorGroundSpot , testStart ) ;
VectorCopy ( groundSpot , testEnd ) ;
// this can be a line trace, we just want the plane normal
Rag_Trace ( & tr , testEnd , 0 , 0 , testStart , ignoreNum , RAG_MASK , G2_NOCOLLIDE , 0 ) ;
if ( tr . entityNum = = 0 )
{
VectorAdvance ( testStart , .5f , testEnd , tr . endpos ) ;
}
horzontalTraceFraction = tr . fraction ;
if ( ! tr . startsolid & & tr . fraction < 0.7f )
{
//SRagDollEffectorCollision args(e.currentOrigin,tr);
//args.useTracePlane=true;
//params->EffectorCollision(args);
# ifndef DEDICATED
if ( cgvm )
{ //make a callback and see if the cgame wants to help us out
ragCallbackBoneInSolid_t * callData = ( ragCallbackBoneInSolid_t * ) cl . mSharedMemory ;
VectorCopy ( e . currentOrigin , callData - > bonePos ) ;
callData - > entNum = params - > me ;
callData - > solidCount = bone . solidCount ;
VM_Call ( cgvm , CG_RAG_CALLBACK , RAG_CALLBACK_BONEINSOLID ) ;
}
# endif
}
}
}
}
}
vec3_t goalSpot = { 0 , 0 , 0 } ;
// now lets trace down
VectorCopy ( HorizontalHitSpot , testStart ) ;
VectorCopy ( testStart , testEnd ) ; //last arg is dest
testEnd [ 2 ] = e . currentOrigin [ 2 ] - 30.0f ;
{
trace_t tr ;
Rag_Trace ( & tr , testStart , NULL , NULL , testEnd , ignoreNum , RAG_MASK , G2_NOCOLLIDE , 0 ) ;
if ( tr . entityNum = = 0 )
{
VectorAdvance ( testStart , .5f , testEnd , tr . endpos ) ;
}
if ( tr . startsolid )
{
// punt, go to the origin I guess
VectorCopy ( currentOrg , goalSpot ) ;
}
else
{
VectorCopy ( tr . endpos , goalSpot ) ;
int magicFactor47 = 0.5f ; // shorten percentage to make sure we can go down along a wall
VectorAdvance ( tr . endpos , magicFactor47 , testStart , goalSpot ) ; // VA(a,t,b,c)-> c := (1-t)a+tb
}
}
// ok now as the horizontal trace fraction approaches zero, we want to head toward the horizontalHitSpot
//geeze I would like some reasonable trace fractions
assert ( horzontalTraceFraction > = 0.0f & & horzontalTraceFraction < = 1.0f ) ;
VectorAdvance ( HorizontalHitSpot , horzontalTraceFraction * horzontalTraceFraction , goalSpot , goalSpot ) ; // VA(a,t,b,c)-> c := (1-t)a+tb
#if 0
if ( ( bone . RagFlags & RAG_EFFECTOR ) & & ( bone . RagFlags & RAG_BONE_LIGHTWEIGHT ) )
{ //new rule - don't even bother unless it's a lightweight effector
//rww - Factor object velocity into the final desired spot..
//We want the limbs with a "light" weight to drag behind the general mass.
//If we got here, we shouldn't be the pelvis or the root, so we should be
//fine to treat as lightweight. However, we can flag bones as being particularly
//light. They're given less downscale for the reduction factor.
vec3_t givenVelocity ;
vec3_t vSpot ;
trace_t vtr ;
float vSpeed = 0 ;
float verticalSpeed = 0 ;
float vReductionFactor = 0.03f ;
float verticalSpeedReductionFactor = 0.06f ; //want this to be more obvious
float lwVReductionFactor = 0.1f ;
float lwVerticalSpeedReductionFactor = 0.3f ; //want this to be more obvious
VectorCopy ( params - > velocity , givenVelocity ) ;
vSpeed = VectorNormalize ( givenVelocity ) ;
vSpeed = - vSpeed ; //go in the opposite direction of velocity
verticalSpeed = vSpeed ;
if ( bone . RagFlags & RAG_BONE_LIGHTWEIGHT )
{
vSpeed * = lwVReductionFactor ;
verticalSpeed * = lwVerticalSpeedReductionFactor ;
}
else
{
vSpeed * = vReductionFactor ;
verticalSpeed * = verticalSpeedReductionFactor ;
}
vSpot [ 0 ] = givenVelocity [ 0 ] * vSpeed ;
vSpot [ 1 ] = givenVelocity [ 1 ] * vSpeed ;
vSpot [ 2 ] = givenVelocity [ 2 ] * verticalSpeed ;
VectorAdd ( goalSpot , vSpot , vSpot ) ;
if ( vSpot [ 0 ] | | vSpot [ 1 ] | | vSpot [ 2 ] )
{
Rag_Trace ( & vtr , goalSpot , testMins , testMaxs , vSpot , ignoreNum , RAG_MASK , G2_NOCOLLIDE , 0 ) ;
if ( vtr . fraction = = 1 )
{
VectorCopy ( vSpot , goalSpot ) ;
}
}
}
# endif
int k ;
int magicFactor12 = 0.8f ; // dampening of velocity applied
int magicFactor16 = 10.0f ; // effect multiplier of velocity applied
if ( iAmStartSolid )
{
magicFactor16 = 30.0f ;
}
for ( k = 0 ; k < 3 ; k + + )
{
e . desiredDirection [ k ] = goalSpot [ k ] - e . currentOrigin [ k ] ;
e . desiredDirection [ k ] + = magicFactor16 * bone . velocityEffector [ k ] ;
e . desiredDirection [ k ] + = flrand ( - 0.75f , 0.75f ) * flrand ( - 0.75f , 0.75f ) ;
bone . velocityEffector [ k ] * = magicFactor12 ;
}
VectorCopy ( e . currentOrigin , bone . lastPosition ) ; // last arg is dest
}
return anyStartSolid ;
}
# else
#if 0
static inline int G2_RagIndexForBoneNum ( int boneNum )
{
for ( int i = 0 ; i < numRags ; i + + )
{
// these are used for affecting the end result
if ( ragBoneData [ i ] . boneNum = = boneNum )
{
return i ;
}
}
return - 1 ;
}
# endif
# ifdef _RAG_PRINT_TEST
void G2_RagPrintMatrix ( mdxaBone_t * mat )
{
char x [ 1024 ] ;
x [ 0 ] = 0 ;
int n = 0 ;
while ( n < 3 )
{
int o = 0 ;
while ( o < 4 )
{
strcat ( x , va ( " %f " , mat - > matrix [ n ] [ o ] ) ) ;
o + + ;
}
n + + ;
}
strcat ( x , " \n " ) ;
Com_Printf ( x ) ;
}
# endif
extern mdxaBone_t worldMatrix ;
void G2_RagGetBoneBasePoseMatrixLow ( CGhoul2Info & ghoul2 , int boneNum , mdxaBone_t & boneMatrix , mdxaBone_t & retMatrix , vec3_t scale ) ;
void G2_RagGetAnimMatrix ( CGhoul2Info & ghoul2 , const int boneNum , mdxaBone_t & matrix , const int frame ) ;
static inline void G2_RagGetWorldAnimMatrix ( CGhoul2Info & ghoul2 , boneInfo_t & bone , CRagDollUpdateParams * params , mdxaBone_t & retMatrix )
{
static mdxaBone_t trueBaseMatrix , baseBoneMatrix ;
//get matrix for the settleFrame to use as an ideal
G2_RagGetAnimMatrix ( ghoul2 , bone . boneNumber , trueBaseMatrix , params - > settleFrame ) ;
assert ( bone . hasAnimFrameMatrix = = params - > settleFrame ) ;
G2_RagGetBoneBasePoseMatrixLow ( ghoul2 , bone . boneNumber ,
trueBaseMatrix , baseBoneMatrix , params - > scale ) ;
//Use params to multiply world coordinate/dir matrix into the
//bone matrix and give us a useable world position
Multiply_3x4Matrix ( & retMatrix , & worldMatrix , & baseBoneMatrix ) ;
assert ( ! _isnan ( retMatrix . matrix [ 2 ] [ 3 ] ) ) ;
}
//get the current pelvis Z direction and the base anim matrix Z direction
//so they can be compared and used to offset -rww
void G2_GetRagBoneMatrixLow ( CGhoul2Info & ghoul2 , int boneNum , mdxaBone_t & retMatrix ) ;
void G2_GetBoltMatrixLow ( CGhoul2Info & ghoul2 , int boltNum , const vec3_t scale , mdxaBone_t & retMatrix ) ;
static inline void G2_RagGetPelvisLumbarOffsets ( CGhoul2Info & ghoul2 , CRagDollUpdateParams * params , vec3_t pos , vec3_t dir , vec3_t animPos , vec3_t animDir )
{
static mdxaBone_t final ;
static mdxaBone_t x ;
static mdxaBone_t * unused1 , * unused2 ;
//static vec3_t lumbarPos;
assert ( ghoul2 . animModel ) ;
int boneIndex = G2_Find_Bone ( ghoul2 . animModel , ghoul2 . mBlist , " pelvis " ) ;
assert ( boneIndex ! = - 1 ) ;
G2_RagGetWorldAnimMatrix ( ghoul2 , ghoul2 . mBlist [ boneIndex ] , params , final ) ;
G2API_GiveMeVectorFromMatrix ( & final , ORIGIN , animPos ) ;
G2API_GiveMeVectorFromMatrix ( & final , POSITIVE_X , animDir ) ;
#if 0
//We have the anim matrix pelvis pos now, so get the normal one as well
G2_GetBoneMatrixLow ( ghoul2 , boneIndex , params - > scale , final , unused1 , unused2 ) ;
G2API_GiveMeVectorFromMatrix ( & final , ORIGIN , pos ) ;
G2API_GiveMeVectorFromMatrix ( & final , POSITIVE_X , dir ) ;
# else
//We have the anim matrix pelvis pos now, so get the normal one as well
//G2_GetRagBoneMatrixLow(ghoul2, boneIndex, x);
int bolt = G2_Add_Bolt ( & ghoul2 , ghoul2 . mBltlist , ghoul2 . mSlist , " pelvis " ) ;
G2_GetBoltMatrixLow ( ghoul2 , bolt , params - > scale , x ) ;
Multiply_3x4Matrix ( & final , & worldMatrix , & x ) ;
G2API_GiveMeVectorFromMatrix ( & final , ORIGIN , pos ) ;
G2API_GiveMeVectorFromMatrix ( & final , POSITIVE_X , dir ) ;
# endif
/*
//now get lumbar
boneIndex = G2_Find_Bone ( ghoul2 . animModel , ghoul2 . mBlist , " lower_lumbar " ) ;
assert ( boneIndex ! = - 1 ) ;
G2_RagGetWorldAnimMatrix ( ghoul2 , ghoul2 . mBlist [ boneIndex ] , params , final ) ;
G2API_GiveMeVectorFromMatrix ( & final , ORIGIN , lumbarPos ) ;
VectorSubtract ( animPos , lumbarPos , animDir ) ;
VectorNormalize ( animDir ) ;
//We have the anim matrix lumbar dir now, so get the normal one as well
G2_GetBoneMatrixLow ( ghoul2 , boneIndex , params - > scale , final , unused1 , unused2 ) ;
G2API_GiveMeVectorFromMatrix ( & final , ORIGIN , lumbarPos ) ;
VectorSubtract ( pos , lumbarPos , dir ) ;
VectorNormalize ( dir ) ;
*/
}
static bool G2_RagDollSettlePositionNumeroTrois ( CGhoul2Info_v & ghoul2V , const vec3_t currentOrg , CRagDollUpdateParams * params , int curTime )
{ //now returns true if any bone was in solid, otherwise false
int ignoreNum = params - > me ;
static int i ;
static vec3_t goalSpot ;
static trace_t tr ;
static trace_t solidTr ;
static int k ;
static const float velocityDampening = 1.0f ;
static const float velocityMultiplier = 60.0f ;
static vec3_t testMins ;
static vec3_t testMaxs ;
vec3_t velDir ;
static bool startSolid ;
bool anySolid = false ;
static mdxaBone_t worldBaseMatrix ;
static vec3_t parentOrigin ;
static vec3_t basePos ;
static vec3_t entScale ;
static bool hasDaddy ;
static bool hasBasePos ;
static vec3_t animPelvisDir , pelvisDir , animPelvisPos , pelvisPos ;
//Maybe customize per-bone?
static const float gravity = 3.0f ;
static const float mass = 0.09f ;
static const float bounce = 0.0f ; //1.3f;
//Bouncing and stuff unfortunately does not work too well at the moment.
//Need to keep a seperate "physics origin" or make the filthy solve stuff
//better.
bool inAir = false ;
if ( params - > velocity [ 0 ] | | params - > velocity [ 1 ] | | params - > velocity [ 2 ] )
{
inAir = true ;
}
if ( ! params - > scale [ 0 ] & & ! params - > scale [ 1 ] & & ! params - > scale [ 2 ] )
{
VectorSet ( entScale , 1.0f , 1.0f , 1.0f ) ;
}
else
{
VectorCopy ( params - > scale , entScale ) ;
}
if ( broadsword_ragtobase & &
broadsword_ragtobase - > integer > 1 )
{
//grab the pelvis directions to offset base positions for bones
G2_RagGetPelvisLumbarOffsets ( ghoul2V [ 0 ] , params , pelvisPos , pelvisDir , animPelvisPos ,
animPelvisDir ) ;
//don't care about the pitch offsets
pelvisDir [ 2 ] = 0 ;
animPelvisDir [ 2 ] = 0 ;
/*
vec3_t upelvisPos , uanimPelvisPos ;
vec3_t blah ;
VectorCopy ( pelvisPos , upelvisPos ) ;
VectorCopy ( animPelvisPos , uanimPelvisPos ) ;
upelvisPos [ 2 ] + = 64 ;
uanimPelvisPos [ 2 ] + = 64 ;
VectorMA ( upelvisPos , 32.0f , pelvisDir , blah ) ;
G2_RagDebugLine ( upelvisPos , blah , 50 , 0x00ff00 , 1 ) ;
VectorMA ( uanimPelvisPos , 32.0f , animPelvisDir , blah ) ;
G2_RagDebugLine ( uanimPelvisPos , blah , 50 , 0xff0000 , 1 ) ;
*/
//just convert to angles now, that's all we'll ever use them for
vectoangles ( pelvisDir , pelvisDir ) ;
vectoangles ( animPelvisDir , animPelvisDir ) ;
}
for ( i = 0 ; i < numRags ; i + + )
{
boneInfo_t & bone = * ragBoneData [ i ] ;
SRagEffector & e = ragEffectors [ i ] ;
if ( inAir )
{
bone . airTime = curTime + 30 ;
}
if ( bone . RagFlags & RAG_PCJ_PELVIS )
{
VectorSet ( goalSpot , params - > position [ 0 ] , params - > position [ 1 ] , ( params - > position [ 2 ] + DEFAULT_MINS_2 ) + ( ( bone . radius * entScale [ 2 ] ) + 2 ) ) ;
VectorSubtract ( goalSpot , e . currentOrigin , desiredPelvisOffset ) ;
haveDesiredPelvisOffset = true ;
VectorCopy ( e . currentOrigin , bone . lastPosition ) ;
continue ;
}
if ( ! ( bone . RagFlags & RAG_EFFECTOR ) )
{
continue ;
}
if ( bone . hasOverGoal )
{ //api call was made to override the goal spot
VectorCopy ( bone . overGoalSpot , goalSpot ) ;
bone . solidCount = 0 ;
for ( k = 0 ; k < 3 ; k + + )
{
e . desiredDirection [ k ] = ( goalSpot [ k ] - e . currentOrigin [ k ] ) ;
e . desiredDirection [ k ] + = ( velocityMultiplier * bone . velocityEffector [ k ] ) ;
bone . velocityEffector [ k ] * = velocityDampening ;
}
VectorCopy ( e . currentOrigin , bone . lastPosition ) ;
continue ;
}
VectorSet ( testMins , - e . radius * entScale [ 0 ] , - e . radius * entScale [ 1 ] , - e . radius * entScale [ 2 ] ) ;
VectorSet ( testMaxs , e . radius * entScale [ 0 ] , e . radius * entScale [ 1 ] , e . radius * entScale [ 2 ] ) ;
assert ( ghoul2V [ 0 ] . mBoneCache ) ;
//get the parent bone's position
hasDaddy = false ;
if ( bone . boneNumber )
{
assert ( ghoul2V [ 0 ] . animModel ) ;
assert ( ghoul2V [ 0 ] . aHeader ) ;
if ( bone . parentBoneIndex = = - 1 )
{
mdxaSkel_t * skel ;
mdxaSkelOffsets_t * offsets ;
int bParentIndex , bParentListIndex = - 1 ;
offsets = ( mdxaSkelOffsets_t * ) ( ( byte * ) ghoul2V [ 0 ] . aHeader + sizeof ( mdxaHeader_t ) ) ;
skel = ( mdxaSkel_t * ) ( ( byte * ) ghoul2V [ 0 ] . aHeader + sizeof ( mdxaHeader_t ) + offsets - > offsets [ bone . boneNumber ] ) ;
bParentIndex = skel - > parent ;
while ( bParentIndex > 0 )
{ //go upward through hierarchy searching for the first parent that is a rag bone
skel = ( mdxaSkel_t * ) ( ( byte * ) ghoul2V [ 0 ] . aHeader + sizeof ( mdxaHeader_t ) + offsets - > offsets [ bParentIndex ] ) ;
bParentIndex = skel - > parent ;
bParentListIndex = G2_Find_Bone ( ghoul2V [ 0 ] . animModel , ghoul2V [ 0 ] . mBlist , skel - > name ) ;
if ( bParentListIndex ! = - 1 )
{
boneInfo_t & pbone = ghoul2V [ 0 ] . mBlist [ bParentListIndex ] ;
if ( pbone . flags & BONE_ANGLES_RAGDOLL )
{ //valid rag bone
break ;
}
}
//didn't work out, reset to -1 again
bParentListIndex = - 1 ;
}
bone . parentBoneIndex = bParentListIndex ;
}
if ( bone . parentBoneIndex ! = - 1 )
{
boneInfo_t & pbone = ghoul2V [ 0 ] . mBlist [ bone . parentBoneIndex ] ;
if ( pbone . flags & BONE_ANGLES_RAGDOLL )
{ //has origin calculated for us already
VectorCopy ( ragEffectors [ pbone . ragIndex ] . currentOrigin , parentOrigin ) ;
hasDaddy = true ;
}
}
}
//get the position this bone would be in if we were in the desired frame
hasBasePos = false ;
if ( broadsword_ragtobase & &
broadsword_ragtobase - > integer )
{
vec3_t v , a ;
float f ;
G2_RagGetWorldAnimMatrix ( ghoul2V [ 0 ] , bone , params , worldBaseMatrix ) ;
G2API_GiveMeVectorFromMatrix ( & worldBaseMatrix , ORIGIN , basePos ) ;
if ( broadsword_ragtobase - > integer > 1 )
{
float fa = AngleNormalize180 ( animPelvisDir [ YAW ] - pelvisDir [ YAW ] ) ;
float d = fa - bone . offsetRotation ;
if ( d > 16.0f | |
d < - 16.0f )
{ //don't update unless x degrees away from the ideal to avoid moving goal spots too much if pelvis rotates
bone . offsetRotation = fa ;
}
else
{
fa = bone . offsetRotation ;
}
//Rotate the point around the pelvis based on the offsets between pelvis positions
VectorSubtract ( basePos , animPelvisPos , v ) ;
f = VectorLength ( v ) ;
vectoangles ( v , a ) ;
a [ YAW ] - = fa ;
AngleVectors ( a , v , 0 , 0 ) ;
VectorNormalize ( v ) ;
VectorMA ( animPelvisPos , f , v , basePos ) ;
//re-orient the position of the bone to the current position of the pelvis
VectorSubtract ( basePos , animPelvisPos , v ) ;
//push the spots outward? (to stretch the skeleton more)
//v[0] *= 1.5f;
//v[1] *= 1.5f;
VectorAdd ( pelvisPos , v , basePos ) ;
}
#if 0 //for debugging frame skeleton
mdxaSkel_t * skel ;
mdxaSkelOffsets_t * offsets ;
offsets = ( mdxaSkelOffsets_t * ) ( ( byte * ) ghoul2V [ 0 ] . aHeader + sizeof ( mdxaHeader_t ) ) ;
skel = ( mdxaSkel_t * ) ( ( byte * ) ghoul2V [ 0 ] . aHeader + sizeof ( mdxaHeader_t ) + offsets - > offsets [ bone . boneNumber ] ) ;
vec3_t pu ;
VectorCopy ( basePos , pu ) ;
pu [ 2 ] + = 32 ;
if ( bone . boneNumber < 11 )
{
G2_RagDebugLine ( basePos , pu , 50 , 0xff00ff , 1 ) ;
}
else if ( skel - > name [ 0 ] = = ' l ' )
{
G2_RagDebugLine ( basePos , pu , 50 , 0xffff00 , 1 ) ;
}
else if ( skel - > name [ 0 ] = = ' r ' )
{
G2_RagDebugLine ( basePos , pu , 50 , 0xffffff , 1 ) ;
}
else
{
G2_RagDebugLine ( basePos , pu , 50 , 0x00ffff , 1 ) ;
}
# endif
hasBasePos = true ;
}
//Are we in solid?
if ( hasDaddy )
{
Rag_Trace ( & tr , e . currentOrigin , testMins , testMaxs , parentOrigin , ignoreNum , RAG_MASK , G2_NOCOLLIDE , 0 ) ;
//Rag_Trace(&tr, parentOrigin, testMins, testMaxs, e.currentOrigin, ignoreNum, RAG_MASK, G2_NOCOLLIDE, 0);
}
else
{
Rag_Trace ( & tr , e . currentOrigin , testMins , testMaxs , params - > position , ignoreNum , RAG_MASK , G2_NOCOLLIDE , 0 ) ;
}
if ( tr . startsolid | | tr . allsolid | | tr . fraction ! = 1.0f )
{ //currently in solid, see what we can do about it
vec3_t vSub ;
startSolid = true ;
anySolid = true ;
if ( hasBasePos ) // && bone.solidCount < 32)
{ //only go to the base pos for slightly in solid bones
#if 0 //over-compensation
float fl ;
float floorBase ;
VectorSubtract ( basePos , e . currentOrigin , vSub ) ;
fl = VectorNormalize ( vSub ) ;
VectorMA ( e . currentOrigin , /*fl*8.0f*/ 64.0f , vSub , goalSpot ) ;
floorBase = ( ( params - > position [ 2 ] - 23 ) - testMins [ 2 ] ) + 8 ;
if ( goalSpot [ 2 ] > floorBase )
{
goalSpot [ 2 ] = floorBase ;
}
# else //just use the spot directly
VectorCopy ( basePos , goalSpot ) ;
goalSpot [ 2 ] = ( params - > position [ 2 ] - 23 ) - testMins [ 2 ] ;
# endif
//Com_Printf("%i: %f %f %f\n", bone.boneNumber, basePos[0], basePos[1], basePos[2]);
}
else
{ //if deep in solid want to try to rise up out of solid before hinting back to base
VectorSubtract ( e . currentOrigin , params - > position , vSub ) ;
VectorNormalize ( vSub ) ;
VectorMA ( params - > position , 40.0f , vSub , goalSpot ) ;
//should be 1 unit above the ground taking bounding box sizes into account
goalSpot [ 2 ] = ( params - > position [ 2 ] - 23 ) - testMins [ 2 ] ;
}
//Trace from the entity origin in the direction between the origin and current bone position to
//find a good eventual goal position
Rag_Trace ( & tr , params - > position , testMins , testMaxs , goalSpot , params - > me , RAG_MASK , G2_NOCOLLIDE , 0 ) ;
VectorCopy ( tr . endpos , goalSpot ) ;
}
else
{
startSolid = false ;
# if 1 //do hinting?
//Hint the bone back to the base origin
if ( hasDaddy | | hasBasePos )
{
if ( hasBasePos )
{
VectorSubtract ( basePos , e . currentOrigin , velDir ) ;
}
else
{
VectorSubtract ( e . currentOrigin , parentOrigin , velDir ) ;
}
}
else
{
VectorSubtract ( e . currentOrigin , params - > position , velDir ) ;
}
if ( VectorLength ( velDir ) > 2.0f )
{ //don't bother if already close
VectorNormalize ( velDir ) ;
VectorScale ( velDir , 8.0f , velDir ) ;
velDir [ 2 ] = 0 ; //don't want to nudge on Z, the gravity will take care of things.
VectorAdd ( bone . epVelocity , velDir , bone . epVelocity ) ;
}
# endif
//Factor the object's velocity into the bone's velocity, by pushing the bone
//opposite the velocity to give the apperance the lighter limbs are being "dragged"
//behind those of greater mass.
if ( bone . RagFlags & RAG_BONE_LIGHTWEIGHT )
{
vec3_t vel ;
float vellen ;
VectorCopy ( params - > velocity , vel ) ;
//Scale down since our velocity scale is different from standard game physics
VectorScale ( vel , 0.5f , vel ) ;
vellen = VectorLength ( vel ) ;
if ( vellen > 64.0f )
{ //cap it off
VectorScale ( vel , 64.0f / vellen , vel ) ;
}
//Invert the velocity so we go opposite the heavier parts and drag behind
VectorInverse ( vel ) ;
if ( vel [ 2 ] )
{ //want to override entirely instead then
VectorCopy ( vel , bone . epVelocity ) ;
}
else
{
VectorAdd ( bone . epVelocity , vel , bone . epVelocity ) ;
}
}
//We're not in solid so we can apply physics freely now.
if ( ! G2_ApplyRealBonePhysics ( bone , e , params , goalSpot , testMins , testMaxs ,
gravity , mass , bounce ) )
{ //if this is the case then somehow we failed to apply physics/get a good goal spot, just use the ent origin
VectorCopy ( params - > position , goalSpot ) ;
}
}
//Set this now so we know what to do for angle limiting
if ( startSolid )
{
bone . solidCount + + ;
#if 0
# ifndef DEDICATED
if ( cgvm & & bone . solidCount > 8 )
{ //make a callback and see if the cgame wants to help us out
Rag_Trace ( & solidTr , params - > position , testMins , testMaxs , e . currentOrigin , ignoreNum , RAG_MASK , G2_NOCOLLIDE , 0 ) ;
if ( solidTr . fraction ! = 1.0f & &
( solidTr . plane . normal [ 0 ] | | solidTr . plane . normal [ 1 ] ) & &
( solidTr . plane . normal [ 2 ] < 0.1f | | solidTr . plane . normal [ 2 ] > - 0.1f ) ) // && //don't do anything against flat around
// e.currentOrigin[2] > pelvisPos[2])
{
ragCallbackBoneInSolid_t * callData = ( ragCallbackBoneInSolid_t * ) cl . mSharedMemory ;
VectorCopy ( e . currentOrigin , callData - > bonePos ) ;
callData - > entNum = params - > me ;
callData - > solidCount = bone . solidCount ;
VM_Call ( cgvm , CG_RAG_CALLBACK , RAG_CALLBACK_BONEINSOLID ) ;
}
}
# endif
# endif
# ifdef _DEBUG_BONE_NAMES
if ( bone . solidCount > 64 )
{
char * debugBoneName = G2_Get_Bone_Name ( & ghoul2V [ 0 ] , ghoul2V [ 0 ] . mBlist , bone . boneNumber ) ;
vec3_t absmin , absmax ;
assert ( debugBoneName ) ;
Com_Printf ( " High bone (%s, %i) solid count: %i \n " , debugBoneName , bone . boneNumber , bone . solidCount ) ;
VectorAdd ( e . currentOrigin , testMins , absmin ) ;
VectorAdd ( e . currentOrigin , testMaxs , absmax ) ;
G2_RagDebugBox ( absmin , absmax , 50 ) ;
G2_RagDebugLine ( e . currentOrigin , goalSpot , 50 , 0x00ff00 , 1 ) ;
}
# endif
}
else
{
bone . solidCount = 0 ;
}
#if 0 //standard goalSpot capping?
//unless we are really in solid, we should keep adjustments minimal
if ( /*bone.epGravFactor < 64 &&*/ bone . solidCount < 2 & &
! inAir )
{
vec3_t moveDist ;
const float extent = 32.0f ;
float len ;
VectorSubtract ( goalSpot , e . currentOrigin , moveDist ) ;
len = VectorLength ( moveDist ) ;
if ( len > extent )
{ //if greater than the extent then scale the vector down to the extent and factor it back into the goalspot
VectorScale ( moveDist , extent / len , moveDist ) ;
VectorAdd ( e . currentOrigin , moveDist , goalSpot ) ;
}
}
# endif
//Set the desired direction based on the goal position and other factors.
for ( k = 0 ; k < 3 ; k + + )
{
e . desiredDirection [ k ] = ( goalSpot [ k ] - e . currentOrigin [ k ] ) ;
if ( broadsword_dircap & &
broadsword_dircap - > value )
{
float cap = broadsword_dircap - > value ;
if ( bone . solidCount > 5 )
{
float solidFactor = bone . solidCount * 0.2f ;
if ( solidFactor > 16.0f )
{ //don't go too high or something ugly might happen
solidFactor = 16.0f ;
}
e . desiredDirection [ k ] * = solidFactor ;
cap * = 8 ;
}
if ( e . desiredDirection [ k ] > cap )
{
e . desiredDirection [ k ] = cap ;
}
else if ( e . desiredDirection [ k ] < - cap )
{
e . desiredDirection [ k ] = - cap ;
}
}
e . desiredDirection [ k ] + = ( velocityMultiplier * bone . velocityEffector [ k ] ) ;
e . desiredDirection [ k ] + = ( flrand ( - 0.75f , 0.75f ) * flrand ( - 0.75f , 0.75f ) ) ;
bone . velocityEffector [ k ] * = velocityDampening ;
}
VectorCopy ( e . currentOrigin , bone . lastPosition ) ;
}
return anySolid ;
}
# endif
static float AngleNormZero ( float theta )
{
float ret = fmodf ( theta , 360.0f ) ;
if ( ret < - 180.0f )
{
ret + = 360.0f ;
}
else if ( ret > 180.0f )
{
ret - = 360.0f ;
}
assert ( ret > = - 180.0f & & ret < = 180.0f ) ;
return ret ;
}
static inline void G2_BoneSnap ( CGhoul2Info_v & ghoul2V , boneInfo_t & bone , CRagDollUpdateParams * params )
{
# ifdef DEDICATED
return ;
# else
if ( ! cgvm | | ! params )
{
return ;
}
ragCallbackBoneSnap_t * callData = ( ragCallbackBoneSnap_t * ) cl . mSharedMemory ;
callData - > entNum = params - > me ;
strcpy ( callData - > boneName , G2_Get_Bone_Name ( & ghoul2V [ 0 ] , ghoul2V [ 0 ] . mBlist , bone . boneNumber ) ) ;
VM_Call ( cgvm , CG_RAG_CALLBACK , RAG_CALLBACK_BONESNAP ) ;
# endif
}
static void G2_RagDollSolve ( CGhoul2Info_v & ghoul2V , int g2Index , float decay , int frameNum , const vec3_t currentOrg , bool limitAngles , CRagDollUpdateParams * params )
{
int i ;
CGhoul2Info & ghoul2 = ghoul2V [ g2Index ] ;
mdxaBone_t N ;
mdxaBone_t P ;
mdxaBone_t temp1 ;
mdxaBone_t temp2 ;
mdxaBone_t curRot ;
mdxaBone_t curRotInv ;
mdxaBone_t Gs [ 3 ] ;
mdxaBone_t Enew [ 3 ] ;
assert ( ghoul2 . mFileName [ 0 ] ) ;
boneInfo_v & blist = ghoul2 . mBlist ;
// END this is the objective function thing
for ( i = 0 ; i < numRags ; i + + )
{
// these are used for affecting the end result
boneInfo_t & bone = * ragBoneData [ i ] ;
if ( ! ( bone . RagFlags & RAG_PCJ ) )
{
continue ; // not an active ragdoll PCJ
}
/* the situation is thus. (the dependent bone is in essence an effector)
The effector true bone matrix is :
Ecur = ragBones [ depIndex ] =
EntToWorld * [ skeletal heirachy1 ] *
MyAnimMatrix * ragBasepose [ i ] * current_rot_matrix * ragBaseposeInv [ i ] *
[ skeletal heirachy2 ] * EffectorAnimMatrix * ragBasepose [ depIndex ]
My ( sub - i ) true bone matrix is :
M = ragBones [ i ] = EntToWorld * [ skeletal heirachry1 ] *
MyAnimMatrix * ragBasepose [ i ] * current_rot_matrix * ragBaseposeInv [ i ] * ragBasepose [ i ]
Simplifies to :
M = ragBones [ i ] = EntToWorld * [ skeletal heirachry1 ] *
MyAnimMatrix * ragBasepose [ i ] * current_rot_matrix
Enew is :
Enew = M *
inv ( current_rot_matrix ) * ragBaseposeInv [ i ] *
ragBasepose [ i ] * new_rot_matrix * ragBaseposeInv [ i ] *
inv ( M * ragBaseposeInv [ i ] ) * Ecur
We can simplify a bit :
Enew = M *
inv ( current_rot_matrix ) * ragBaseposeInv [ i ] *
ragBasepose [ i ] * new_rot_matrix * ragBaseposeInv [ i ] *
ragBasepose [ i ] * inv ( M ) * Ecur
Enew =
M * inv ( current_rot_matrix ) *
new_rot_matrix * inv ( M ) * Ecur
We define P to be :
P = M * inv ( current_rot_matrix )
We define N to be :
N = inv ( M )
then it is just :
Enew = P * new_rot_matrix * N * Ecur
Ri = new_rot_matrix ( for each euler angle )
we are gonna use three R ' s , so will will precompute them as Gi = P * Ri * N
and then Enewi = Gi * Ecur
we are gonna evaluate Enewi for " goodness " and accumulate changes in delAngles
*/
Inverse_Matrix ( & ragBones [ i ] , & N ) ; // dest 2nd arg
int k ;
vec3_t tAngles ;
VectorCopy ( bone . currentAngles , tAngles ) ;
Create_Matrix ( tAngles , & curRot ) ; //dest 2nd arg
Inverse_Matrix ( & curRot , & curRotInv ) ; // dest 2nd arg
Multiply_3x4Matrix ( & P , & ragBones [ i ] , & curRotInv ) ; //dest first arg
if ( bone . RagFlags & RAG_PCJ_MODEL_ROOT )
{
if ( haveDesiredPelvisOffset )
{
float magicFactor12 = 0.25f ; // dampfactor for pelvis pos
float magicFactor13 = 0.20f ; //controls the speed of the gradient descent (pelvis pos)
assert ( ! _isnan ( bone . ragOverrideMatrix . matrix [ 2 ] [ 3 ] ) ) ;
vec3_t deltaInEntitySpace ;
TransformPoint ( desiredPelvisOffset , deltaInEntitySpace , & N ) ; // dest middle arg
for ( k = 0 ; k < 3 ; k + + )
{
float moveTo = bone . velocityRoot [ k ] + deltaInEntitySpace [ k ] * magicFactor13 ;
bone . velocityRoot [ k ] = ( bone . velocityRoot [ k ] - moveTo ) * magicFactor12 + moveTo ;
/*
if ( bone . velocityRoot [ k ] > 50.0f )
{
bone . velocityRoot [ k ] = 50.0f ;
}
if ( bone . velocityRoot [ k ] < - 50.0f )
{
bone . velocityRoot [ k ] = - 50.0f ;
}
*/
//No -rww
bone . ragOverrideMatrix . matrix [ k ] [ 3 ] = bone . velocityRoot [ k ] ;
}
}
}
else
{
vec3_t delAngles ;
VectorClear ( delAngles ) ;
for ( k = 0 ; k < 3 ; k + + )
{
tAngles [ k ] + = 0.5f ;
Create_Matrix ( tAngles , & temp2 ) ; //dest 2nd arg
tAngles [ k ] - = 0.5f ;
Multiply_3x4Matrix ( & temp1 , & P , & temp2 ) ; //dest first arg
Multiply_3x4Matrix ( & Gs [ k ] , & temp1 , & N ) ; //dest first arg
}
int allSolidCount = 0 ; //bone.solidCount;
// fixme precompute this
int numDep = G2_GetBoneDependents ( ghoul2 , bone . boneNumber , tempDependents , MAX_BONES_RAG ) ;
int j ;
int numRagDep = 0 ;
for ( j = 0 ; j < numDep ; j + + )
{
//fixme why do this for the special roots?
if ( ! ( tempDependents [ j ] < rag . size ( ) & & rag [ tempDependents [ j ] ] ) )
{
continue ;
}
int depIndex = rag [ tempDependents [ j ] ] - > ragIndex ;
assert ( depIndex > i ) ; // these are supposed to be topologically sorted
assert ( ragBoneData [ depIndex ] ) ;
boneInfo_t & depBone = * ragBoneData [ depIndex ] ;
if ( depBone . RagFlags & RAG_EFFECTOR ) // rag doll effector
{
// this is a dependent of me, and also a rag
numRagDep + + ;
for ( k = 0 ; k < 3 ; k + + )
{
Multiply_3x4Matrix ( & Enew [ k ] , & Gs [ k ] , & ragBones [ depIndex ] ) ; //dest first arg
vec3_t tPosition ;
tPosition [ 0 ] = Enew [ k ] . matrix [ 0 ] [ 3 ] ;
tPosition [ 1 ] = Enew [ k ] . matrix [ 1 ] [ 3 ] ;
tPosition [ 2 ] = Enew [ k ] . matrix [ 2 ] [ 3 ] ;
vec3_t change ;
VectorSubtract ( tPosition , ragEffectors [ depIndex ] . currentOrigin , change ) ; // dest is last arg
float goodness = DotProduct ( change , ragEffectors [ depIndex ] . desiredDirection ) ;
assert ( ! _isnan ( goodness ) ) ;
goodness * = depBone . weight ;
delAngles [ k ] + = goodness ; // keep bigger stuff more out of wall or something
assert ( ! _isnan ( delAngles [ k ] ) ) ;
}
allSolidCount + = depBone . solidCount ;
}
}
//bone.solidCount = allSolidCount;
allSolidCount + = bone . solidCount ;
VectorCopy ( bone . currentAngles , bone . lastAngles ) ;
// Update angles
float magicFactor9 = 0.75f ; // dampfactor for angle changes
float magicFactor1 = 0.40f ; //controls the speed of the gradient descent
float magicFactor32 = 1.5f ;
float recip = 0.0f ;
if ( numRagDep )
{
recip = sqrt ( 4.0f / float ( numRagDep ) ) ;
}
if ( allSolidCount > 32 )
{
magicFactor1 = 0.6f ;
}
else if ( allSolidCount > 10 )
{
magicFactor1 = 0.5f ;
}
if ( bone . overGradSpeed )
{ //api call was made to specify a speed for this bone
magicFactor1 = bone . overGradSpeed ;
}
float fac = decay * recip * magicFactor1 ;
assert ( fac > = 0.0f ) ;
#if 0
if ( bone . RagFlags & RAG_PCJ_PELVIS )
{
magicFactor9 = .85f ; // we don't want this swinging radically, make the whole thing kindof unstable
}
# endif
if ( ragState = = ERS_DYNAMIC )
{
magicFactor9 = .85f ; // we don't want this swinging radically, make the whole thing kindof unstable
}
# if 1 //constraint breaks?
if ( bone . RagFlags & RAG_UNSNAPPABLE )
{
magicFactor32 = 1.0f ;
}
# endif
for ( k = 0 ; k < 3 ; k + + )
{
bone . currentAngles [ k ] + = delAngles [ k ] * fac ;
bone . currentAngles [ k ] = ( bone . lastAngles [ k ] - bone . currentAngles [ k ] ) * magicFactor9 + bone . currentAngles [ k ] ;
bone . currentAngles [ k ] = AngleNormZero ( bone . currentAngles [ k ] ) ;
// bone.currentAngles[k]=flrand(bone.minAngles[k],bone.maxAngles[k]);
# if 1 //constraint breaks?
if ( limitAngles & & ( allSolidCount < 32 | | ( bone . RagFlags & RAG_UNSNAPPABLE ) ) ) //32 tries and still in solid? Then we'll let you move freely
# else
if ( limitAngles )
# endif
{
if ( ! bone . snapped | | ( bone . RagFlags & RAG_UNSNAPPABLE ) )
{
//magicFactor32 += (allSolidCount/32);
if ( bone . currentAngles [ k ] > bone . maxAngles [ k ] * magicFactor32 )
{
bone . currentAngles [ k ] = bone . maxAngles [ k ] * magicFactor32 ;
}
if ( bone . currentAngles [ k ] < bone . minAngles [ k ] * magicFactor32 )
{
bone . currentAngles [ k ] = bone . minAngles [ k ] * magicFactor32 ;
}
}
}
}
bool isSnapped = false ;
for ( k = 0 ; k < 3 ; k + + )
{
if ( bone . currentAngles [ k ] > bone . maxAngles [ k ] * magicFactor32 )
{
isSnapped = true ;
break ;
}
if ( bone . currentAngles [ k ] < bone . minAngles [ k ] * magicFactor32 )
{
isSnapped = true ;
break ;
}
}
if ( isSnapped ! = bone . snapped )
{
G2_BoneSnap ( ghoul2V , bone , params ) ;
bone . snapped = isSnapped ;
}
Create_Matrix ( bone . currentAngles , & temp1 ) ;
Multiply_3x4Matrix ( & temp2 , & temp1 , bone . baseposeInv ) ;
Multiply_3x4Matrix ( & bone . ragOverrideMatrix , bone . basepose , & temp2 ) ;
assert ( ! _isnan ( bone . ragOverrideMatrix . matrix [ 2 ] [ 3 ] ) ) ;
}
G2_Generate_MatrixRag ( blist , ragBlistIndex [ bone . boneNumber ] ) ;
}
}
static void G2_IKReposition ( const vec3_t currentOrg , CRagDollUpdateParams * params )
{
int i ;
assert ( params ) ;
for ( i = 0 ; i < numRags ; i + + )
{
boneInfo_t & bone = * ragBoneData [ i ] ;
SRagEffector & e = ragEffectors [ i ] ;
if ( ! ( bone . RagFlags & RAG_EFFECTOR ) )
{
continue ;
}
//Most effectors are not going to be PCJ, so this is not appplicable.
//The actual desired angle of the PCJ is factored around the desired
//directions of the effectors which are dependant on it.
/*
if ( ! ( bone . RagFlags & RAG_PCJ_IK_CONTROLLED ) )
{
continue ;
}
*/
int k ;
float magicFactor12 = 0.8f ; // dampening of velocity applied
float magicFactor16 = 10.0f ; // effect multiplier of velocity applied
for ( k = 0 ; k < 3 ; k + + )
{
e . desiredDirection [ k ] = bone . ikPosition [ k ] - e . currentOrigin [ k ] ;
e . desiredDirection [ k ] + = magicFactor16 * bone . velocityEffector [ k ] ;
e . desiredDirection [ k ] + = flrand ( - 0.75f , 0.75f ) * flrand ( - 0.75f , 0.75f ) ;
bone . velocityEffector [ k ] * = magicFactor12 ;
}
VectorCopy ( e . currentOrigin , bone . lastPosition ) ; // last arg is dest
}
}
static void G2_IKSolve ( CGhoul2Info_v & ghoul2V , int g2Index , float decay , int frameNum , const vec3_t currentOrg , bool limitAngles )
{
int i ;
CGhoul2Info & ghoul2 = ghoul2V [ g2Index ] ;
mdxaBone_t N ;
mdxaBone_t P ;
mdxaBone_t temp1 ;
mdxaBone_t temp2 ;
mdxaBone_t curRot ;
mdxaBone_t curRotInv ;
mdxaBone_t Gs [ 3 ] ;
mdxaBone_t Enew [ 3 ] ;
assert ( ghoul2 . mFileName [ 0 ] ) ;
boneInfo_v & blist = ghoul2 . mBlist ;
// END this is the objective function thing
for ( i = 0 ; i < numRags ; i + + )
{
// these are used for affecting the end result
boneInfo_t & bone = * ragBoneData [ i ] ;
if ( bone . RagFlags & RAG_PCJ_MODEL_ROOT )
{
continue ;
}
if ( ! ( bone . RagFlags & RAG_PCJ_IK_CONTROLLED ) )
{
continue ;
}
Inverse_Matrix ( & ragBones [ i ] , & N ) ; // dest 2nd arg
int k ;
vec3_t tAngles ;
VectorCopy ( bone . currentAngles , tAngles ) ;
Create_Matrix ( tAngles , & curRot ) ; //dest 2nd arg
Inverse_Matrix ( & curRot , & curRotInv ) ; // dest 2nd arg
Multiply_3x4Matrix ( & P , & ragBones [ i ] , & curRotInv ) ; //dest first arg
vec3_t delAngles ;
VectorClear ( delAngles ) ;
for ( k = 0 ; k < 3 ; k + + )
{
tAngles [ k ] + = 0.5f ;
Create_Matrix ( tAngles , & temp2 ) ; //dest 2nd arg
tAngles [ k ] - = 0.5f ;
Multiply_3x4Matrix ( & temp1 , & P , & temp2 ) ; //dest first arg
Multiply_3x4Matrix ( & Gs [ k ] , & temp1 , & N ) ; //dest first arg
}
// fixme precompute this
int numDep = G2_GetBoneDependents ( ghoul2 , bone . boneNumber , tempDependents , MAX_BONES_RAG ) ;
int j ;
int numRagDep = 0 ;
for ( j = 0 ; j < numDep ; j + + )
{
//fixme why do this for the special roots?
if ( ! ( tempDependents [ j ] < rag . size ( ) & & rag [ tempDependents [ j ] ] ) )
{
continue ;
}
int depIndex = rag [ tempDependents [ j ] ] - > ragIndex ;
if ( ! ragBoneData [ depIndex ] )
{
continue ;
}
boneInfo_t & depBone = * ragBoneData [ depIndex ] ;
if ( depBone . RagFlags & RAG_EFFECTOR )
{
// this is a dependent of me, and also a rag
numRagDep + + ;
for ( k = 0 ; k < 3 ; k + + )
{
Multiply_3x4Matrix ( & Enew [ k ] , & Gs [ k ] , & ragBones [ depIndex ] ) ; //dest first arg
vec3_t tPosition ;
tPosition [ 0 ] = Enew [ k ] . matrix [ 0 ] [ 3 ] ;
tPosition [ 1 ] = Enew [ k ] . matrix [ 1 ] [ 3 ] ;
tPosition [ 2 ] = Enew [ k ] . matrix [ 2 ] [ 3 ] ;
vec3_t change ;
VectorSubtract ( tPosition , ragEffectors [ depIndex ] . currentOrigin , change ) ; // dest is last arg
float goodness = DotProduct ( change , ragEffectors [ depIndex ] . desiredDirection ) ;
assert ( ! _isnan ( goodness ) ) ;
goodness * = depBone . weight ;
delAngles [ k ] + = goodness ; // keep bigger stuff more out of wall or something
assert ( ! _isnan ( delAngles [ k ] ) ) ;
}
}
}
VectorCopy ( bone . currentAngles , bone . lastAngles ) ;
// Update angles
float magicFactor9 = 0.75f ; // dampfactor for angle changes
float magicFactor1 = bone . ikSpeed ; //controls the speed of the gradient descent
float magicFactor32 = 1.0f ;
float recip = 0.0f ;
bool freeThisBone = false ;
if ( ! magicFactor1 )
{
magicFactor1 = 0.40f ;
}
recip = sqrt ( 4.0f / 1.0f ) ;
float fac = ( decay * recip * magicFactor1 ) ;
assert ( fac > = 0.0f ) ;
if ( ragState = = ERS_DYNAMIC )
{
magicFactor9 = 0.85f ; // we don't want this swinging radically, make the whole thing kindof unstable
}
if ( ! bone . maxAngles [ 0 ] & & ! bone . maxAngles [ 1 ] & & ! bone . maxAngles [ 2 ] & &
! bone . minAngles [ 0 ] & & ! bone . minAngles [ 1 ] & & ! bone . minAngles [ 2 ] )
{
freeThisBone = true ;
}
for ( k = 0 ; k < 3 ; k + + )
{
bone . currentAngles [ k ] + = delAngles [ k ] * fac ;
bone . currentAngles [ k ] = ( bone . lastAngles [ k ] - bone . currentAngles [ k ] ) * magicFactor9 + bone . currentAngles [ k ] ;
bone . currentAngles [ k ] = AngleNormZero ( bone . currentAngles [ k ] ) ;
if ( limitAngles & & ! freeThisBone )
{
if ( bone . currentAngles [ k ] > bone . maxAngles [ k ] * magicFactor32 )
{
bone . currentAngles [ k ] = bone . maxAngles [ k ] * magicFactor32 ;
}
if ( bone . currentAngles [ k ] < bone . minAngles [ k ] * magicFactor32 )
{
bone . currentAngles [ k ] = bone . minAngles [ k ] * magicFactor32 ;
}
}
}
Create_Matrix ( bone . currentAngles , & temp1 ) ;
Multiply_3x4Matrix ( & temp2 , & temp1 , bone . baseposeInv ) ;
Multiply_3x4Matrix ( & bone . ragOverrideMatrix , bone . basepose , & temp2 ) ;
assert ( ! _isnan ( bone . ragOverrideMatrix . matrix [ 2 ] [ 3 ] ) ) ;
G2_Generate_MatrixRag ( blist , ragBlistIndex [ bone . boneNumber ] ) ;
}
}
static void G2_DoIK ( CGhoul2Info_v & ghoul2V , int g2Index , CRagDollUpdateParams * params )
{
int i ;
if ( ! params )
{
assert ( 0 ) ;
return ;
}
int frameNum = G2API_GetTime ( 0 ) ;
CGhoul2Info & ghoul2 = ghoul2V [ g2Index ] ;
assert ( ghoul2 . mFileName [ 0 ] ) ;
float decay = 1.0f ;
bool resetOrigin = false ;
bool anyRendered = false ;
int iters = 12 ; //since we don't trace or anything, we can afford this.
if ( iters )
{
if ( ! G2_RagDollSetup ( ghoul2 , frameNum , resetOrigin , params - > position , anyRendered ) )
{
return ;
}
// ok, now our data structures are compact and set up in topological order
for ( i = 0 ; i < iters ; i + + )
{
G2_RagDollCurrentPosition ( ghoul2V , g2Index , frameNum , params - > angles , params - > position , params - > scale ) ;
G2_IKReposition ( params - > position , params ) ;
G2_IKSolve ( ghoul2V , g2Index , decay * 2.0f , frameNum , params - > position , true ) ;
}
}
if ( params - > me ! = ENTITYNUM_NONE )
{
G2_RagDollCurrentPosition ( ghoul2V , g2Index , frameNum , params - > angles , params - > position , params - > scale ) ;
}
}
//rww - cut out the entire non-ragdoll section of this..
void G2_Animate_Bone_List ( CGhoul2Info_v & ghoul2 , const int currentTime , const int index , CRagDollUpdateParams * params )
{
int i ;
bool anyRagDoll = false ;
bool anyIK = false ;
for ( i = 0 ; i < ghoul2 [ index ] . mBlist . size ( ) ; i + + )
{
if ( ghoul2 [ index ] . mBlist [ i ] . boneNumber ! = - 1 )
{
if ( ghoul2 [ index ] . mBlist [ i ] . flags & BONE_ANGLES_RAGDOLL )
{
if ( ghoul2 [ index ] . mBlist [ i ] . RagFlags & RAG_PCJ_IK_CONTROLLED )
{
anyIK = true ;
}
anyRagDoll = true ;
if ( anyIK & & anyRagDoll )
{
break ;
}
}
}
}
if ( ! index & & params )
{
if ( anyIK )
{ //we use ragdoll params so we know what our current position, etc. is.
G2_DoIK ( ghoul2 , 0 , params ) ;
}
else
{
G2_RagDoll ( ghoul2 , 0 , params , currentTime ) ;
}
}
}
//rww - RAGDOLL_END
static int G2_Set_Bone_Angles_IK (
CGhoul2Info & ghoul2 ,
const mdxaHeader_t * mod_a ,
boneInfo_v & blist ,
const char * boneName ,
const int flags ,
const float radius ,
const vec3_t angleMin = 0 ,
const vec3_t angleMax = 0 ,
const int blendTime = 500 )
{
int index = G2_Find_Bone_Rag ( & ghoul2 , blist , boneName ) ;
if ( index = = - 1 )
{
index = G2_Add_Bone ( ghoul2 . animModel , blist , boneName ) ;
}
if ( index ! = - 1 )
{
boneInfo_t & bone = blist [ index ] ;
bone . flags | = BONE_ANGLES_IK ;
bone . flags & = ~ BONE_ANGLES_RAGDOLL ;
bone . ragStartTime = G2API_GetTime ( 0 ) ;
bone . radius = radius ;
bone . weight = 1.0f ;
if ( angleMin & & angleMax )
{
VectorCopy ( angleMin , bone . minAngles ) ;
VectorCopy ( angleMax , bone . maxAngles ) ;
}
else
{
VectorCopy ( bone . currentAngles , bone . minAngles ) ; // I guess this isn't a rag pcj then
VectorCopy ( bone . currentAngles , bone . maxAngles ) ;
}
if ( ! bone . lastTimeUpdated )
{
static mdxaBone_t id =
{
1.0f , 0.0f , 0.0f , 0.0f ,
0.0f , 1.0f , 0.0f , 0.0f ,
0.0f , 0.0f , 1.0f , 0.0f
} ;
memcpy ( & bone . ragOverrideMatrix , & id , sizeof ( mdxaBone_t ) ) ;
VectorClear ( bone . anglesOffset ) ;
VectorClear ( bone . positionOffset ) ;
VectorClear ( bone . velocityEffector ) ; // this is actually a velocity now
VectorClear ( bone . velocityRoot ) ; // this is actually a velocity now
VectorClear ( bone . lastPosition ) ;
VectorClear ( bone . lastShotDir ) ;
bone . lastContents = 0 ;
// if this is non-zero, we are in a dynamic state
bone . firstCollisionTime = bone . ragStartTime ;
// if this is non-zero, we are in a settling state
bone . restTime = 0 ;
// if they are both zero, we are in a settled state
bone . firstTime = 0 ;
bone . RagFlags = flags ;
bone . DependentRagIndexMask = 0 ;
G2_Generate_MatrixRag ( blist , index ) ; // set everything to th id
VectorClear ( bone . currentAngles ) ;
VectorCopy ( bone . currentAngles , bone . lastAngles ) ;
}
}
return index ;
}
void G2_InitIK ( CGhoul2Info_v & ghoul2V , sharedRagDollUpdateParams_t * parms , int time , const mdxaHeader_t * mod_a , int model )
{
CGhoul2Info & ghoul2 = ghoul2V [ model ] ;
int curTime = time ;
boneInfo_v & blist = ghoul2 . mBlist ;
G2_GenerateWorldMatrix ( parms - > angles , parms - > position ) ;
G2_ConstructGhoulSkeleton ( ghoul2V , curTime , false , parms - > scale ) ;
// new base anim, unconscious flop
int pcjFlags ;
#if 0
vec3_t pcjMin , pcjMax ;
VectorClear ( pcjMin ) ;
VectorClear ( pcjMax ) ;
pcjFlags = RAG_PCJ | RAG_PCJ_POST_MULT ; //|RAG_EFFECTOR;
G2_Set_Bone_Angles_IK ( ghoul2 , mod_a , blist , " model_root " , RAG_PCJ_MODEL_ROOT | RAG_PCJ , 10.0f , pcjMin , pcjMax , 100 ) ;
G2_Set_Bone_Angles_IK ( ghoul2 , mod_a , blist , " pelvis " , RAG_PCJ_PELVIS | RAG_PCJ | RAG_PCJ_POST_MULT , 10.0f , pcjMin , pcjMax , 100 ) ;
G2_Set_Bone_Angles_IK ( ghoul2 , mod_a , blist , " lower_lumbar " , pcjFlags , 10.0f , pcjMin , pcjMax , 500 ) ;
G2_Set_Bone_Angles_IK ( ghoul2 , mod_a , blist , " upper_lumbar " , pcjFlags , 10.0f , pcjMin , pcjMax , 500 ) ;
G2_Set_Bone_Angles_IK ( ghoul2 , mod_a , blist , " thoracic " , pcjFlags | RAG_EFFECTOR , 12.0f , pcjMin , pcjMax , 500 ) ;
G2_Set_Bone_Angles_IK ( ghoul2 , mod_a , blist , " cranium " , pcjFlags , 6.0f , pcjMin , pcjMax , 500 ) ;
G2_Set_Bone_Angles_IK ( ghoul2 , mod_a , blist , " rhumerus " , pcjFlags , 4.0f , pcjMin , pcjMax , 500 ) ;
G2_Set_Bone_Angles_IK ( ghoul2 , mod_a , blist , " lhumerus " , pcjFlags , 4.0f , pcjMin , pcjMax , 500 ) ;
G2_Set_Bone_Angles_IK ( ghoul2 , mod_a , blist , " rradius " , pcjFlags , 3.0f , pcjMin , pcjMax , 500 ) ;
G2_Set_Bone_Angles_IK ( ghoul2 , mod_a , blist , " lradius " , pcjFlags , 3.0f , pcjMin , pcjMax , 500 ) ;
G2_Set_Bone_Angles_IK ( ghoul2 , mod_a , blist , " rfemurYZ " , pcjFlags , 6.0f , pcjMin , pcjMax , 500 ) ;
G2_Set_Bone_Angles_IK ( ghoul2 , mod_a , blist , " lfemurYZ " , pcjFlags , 6.0f , pcjMin , pcjMax , 500 ) ;
G2_Set_Bone_Angles_IK ( ghoul2 , mod_a , blist , " rtibia " , pcjFlags , 4.0f , pcjMin , pcjMax , 500 ) ;
G2_Set_Bone_Angles_IK ( ghoul2 , mod_a , blist , " ltibia " , pcjFlags , 4.0f , pcjMin , pcjMax , 500 ) ;
G2_ConstructGhoulSkeleton ( ghoul2V , curTime , false , parms - > scale ) ;
# endif
//Only need the standard effectors for this.
pcjFlags = RAG_PCJ | RAG_PCJ_POST_MULT | RAG_EFFECTOR ;
G2_Set_Bone_Angles_IK ( ghoul2 , mod_a , blist , " rhand " , pcjFlags , 6.0f ) ;
G2_Set_Bone_Angles_IK ( ghoul2 , mod_a , blist , " lhand " , pcjFlags , 6.0f ) ;
// G2_Set_Bone_Angles_IK(ghoul2, mod_a,blist,"rtarsal",pcjFlags,4.0f);
// G2_Set_Bone_Angles_IK(ghoul2, mod_a,blist,"ltarsal",pcjFlags,4.0f);
G2_Set_Bone_Angles_IK ( ghoul2 , mod_a , blist , " rtibia " , pcjFlags , 4.0f ) ;
G2_Set_Bone_Angles_IK ( ghoul2 , mod_a , blist , " ltibia " , pcjFlags , 4.0f ) ;
G2_Set_Bone_Angles_IK ( ghoul2 , mod_a , blist , " rtalus " , pcjFlags , 4.0f ) ;
G2_Set_Bone_Angles_IK ( ghoul2 , mod_a , blist , " ltalus " , pcjFlags , 4.0f ) ;
G2_Set_Bone_Angles_IK ( ghoul2 , mod_a , blist , " rradiusX " , pcjFlags , 6.0f ) ;
G2_Set_Bone_Angles_IK ( ghoul2 , mod_a , blist , " lradiusX " , pcjFlags , 6.0f ) ;
G2_Set_Bone_Angles_IK ( ghoul2 , mod_a , blist , " rfemurX " , pcjFlags , 10.0f ) ;
G2_Set_Bone_Angles_IK ( ghoul2 , mod_a , blist , " lfemurX " , pcjFlags , 10.0f ) ;
G2_Set_Bone_Angles_IK ( ghoul2 , mod_a , blist , " ceyebrow " , pcjFlags , 10.0f ) ;
}
qboolean G2_SetBoneIKState ( CGhoul2Info_v & ghoul2 , int time , const char * boneName , int ikState , sharedSetBoneIKStateParams_t * params )
{
model_t * mod_a ;
int g2index = 0 ;
int curTime = time ;
CGhoul2Info & g2 = ghoul2 [ g2index ] ;
const mdxaHeader_t * rmod_a = G2_GetModA ( g2 ) ;
boneInfo_v & blist = g2 . mBlist ;
mod_a = ( model_t * ) g2 . animModel ;
if ( ! boneName )
{ //null bonename param means it's time to init the ik stuff on this instance
sharedRagDollUpdateParams_t sRDUP ;
if ( ikState = = IKS_NONE )
{ //this means we want to reset the IK state completely.. run through the bone list, and reset all the appropriate flags
int i = 0 ;
while ( i < blist . size ( ) )
{ //we can't use this method for ragdoll. However, since we expect them to set their anims/angles again on the PCJ
//limb after they reset it gameside, it's reasonable for IK bones.
boneInfo_t & bone = blist [ i ] ;
if ( bone . boneNumber ! = - 1 )
{
bone . flags & = ~ BONE_ANGLES_RAGDOLL ;
bone . flags & = ~ BONE_ANGLES_IK ;
bone . RagFlags = 0 ;
bone . lastTimeUpdated = 0 ;
}
i + + ;
}
return qtrue ;
}
assert ( params ) ;
if ( ! params )
{
return qfalse ;
}
sRDUP . me = 0 ;
VectorCopy ( params - > angles , sRDUP . angles ) ;
VectorCopy ( params - > origin , sRDUP . position ) ;
VectorCopy ( params - > scale , sRDUP . scale ) ;
VectorClear ( sRDUP . velocity ) ;
G2_InitIK ( ghoul2 , & sRDUP , curTime , rmod_a , g2index ) ;
return qtrue ;
}
if ( ! rmod_a | | ! mod_a )
{
return qfalse ;
}
int index = G2_Find_Bone ( mod_a , blist , boneName ) ;
if ( index = = - 1 )
{
index = G2_Add_Bone ( mod_a , blist , boneName ) ;
}
if ( index = = - 1 )
{ //couldn't find or add the bone..
return qfalse ;
}
boneInfo_t & bone = blist [ index ] ;
if ( ikState = = IKS_NONE )
{ //remove the bone from the list then, so it has to reinit. I don't think this should hurt anything since
//we don't store bone index handles gameside anywhere.
if ( ! ( bone . flags & BONE_ANGLES_RAGDOLL ) )
{ //you can't set the ik state to none if it's not a rag/ik bone.
return qfalse ;
}
//bone.flags = 0;
//G2_Remove_Bone_Index(blist, index);
//actually, I want to keep it on the rag list, and remove it as an IK bone instead.
bone . flags & = ~ BONE_ANGLES_RAGDOLL ;
bone . flags | = BONE_ANGLES_IK ;
bone . RagFlags & = ~ RAG_PCJ_IK_CONTROLLED ;
return qtrue ;
}
//need params if we're not resetting.
if ( ! params )
{
assert ( 0 ) ;
return qfalse ;
}
if ( bone . flags & BONE_ANGLES_RAGDOLL )
{ //otherwise if the bone is already flagged as rag, then we can't set it again. (non-active ik bones will be BONE_ANGLES_IK, active are considered rag)
return qfalse ;
}
#if 0 //this is wrong now.. we're only initing effectors with initik now.. which SHOULDN'T be used as pcj's
if ( ! ( bone . flags & BONE_ANGLES_IK ) & & ! ( bone . flags & BONE_ANGLES_RAGDOLL ) )
{ //IK system has not been inited yet, because any bone that can be IK should be in the ragdoll list, not flagged as BONE_ANGLES_RAGDOLL but as BONE_ANGLES_IK
sharedRagDollUpdateParams_t sRDUP ;
sRDUP . me = 0 ;
VectorCopy ( params - > angles , sRDUP . angles ) ;
VectorCopy ( params - > origin , sRDUP . position ) ;
VectorCopy ( params - > scale , sRDUP . scale ) ;
VectorClear ( sRDUP . velocity ) ;
G2_InitIK ( ghoul2 , & sRDUP , curTime , rmod_a , g2index ) ;
G2_ConstructGhoulSkeleton ( ghoul2 , curTime , false , params - > scale ) ;
}
else
{
G2_GenerateWorldMatrix ( params - > angles , params - > origin ) ;
G2_ConstructGhoulSkeleton ( ghoul2 , curTime , false , params - > scale ) ;
}
# else
G2_GenerateWorldMatrix ( params - > angles , params - > origin ) ;
G2_ConstructGhoulSkeleton ( ghoul2 , curTime , false , params - > scale ) ;
# endif
int pcjFlags = RAG_PCJ | RAG_PCJ_IK_CONTROLLED | RAG_PCJ_POST_MULT | RAG_EFFECTOR ;
if ( params - > pcjOverrides )
{
pcjFlags = params - > pcjOverrides ;
}
bone . ikSpeed = 0.4f ;
VectorClear ( bone . ikPosition ) ;
G2_Set_Bone_Rag ( rmod_a , blist , boneName , g2 , params - > scale , params - > origin ) ;
int startFrame = params - > startFrame , endFrame = params - > endFrame ;
if ( bone . startFrame ! = startFrame | | bone . endFrame ! = endFrame | | params - > forceAnimOnBone )
{ //if it's already on this anim leave it alone, to allow smooth transitions into IK on the current anim if it is so desired.
G2_Set_Bone_Anim_No_BS ( g2 , rmod_a , blist , boneName , startFrame , endFrame - 1 ,
BONE_ANIM_OVERRIDE_FREEZE | BONE_ANIM_BLEND ,
1.0f , curTime , float ( startFrame ) , 150 , 0 , true ) ;
}
G2_ConstructGhoulSkeleton ( ghoul2 , curTime , false , params - > scale ) ;
bone . lastTimeUpdated = 0 ;
G2_Set_Bone_Angles_Rag ( g2 , rmod_a , blist , boneName , pcjFlags , params - > radius , params - > pcjMins , params - > pcjMaxs , params - > blendTime ) ;
if ( ! G2_RagDollSetup ( g2 , curTime , true , params - > origin , false ) )
{
assert ( ! " failed to add any rag bones " ) ;
return qfalse ;
}
return qtrue ;
}
qboolean G2_IKMove ( CGhoul2Info_v & ghoul2 , int time , sharedIKMoveParams_t * params )
{
#if 0
model_t * mod_a ;
int g2index = 0 ;
int curTime = time ;
CGhoul2Info & g2 = ghoul2 [ g2index ] ;
boneInfo_v & blist = g2 . mBlist ;
mod_a = ( model_t * ) g2 . animModel ;
if ( ! mod_a )
{
return qfalse ;
}
int index = G2_Find_Bone ( mod_a , blist , params - > boneName ) ;
//don't add here if you can't find it.. ik bones should already be there, because they need to have special stuff done to them anyway.
if ( index = = - 1 )
{ //couldn't find the bone..
return qfalse ;
}
if ( ! params )
{
assert ( 0 ) ;
return qfalse ;
}
if ( ! ( blist [ index ] . flags & BONE_ANGLES_RAGDOLL ) & & ! ( blist [ index ] . flags & BONE_ANGLES_IK ) )
{ //no-can-do, buddy
return qfalse ;
}
VectorCopy ( params - > desiredOrigin , blist [ index ] . ikPosition ) ;
blist [ index ] . ikSpeed = params - > movementSpeed ;
# else
int g2index = 0 ;
int curTime = time ;
CGhoul2Info & g2 = ghoul2 [ g2index ] ;
//rwwFIXMEFIXME: Doing this on all bones at the moment, fix this later?
if ( ! G2_RagDollSetup ( g2 , curTime , true , params - > origin , false ) )
{ //changed models, possibly.
return qfalse ;
}
for ( int i = 0 ; i < numRags ; i + + )
{
boneInfo_t & bone = * ragBoneData [ i ] ;
//if (bone.boneNumber == blist[index].boneNumber)
{
VectorCopy ( params - > desiredOrigin , bone . ikPosition ) ;
bone . ikSpeed = params - > movementSpeed ;
}
}
# endif
return qtrue ;
}
// 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 ) ) ;
}