2013-04-19 02:52:48 +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
# if !defined(G2_H_INC)
# include "G2.h"
# endif
# include "G2_local.h"
# include "../qcommon/MiniHeap.h"
//rww - RAGDOLL_BEGIN
# include "G2_gore.h"
//rww - RAGDOLL_END
extern vm_t * gvm ;
extern vm_t * currentVM ; //Yeah. So very wrong.
# include <set>
# pragma warning (push, 3) //go back down to 3 for the stl include
# include <list>
# include <string>
# pragma warning (pop)
# ifdef _FULL_G2_LEAK_CHECKING
int g_Ghoul2Allocations = 0 ;
int g_G2ServerAlloc = 0 ;
int g_G2ClientAlloc = 0 ;
int g_G2AllocServer = 0 ;
//stupid debug crap to track leaks in case they happen.
//we used to shove everything into a map and delete it all and not care about
//leaks, but that was not the Right Thing. -rww
# define MAX_TRACKED_ALLOC 4096
static bool g_G2AllocTrackInit = false ; //want to keep this thing contained
static CGhoul2Info_v * g_G2AllocTrack [ MAX_TRACKED_ALLOC ] ;
void G2_DEBUG_InitPtrTracker ( void )
{
memset ( g_G2AllocTrack , 0 , sizeof ( g_G2AllocTrack ) ) ;
g_G2AllocTrackInit = true ;
}
void G2_DEBUG_ReportLeaks ( void )
{
int i = 0 ;
if ( ! g_G2AllocTrackInit )
{
Com_Printf ( " g2 leak tracker was never initialized! \n " ) ;
return ;
}
while ( i < MAX_TRACKED_ALLOC )
{
if ( g_G2AllocTrack [ i ] )
{
Com_Printf ( " Bad guy found in slot %i, attempting to access... " , i ) ;
CGhoul2Info_v & g2v = * g_G2AllocTrack [ i ] ;
CGhoul2Info & g2 = g2v [ 0 ] ;
if ( g2v . IsValid ( ) & & g2 . mFileName & & g2 . mFileName [ 0 ] )
{
Com_Printf ( " Bad guy's filename is %s \n " , g2 . mFileName ) ;
}
else
{
Com_Printf ( " He's not valid! BURN HIM! \n " ) ;
}
}
i + + ;
}
}
void G2_DEBUG_ShovePtrInTracker ( CGhoul2Info_v * g2 )
{
int i = 0 ;
if ( ! g_G2AllocTrackInit )
{
G2_DEBUG_InitPtrTracker ( ) ;
}
if ( ! g_G2AllocTrackInit )
{
G2_DEBUG_InitPtrTracker ( ) ;
}
while ( i < MAX_TRACKED_ALLOC )
{
if ( ! g_G2AllocTrack [ i ] )
{
g_G2AllocTrack [ i ] = g2 ;
return ;
}
i + + ;
}
CGhoul2Info_v & g2v = * g2 ;
if ( g2v [ 0 ] . currentModel & & g2v [ 0 ] . currentModel - > name & & g2v [ 0 ] . currentModel - > name [ 0 ] )
{
Com_Printf ( " %s could not be fit into g2 debug instance tracker. \n " , g2v [ 0 ] . currentModel - > name ) ;
}
else
{
Com_Printf ( " Crap g2 instance passed to instance tracker (in). \n " ) ;
}
}
void G2_DEBUG_RemovePtrFromTracker ( CGhoul2Info_v * g2 )
{
int i = 0 ;
if ( ! g_G2AllocTrackInit )
{
G2_DEBUG_InitPtrTracker ( ) ;
}
while ( i < MAX_TRACKED_ALLOC )
{
if ( g_G2AllocTrack [ i ] = = g2 )
{
g_G2AllocTrack [ i ] = NULL ;
return ;
}
i + + ;
}
CGhoul2Info_v & g2v = * g2 ;
if ( g2v [ 0 ] . currentModel & & g2v [ 0 ] . currentModel - > name & & g2v [ 0 ] . currentModel - > name [ 0 ] )
{
Com_Printf ( " %s not in g2 debug instance tracker. \n " , g2v [ 0 ] . currentModel - > name ) ;
}
else
{
Com_Printf ( " Crap g2 instance passed to instance tracker (out). \n " ) ;
}
}
# endif
extern mdxaBone_t worldMatrix ;
extern mdxaBone_t worldMatrixInv ;
qboolean G2_SetupModelPointers ( CGhoul2Info * ghlInfo ) ;
qboolean G2_SetupModelPointers ( CGhoul2Info_v & ghoul2 ) ;
qboolean G2_TestModelPointers ( CGhoul2Info * ghlInfo ) ;
//rww - RAGDOLL_BEGIN
# define NUM_G2T_TIME (2)
static int G2TimeBases [ NUM_G2T_TIME ] ;
void G2API_SetTime ( int currentTime , int clock )
{
assert ( clock > = 0 & & clock < NUM_G2T_TIME ) ;
# if G2_DEBUG_TIME
Com_Printf ( " Set Time: before c%6d s%6d " , G2TimeBases [ 1 ] , G2TimeBases [ 0 ] ) ;
# endif
G2TimeBases [ clock ] = currentTime ;
if ( G2TimeBases [ 1 ] > G2TimeBases [ 0 ] + 200 )
{
G2TimeBases [ 1 ] = 0 ; // use server time instead
return ;
}
# if G2_DEBUG_TIME
Com_Printf ( " after c%6d s%6d \n " , G2TimeBases [ 1 ] , G2TimeBases [ 0 ] ) ;
# endif
}
int G2API_GetTime ( int argTime ) // this may or may not return arg depending on ghoul2_time cvar
{
int ret = G2TimeBases [ 1 ] ;
if ( ! ret )
{
ret = G2TimeBases [ 0 ] ;
}
return ret ;
}
//rww - RAGDOLL_END
//rww - Stuff to allow association of ghoul2 instances to entity numbers.
//This way, on listen servers when both the client and server are doing
//ghoul2 operations, we can copy relevant data off the client instance
//directly onto the server instance and slash the transforms and whatnot
//right in half.
# ifdef _G2_LISTEN_SERVER_OPT
CGhoul2Info_v * g2ClientAttachments [ MAX_GENTITIES ] ;
# endif
void G2API_AttachInstanceToEntNum ( CGhoul2Info_v & ghoul2 , int entityNum , qboolean server )
{ //Assign the pointers in the arrays
# ifdef _G2_LISTEN_SERVER_OPT
if ( server )
{
ghoul2 [ 0 ] . entityNum = entityNum ;
}
else
{
g2ClientAttachments [ entityNum ] = & ghoul2 ;
}
# endif
}
void G2API_ClearAttachedInstance ( int entityNum )
{
# ifdef _G2_LISTEN_SERVER_OPT
g2ClientAttachments [ entityNum ] = NULL ;
# endif
}
void G2API_CleanEntAttachments ( void )
{
# ifdef _G2_LISTEN_SERVER_OPT
int i = 0 ;
while ( i < MAX_GENTITIES )
{
g2ClientAttachments [ i ] = NULL ;
i + + ;
}
# endif
}
void RemoveBoneCache ( CBoneCache * boneCache ) ;
# ifdef _G2_LISTEN_SERVER_OPT
void CopyBoneCache ( CBoneCache * to , CBoneCache * from ) ;
# endif
qboolean G2API_OverrideServerWithClientData ( CGhoul2Info * serverInstance )
{
# ifndef _G2_LISTEN_SERVER_OPT
return qfalse ;
# else
CGhoul2Info * clientInstance ;
if ( com_dedicated - > integer )
{ //No client to get from!
return qfalse ;
}
if ( ! g2ClientAttachments [ serverInstance - > entityNum ] )
{ //No clientside instance is attached to this entity
return qfalse ;
}
CGhoul2Info_v & g2Ref = * g2ClientAttachments [ serverInstance - > entityNum ] ;
clientInstance = & g2Ref [ 0 ] ;
int frameNum = G2API_GetTime ( 0 ) ;
if ( clientInstance - > mSkelFrameNum ! = frameNum )
{ //it has to be constructed already
return qfalse ;
}
if ( ! clientInstance - > mBoneCache )
{ //that just won't do
return qfalse ;
}
//Just copy over the essentials
serverInstance - > aHeader = clientInstance - > aHeader ;
serverInstance - > animModel = clientInstance - > animModel ;
serverInstance - > currentAnimModelSize = clientInstance - > currentAnimModelSize ;
serverInstance - > currentModel = clientInstance - > currentModel ;
serverInstance - > currentModelSize = clientInstance - > currentModelSize ;
serverInstance - > mAnimFrameDefault = clientInstance - > mAnimFrameDefault ;
serverInstance - > mModel = clientInstance - > mModel ;
serverInstance - > mModelindex = clientInstance - > mModelindex ;
serverInstance - > mSurfaceRoot = clientInstance - > mSurfaceRoot ;
serverInstance - > mTransformedVertsArray = clientInstance - > mTransformedVertsArray ;
if ( ! serverInstance - > mBoneCache )
{ //if this is the case.. I guess we can use the client one instead
serverInstance - > mBoneCache = clientInstance - > mBoneCache ;
}
//Copy the contents of the client cache over the contents of the server cache
if ( serverInstance - > mBoneCache ! = clientInstance - > mBoneCache )
{
CopyBoneCache ( serverInstance - > mBoneCache , clientInstance - > mBoneCache ) ;
}
serverInstance - > mSkelFrameNum = clientInstance - > mSkelFrameNum ;
return qtrue ;
# endif
}
// must be a power of two
# ifdef _XBOX
# define MAX_G2_MODELS (512)
# define G2_MODEL_BITS (9)
# else
# define MAX_G2_MODELS (1024)
# define G2_MODEL_BITS (10)
# endif
# define G2_INDEX_MASK (MAX_G2_MODELS-1)
class Ghoul2InfoArray : public IGhoul2InfoArray
{
vector < CGhoul2Info > mInfos [ MAX_G2_MODELS ] ;
int mIds [ MAX_G2_MODELS ] ;
list < int > mFreeIndecies ;
void DeleteLow ( int idx )
{
{
int model ;
for ( model = 0 ; model < mInfos [ idx ] . size ( ) ; model + + )
{
if ( mInfos [ idx ] [ model ] . mBoneCache )
{
RemoveBoneCache ( mInfos [ idx ] [ model ] . mBoneCache ) ;
mInfos [ idx ] [ model ] . mBoneCache = 0 ;
}
}
}
mInfos [ idx ] . clear ( ) ;
if ( ( mIds [ idx ] > > G2_MODEL_BITS ) > ( 1 < < ( 31 - G2_MODEL_BITS ) ) )
{
mIds [ idx ] = MAX_G2_MODELS + idx ; //rollover reset id to minimum value
mFreeIndecies . push_back ( idx ) ;
}
else
{
mIds [ idx ] + = MAX_G2_MODELS ;
mFreeIndecies . push_front ( idx ) ;
}
}
public :
Ghoul2InfoArray ( )
{
int i ;
for ( i = 0 ; i < MAX_G2_MODELS ; i + + )
{
mIds [ i ] = MAX_G2_MODELS + i ;
mFreeIndecies . push_back ( i ) ;
}
}
# if G2API_DEBUG
~ Ghoul2InfoArray ( )
{
char mess [ 1000 ] ;
if ( mFreeIndecies . size ( ) < MAX_G2_MODELS )
{
sprintf ( mess , " ************************ \n Leaked %d ghoul2info slots \n " , MAX_G2_MODELS - mFreeIndecies . size ( ) ) ;
OutputDebugString ( mess ) ;
int i ;
for ( i = 0 ; i < MAX_G2_MODELS ; i + + )
{
list < int > : : iterator j ;
for ( j = mFreeIndecies . begin ( ) ; j ! = mFreeIndecies . end ( ) ; j + + )
{
if ( * j = = i )
break ;
}
if ( j = = mFreeIndecies . end ( ) )
{
sprintf ( mess , " Leaked Info idx=%d id=%d sz=%d \n " , i , mIds [ i ] , mInfos [ i ] . size ( ) ) ;
OutputDebugString ( mess ) ;
if ( mInfos [ i ] . size ( ) )
{
sprintf ( mess , " %s \n " , mInfos [ i ] [ 0 ] . mFileName ) ;
OutputDebugString ( mess ) ;
}
}
}
}
else
{
OutputDebugString ( " No ghoul2 info slots leaked \n " ) ;
}
}
# endif
int New ( )
{
if ( mFreeIndecies . empty ( ) )
{
assert ( 0 ) ;
Com_Error ( ERR_FATAL , " Out of ghoul2 info slots " ) ;
}
// gonna pull from the front, doing a
int idx = * mFreeIndecies . begin ( ) ;
mFreeIndecies . erase ( mFreeIndecies . begin ( ) ) ;
return mIds [ idx ] ;
}
bool IsValid ( int handle ) const
{
if ( ! handle )
{
return false ;
}
assert ( handle > 0 ) ; //negative handle???
assert ( ( handle & G2_INDEX_MASK ) > = 0 & & ( handle & G2_INDEX_MASK ) < MAX_G2_MODELS ) ; //junk handle
if ( mIds [ handle & G2_INDEX_MASK ] ! = handle ) // not a valid handle, could be old
{
return false ;
}
return true ;
}
void Delete ( int handle )
{
if ( ! handle )
{
return ;
}
assert ( handle > 0 ) ; //null handle
assert ( ( handle & G2_INDEX_MASK ) > = 0 & & ( handle & G2_INDEX_MASK ) < MAX_G2_MODELS ) ; //junk handle
assert ( mIds [ handle & G2_INDEX_MASK ] = = handle ) ; // not a valid handle, could be old or garbage
if ( mIds [ handle & G2_INDEX_MASK ] = = handle )
{
DeleteLow ( handle & G2_INDEX_MASK ) ;
}
}
vector < CGhoul2Info > & Get ( int handle )
{
static vector < CGhoul2Info > null ;
assert ( handle > 0 ) ; //null handle
assert ( ( handle & G2_INDEX_MASK ) > = 0 & & ( handle & G2_INDEX_MASK ) < MAX_G2_MODELS ) ; //junk handle
assert ( mIds [ handle & G2_INDEX_MASK ] = = handle ) ; // not a valid handle, could be old or garbage
if ( handle < = 0 | | ( handle & G2_INDEX_MASK ) < 0 | | ( handle & G2_INDEX_MASK ) > = MAX_G2_MODELS | | mIds [ handle & G2_INDEX_MASK ] ! = handle )
{
null . clear ( ) ;
return null ;
}
return mInfos [ handle & G2_INDEX_MASK ] ;
}
const vector < CGhoul2Info > & Get ( int handle ) const
{
assert ( handle > 0 ) ;
assert ( mIds [ handle & G2_INDEX_MASK ] = = handle ) ; // not a valid handle, could be old or garbage
return mInfos [ handle & G2_INDEX_MASK ] ;
}
# if G2API_DEBUG
vector < CGhoul2Info > & GetDebug ( int handle )
{
static vector < CGhoul2Info > null ;
if ( handle < = 0 | | ( handle & G2_INDEX_MASK ) < 0 | | ( handle & G2_INDEX_MASK ) > = MAX_G2_MODELS | | mIds [ handle & G2_INDEX_MASK ] ! = handle )
{
return * ( vector < CGhoul2Info > * ) 0 ; // null reference, intentional
}
return mInfos [ handle & G2_INDEX_MASK ] ;
}
void TestAllAnims ( )
{
int j ;
for ( j = 0 ; j < MAX_G2_MODELS ; j + + )
{
vector < CGhoul2Info > & ghoul2 = mInfos [ j ] ;
int i ;
for ( i = 0 ; i < ghoul2 . size ( ) ; i + + )
{
if ( G2_SetupModelPointers ( & ghoul2 [ i ] ) )
{
G2ANIM ( & ghoul2 [ i ] , " Test All " ) ;
}
}
}
}
# endif
} ;
static Ghoul2InfoArray * singleton = NULL ;
IGhoul2InfoArray & TheGhoul2InfoArray ( )
{
if ( ! singleton ) {
singleton = new Ghoul2InfoArray ;
}
return * singleton ;
}
void Ghoul2InfoArray_Free ( void )
{
if ( singleton ) {
delete singleton ;
singleton = NULL ;
}
}
// this is the ONLY function to read entity states directly
void G2API_CleanGhoul2Models ( CGhoul2Info_v * * ghoul2Ptr )
{
if ( * ghoul2Ptr )
{
CGhoul2Info_v & ghoul2 = * ( * ghoul2Ptr ) ;
#if 0 //rwwFIXMEFIXME: Disable this before release!!!!!! I am just trying to find a crash bug.
extern int R_GetRNumEntities ( void ) ;
extern void R_SetRNumEntities ( int num ) ;
//check if this instance is actually on a refentity
int i = 0 ;
int r = R_GetRNumEntities ( ) ;
while ( i < r )
{
if ( ( CGhoul2Info_v * ) backEndData - > entities [ i ] . e . ghoul2 = = * ghoul2Ptr )
{
char fName [ MAX_QPATH ] ;
char mName [ MAX_QPATH ] ;
if ( ghoul2 [ 0 ] . currentModel )
{
strcpy ( mName , ghoul2 [ 0 ] . currentModel - > name ) ;
}
else
{
strcpy ( mName , " NULL! " ) ;
}
if ( ghoul2 [ 0 ] . mFileName & & ghoul2 [ 0 ] . mFileName [ 0 ] )
{
strcpy ( fName , ghoul2 [ 0 ] . mFileName ) ;
}
else
{
strcpy ( fName , " None?! " ) ;
}
Com_Printf ( " ERROR, GHOUL2 INSTANCE BEING REMOVED BELONGS TO A REFENTITY! \n This is in caps because it's important. Tell Rich and save the following text. \n \n " ) ;
Com_Printf ( " Ref num: %i \n Model: %s \n Filename: %s \n " , i , mName , fName ) ;
R_SetRNumEntities ( 0 ) ; //avoid recursive error
Com_Error ( ERR_DROP , " Write down or save this error message, show it to Rich \n Ref num: %i \n Model: %s \n Filename: %s \n " , i , mName , fName ) ;
}
i + + ;
}
# endif
# ifdef _G2_GORE
G2API_ClearSkinGore ( ghoul2 ) ;
# endif
ghoul2 . ~ CGhoul2Info_v ( ) ;
# ifdef _FULL_G2_LEAK_CHECKING
if ( g_G2AllocServer )
{
g_G2ServerAlloc - = sizeof ( * ghoul2Ptr ) ;
}
else
{
g_G2ClientAlloc - = sizeof ( * ghoul2Ptr ) ;
}
g_Ghoul2Allocations - = sizeof ( * ghoul2Ptr ) ;
G2_DEBUG_RemovePtrFromTracker ( * ghoul2Ptr ) ;
# endif
delete * ghoul2Ptr ;
* ghoul2Ptr = NULL ;
}
}
extern qboolean Com_TheHunkMarkHasBeenMade ( void ) ;
extern qboolean ShaderHashTableExists ( void ) ;
qboolean G2_ShouldRegisterServer ( void )
{
if ( currentVM & & currentVM = = gvm )
{
if ( com_cl_running & & com_cl_running - > integer & &
Com_TheHunkMarkHasBeenMade ( ) & & ShaderHashTableExists ( ) )
{ //if the hunk has been marked then we are now loading client assets so don't load on server.
return qfalse ;
}
return qtrue ;
}
return qfalse ;
}
qhandle_t G2API_PrecacheGhoul2Model ( const char * fileName )
{
if ( G2_ShouldRegisterServer ( ) )
{
return RE_RegisterServerModel ( ( char * ) fileName ) ;
}
else
{
return RE_RegisterModel ( ( char * ) fileName ) ;
}
}
void CL_InitRef ( void ) ;
void R_Register ( void ) ;
// initialise all that needs to be on a new Ghoul II model
int G2API_InitGhoul2Model ( CGhoul2Info_v * * ghoul2Ptr , const char * fileName , int modelIndex , qhandle_t customSkin ,
qhandle_t customShader , int modelFlags , int lodBias )
{
int model ;
CGhoul2Info newModel ;
// are we actually asking for a model to be loaded.
if ( ! fileName | | ! fileName [ 0 ] )
{
assert ( 0 ) ;
return - 1 ;
}
if ( ! ( * ghoul2Ptr ) )
{
* ghoul2Ptr = new CGhoul2Info_v ;
# ifdef _FULL_G2_LEAK_CHECKING
if ( g_G2AllocServer )
{
g_G2ServerAlloc + = sizeof ( CGhoul2Info_v ) ;
}
else
{
g_G2ClientAlloc + = sizeof ( CGhoul2Info_v ) ;
}
g_Ghoul2Allocations + = sizeof ( CGhoul2Info_v ) ;
G2_DEBUG_ShovePtrInTracker ( * ghoul2Ptr ) ;
# endif
}
CGhoul2Info_v & ghoul2 = * ( * ghoul2Ptr ) ;
// find a free spot in the list
for ( model = 0 ; model < ghoul2 . size ( ) ; model + + )
{
if ( ghoul2 [ model ] . mModelindex = = - 1 )
{
ghoul2 [ model ] = CGhoul2Info ( ) ;
break ;
}
}
if ( model = = ghoul2 . size ( ) )
{ //init should not be used to create additional models, only the first one
assert ( ghoul2 . size ( ) < 4 ) ; //use G2API_CopySpecificG2Model to add models
ghoul2 . push_back ( CGhoul2Info ( ) ) ;
}
strcpy ( ghoul2 [ model ] . mFileName , fileName ) ;
ghoul2 [ model ] . mModelindex = model ;
if ( ! G2_TestModelPointers ( & ghoul2 [ model ] ) )
{
ghoul2 [ model ] . mFileName [ 0 ] = 0 ;
ghoul2 [ model ] . mModelindex = - 1 ;
}
else
{
G2_Init_Bone_List ( ghoul2 [ model ] . mBlist ) ;
G2_Init_Bolt_List ( ghoul2 [ model ] . mBltlist ) ;
ghoul2 [ model ] . mCustomShader = customShader ;
ghoul2 [ model ] . mCustomSkin = customSkin ;
ghoul2 [ model ] . mLodBias = lodBias ;
ghoul2 [ model ] . mAnimFrameDefault = 0 ;
ghoul2 [ model ] . mFlags = 0 ;
ghoul2 [ model ] . mModelBoltLink = - 1 ;
}
return ghoul2 [ model ] . mModelindex ;
}
qboolean G2API_SetLodBias ( CGhoul2Info * ghlInfo , int lodBias )
{
if ( ghlInfo )
{
ghlInfo - > mLodBias = lodBias ;
return qtrue ;
}
return qfalse ;
}
void G2_SetSurfaceOnOffFromSkin ( CGhoul2Info * ghlInfo , qhandle_t renderSkin ) ;
qboolean G2API_SetSkin ( CGhoul2Info * ghlInfo , qhandle_t customSkin , qhandle_t renderSkin )
{
if ( ghlInfo )
{
ghlInfo - > mCustomSkin = customSkin ;
if ( renderSkin )
{ //this is going to set the surfs on/off matching the skin file
G2_SetSurfaceOnOffFromSkin ( ghlInfo , renderSkin ) ;
}
return qtrue ;
}
return qfalse ;
}
qboolean G2API_SetShader ( CGhoul2Info * ghlInfo , qhandle_t customShader )
{
if ( ghlInfo )
{
ghlInfo - > mCustomShader = customShader ;
return qtrue ;
}
return qfalse ;
}
qboolean G2API_SetSurfaceOnOff ( CGhoul2Info_v & ghoul2 , const char * surfaceName , const int flags )
{
CGhoul2Info * ghlInfo = NULL ;
if ( ( int ) & ghoul2 & & ghoul2 . size ( ) > 0 )
{
ghlInfo = & ghoul2 [ 0 ] ;
}
if ( G2_SetupModelPointers ( ghlInfo ) )
{
// ensure we flush the cache
ghlInfo - > mMeshFrameNum = 0 ;
return G2_SetSurfaceOnOff ( ghlInfo , ghlInfo - > mSlist , surfaceName , flags ) ;
}
return qfalse ;
}
int G2API_GetSurfaceOnOff ( CGhoul2Info * ghlInfo , const char * surfaceName )
{
if ( ghlInfo )
{
return G2_IsSurfaceOff ( ghlInfo , ghlInfo - > mSlist , surfaceName ) ;
}
return - 1 ;
}
qboolean G2API_SetRootSurface ( CGhoul2Info_v & ghoul2 , const int modelIndex , const char * surfaceName )
{
if ( G2_SetupModelPointers ( ghoul2 ) )
{
return G2_SetRootSurface ( ghoul2 , modelIndex , surfaceName ) ;
}
return qfalse ;
}
int G2API_AddSurface ( CGhoul2Info * ghlInfo , int surfaceNumber , int polyNumber , float BarycentricI , float BarycentricJ , int lod )
{
if ( G2_SetupModelPointers ( ghlInfo ) )
{
// ensure we flush the cache
ghlInfo - > mMeshFrameNum = 0 ;
return G2_AddSurface ( ghlInfo , surfaceNumber , polyNumber , BarycentricI , BarycentricJ , lod ) ;
}
return - 1 ;
}
qboolean G2API_RemoveSurface ( CGhoul2Info * ghlInfo , const int index )
{
if ( G2_SetupModelPointers ( ghlInfo ) )
{
// ensure we flush the cache
ghlInfo - > mMeshFrameNum = 0 ;
return G2_RemoveSurface ( ghlInfo - > mSlist , index ) ;
}
return qfalse ;
}
int G2API_GetParentSurface ( CGhoul2Info * ghlInfo , const int index )
{
if ( G2_SetupModelPointers ( ghlInfo ) )
{
return G2_GetParentSurface ( ghlInfo , index ) ;
}
return - 1 ;
}
int G2API_GetSurfaceRenderStatus ( CGhoul2Info * ghlInfo , const char * surfaceName )
{
if ( G2_SetupModelPointers ( ghlInfo ) )
{
return G2_IsSurfaceRendered ( ghlInfo , surfaceName , ghlInfo - > mSlist ) ;
}
return - 1 ;
}
qboolean G2API_HasGhoul2ModelOnIndex ( CGhoul2Info_v * * ghlRemove , const int modelIndex )
{
CGhoul2Info_v & ghlInfo = * * ghlRemove ;
if ( ! ghlInfo . size ( ) | | ( ghlInfo . size ( ) < = modelIndex ) | | ( ghlInfo [ modelIndex ] . mModelindex = = - 1 ) )
{
return qfalse ;
}
return qtrue ;
}
qboolean G2API_RemoveGhoul2Model ( CGhoul2Info_v * * ghlRemove , const int modelIndex )
{
CGhoul2Info_v & ghlInfo = * * ghlRemove ;
// sanity check
if ( ! ghlInfo . size ( ) | | ( ghlInfo . size ( ) < = modelIndex ) | | ( ghlInfo [ modelIndex ] . mModelindex = = - 1 ) )
{
// if we hit this assert then we are trying to delete a ghoul2 model on a ghoul2 instance that
// one way or another is already gone.
assert ( 0 ) ;
return qfalse ;
}
if ( ghlInfo . size ( ) > modelIndex )
{
# ifdef _G2_GORE
// Cleanup the gore attached to this model
if ( ghlInfo [ modelIndex ] . mGoreSetTag )
{
DeleteGoreSet ( ghlInfo [ modelIndex ] . mGoreSetTag ) ;
ghlInfo [ modelIndex ] . mGoreSetTag = 0 ;
}
# endif
if ( ghlInfo [ modelIndex ] . mBoneCache )
{
RemoveBoneCache ( ghlInfo [ modelIndex ] . mBoneCache ) ;
ghlInfo [ modelIndex ] . mBoneCache = 0 ;
}
// clear out the vectors this model used.
ghlInfo [ modelIndex ] . mBlist . clear ( ) ;
ghlInfo [ modelIndex ] . mBltlist . clear ( ) ;
ghlInfo [ modelIndex ] . mSlist . clear ( ) ;
// set us to be the 'not active' state
ghlInfo [ modelIndex ] . mModelindex = - 1 ;
int newSize = ghlInfo . 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 = ghlInfo . size ( ) - 1 ; i > - 1 ; i - - )
{
if ( ghlInfo [ i ] . mModelindex = = - 1 )
{
newSize = i ;
}
// once we hit one that isn't a -1, we are done.
else
{
break ;
}
}
// do we need to resize?
if ( newSize ! = ghlInfo . size ( ) )
{
// yes, so lets do it
ghlInfo . resize ( newSize ) ;
}
// if we are not using any space, just delete the ghoul2 vector entirely
if ( ! ghlInfo . size ( ) )
{
# ifdef _FULL_G2_LEAK_CHECKING
if ( g_G2AllocServer )
{
g_G2ServerAlloc - = sizeof ( * ghlRemove ) ;
}
else
{
g_G2ClientAlloc - = sizeof ( * ghlRemove ) ;
}
g_Ghoul2Allocations - = sizeof ( * ghlRemove ) ;
# endif
delete * ghlRemove ;
* ghlRemove = NULL ;
}
}
return qtrue ;
}
qboolean G2API_RemoveGhoul2Models ( CGhoul2Info_v * * ghlRemove )
{ //remove 'em ALL!
CGhoul2Info_v & ghlInfo = * * ghlRemove ;
int modelIndex = 0 ;
int newSize = 0 ;
int i ;
// sanity check
if ( ! ghlInfo . size ( ) )
{ // if we hit this then we are trying to delete a ghoul2 model on a ghoul2 instance that
// one way or another is already gone.
return qfalse ;
}
for ( modelIndex = 0 ; modelIndex < ghlInfo . size ( ) ; modelIndex + + )
{
if ( ghlInfo [ modelIndex ] . mModelindex = = - 1 )
{
continue ;
}
# ifdef _G2_GORE
// Cleanup the gore attached to this model
if ( ghlInfo [ modelIndex ] . mGoreSetTag )
{
DeleteGoreSet ( ghlInfo [ modelIndex ] . mGoreSetTag ) ;
ghlInfo [ modelIndex ] . mGoreSetTag = 0 ;
}
# endif
if ( ghlInfo [ modelIndex ] . mBoneCache )
{
RemoveBoneCache ( ghlInfo [ modelIndex ] . mBoneCache ) ;
ghlInfo [ modelIndex ] . mBoneCache = 0 ;
}
// clear out the vectors this model used.
ghlInfo [ modelIndex ] . mBlist . clear ( ) ;
ghlInfo [ modelIndex ] . mBltlist . clear ( ) ;
ghlInfo [ modelIndex ] . mSlist . clear ( ) ;
// set us to be the 'not active' state
ghlInfo [ modelIndex ] . mModelindex = - 1 ;
}
newSize = ghlInfo . 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 ( i = ghlInfo . size ( ) - 1 ; i > - 1 ; i - - )
{
if ( ghlInfo [ i ] . mModelindex = = - 1 )
{
newSize = i ;
}
// once we hit one that isn't a -1, we are done.
else
{
break ;
}
}
// do we need to resize?
if ( newSize ! = ghlInfo . size ( ) )
{
// yes, so lets do it
ghlInfo . resize ( newSize ) ;
}
// if we are not using any space, just delete the ghoul2 vector entirely
if ( ! ghlInfo . size ( ) )
{
# ifdef _FULL_G2_LEAK_CHECKING
if ( g_G2AllocServer )
{
g_G2ServerAlloc - = sizeof ( * ghlRemove ) ;
}
else
{
g_G2ClientAlloc - = sizeof ( * ghlRemove ) ;
}
g_Ghoul2Allocations - = sizeof ( * ghlRemove ) ;
# endif
delete * ghlRemove ;
* ghlRemove = NULL ;
}
return qtrue ;
}
//check if a bone exists on skeleton without actually adding to the bone list -rww
qboolean G2API_DoesBoneExist ( CGhoul2Info * ghlInfo , const char * boneName )
{
if ( G2_SetupModelPointers ( ghlInfo ) )
{ //model is valid
mdxaHeader_t * mdxa = ghlInfo - > currentModel - > mdxa ;
if ( mdxa )
{ //get the skeleton data and iterate through the bones
int i ;
mdxaSkel_t * skel ;
mdxaSkelOffsets_t * offsets ;
offsets = ( mdxaSkelOffsets_t * ) ( ( byte * ) mdxa + sizeof ( mdxaHeader_t ) ) ;
for ( i = 0 ; i < mdxa - > numBones ; i + + )
{
skel = ( mdxaSkel_t * ) ( ( byte * ) mdxa + sizeof ( mdxaHeader_t ) + offsets - > offsets [ i ] ) ;
if ( ! Q_stricmp ( skel - > name , boneName ) )
{ //got it
return qtrue ;
}
}
}
}
//guess it doesn't exist
return qfalse ;
}
//rww - RAGDOLL_BEGIN
# define GHOUL2_RAG_STARTED 0x0010
# define GHOUL2_RAG_FORCESOLVE 0x1000 //api-override, determine if ragdoll should be forced to continue solving even if it thinks it is settled
//rww - RAGDOLL_END
qboolean G2API_SetBoneAnimIndex ( CGhoul2Info * ghlInfo , const int index , const int AstartFrame , const int AendFrame , const int flags , const float animSpeed , const int currentTime , const float AsetFrame , const int blendTime )
{
qboolean setPtrs = qfalse ;
qboolean res = qfalse ;
//rww - RAGDOLL_BEGIN
if ( ghlInfo )
{
res = G2_SetupModelPointers ( ghlInfo ) ;
setPtrs = qtrue ;
if ( res )
{
if ( ghlInfo - > mFlags & GHOUL2_RAG_STARTED )
{
return qfalse ;
}
}
}
//rww - RAGDOLL_END
int endFrame = AendFrame ;
int startFrame = AstartFrame ;
float setFrame = AsetFrame ;
assert ( endFrame > 0 ) ;
assert ( startFrame > = 0 ) ;
assert ( endFrame < 100000 ) ;
assert ( startFrame < 100000 ) ;
assert ( setFrame > = 0.0f | | setFrame = = - 1.0f ) ;
assert ( setFrame < = 100000.0f ) ;
if ( endFrame < = 0 )
{
endFrame = 1 ;
}
if ( endFrame > = 100000 )
{
endFrame = 1 ;
}
if ( startFrame < 0 )
{
startFrame = 0 ;
}
if ( startFrame > = 100000 )
{
startFrame = 0 ;
}
if ( setFrame < 0.0f & & setFrame ! = - 1.0f )
{
setFrame = 0.0f ;
}
if ( setFrame > 100000.0f )
{
setFrame = 0.0f ;
}
if ( ! setPtrs )
{
res = G2_SetupModelPointers ( ghlInfo ) ;
}
if ( res )
{
// ensure we flush the cache
ghlInfo - > mSkelFrameNum = 0 ;
return G2_Set_Bone_Anim_Index ( ghlInfo - > mBlist , index , startFrame , endFrame , flags , animSpeed , currentTime , setFrame , blendTime , ghlInfo - > aHeader - > numFrames ) ;
}
return qfalse ;
}
# define _PLEASE_SHUT_THE_HELL_UP
qboolean G2API_SetBoneAnim ( CGhoul2Info_v & ghoul2 , const int modelIndex , const char * boneName , const int AstartFrame , const int AendFrame , const int flags , const float animSpeed , const int currentTime , const float AsetFrame , const int blendTime )
{
int endFrame = AendFrame ;
int startFrame = AstartFrame ;
float setFrame = AsetFrame ;
# ifndef _PLEASE_SHUT_THE_HELL_UP
assert ( endFrame > 0 ) ;
assert ( startFrame > = 0 ) ;
assert ( endFrame < 100000 ) ;
assert ( startFrame < 100000 ) ;
assert ( setFrame > = 0.0f | | setFrame = = - 1.0f ) ;
assert ( setFrame < = 100000.0f ) ;
# endif
if ( endFrame < = 0 )
{
endFrame = 1 ;
}
if ( endFrame > = 100000 )
{
endFrame = 1 ;
}
if ( startFrame < 0 )
{
startFrame = 0 ;
}
if ( startFrame > = 100000 )
{
startFrame = 0 ;
}
if ( setFrame < 0.0f & & setFrame ! = - 1.0f )
{
setFrame = 0.0f ;
}
if ( setFrame > 100000.0f )
{
setFrame = 0.0f ;
}
if ( ( int ) & ghoul2 & & ghoul2 . size ( ) > modelIndex )
{
CGhoul2Info * ghlInfo = & ghoul2 [ modelIndex ] ;
qboolean setPtrs = qfalse ;
qboolean res = qfalse ;
//rww - RAGDOLL_BEGIN
if ( ghlInfo )
{
res = G2_SetupModelPointers ( ghlInfo ) ;
setPtrs = qtrue ;
if ( res )
{
if ( ghlInfo - > mFlags & GHOUL2_RAG_STARTED )
{
return qfalse ;
}
}
}
//rww - RAGDOLL_END
if ( ! setPtrs )
{
res = G2_SetupModelPointers ( ghlInfo ) ;
}
if ( res )
{
// ensure we flush the cache
ghlInfo - > mSkelFrameNum = 0 ;
return G2_Set_Bone_Anim ( ghlInfo , ghlInfo - > mBlist , boneName , startFrame , endFrame , flags , animSpeed , currentTime , setFrame , blendTime ) ;
}
}
return qfalse ;
}
qboolean G2API_GetBoneAnim ( CGhoul2Info * ghlInfo , const char * boneName , const int currentTime , float * currentFrame ,
int * startFrame , int * endFrame , int * flags , float * animSpeed , int * modelList )
{
assert ( startFrame ! = endFrame ) ; //this is bad
assert ( startFrame ! = flags ) ; //this is bad
assert ( endFrame ! = flags ) ; //this is bad
assert ( currentFrame ! = animSpeed ) ; //this is bad
if ( G2_SetupModelPointers ( ghlInfo ) )
{
int aCurrentTime = G2API_GetTime ( currentTime ) ;
qboolean ret = G2_Get_Bone_Anim ( ghlInfo , ghlInfo - > mBlist , boneName , aCurrentTime , currentFrame ,
startFrame , endFrame , flags , animSpeed , modelList , ghlInfo - > mModelindex ) ;
# ifdef _DEBUG
/*
assert ( * endFrame > 0 ) ;
assert ( * endFrame < 100000 ) ;
assert ( * startFrame > = 0 ) ;
assert ( * startFrame < 100000 ) ;
assert ( * currentFrame > = 0.0f ) ;
assert ( * currentFrame < 100000.0f ) ;
*/
if ( * endFrame < 1 )
{
* endFrame = 1 ;
}
if ( * endFrame > 100000 )
{
* endFrame = 1 ;
}
if ( * startFrame < 0 )
{
* startFrame = 0 ;
}
if ( * startFrame > 100000 )
{
* startFrame = 1 ;
}
if ( * currentFrame < 0.0f )
{
* currentFrame = 0.0f ;
}
if ( * currentFrame > 100000 )
{
* currentFrame = 1 ;
}
# endif
return ret ;
}
return qfalse ;
}
qboolean G2API_GetAnimRange ( CGhoul2Info * ghlInfo , const char * boneName , int * startFrame , int * endFrame )
{
assert ( startFrame ! = endFrame ) ; //this is bad
if ( G2_SetupModelPointers ( ghlInfo ) )
{
qboolean ret = G2_Get_Bone_Anim_Range ( ghlInfo , ghlInfo - > mBlist , boneName , startFrame , endFrame ) ;
# ifdef _DEBUG
assert ( * endFrame > 0 ) ;
assert ( * endFrame < 100000 ) ;
assert ( * startFrame > = 0 ) ;
assert ( * startFrame < 100000 ) ;
if ( * endFrame < 1 )
{
* endFrame = 1 ;
}
if ( * endFrame > 100000 )
{
* endFrame = 1 ;
}
if ( * startFrame < 0 )
{
* startFrame = 0 ;
}
if ( * startFrame > 100000 )
{
* startFrame = 1 ;
}
# endif
return ret ;
}
return qfalse ;
}
qboolean G2API_PauseBoneAnim ( CGhoul2Info * ghlInfo , const char * boneName , const int currentTime )
{
if ( G2_SetupModelPointers ( ghlInfo ) )
{
return G2_Pause_Bone_Anim ( ghlInfo , ghlInfo - > mBlist , boneName , currentTime ) ;
}
return qfalse ;
}
qboolean G2API_IsPaused ( CGhoul2Info * ghlInfo , const char * boneName )
{
if ( G2_SetupModelPointers ( ghlInfo ) )
{
return G2_IsPaused ( ghlInfo - > mFileName , ghlInfo - > mBlist , boneName ) ;
}
return qfalse ;
}
qboolean G2API_StopBoneAnimIndex ( CGhoul2Info * ghlInfo , const int index )
{
if ( G2_SetupModelPointers ( ghlInfo ) )
{
return G2_Stop_Bone_Anim_Index ( ghlInfo - > mBlist , index ) ;
}
return qfalse ;
}
qboolean G2API_StopBoneAnim ( CGhoul2Info * ghlInfo , const char * boneName )
{
if ( G2_SetupModelPointers ( ghlInfo ) )
{
return G2_Stop_Bone_Anim ( ghlInfo - > mFileName , ghlInfo - > mBlist , boneName ) ;
}
return qfalse ;
}
qboolean G2API_SetBoneAnglesIndex ( CGhoul2Info * ghlInfo , const int index , const vec3_t angles , const int flags ,
const Eorientations yaw , const Eorientations pitch , const Eorientations roll ,
qhandle_t * modelList , int blendTime , int currentTime )
{
qboolean setPtrs = qfalse ;
qboolean res = qfalse ;
//rww - RAGDOLL_BEGIN
if ( ghlInfo )
{
res = G2_SetupModelPointers ( ghlInfo ) ;
setPtrs = qtrue ;
if ( res )
{
if ( ghlInfo - > mFlags & GHOUL2_RAG_STARTED )
{
return qfalse ;
}
}
}
//rww - RAGDOLL_END
if ( ! setPtrs )
{
res = G2_SetupModelPointers ( ghlInfo ) ;
}
if ( res )
{
// ensure we flush the cache
ghlInfo - > mSkelFrameNum = 0 ;
return G2_Set_Bone_Angles_Index ( ghlInfo - > mBlist , index , angles , flags , yaw , pitch , roll , modelList , ghlInfo - > mModelindex , blendTime , currentTime ) ;
}
return qfalse ;
}
qboolean G2API_SetBoneAngles ( CGhoul2Info_v & ghoul2 , const int modelIndex , const char * boneName , const vec3_t angles , const int flags ,
const Eorientations up , const Eorientations left , const Eorientations forward ,
qhandle_t * modelList , int blendTime , int currentTime )
{
if ( ( int ) & ghoul2 & & ghoul2 . size ( ) > modelIndex )
{
CGhoul2Info * ghlInfo = & ghoul2 [ modelIndex ] ;
qboolean setPtrs = qfalse ;
qboolean res = qfalse ;
//rww - RAGDOLL_BEGIN
if ( ghlInfo )
{
res = G2_SetupModelPointers ( ghlInfo ) ;
setPtrs = qtrue ;
if ( res )
{
if ( ghlInfo - > mFlags & GHOUL2_RAG_STARTED )
{
return qfalse ;
}
}
}
//rww - RAGDOLL_END
if ( ! setPtrs )
{
res = G2_SetupModelPointers ( ghoul2 ) ;
}
if ( res )
{
// ensure we flush the cache
ghlInfo - > mSkelFrameNum = 0 ;
return G2_Set_Bone_Angles ( ghlInfo , ghlInfo - > mBlist , boneName , angles , flags , up , left , forward , modelList , ghlInfo - > mModelindex , blendTime , currentTime ) ;
}
}
return qfalse ;
}
qboolean G2API_SetBoneAnglesMatrixIndex ( CGhoul2Info * ghlInfo , const int index , const mdxaBone_t & matrix ,
const int flags , qhandle_t * modelList , int blendTime , int currentTime )
{
if ( G2_SetupModelPointers ( ghlInfo ) )
{
// ensure we flush the cache
ghlInfo - > mSkelFrameNum = 0 ;
return G2_Set_Bone_Angles_Matrix_Index ( ghlInfo - > mBlist , index , matrix , flags , modelList , ghlInfo - > mModelindex , blendTime , currentTime ) ;
}
return qfalse ;
}
qboolean G2API_SetBoneAnglesMatrix ( CGhoul2Info * ghlInfo , const char * boneName , const mdxaBone_t & matrix ,
const int flags , qhandle_t * modelList , int blendTime , int currentTime )
{
if ( G2_SetupModelPointers ( ghlInfo ) )
{
// ensure we flush the cache
ghlInfo - > mSkelFrameNum = 0 ;
return G2_Set_Bone_Angles_Matrix ( ghlInfo - > mFileName , ghlInfo - > mBlist , boneName , matrix , flags , modelList , ghlInfo - > mModelindex , blendTime , currentTime ) ;
}
return qfalse ;
}
qboolean G2API_StopBoneAnglesIndex ( CGhoul2Info * ghlInfo , const int index )
{
if ( G2_SetupModelPointers ( ghlInfo ) )
{
// ensure we flush the cache
ghlInfo - > mSkelFrameNum = 0 ;
return G2_Stop_Bone_Angles_Index ( ghlInfo - > mBlist , index ) ;
}
return qfalse ;
}
qboolean G2API_StopBoneAngles ( CGhoul2Info * ghlInfo , const char * boneName )
{
if ( G2_SetupModelPointers ( ghlInfo ) )
{
// ensure we flush the cache
ghlInfo - > mSkelFrameNum = 0 ;
return G2_Stop_Bone_Angles ( ghlInfo - > mFileName , ghlInfo - > mBlist , boneName ) ;
}
return qfalse ;
}
void G2API_AbsurdSmoothing ( CGhoul2Info_v & ghoul2 , qboolean status )
{
assert ( ghoul2 . size ( ) ) ;
CGhoul2Info * ghlInfo = & ghoul2 [ 0 ] ;
if ( status )
{ //turn it on
ghlInfo - > mFlags | = GHOUL2_CRAZY_SMOOTH ;
}
else
{ //off
ghlInfo - > mFlags & = ~ GHOUL2_CRAZY_SMOOTH ;
}
}
//rww - RAGDOLL_BEGIN
class CRagDollParams ;
void G2_SetRagDoll ( CGhoul2Info_v & ghoul2V , CRagDollParams * parms ) ;
void G2API_SetRagDoll ( CGhoul2Info_v & ghoul2 , CRagDollParams * parms )
{
G2_SetRagDoll ( ghoul2 , parms ) ;
}
void G2_ResetRagDoll ( CGhoul2Info_v & ghoul2V ) ;
void G2API_ResetRagDoll ( CGhoul2Info_v & ghoul2 )
{
G2_ResetRagDoll ( ghoul2 ) ;
}
//rww - RAGDOLL_END
qboolean G2API_RemoveBone ( CGhoul2Info * ghlInfo , const char * boneName )
{
if ( G2_SetupModelPointers ( ghlInfo ) )
{
// ensure we flush the cache
ghlInfo - > mSkelFrameNum = 0 ;
return G2_Remove_Bone ( ghlInfo , ghlInfo - > mBlist , boneName ) ;
}
return qfalse ;
}
//rww - RAGDOLL_BEGIN
# ifdef _DEBUG
extern int ragTraceTime ;
extern int ragSSCount ;
extern int ragTraceCount ;
# endif
void G2API_AnimateG2Models ( CGhoul2Info_v & ghoul2 , int AcurrentTime , CRagDollUpdateParams * params )
{
int model ;
int currentTime = G2API_GetTime ( AcurrentTime ) ;
# ifdef _DEBUG
ragTraceTime = 0 ;
ragSSCount = 0 ;
ragTraceCount = 0 ;
# endif
// Walk the list and find all models that are active
for ( model = 0 ; model < ghoul2 . size ( ) ; model + + )
{
if ( ghoul2 [ model ] . mModel )
{
G2_Animate_Bone_List ( ghoul2 , currentTime , model , params ) ;
}
}
# ifdef _DEBUG
/*
if ( ragTraceTime )
{
Com_Printf ( " Rag trace time: %i (%i STARTSOLID, %i TOTAL) \n " , ragTraceTime , ragSSCount , ragTraceCount ) ;
}
*/
//keep sane limits here, if it gets too slow an assert is proper.
// assert(ragTraceTime < 150);
// assert(ragTraceCount < 1500);
# endif
}
//rww - RAGDOLL_END
int G2_Find_Bone_Rag ( CGhoul2Info * ghlInfo , boneInfo_v & blist , const char * boneName ) ;
# define RAG_PCJ (0x00001)
# define RAG_EFFECTOR (0x00100)
static inline boneInfo_t * G2_GetRagBoneConveniently ( CGhoul2Info_v & ghoul2 , const char * boneName )
{
assert ( ghoul2 . size ( ) ) ;
CGhoul2Info * ghlInfo = & ghoul2 [ 0 ] ;
if ( ! ( ghlInfo - > mFlags & GHOUL2_RAG_STARTED ) )
{ //can't do this if not in ragdoll
return NULL ;
}
int boneIndex = G2_Find_Bone_Rag ( ghlInfo , ghlInfo - > mBlist , boneName ) ;
if ( boneIndex < 0 )
{ //bad bone specification
return NULL ;
}
boneInfo_t * bone = & ghlInfo - > mBlist [ boneIndex ] ;
if ( ! ( bone - > flags & BONE_ANGLES_RAGDOLL ) )
{ //only want to return rag bones
return NULL ;
}
return bone ;
}
qboolean G2API_RagPCJConstraint ( CGhoul2Info_v & ghoul2 , const char * boneName , vec3_t min , vec3_t max )
{
boneInfo_t * bone = G2_GetRagBoneConveniently ( ghoul2 , boneName ) ;
if ( ! bone )
{
return qfalse ;
}
if ( ! ( bone - > RagFlags & RAG_PCJ ) )
{ //this function is only for PCJ bones
return qfalse ;
}
VectorCopy ( min , bone - > minAngles ) ;
VectorCopy ( max , bone - > maxAngles ) ;
return qtrue ;
}
qboolean G2API_RagPCJGradientSpeed ( CGhoul2Info_v & ghoul2 , const char * boneName , const float speed )
{
boneInfo_t * bone = G2_GetRagBoneConveniently ( ghoul2 , boneName ) ;
if ( ! bone )
{
return qfalse ;
}
if ( ! ( bone - > RagFlags & RAG_PCJ ) )
{ //this function is only for PCJ bones
return qfalse ;
}
bone - > overGradSpeed = speed ;
return qtrue ;
}
qboolean G2API_RagEffectorGoal ( CGhoul2Info_v & ghoul2 , const char * boneName , vec3_t pos )
{
boneInfo_t * bone = G2_GetRagBoneConveniently ( ghoul2 , boneName ) ;
if ( ! bone )
{
return qfalse ;
}
if ( ! ( bone - > RagFlags & RAG_EFFECTOR ) )
{ //this function is only for effectors
return qfalse ;
}
if ( ! pos )
{ //go back to none in case we have one then
bone - > hasOverGoal = false ;
}
else
{
VectorCopy ( pos , bone - > overGoalSpot ) ;
bone - > hasOverGoal = true ;
}
return qtrue ;
}
qboolean G2API_GetRagBonePos ( CGhoul2Info_v & ghoul2 , const char * boneName , vec3_t pos , vec3_t entAngles , vec3_t entPos , vec3_t entScale )
{ //do something?
return qfalse ;
}
qboolean G2API_RagEffectorKick ( CGhoul2Info_v & ghoul2 , const char * boneName , vec3_t velocity )
{
boneInfo_t * bone = G2_GetRagBoneConveniently ( ghoul2 , boneName ) ;
if ( ! bone )
{
return qfalse ;
}
if ( ! ( bone - > RagFlags & RAG_EFFECTOR ) )
{ //this function is only for effectors
return qfalse ;
}
bone - > epVelocity [ 2 ] = 0 ;
VectorAdd ( bone - > epVelocity , velocity , bone - > epVelocity ) ;
bone - > physicsSettled = false ;
return qtrue ;
}
qboolean G2API_RagForceSolve ( CGhoul2Info_v & ghoul2 , qboolean force )
{
assert ( ghoul2 . size ( ) ) ;
CGhoul2Info * ghlInfo = & ghoul2 [ 0 ] ;
if ( ! ( ghlInfo - > mFlags & GHOUL2_RAG_STARTED ) )
{ //can't do this if not in ragdoll
return qfalse ;
}
if ( force )
{
ghlInfo - > mFlags | = GHOUL2_RAG_FORCESOLVE ;
}
else
{
ghlInfo - > mFlags & = ~ GHOUL2_RAG_FORCESOLVE ;
}
return qtrue ;
}
qboolean G2_SetBoneIKState ( CGhoul2Info_v & ghoul2 , int time , const char * boneName , int ikState , sharedSetBoneIKStateParams_t * params ) ;
qboolean G2API_SetBoneIKState ( CGhoul2Info_v & ghoul2 , int time , const char * boneName , int ikState , sharedSetBoneIKStateParams_t * params )
{
return G2_SetBoneIKState ( ghoul2 , time , boneName , ikState , params ) ;
}
qboolean G2_IKMove ( CGhoul2Info_v & ghoul2 , int time , sharedIKMoveParams_t * params ) ;
qboolean G2API_IKMove ( CGhoul2Info_v & ghoul2 , int time , sharedIKMoveParams_t * params )
{
return G2_IKMove ( ghoul2 , time , params ) ;
}
qboolean G2API_RemoveBolt ( CGhoul2Info * ghlInfo , const int index )
{
if ( G2_SetupModelPointers ( ghlInfo ) )
{
return G2_Remove_Bolt ( ghlInfo - > mBltlist , index ) ;
}
return qfalse ;
}
int G2API_AddBolt ( CGhoul2Info_v & ghoul2 , const int modelIndex , const char * boneName )
{
assert ( ghoul2 . size ( ) > modelIndex ) ;
if ( ( int ) & ghoul2 & & ghoul2 . size ( ) > modelIndex )
{
CGhoul2Info * ghlInfo = & ghoul2 [ modelIndex ] ;
if ( G2_SetupModelPointers ( ghlInfo ) )
{
return G2_Add_Bolt ( ghlInfo , ghlInfo - > mBltlist , ghlInfo - > mSlist , boneName ) ;
}
}
return - 1 ;
}
int G2API_AddBoltSurfNum ( CGhoul2Info * ghlInfo , const int surfIndex )
{
if ( G2_SetupModelPointers ( ghlInfo ) )
{
return G2_Add_Bolt_Surf_Num ( ghlInfo , ghlInfo - > mBltlist , ghlInfo - > mSlist , surfIndex ) ;
}
return - 1 ;
}
qboolean G2API_AttachG2Model ( CGhoul2Info_v & ghoul2From , int modelFrom , CGhoul2Info_v & ghoul2To , int toBoltIndex , int toModel )
{
assert ( toBoltIndex > = 0 ) ;
if ( toBoltIndex < 0 )
{
return qfalse ;
}
if ( G2_SetupModelPointers ( ghoul2From ) & & G2_SetupModelPointers ( ghoul2To ) )
{
// make sure we have a model to attach, a model to attach to, and a bolt on that model
if ( ( ( int ) & ghoul2From ) & &
( ( int ) & ghoul2To ) & &
( ghoul2From . size ( ) > modelFrom ) & &
( ghoul2To . size ( ) > toModel ) & &
( ( ghoul2To [ toModel ] . mBltlist [ toBoltIndex ] . boneNumber ! = - 1 ) | | ( ghoul2To [ toModel ] . mBltlist [ toBoltIndex ] . surfaceNumber ! = - 1 ) ) )
{
// encode the bolt address into the model bolt link
toModel & = MODEL_AND ;
toBoltIndex & = BOLT_AND ;
ghoul2From [ modelFrom ] . mModelBoltLink = ( toModel < < MODEL_SHIFT ) | ( toBoltIndex < < BOLT_SHIFT ) ;
return qtrue ;
}
}
return qfalse ;
}
void G2API_SetBoltInfo ( CGhoul2Info_v & ghoul2 , int modelIndex , int boltInfo )
{
if ( ( int ) & ghoul2 )
{
if ( ghoul2 . size ( ) > modelIndex )
{
ghoul2 [ modelIndex ] . mModelBoltLink = boltInfo ;
}
}
}
qboolean G2API_DetachG2Model ( CGhoul2Info * ghlInfo )
{
if ( G2_SetupModelPointers ( ghlInfo ) )
{
ghlInfo - > mModelBoltLink = - 1 ;
return qtrue ;
}
return qfalse ;
}
qboolean G2API_AttachEnt ( int * boltInfo , CGhoul2Info * ghlInfoTo , int toBoltIndex , int entNum , int toModelNum )
{
if ( boltInfo & & G2_SetupModelPointers ( ghlInfoTo ) )
{
// make sure we have a model to attach, a model to attach to, and a bolt on that model
if ( ghlInfoTo - > mBltlist . size ( ) & & ( ( ghlInfoTo - > mBltlist [ toBoltIndex ] . boneNumber ! = - 1 ) | | ( ghlInfoTo - > mBltlist [ toBoltIndex ] . surfaceNumber ! = - 1 ) ) )
{
// encode the bolt address into the model bolt link
toModelNum & = MODEL_AND ;
toBoltIndex & = BOLT_AND ;
entNum & = ENTITY_AND ;
* boltInfo = ( toBoltIndex < < BOLT_SHIFT ) | ( toModelNum < < MODEL_SHIFT ) | ( entNum < < ENTITY_SHIFT ) ;
return qtrue ;
}
}
return qfalse ;
}
qboolean gG2_GBMNoReconstruct ;
qboolean gG2_GBMUseSPMethod ;
qboolean G2API_GetBoltMatrix_SPMethod ( CGhoul2Info_v & ghoul2 , const int modelIndex , const int boltIndex , mdxaBone_t * matrix , const vec3_t angles ,
const vec3_t position , const int frameNum , qhandle_t * modelList , const vec3_t scale )
{
assert ( ghoul2 . size ( ) > modelIndex ) ;
if ( ( int ) & ghoul2 & & ( ghoul2 . size ( ) > modelIndex ) )
{
CGhoul2Info * ghlInfo = & ghoul2 [ modelIndex ] ;
//assert(boltIndex < ghlInfo->mBltlist.size());
if ( ghlInfo & & ( boltIndex < ghlInfo - > mBltlist . size ( ) ) & & boltIndex > = 0 )
{
// make sure we have transformed the skeleton
if ( ! gG2_GBMNoReconstruct )
{
G2_ConstructGhoulSkeleton ( ghoul2 , frameNum , true , scale ) ;
}
gG2_GBMNoReconstruct = qfalse ;
mdxaBone_t scaled ;
mdxaBone_t * use ;
use = & ghlInfo - > mBltlist [ boltIndex ] . position ;
if ( scale [ 0 ] | | scale [ 1 ] | | scale [ 2 ] )
{
scaled = * use ;
use = & scaled ;
// scale the bolt position by the scale factor for this model since at this point its still in model space
if ( scale [ 0 ] )
{
scaled . matrix [ 0 ] [ 3 ] * = scale [ 0 ] ;
}
if ( scale [ 1 ] )
{
scaled . matrix [ 1 ] [ 3 ] * = scale [ 1 ] ;
}
if ( scale [ 2 ] )
{
scaled . matrix [ 2 ] [ 3 ] * = scale [ 2 ] ;
}
}
// pre generate the world matrix
G2_GenerateWorldMatrix ( angles , position ) ;
VectorNormalize ( ( float * ) use - > matrix [ 0 ] ) ;
VectorNormalize ( ( float * ) use - > matrix [ 1 ] ) ;
VectorNormalize ( ( float * ) use - > matrix [ 2 ] ) ;
Multiply_3x4Matrix ( matrix , & worldMatrix , use ) ;
return qtrue ;
}
}
return qfalse ;
}
# define G2ERROR(exp,m) ((void)0) //rwwFIXMEFIXME: This is because I'm lazy.
# define G2WARNING(exp,m) ((void)0)
# define G2NOTE(exp,m) ((void)0)
# define G2ANIM(ghlInfo,m) ((void)0)
bool G2_NeedsRecalc ( CGhoul2Info * ghlInfo , int frameNum ) ;
void G2_GetBoltMatrixLow ( CGhoul2Info & ghoul2 , int boltNum , const vec3_t scale , mdxaBone_t & retMatrix ) ;
void G2_GetBoneMatrixLow ( CGhoul2Info & ghoul2 , int boneNum , const vec3_t scale , mdxaBone_t & retMatrix , mdxaBone_t * & retBasepose , mdxaBone_t * & retBaseposeInv ) ;
//qboolean G2API_GetBoltMatrix(CGhoul2Info_v &ghoul2, const int modelIndex, const int boltIndex, mdxaBone_t *matrix, const vec3_t angles,
// const vec3_t position, const int AframeNum, qhandle_t *modelList, const vec3_t scale )
qboolean G2API_GetBoltMatrix ( CGhoul2Info_v & ghoul2 , const int modelIndex , const int boltIndex , mdxaBone_t * matrix , const vec3_t angles ,
const vec3_t position , const int frameNum , qhandle_t * modelList , vec3_t scale )
{
// G2ERROR(ghoul2.IsValid(),"Invalid ghlInfo");
G2ERROR ( matrix , " NULL matrix " ) ;
G2ERROR ( modelIndex > = 0 & & modelIndex < ghoul2 . size ( ) , " Invalid ModelIndex " ) ;
const static mdxaBone_t identityMatrix =
{
0.0f , - 1.0f , 0.0f , 0.0f ,
1.0f , 0.0f , 0.0f , 0.0f ,
0.0f , 0.0f , 1.0f , 0.0f
} ;
G2_GenerateWorldMatrix ( angles , position ) ;
if ( G2_SetupModelPointers ( ghoul2 ) )
{
if ( matrix & & modelIndex > = 0 & & modelIndex < ghoul2 . size ( ) )
{
int tframeNum = G2API_GetTime ( frameNum ) ;
CGhoul2Info * ghlInfo = & ghoul2 [ modelIndex ] ;
G2ERROR ( boltIndex > = 0 & & ( boltIndex < ghlInfo - > mBltlist . size ( ) ) , va ( " Invalid Bolt Index (%d:%s) " , boltIndex , ghlInfo - > mFileName ) ) ;
if ( boltIndex > = 0 & & ghlInfo & & ( boltIndex < ghlInfo - > mBltlist . size ( ) ) )
{
mdxaBone_t bolt ;
#if 0 //yeah, screw it
if ( ! gG2_GBMNoReconstruct )
{ //This should only be used when you know what you're doing.
if ( G2_NeedsRecalc ( ghlInfo , tframeNum ) )
{
G2_ConstructGhoulSkeleton ( ghoul2 , tframeNum , true , scale ) ;
}
}
else
{
gG2_GBMNoReconstruct = qfalse ;
}
# else
if ( G2_NeedsRecalc ( ghlInfo , tframeNum ) )
{
G2_ConstructGhoulSkeleton ( ghoul2 , tframeNum , true , scale ) ;
}
# endif
G2_GetBoltMatrixLow ( * ghlInfo , boltIndex , scale , bolt ) ;
// scale the bolt position by the scale factor for this model since at this point its still in model space
if ( scale [ 0 ] )
{
bolt . matrix [ 0 ] [ 3 ] * = scale [ 0 ] ;
}
if ( scale [ 1 ] )
{
bolt . matrix [ 1 ] [ 3 ] * = scale [ 1 ] ;
}
if ( scale [ 2 ] )
{
bolt . matrix [ 2 ] [ 3 ] * = scale [ 2 ] ;
}
VectorNormalize ( ( float * ) & bolt . matrix [ 0 ] ) ;
VectorNormalize ( ( float * ) & bolt . matrix [ 1 ] ) ;
VectorNormalize ( ( float * ) & bolt . matrix [ 2 ] ) ;
Multiply_3x4Matrix ( matrix , & worldMatrix , & bolt ) ;
# if G2API_DEBUG
for ( int i = 0 ; i < 3 ; i + + )
{
for ( int j = 0 ; j < 4 ; j + + )
{
assert ( ! _isnan ( matrix - > matrix [ i ] [ j ] ) ) ;
}
}
# endif // _DEBUG
G2ANIM ( ghlInfo , " G2API_GetBoltMatrix " ) ;
if ( ! gG2_GBMUseSPMethod )
{ //this is horribly stupid and I hate it. But lots of game code is written to assume this 90 degree offset thing.
mdxaBone_t rotMat , tempMatrix ;
vec3_t newangles = { 0 , 270 , 0 } ;
Create_Matrix ( newangles , & rotMat ) ;
// make the model space matrix we have for this bolt into a world matrix
Multiply_3x4Matrix ( & tempMatrix , & worldMatrix , & bolt ) ;
vec3_t origin ;
origin [ 0 ] = tempMatrix . matrix [ 0 ] [ 3 ] ;
origin [ 1 ] = tempMatrix . matrix [ 1 ] [ 3 ] ;
origin [ 2 ] = tempMatrix . matrix [ 2 ] [ 3 ] ;
tempMatrix . matrix [ 0 ] [ 3 ] = tempMatrix . matrix [ 1 ] [ 3 ] = tempMatrix . matrix [ 2 ] [ 3 ] = 0 ;
Multiply_3x4Matrix ( matrix , & tempMatrix , & rotMat ) ;
matrix - > matrix [ 0 ] [ 3 ] = origin [ 0 ] ;
matrix - > matrix [ 1 ] [ 3 ] = origin [ 1 ] ;
matrix - > matrix [ 2 ] [ 3 ] = origin [ 2 ] ;
}
else
{ //reset it
gG2_GBMUseSPMethod = qfalse ;
}
return qtrue ;
}
}
}
else
{
G2WARNING ( 0 , " G2API_GetBoltMatrix Failed on empty or bad model " ) ;
}
Multiply_3x4Matrix ( matrix , & worldMatrix , ( mdxaBone_t * ) & identityMatrix ) ;
return qfalse ;
}
void G2API_ListSurfaces ( CGhoul2Info * ghlInfo )
{
if ( G2_SetupModelPointers ( ghlInfo ) )
{
G2_List_Model_Surfaces ( ghlInfo - > mFileName ) ;
}
}
void G2API_ListBones ( CGhoul2Info * ghlInfo , int frame )
{
if ( G2_SetupModelPointers ( ghlInfo ) )
{
G2_List_Model_Bones ( ghlInfo - > mFileName , frame ) ;
}
}
// decide if we have Ghoul2 models associated with this ghoul list or not
qboolean G2API_HaveWeGhoul2Models ( CGhoul2Info_v & ghoul2 )
{
int i ;
if ( ( int ) & ghoul2 )
{
for ( i = 0 ; i < ghoul2 . size ( ) ; i + + )
{
if ( ghoul2 [ i ] . mModelindex ! = - 1 )
{
return qtrue ;
}
}
}
return qfalse ;
}
// run through the Ghoul2 models and set each of the mModel values to the correct one from the cgs.gameModel offset lsit
void G2API_SetGhoul2ModelIndexes ( CGhoul2Info_v & ghoul2 , qhandle_t * modelList , qhandle_t * skinList )
{
return ;
#if 0
int i ;
if ( ( int ) & ghoul2 )
{
for ( i = 0 ; i < ghoul2 . size ( ) ; i + + )
{
if ( ghoul2 [ i ] . mModelindex ! = - 1 )
{
// broken into 3 lines for debugging, STL is a pain to view...
//
int iModelIndex = ghoul2 [ i ] . mModelindex ;
qhandle_t mModel = modelList [ iModelIndex ] ;
ghoul2 [ i ] . mModel = mModel ;
ghoul2 [ i ] . mSkin = skinList [ ghoul2 [ i ] . mCustomSkin ] ;
}
}
}
# endif
}
char * G2API_GetAnimFileNameIndex ( qhandle_t modelIndex )
{
model_t * mod_m = R_GetModelByHandle ( modelIndex ) ;
return mod_m - > mdxm - > animName ;
}
/************************************************************************************************
* G2API_GetAnimFileName
* obtains the name of a model ' s . gla ( animation ) file
*
* Input
* pointer to list of CGhoul2Info ' s , WraithID of specific model in that list
*
* Output
* true if a good filename was obtained , false otherwise
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
qboolean G2API_GetAnimFileName ( CGhoul2Info * ghlInfo , char * * filename )
{
if ( G2_SetupModelPointers ( ghlInfo ) )
{
return G2_GetAnimFileName ( ghlInfo - > mFileName , filename ) ;
}
return qfalse ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = =
SV_QsortEntityNumbers
= = = = = = = = = = = = = = = = = = = = = = =
*/
static int QDECL QsortDistance ( const void * a , const void * b ) {
const float & ea = ( ( CollisionRecord_t * ) a ) - > mDistance ;
const float & eb = ( ( CollisionRecord_t * ) b ) - > mDistance ;
if ( ea < eb ) {
return - 1 ;
}
return 1 ;
}
static inline bool G2_NeedRetransform ( CGhoul2Info * g2 , int frameNum )
{ //see if we need to do another transform
int i = 0 ;
bool needTrans = false ;
while ( i < g2 - > mBlist . size ( ) )
{
float time ;
boneInfo_t & bone = g2 - > mBlist [ i ] ;
if ( bone . pauseTime )
{
time = ( bone . pauseTime - bone . startTime ) / 50.0f ;
}
else
{
time = ( frameNum - bone . startTime ) / 50.0f ;
}
int newFrame = bone . startFrame + ( time * bone . animSpeed ) ;
if ( newFrame < bone . endFrame | |
( bone . flags & BONE_ANIM_OVERRIDE_LOOP ) | |
( bone . flags & BONE_NEED_TRANSFORM ) )
{ //ok, we're gonna have to do it. bone is apparently animating.
bone . flags & = ~ BONE_NEED_TRANSFORM ;
needTrans = true ;
}
i + + ;
}
return needTrans ;
}
void G2API_CollisionDetectCache ( CollisionRecord_t * collRecMap , CGhoul2Info_v & ghoul2 , const vec3_t angles , const vec3_t position ,
int frameNumber , int entNum , vec3_t rayStart , vec3_t rayEnd , vec3_t scale , CMiniHeap * G2VertSpace , int traceFlags , int useLod , float fRadius )
{ //this will store off the transformed verts for the next trace - this is slower, but for models that do not animate
//frequently it is much much faster. -rww
int * test = ghoul2 [ 0 ] . mTransformedVertsArray ;
if ( G2_SetupModelPointers ( ghoul2 ) )
{
vec3_t transRayStart , transRayEnd ;
int tframeNum = G2API_GetTime ( frameNumber ) ;
// make sure we have transformed the whole skeletons for each model
if ( G2_NeedRetransform ( & ghoul2 [ 0 ] , tframeNum ) | | ! ghoul2 [ 0 ] . mTransformedVertsArray )
{ //optimization, only create new transform space if we need to, otherwise
//store it off!
int i = 0 ;
while ( i < ghoul2 . size ( ) )
{
CGhoul2Info & g2 = ghoul2 [ i ] ;
/*
if ( ( g2 . mFlags & GHOUL2_ZONETRANSALLOC ) & & g2 . mTransformedVertsArray )
{ //clear it out, yo.
Z_Free ( g2 . mTransformedVertsArray ) ;
g2 . mTransformedVertsArray = 0 ;
}
*/
if ( ! g2 . mTransformedVertsArray | | ! ( g2 . mFlags & GHOUL2_ZONETRANSALLOC ) )
{ //reworked so we only alloc once!
//if we have a pointer, but not a ghoul2_zonetransalloc flag, then that means
//it is a miniheap pointer. Just stomp over it.
int iSize = g2 . currentModel - > mdxm - > numSurfaces * 4 ;
g2 . mTransformedVertsArray = ( int * ) Z_Malloc ( iSize , TAG_GHOUL2 , qtrue ) ;
}
g2 . mFlags | = GHOUL2_ZONETRANSALLOC ;
i + + ;
}
G2_ConstructGhoulSkeleton ( ghoul2 , frameNumber , true , scale ) ;
G2VertSpace - > ResetHeap ( ) ;
// now having done that, time to build the model
# ifdef _G2_GORE
G2_TransformModel ( ghoul2 , frameNumber , scale , G2VertSpace , useLod , false ) ;
# else
G2_TransformModel ( ghoul2 , frameNumber , scale , G2VertSpace , useLod ) ;
# endif
//don't need to do this anymore now that I am using a flag for zone alloc.
/*
i = 0 ;
while ( i < ghoul2 . size ( ) )
{
CGhoul2Info & g2 = ghoul2 [ i ] ;
int iSize = g2 . currentModel - > mdxm - > numSurfaces * 4 ;
int * zoneMem = ( int * ) Z_Malloc ( iSize , TAG_GHOUL2 , qtrue ) ;
memcpy ( zoneMem , g2 . mTransformedVertsArray , iSize ) ;
g2 . mTransformedVertsArray = zoneMem ;
g2 . mFlags | = GHOUL2_ZONETRANSALLOC ;
i + + ;
}
*/
}
// pre generate the world matrix - used to transform the incoming ray
G2_GenerateWorldMatrix ( angles , position ) ;
// model is built. Lets check to see if any triangles are actually hit.
// first up, translate the ray to model space
TransformAndTranslatePoint ( rayStart , transRayStart , & worldMatrixInv ) ;
TransformAndTranslatePoint ( rayEnd , transRayEnd , & worldMatrixInv ) ;
// now walk each model and check the ray against each poly - sigh, this is SO expensive. I wish there was a better way to do this.
# ifdef _G2_GORE
G2_TraceModels ( ghoul2 , transRayStart , transRayEnd , collRecMap , entNum , traceFlags , useLod , fRadius , 0 , 0 , 0 , 0 , 0 , qfalse ) ;
# else
G2_TraceModels ( ghoul2 , transRayStart , transRayEnd , collRecMap , entNum , traceFlags , useLod , fRadius ) ;
# endif
int i ;
for ( i = 0 ; i < MAX_G2_COLLISIONS & & collRecMap [ i ] . mEntityNum ! = - 1 ; i + + ) ;
// now sort the resulting array of collision records so they are distance ordered
qsort ( collRecMap , i ,
sizeof ( CollisionRecord_t ) , QsortDistance ) ;
}
}
void G2API_CollisionDetect ( CollisionRecord_t * collRecMap , CGhoul2Info_v & ghoul2 , const vec3_t angles , const vec3_t position ,
int frameNumber , int entNum , vec3_t rayStart , vec3_t rayEnd , vec3_t scale , CMiniHeap * G2VertSpace , int traceFlags , int useLod , float fRadius )
{
/*
if ( 1 )
{
G2API_CollisionDetectCache ( collRecMap , ghoul2 , angles , position , frameNumber , entNum ,
rayStart , rayEnd , scale , G2VertSpace , traceFlags , useLod , fRadius ) ;
return ;
}
*/
if ( G2_SetupModelPointers ( ghoul2 ) )
{
vec3_t transRayStart , transRayEnd ;
// make sure we have transformed the whole skeletons for each model
G2_ConstructGhoulSkeleton ( ghoul2 , frameNumber , true , scale ) ;
// pre generate the world matrix - used to transform the incoming ray
G2_GenerateWorldMatrix ( angles , position ) ;
G2VertSpace - > ResetHeap ( ) ;
// now having done that, time to build the model
# ifdef _G2_GORE
G2_TransformModel ( ghoul2 , frameNumber , scale , G2VertSpace , useLod , false ) ;
# else
G2_TransformModel ( ghoul2 , frameNumber , scale , G2VertSpace , useLod ) ;
# endif
// model is built. Lets check to see if any triangles are actually hit.
// first up, translate the ray to model space
TransformAndTranslatePoint ( rayStart , transRayStart , & worldMatrixInv ) ;
TransformAndTranslatePoint ( rayEnd , transRayEnd , & worldMatrixInv ) ;
// now walk each model and check the ray against each poly - sigh, this is SO expensive. I wish there was a better way to do this.
# ifdef _G2_GORE
G2_TraceModels ( ghoul2 , transRayStart , transRayEnd , collRecMap , entNum , traceFlags , useLod , fRadius , 0 , 0 , 0 , 0 , 0 , qfalse ) ;
# else
G2_TraceModels ( ghoul2 , transRayStart , transRayEnd , collRecMap , entNum , traceFlags , useLod , fRadius ) ;
# endif
int i ;
for ( i = 0 ; i < MAX_G2_COLLISIONS & & collRecMap [ i ] . mEntityNum ! = - 1 ; i + + ) ;
// now sort the resulting array of collision records so they are distance ordered
qsort ( collRecMap , i ,
sizeof ( CollisionRecord_t ) , QsortDistance ) ;
}
}
qboolean G2API_SetGhoul2ModelFlags ( CGhoul2Info * ghlInfo , const int flags )
{
if ( G2_SetupModelPointers ( ghlInfo ) )
{
ghlInfo - > mFlags & = GHOUL2_NEWORIGIN ;
ghlInfo - > mFlags | = flags ;
return qtrue ;
}
return qfalse ;
}
int G2API_GetGhoul2ModelFlags ( CGhoul2Info * ghlInfo )
{
if ( G2_SetupModelPointers ( ghlInfo ) )
{
return ( ghlInfo - > mFlags & ~ GHOUL2_NEWORIGIN ) ;
}
return 0 ;
}
// given a boltmatrix, return in vec a normalised vector for the axis requested in flags
void G2API_GiveMeVectorFromMatrix ( mdxaBone_t * boltMatrix , Eorientations flags , vec3_t vec )
{
switch ( flags )
{
case ORIGIN :
vec [ 0 ] = boltMatrix - > matrix [ 0 ] [ 3 ] ;
vec [ 1 ] = boltMatrix - > matrix [ 1 ] [ 3 ] ;
vec [ 2 ] = boltMatrix - > matrix [ 2 ] [ 3 ] ;
break ;
case POSITIVE_Y :
vec [ 0 ] = boltMatrix - > matrix [ 0 ] [ 1 ] ;
vec [ 1 ] = boltMatrix - > matrix [ 1 ] [ 1 ] ;
vec [ 2 ] = boltMatrix - > matrix [ 2 ] [ 1 ] ;
break ;
case POSITIVE_X :
vec [ 0 ] = boltMatrix - > matrix [ 0 ] [ 0 ] ;
vec [ 1 ] = boltMatrix - > matrix [ 1 ] [ 0 ] ;
vec [ 2 ] = boltMatrix - > matrix [ 2 ] [ 0 ] ;
break ;
case POSITIVE_Z :
vec [ 0 ] = boltMatrix - > matrix [ 0 ] [ 2 ] ;
vec [ 1 ] = boltMatrix - > matrix [ 1 ] [ 2 ] ;
vec [ 2 ] = boltMatrix - > matrix [ 2 ] [ 2 ] ;
break ;
case NEGATIVE_Y :
vec [ 0 ] = - boltMatrix - > matrix [ 0 ] [ 1 ] ;
vec [ 1 ] = - boltMatrix - > matrix [ 1 ] [ 1 ] ;
vec [ 2 ] = - boltMatrix - > matrix [ 2 ] [ 1 ] ;
break ;
case NEGATIVE_X :
vec [ 0 ] = - boltMatrix - > matrix [ 0 ] [ 0 ] ;
vec [ 1 ] = - boltMatrix - > matrix [ 1 ] [ 0 ] ;
vec [ 2 ] = - boltMatrix - > matrix [ 2 ] [ 0 ] ;
break ;
case NEGATIVE_Z :
vec [ 0 ] = - boltMatrix - > matrix [ 0 ] [ 2 ] ;
vec [ 1 ] = - boltMatrix - > matrix [ 1 ] [ 2 ] ;
vec [ 2 ] = - boltMatrix - > matrix [ 2 ] [ 2 ] ;
break ;
}
}
int G2API_CopyGhoul2Instance ( CGhoul2Info_v & g2From , CGhoul2Info_v & g2To , int modelIndex )
{
assert ( modelIndex = = - 1 ) ; // copy individual bolted parts is not used in jk2 and I didn't want to deal with it
// if ya want it, we will add it back correctly
//G2ERROR(ghoul2From.IsValid(),"Invalid ghlInfo");
if ( g2From . IsValid ( ) )
{
# ifdef _DEBUG
if ( g2To . IsValid ( ) )
{
assert ( ! " Copying to a valid g2 instance?! " ) ;
if ( g2To [ 0 ] . mBoneCache )
{
assert ( ! " Instance has a bonecache too.. it's gonna get stomped " ) ;
}
}
# endif
g2To . DeepCopy ( g2From ) ;
# ifdef _G2_GORE //check through gore stuff then, as well.
int model = 0 ;
while ( model < g2To . size ( ) )
{
if ( g2To [ model ] . mGoreSetTag )
{
CGoreSet * gore = FindGoreSet ( g2To [ model ] . mGoreSetTag ) ;
assert ( gore ) ;
gore - > mRefCount + + ;
}
model + + ;
}
# endif
//G2ANIM(ghoul2From,"G2API_CopyGhoul2Instance (source)");
//G2ANIM(ghoul2To,"G2API_CopyGhoul2Instance (dest)");
}
return - 1 ;
}
void G2API_CopySpecificG2Model ( CGhoul2Info_v & ghoul2From , int modelFrom , CGhoul2Info_v & ghoul2To , int modelTo )
{
#if 0
qboolean forceReconstruct = qtrue ;
# endif //model1 was not getting reconstructed like it should for thrown sabers?
//might have been a bug in the reconstruct checking which has since been
//mangled and probably fixed. -rww
// have we real ghoul2 models yet?
if ( ( ( int ) & ghoul2From ) & & ( ( int ) & ghoul2To ) )
{
// assume we actually have a model to copy from
if ( ghoul2From . size ( ) > modelFrom )
{
// if we don't have enough models on the to side, resize us so we do
if ( ghoul2To . size ( ) < = modelTo )
{
assert ( modelTo < 5 ) ;
ghoul2To . resize ( modelTo + 1 ) ;
#if 0
forceReconstruct = qtrue ;
# endif
}
// do the copy
if ( ghoul2To . IsValid ( ) & & ghoul2To . size ( ) > = modelTo )
{ //remove the bonecache before we stomp over this instance.
if ( ghoul2To [ modelTo ] . mBoneCache )
{
RemoveBoneCache ( ghoul2To [ modelTo ] . mBoneCache ) ;
ghoul2To [ modelTo ] . mBoneCache = 0 ;
}
}
ghoul2To [ modelTo ] = ghoul2From [ modelFrom ] ;
#if 0
if ( forceReconstruct )
{ //rww - we should really do this shouldn't we? If we don't mark a reconstruct after this,
//and we do a GetBoltMatrix in the same frame, it doesn't reconstruct the skeleton and returns
//a completely invalid matrix
ghoul2To [ 0 ] . mSkelFrameNum = 0 ;
}
# endif
}
}
}
// This version will automatically copy everything about this model, and make a new one if necessary.
void G2API_DuplicateGhoul2Instance ( CGhoul2Info_v & g2From , CGhoul2Info_v * * g2To )
{
int ignore ;
if ( * g2To )
{ // This is bad. We only want to do this if there is not yet a to declared.
assert ( 0 ) ;
return ;
}
* g2To = new CGhoul2Info_v ;
# ifdef _FULL_G2_LEAK_CHECKING
if ( g_G2AllocServer )
{
g_G2ServerAlloc + = sizeof ( CGhoul2Info_v ) ;
}
else
{
g_G2ClientAlloc + = sizeof ( CGhoul2Info_v ) ;
}
g_Ghoul2Allocations + = sizeof ( CGhoul2Info_v ) ;
G2_DEBUG_ShovePtrInTracker ( * g2To ) ;
# endif
CGhoul2Info_v & ghoul2 = * ( * g2To ) ;
ignore = G2API_CopyGhoul2Instance ( g2From , ghoul2 , - 1 ) ;
return ;
}
char * G2API_GetSurfaceName ( CGhoul2Info * ghlInfo , int surfNumber )
{
static char noSurface [ 1 ] = " " ;
if ( G2_SetupModelPointers ( ghlInfo ) )
{
model_t * mod = ( model_t * ) ghlInfo - > currentModel ;
mdxmSurface_t * surf = 0 ;
mdxmSurfHierarchy_t * surfInfo = 0 ;
# ifndef FINAL_BUILD
if ( ! mod | | ! mod - > mdxm )
{
Com_Error ( ERR_DROP , " G2API_GetSurfaceName: Bad model on instance %s. " , ghlInfo - > mFileName ) ;
}
# endif
//ok, I guess it's semi-valid for the user to be passing in surface > numSurfs because they don't know how many surfs a model
//may have.. but how did they get that surf index to begin with? Oh well.
if ( surfNumber < 0 | | surfNumber > = mod - > mdxm - > numSurfaces )
{
Com_Printf ( " G2API_GetSurfaceName: You passed in an invalid surface number (%i) for model %s. \n " , surfNumber , ghlInfo - > mFileName ) ;
return noSurface ;
}
surf = ( mdxmSurface_t * ) G2_FindSurface ( ( void * ) mod , surfNumber , 0 ) ;
if ( surf )
{
# ifndef FINAL_BUILD
if ( surf - > thisSurfaceIndex < 0 | | surf - > thisSurfaceIndex > = mod - > mdxm - > numSurfaces )
{
Com_Error ( ERR_DROP , " G2API_GetSurfaceName: Bad surf num (%i) on surf for instance %s. " , surf - > thisSurfaceIndex , ghlInfo - > mFileName ) ;
}
# endif
mdxmHierarchyOffsets_t * surfIndexes = ( mdxmHierarchyOffsets_t * ) ( ( byte * ) mod - > mdxm + sizeof ( mdxmHeader_t ) ) ;
surfInfo = ( mdxmSurfHierarchy_t * ) ( ( byte * ) surfIndexes + surfIndexes - > offsets [ surf - > thisSurfaceIndex ] ) ;
return surfInfo - > name ;
}
}
return noSurface ;
}
int G2API_GetSurfaceIndex ( CGhoul2Info * ghlInfo , const char * surfaceName )
{
if ( G2_SetupModelPointers ( ghlInfo ) )
{
return G2_GetSurfaceIndex ( ghlInfo , surfaceName ) ;
}
return - 1 ;
}
char * G2API_GetGLAName ( CGhoul2Info_v & ghoul2 , int modelIndex )
{
if ( G2_SetupModelPointers ( ghoul2 ) )
{
if ( ( ( int ) & ghoul2 ) & & ( ghoul2 . size ( ) > modelIndex ) )
{
//model_t *mod = R_GetModelByHandle(RE_RegisterModel(ghoul2[modelIndex].mFileName));
//return mod->mdxm->animName;
assert ( ghoul2 [ modelIndex ] . currentModel & & ghoul2 [ modelIndex ] . currentModel - > mdxm ) ;
return ghoul2 [ modelIndex ] . currentModel - > mdxm - > animName ;
}
}
return NULL ;
}
qboolean G2API_SetNewOrigin ( CGhoul2Info_v & ghoul2 , const int boltIndex )
{
CGhoul2Info * ghlInfo = NULL ;
if ( ( int ) & ghoul2 & & ghoul2 . size ( ) > 0 )
{
ghlInfo = & ghoul2 [ 0 ] ;
}
if ( G2_SetupModelPointers ( ghlInfo ) )
{
if ( boltIndex < 0 )
{
char modelName [ MAX_QPATH ] ;
if ( ghlInfo - > currentModel & &
ghlInfo - > currentModel - > name & &
ghlInfo - > currentModel - > name [ 0 ] )
{
strcpy ( modelName , ghlInfo - > currentModel - > name ) ;
}
else
{
strcpy ( modelName , " None?! " ) ;
}
Com_Error ( ERR_DROP , " Bad boltindex (%i) trying to SetNewOrigin (naughty naughty!) \n Model %s \n " , boltIndex , modelName ) ;
}
ghlInfo - > mNewOrigin = boltIndex ;
ghlInfo - > mFlags | = GHOUL2_NEWORIGIN ;
return qtrue ;
}
return qfalse ;
}
int G2API_GetBoneIndex ( CGhoul2Info * ghlInfo , const char * boneName )
{
if ( G2_SetupModelPointers ( ghlInfo ) )
{
return G2_Get_Bone_Index ( ghlInfo , boneName ) ;
}
return - 1 ;
}
qboolean G2API_SaveGhoul2Models ( CGhoul2Info_v & ghoul2 , char * * buffer , int * size )
{
return G2_SaveGhoul2Models ( ghoul2 , buffer , size ) ;
}
void G2API_LoadGhoul2Models ( CGhoul2Info_v & ghoul2 , char * buffer )
{
G2_LoadGhoul2Model ( ghoul2 , buffer ) ;
}
void G2API_FreeSaveBuffer ( char * buffer )
{
Z_Free ( buffer ) ;
}
// this is kinda sad, but I need to call the destructor in this module (exe), not the game.dll...
//
void G2API_LoadSaveCodeDestructGhoul2Info ( CGhoul2Info_v & ghoul2 )
{
# ifdef _G2_GORE
G2API_ClearSkinGore ( ghoul2 ) ;
# endif
ghoul2 . ~ CGhoul2Info_v ( ) ; // so I can load junk over it then memset to 0 without orphaning
}
//see if surfs have any shader info...
qboolean G2API_SkinlessModel ( CGhoul2Info * g2 )
{
if ( G2_SetupModelPointers ( g2 ) )
{
model_t * mod = ( model_t * ) g2 - > currentModel ;
if ( mod & &
mod - > mdxm )
{
mdxmSurfHierarchy_t * surf ;
int i ;
surf = ( mdxmSurfHierarchy_t * ) ( ( byte * ) mod - > mdxm + mod - > mdxm - > ofsSurfHierarchy ) ;
for ( i = 0 ; i < mod - > mdxm - > numSurfaces ; i + + )
{
if ( surf - > shader & & surf - > shader [ 0 ] )
{ //found a surface with a shader name, ok.
return qfalse ;
}
surf = ( mdxmSurfHierarchy_t * ) ( ( byte * ) surf + ( int ) ( & ( ( mdxmSurfHierarchy_t * ) 0 ) - > childIndexes [ surf - > numChildren ] ) ) ;
}
}
}
//found nothing.
return qtrue ;
}
//#ifdef _SOF2
# ifdef _G2_GORE
void ResetGoreTag ( ) ; // put here to reduce coupling
//way of seeing how many marks are on a model currently -rww
int G2API_GetNumGoreMarks ( CGhoul2Info * g2 )
{
if ( g2 - > mGoreSetTag )
{
CGoreSet * goreSet = FindGoreSet ( g2 - > mGoreSetTag ) ;
if ( goreSet )
{
return goreSet - > mGoreRecords . size ( ) ;
}
}
return 0 ;
}
void G2API_ClearSkinGore ( CGhoul2Info_v & ghoul2 )
{
int i ;
for ( i = 0 ; i < ghoul2 . size ( ) ; i + + )
{
if ( ghoul2 [ i ] . mGoreSetTag )
{
DeleteGoreSet ( ghoul2 [ i ] . mGoreSetTag ) ;
ghoul2 [ i ] . mGoreSetTag = 0 ;
}
}
}
int G2API_Ghoul2Size ( CGhoul2Info_v & ghoul2 )
{
return ghoul2 . size ( ) ;
}
extern int G2_DecideTraceLod ( CGhoul2Info & ghoul2 , int useLod ) ;
void G2API_AddSkinGore ( CGhoul2Info_v & ghoul2 , SSkinGoreData & gore )
{
if ( VectorLength ( gore . rayDirection ) < .1f )
{
assert ( 0 ) ; // can't add gore without a shot direction
return ;
}
// make sure we have transformed the whole skeletons for each model
//G2_ConstructGhoulSkeleton(ghoul2, gore.currentTime, NULL, true, gore.angles, gore.position, gore.scale, false);
G2_ConstructGhoulSkeleton ( ghoul2 , gore . currentTime , true , gore . scale ) ;
// pre generate the world matrix - used to transform the incoming ray
G2_GenerateWorldMatrix ( gore . angles , gore . position ) ;
// first up, translate the ray to model space
vec3_t transRayDirection , transHitLocation ;
TransformAndTranslatePoint ( gore . hitLocation , transHitLocation , & worldMatrixInv ) ;
TransformPoint ( gore . rayDirection , transRayDirection , & worldMatrixInv ) ;
int lod ;
ResetGoreTag ( ) ;
const int lodbias = Com_Clamp ( 0 , 2 , G2_DecideTraceLod ( ghoul2 [ 0 ] , r_lodbias - > integer ) ) ;
const int maxLod = Com_Clamp ( 0 , ghoul2 [ 0 ] . currentModel - > numLods , 3 ) ; //limit to the number of lods the main model has
for ( lod = lodbias ; lod < maxLod ; lod + + )
{
// now having done that, time to build the model
G2VertSpaceServer - > ResetHeap ( ) ;
G2_TransformModel ( ghoul2 , gore . currentTime , gore . scale , G2VertSpaceServer , lod , true ) ;
// now walk each model and compute new texture coordinates
G2_TraceModels ( ghoul2 , transHitLocation , transRayDirection , 0 , gore . entNum , 0 , lod , 0.0f , gore . SSize , gore . TSize , gore . theta , gore . shader , & gore , qtrue ) ;
}
}
# endif
qboolean G2_TestModelPointers ( CGhoul2Info * ghlInfo ) // returns true if the model is properly set up
{
G2ERROR ( ghlInfo , " NULL ghlInfo " ) ;
if ( ! ghlInfo )
{
return qfalse ;
}
ghlInfo - > mValid = false ;
if ( ghlInfo - > mModelindex ! = - 1 )
{
if ( ( com_dedicated & & com_dedicated - > integer ) | |
( G2_ShouldRegisterServer ( ) ) ) //supreme hackery!
{
ghlInfo - > mModel = RE_RegisterServerModel ( ghlInfo - > mFileName ) ;
}
else
{
ghlInfo - > mModel = RE_RegisterModel ( ghlInfo - > mFileName ) ;
}
ghlInfo - > currentModel = R_GetModelByHandle ( ghlInfo - > mModel ) ;
if ( ghlInfo - > currentModel )
{
if ( ghlInfo - > currentModel - > mdxm )
{
if ( ghlInfo - > currentModelSize )
{
if ( ghlInfo - > currentModelSize ! = ghlInfo - > currentModel - > mdxm - > ofsEnd )
{
Com_Error ( ERR_DROP , " Ghoul2 model was reloaded and has changed, map must be restarted. \n " ) ;
}
}
ghlInfo - > currentModelSize = ghlInfo - > currentModel - > mdxm - > ofsEnd ;
ghlInfo - > animModel = R_GetModelByHandle ( ghlInfo - > currentModel - > mdxm - > animIndex ) ;
if ( ghlInfo - > animModel )
{
ghlInfo - > aHeader = ghlInfo - > animModel - > mdxa ;
if ( ghlInfo - > aHeader )
{
if ( ghlInfo - > currentAnimModelSize )
{
if ( ghlInfo - > currentAnimModelSize ! = ghlInfo - > aHeader - > ofsEnd )
{
Com_Error ( ERR_DROP , " Ghoul2 model was reloaded and has changed, map must be restarted. \n " ) ;
}
}
ghlInfo - > currentAnimModelSize = ghlInfo - > aHeader - > ofsEnd ;
ghlInfo - > mValid = true ;
}
}
}
}
}
if ( ! ghlInfo - > mValid )
{
ghlInfo - > currentModel = 0 ;
ghlInfo - > currentModelSize = 0 ;
ghlInfo - > animModel = 0 ;
ghlInfo - > currentAnimModelSize = 0 ;
ghlInfo - > aHeader = 0 ;
}
return ( qboolean ) ghlInfo - > mValid ;
}
# ifdef G2_PERFORMANCE_ANALYSIS
# include "../qcommon/timing.h"
extern timing_c G2PerformanceTimer_G2_SetupModelPointers ;
extern int G2Time_G2_SetupModelPointers ;
# endif
qboolean G2_SetupModelPointers ( CGhoul2Info * ghlInfo ) // returns true if the model is properly set up
{
# ifdef G2_PERFORMANCE_ANALYSIS
G2PerformanceTimer_G2_SetupModelPointers . Start ( ) ;
# endif
G2ERROR ( ghlInfo , " NULL ghlInfo " ) ;
if ( ! ghlInfo )
{
return qfalse ;
}
// if (ghlInfo->mValid && ghlInfo->currentModel)
if ( 0 )
{ //rww - Why are we bothering with all this? We can't change models like this anyway.
//This function goes over 200k on the precision timer (in debug, but still), so I'm
//cutting it off here because it gets called constantly.
# ifdef G2_PERFORMANCE_ANALYSIS
G2Time_G2_SetupModelPointers + = G2PerformanceTimer_G2_SetupModelPointers . End ( ) ;
# endif
return qtrue ;
}
ghlInfo - > mValid = false ;
// G2WARNING(ghlInfo->mModelindex != -1,"Setup request on non-used info slot?");
if ( ghlInfo - > mModelindex ! = - 1 )
{
G2ERROR ( ghlInfo - > mFileName [ 0 ] , " empty ghlInfo->mFileName " ) ;
// RJ - experimental optimization!
if ( ! ghlInfo - > mModel | | 1 )
{
if ( ( com_dedicated & & com_dedicated - > integer ) | |
( G2_ShouldRegisterServer ( ) ) ) //supreme hackery!
{
ghlInfo - > mModel = RE_RegisterServerModel ( ghlInfo - > mFileName ) ;
}
else
{
ghlInfo - > mModel = RE_RegisterModel ( ghlInfo - > mFileName ) ;
}
ghlInfo - > currentModel = R_GetModelByHandle ( ghlInfo - > mModel ) ;
}
G2ERROR ( ghlInfo - > currentModel , va ( " NULL Model (glm) %s " , ghlInfo - > mFileName ) ) ;
if ( ghlInfo - > currentModel )
{
G2ERROR ( ghlInfo - > currentModel - > mdxm , va ( " Model has no mdxm (glm) %s " , ghlInfo - > mFileName ) ) ;
if ( ghlInfo - > currentModel - > mdxm )
{
if ( ghlInfo - > currentModelSize )
{
if ( ghlInfo - > currentModelSize ! = ghlInfo - > currentModel - > mdxm - > ofsEnd )
{
Com_Error ( ERR_DROP , " Ghoul2 model was reloaded and has changed, map must be restarted. \n " ) ;
}
}
ghlInfo - > currentModelSize = ghlInfo - > currentModel - > mdxm - > ofsEnd ;
G2ERROR ( ghlInfo - > currentModelSize , va ( " Zero sized Model? (glm) %s " , ghlInfo - > mFileName ) ) ;
ghlInfo - > animModel = R_GetModelByHandle ( ghlInfo - > currentModel - > mdxm - > animIndex ) ;
G2ERROR ( ghlInfo - > animModel , va ( " NULL Model (gla) %s " , ghlInfo - > mFileName ) ) ;
if ( ghlInfo - > animModel )
{
ghlInfo - > aHeader = ghlInfo - > animModel - > mdxa ;
G2ERROR ( ghlInfo - > aHeader , va ( " Model has no mdxa (gla) %s " , ghlInfo - > mFileName ) ) ;
if ( ghlInfo - > aHeader )
{
if ( ghlInfo - > currentAnimModelSize )
{
if ( ghlInfo - > currentAnimModelSize ! = ghlInfo - > aHeader - > ofsEnd )
{
Com_Error ( ERR_DROP , " Ghoul2 model was reloaded and has changed, map must be restarted. \n " ) ;
}
}
ghlInfo - > currentAnimModelSize = ghlInfo - > aHeader - > ofsEnd ;
G2ERROR ( ghlInfo - > currentAnimModelSize , va ( " Zero sized Model? (gla) %s " , ghlInfo - > mFileName ) ) ;
ghlInfo - > mValid = true ;
}
}
}
}
}
if ( ! ghlInfo - > mValid )
{
ghlInfo - > currentModel = 0 ;
ghlInfo - > currentModelSize = 0 ;
ghlInfo - > animModel = 0 ;
ghlInfo - > currentAnimModelSize = 0 ;
ghlInfo - > aHeader = 0 ;
}
# ifdef G2_PERFORMANCE_ANALYSIS
G2Time_G2_SetupModelPointers + = G2PerformanceTimer_G2_SetupModelPointers . End ( ) ;
# endif
return ( qboolean ) ghlInfo - > mValid ;
}
qboolean G2_SetupModelPointers ( CGhoul2Info_v & ghoul2 ) // returns true if any model is properly set up
{
bool ret = false ;
int i ;
for ( i = 0 ; i < ghoul2 . size ( ) ; i + + )
{
qboolean r = G2_SetupModelPointers ( & ghoul2 [ i ] ) ;
ret = ret | | r ;
}
return ( qboolean ) ret ;
}