2022-09-18 15:37:21 +00:00
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
Copyright ( C ) 2000 - 2013 , Raven Software , Inc .
Copyright ( C ) 2001 - 2013 , Activision , Inc .
Copyright ( C ) 2013 - 2015 , OpenJK contributors
This file is part of the OpenJK source code .
OpenJK is free software ; you can redistribute it and / or modify it
under the terms of the GNU General Public License version 2 as
published by the Free Software Foundation .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , see < http : //www.gnu.org/licenses/>.
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
# include "../server/exe_headers.h"
# include <list>
# include <string>
# include "../qcommon/q_shared.h"
# include "tr_local.h"
# include "tr_common.h"
# include "../ghoul2/G2.h"
# include "../qcommon/MiniHeap.h"
# ifdef FINAL_BUILD
# define G2API_DEBUG (0) // please don't change this
# else
# if defined(_DEBUG)
# define G2API_DEBUG (1)
# else
# define G2API_DEBUG (0) // change this to test g2api in release
# endif
# endif
//rww - RAGDOLL_BEGIN
# include "../ghoul2/ghoul2_gore.h"
//rww - RAGDOLL_END
extern mdxaBone_t worldMatrix ;
extern mdxaBone_t worldMatrixInv ;
extern cvar_t * r_Ghoul2TimeBase ;
extern refexport_t re ;
# define G2_MODEL_OK(g) ((g)&&(g)->mValid&&(g)->aHeader&&(g)->currentModel&&(g)->animModel)
# define G2_DEBUG_TIME (0)
static int G2TimeBases [ NUM_G2T_TIME ] ;
bool G2_TestModelPointers ( CGhoul2Info * ghlInfo ) ;
# if G2API_DEBUG
# include <float.h> //for isnan
# define MAX_ERROR_PRINTS (3)
class ErrorReporter
{
std : : string mName ;
std : : map < std : : string , int > mErrors ;
public :
ErrorReporter ( const std : : string & name ) :
mName ( name )
{
}
~ ErrorReporter ( )
{
char mess [ 1000 ] ;
int total = 0 ;
sprintf ( mess , " ****** %s Error Report Begin****** \n " , mName . c_str ( ) ) ;
Com_DPrintf ( mess ) ;
std : : map < std : : string , int > : : iterator i ;
for ( i = mErrors . begin ( ) ; i ! = mErrors . end ( ) ; + + i )
{
total + = ( * i ) . second ;
sprintf ( mess , " %s (hits %d) \n " , ( * i ) . first . c_str ( ) , ( * i ) . second ) ;
Com_DPrintf ( mess ) ;
}
sprintf ( mess , " ****** %s Error Report End %d errors of %ld kinds****** \n " , mName . c_str ( ) , total , mErrors . size ( ) ) ;
Com_DPrintf ( mess ) ;
}
int AnimTest ( CGhoul2Info_v & ghoul2 , const char * m , const char * , int line )
{
if ( G2_SetupModelPointers ( ghoul2 ) )
{
int i ;
for ( i = 0 ; i < ghoul2 . size ( ) ; i + + )
{
AnimTest ( & ghoul2 [ i ] , m , 0 , line ) ;
}
return i ;
}
return 666 ; //these return values are to saisfy the optimizer
}
int AnimTest ( CGhoul2Info * ghlInfo , const char * m , const char * , int line )
{
bool ok = G2_TestModelPointers ( ghlInfo ) ;
if ( ! ok )
{
return 5 ; // I guess this happens from time to time
}
size_t i ;
int ret = 0 ;
char GLAName1 [ 1000 ] ;
char GLAName2 [ 1000 ] ;
char GLMName1 [ 1000 ] ;
char GLMName2 [ 1000 ] ;
strcpy ( GLAName1 , ghlInfo - > animModel - > name ) ;
strcpy ( GLAName2 , ghlInfo - > aHeader - > name ) ;
strcpy ( GLMName1 , ghlInfo - > mFileName ) ;
strcpy ( GLMName2 , ghlInfo - > currentModel - > name ) ;
int numFramesInFile = ghlInfo - > aHeader - > numFrames ;
int numActiveBones = 0 ;
for ( i = 0 ; i < ghlInfo - > mBlist . size ( ) ; i + + )
{
if ( ghlInfo - > mBlist [ i ] . boneNumber ! = - 1 ) // slot used?
{
if ( ghlInfo - > mBlist [ i ] . flags & BONE_ANIM_TOTAL ) // anim on this?
{
numActiveBones + + ;
bool loop = ! ! ( ghlInfo - > mBlist [ i ] . flags & BONE_ANIM_OVERRIDE_LOOP ) ;
bool not_loop = ! ! ( ghlInfo - > mBlist [ i ] . flags & BONE_ANIM_OVERRIDE ) ;
if ( loop = = not_loop )
{
Error ( " Unusual animation flags, should have some sort of override, but not both " , 1 , 0 , line ) ;
}
bool freeze = ( ghlInfo - > mBlist [ i ] . flags & BONE_ANIM_OVERRIDE_FREEZE ) = = BONE_ANIM_OVERRIDE_FREEZE ;
if ( loop & & freeze )
{
Error ( " Unusual animation flags, loop and freeze " , 1 , 0 , line ) ;
}
bool no_lerp = ! ! ( ghlInfo - > mBlist [ i ] . flags & BONE_ANIM_NO_LERP ) ;
bool blend = ! ! ( ghlInfo - > mBlist [ i ] . flags & BONE_ANIM_BLEND ) ;
//comments according to jake
int startFrame = ghlInfo - > mBlist [ i ] . startFrame ; // start frame for animation
int endFrame = ghlInfo - > mBlist [ i ] . endFrame ; // end frame for animation NOTE anim actually ends on endFrame+1
int startTime = ghlInfo - > mBlist [ i ] . startTime ; // time we started this animation
int pauseTime = ghlInfo - > mBlist [ i ] . pauseTime ; // time we paused this animation - 0 if not paused
float animSpeed = ghlInfo - > mBlist [ i ] . animSpeed ; // speed at which this anim runs. 1.0f means full speed of animation incoming - ie if anim is 20hrtz, we run at 20hrts. If 5hrts, we run at 5 hrts
float blendFrame = 0.0f ; // frame PLUS LERP value to blend
int blendLerpFrame = 0 ; // frame to lerp the blend frame with.
if ( blend )
{
blendFrame = ghlInfo - > mBlist [ i ] . blendFrame ;
blendLerpFrame = ghlInfo - > mBlist [ i ] . blendLerpFrame ;
if ( floor ( blendFrame ) < 0.0f )
{
Error ( " negative blendFrame " , 1 , 0 , line ) ;
}
if ( ceil ( blendFrame ) > = float ( numFramesInFile ) )
{
Error ( " blendFrame >= numFramesInFile " , 1 , 0 , line ) ;
}
if ( blendLerpFrame < 0 )
{
Error ( " negative blendLerpFrame " , 1 , 0 , line ) ;
}
if ( blendLerpFrame > = numFramesInFile )
{
Error ( " blendLerpFrame >= numFramesInFile " , 1 , 0 , line ) ;
}
}
if ( startFrame < 0 )
{
Error ( " negative startFrame " , 1 , 0 , line ) ;
}
if ( startFrame > = numFramesInFile )
{
Error ( " startFrame >= numFramesInFile " , 1 , 0 , line ) ;
}
if ( endFrame < 0 )
{
Error ( " negative endFrame " , 1 , 0 , line ) ;
}
if ( endFrame = = 0 & & animSpeed > 0.0f )
{
Error ( " Zero endFrame " , 1 , 0 , line ) ;
}
if ( endFrame > numFramesInFile )
{
Error ( " endFrame > numFramesInFile " , 1 , 0 , line ) ;
}
// mikeg call out here for further checks.
ret = ( int ) startTime + ( int ) pauseTime + ( int ) no_lerp ; // quiet VC.
}
}
}
return ret ;
}
int Error ( const char * m , int kind , const char * , int line )
{
char mess [ 1000 ] ;
assert ( m ) ;
std : : string full = mName ;
if ( kind = = 2 )
{
full + = " :NOTE: " ;
}
else if ( kind = = 1 )
{
// assert(!"G2API Warning");
full + = " :WARNING: " ;
}
else
{
// assert(!"G2API Error");
full + = " :ERROR : " ;
}
full + = m ;
sprintf ( mess , " [line %d] " , line ) ;
full + = mess ;
// assert(0);
int ret = 0 ; //place a breakpoint here
std : : map < std : : string , int > : : iterator f = mErrors . find ( full ) ;
if ( f = = mErrors . end ( ) )
{
ret + + ; // or a breakpoint here for the first occurance
mErrors . insert ( std : : make_pair ( full , 0 ) ) ;
f = mErrors . find ( full ) ;
}
assert ( f ! = mErrors . end ( ) ) ;
( * f ) . second + + ;
if ( ( * f ) . second = = 1000 )
{
ret * = - 1 ; // breakpoint to find a specific occurance of an error
}
if ( ( * f ) . second < = MAX_ERROR_PRINTS & & kind < 2 )
{
Com_Printf ( " %s (hit # %d) \n " , full . c_str ( ) , ( * f ) . second ) ;
if ( 1 )
{
sprintf ( mess , " %s (hit # %d) \n " , full . c_str ( ) , ( * f ) . second ) ;
Com_DPrintf ( mess ) ;
}
}
return ret ;
}
} ;
# include "assert.h"
ErrorReporter & G2APIError ( )
{
static ErrorReporter singleton ( " G2API " ) ;
return singleton ;
}
# define G2ERROR(exp,m) (void)( (exp) || (G2APIError().Error(m,0,__FILE__,__LINE__), 0) )
# define G2WARNING(exp,m) (void)( (exp) || (G2APIError().Error(m,1,__FILE__,__LINE__), 0) )
# define G2NOTE(exp,m) (void)( (exp) || (G2APIError().Error(m,2,__FILE__,__LINE__), 0) )
# define G2ANIM(ghlInfo,m) (void)((G2APIError().AnimTest(ghlInfo,m,__FILE__,__LINE__), 0) )
# else
# define G2ERROR(exp,m) ((void)0)
# define G2WARNING(exp,m) ((void)0)
# define G2NOTE(exp,m) ((void)0)
# define G2ANIM(ghlInfo,m) ((void)0)
# endif
# ifdef _DEBUG
void G2_Bone_Not_Found ( const char * boneName , const char * modName )
{
G2ERROR ( boneName , " NULL Bone Name " ) ;
G2ERROR ( boneName [ 0 ] , " Empty Bone Name " ) ;
if ( boneName )
{
G2NOTE ( 0 , va ( " Bone Not Found (%s:%s) " , boneName , modName ) ) ;
}
}
void G2_Bolt_Not_Found ( const char * boneName , const char * modName )
{
G2ERROR ( boneName , " NULL Bolt/Bone Name " ) ;
G2ERROR ( boneName [ 0 ] , " Empty Bolt/Bone Name " ) ;
if ( boneName )
{
G2NOTE ( 0 , va ( " Bolt/Bone Not Found (%s:%s) " , boneName , modName ) ) ;
}
}
# endif
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 ;
}
// must be a power of two
# define MAX_G2_MODELS (512)
# define G2_MODEL_BITS (9)
# define G2_INDEX_MASK (MAX_G2_MODELS-1)
void RemoveBoneCache ( CBoneCache * boneCache ) ;
static size_t GetSizeOfGhoul2Info ( const CGhoul2Info & g2Info )
{
size_t size = 0 ;
// This is pretty ugly, but we don't want to save everything in the CGhoul2Info object.
size + = offsetof ( CGhoul2Info , mTransformedVertsArray ) - offsetof ( CGhoul2Info , mModelindex ) ;
// Surface vector + size
size + = sizeof ( int ) ;
size + = g2Info . mSlist . size ( ) * sizeof ( surfaceInfo_t ) ;
// Bone vector + size
size + = sizeof ( int ) ;
size + = g2Info . mBlist . size ( ) * sizeof ( boneInfo_t ) ;
// Bolt vector + size
size + = sizeof ( int ) ;
size + = g2Info . mBltlist . size ( ) * sizeof ( boltInfo_t ) ;
return size ;
}
static size_t SerializeGhoul2Info ( char * buffer , const CGhoul2Info & g2Info )
{
char * base = buffer ;
size_t blockSize ;
// Oh the ugliness...
blockSize = offsetof ( CGhoul2Info , mTransformedVertsArray ) - offsetof ( CGhoul2Info , mModelindex ) ;
memcpy ( buffer , & g2Info . mModelindex , blockSize ) ;
buffer + = blockSize ;
// Surfaces vector + size
* ( int * ) buffer = g2Info . mSlist . size ( ) ;
buffer + = sizeof ( int ) ;
blockSize = g2Info . mSlist . size ( ) * sizeof ( surfaceInfo_t ) ;
memcpy ( buffer , g2Info . mSlist . data ( ) , g2Info . mSlist . size ( ) * sizeof ( surfaceInfo_t ) ) ;
buffer + = blockSize ;
// Bones vector + size
* ( int * ) buffer = g2Info . mBlist . size ( ) ;
buffer + = sizeof ( int ) ;
blockSize = g2Info . mBlist . size ( ) * sizeof ( boneInfo_t ) ;
memcpy ( buffer , g2Info . mBlist . data ( ) , g2Info . mBlist . size ( ) * sizeof ( boneInfo_t ) ) ;
buffer + = blockSize ;
// Bolts vector + size
* ( int * ) buffer = g2Info . mBltlist . size ( ) ;
buffer + = sizeof ( int ) ;
blockSize = g2Info . mBltlist . size ( ) * sizeof ( boltInfo_t ) ;
memcpy ( buffer , g2Info . mBltlist . data ( ) , g2Info . mBltlist . size ( ) * sizeof ( boltInfo_t ) ) ;
buffer + = blockSize ;
return static_cast < size_t > ( buffer - base ) ;
}
static size_t DeserializeGhoul2Info ( const char * buffer , CGhoul2Info & g2Info )
{
const char * base = buffer ;
size_t size ;
size = offsetof ( CGhoul2Info , mTransformedVertsArray ) - offsetof ( CGhoul2Info , mModelindex ) ;
memcpy ( & g2Info . mModelindex , buffer , size ) ;
buffer + = size ;
// Surfaces vector
size = * ( int * ) buffer ;
buffer + = sizeof ( int ) ;
g2Info . mSlist . assign ( ( surfaceInfo_t * ) buffer , ( surfaceInfo_t * ) buffer + size ) ;
buffer + = sizeof ( surfaceInfo_t ) * size ;
// Bones vector
size = * ( int * ) buffer ;
buffer + = sizeof ( int ) ;
g2Info . mBlist . assign ( ( boneInfo_t * ) buffer , ( boneInfo_t * ) buffer + size ) ;
buffer + = sizeof ( boneInfo_t ) * size ;
// Bolt vector
size = * ( int * ) buffer ;
buffer + = sizeof ( int ) ;
g2Info . mBltlist . assign ( ( boltInfo_t * ) buffer , ( boltInfo_t * ) buffer + size ) ;
buffer + = sizeof ( boltInfo_t ) * size ;
return static_cast < size_t > ( buffer - base ) ;
}
class Ghoul2InfoArray : public IGhoul2InfoArray
{
std : : vector < CGhoul2Info > mInfos [ MAX_G2_MODELS ] ;
int mIds [ MAX_G2_MODELS ] ;
std : : list < int > mFreeIndecies ;
void DeleteLow ( int idx )
{
{
size_t model ;
for ( model = 0 ; model < mInfos [ idx ] . size ( ) ; model + + )
{
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 ( )
{
size_t i ;
for ( i = 0 ; i < MAX_G2_MODELS ; i + + )
{
mIds [ i ] = MAX_G2_MODELS + i ;
mFreeIndecies . push_back ( i ) ;
}
}
size_t GetSerializedSize ( ) const
{
size_t size = 0 ;
size + = sizeof ( int ) ; // size of mFreeIndecies linked list
size + = mFreeIndecies . size ( ) * sizeof ( int ) ;
size + = sizeof ( mIds ) ;
for ( size_t i = 0 ; i < MAX_G2_MODELS ; i + + )
{
size + = sizeof ( int ) ; // size of the mInfos[i] vector
for ( size_t j = 0 ; j < mInfos [ i ] . size ( ) ; j + + )
{
size + = GetSizeOfGhoul2Info ( mInfos [ i ] [ j ] ) ;
}
}
return size ;
}
size_t Serialize ( char * buffer ) const
{
char * base = buffer ;
// Free indices
* ( int * ) buffer = mFreeIndecies . size ( ) ;
buffer + = sizeof ( int ) ;
std : : copy ( mFreeIndecies . begin ( ) , mFreeIndecies . end ( ) , ( int * ) buffer ) ;
buffer + = sizeof ( int ) * mFreeIndecies . size ( ) ;
// IDs
memcpy ( buffer , mIds , sizeof ( mIds ) ) ;
buffer + = sizeof ( mIds ) ;
// Ghoul2 infos
for ( size_t i = 0 ; i < MAX_G2_MODELS ; i + + )
{
* ( int * ) buffer = mInfos [ i ] . size ( ) ;
buffer + = sizeof ( int ) ;
for ( size_t j = 0 ; j < mInfos [ i ] . size ( ) ; j + + )
{
buffer + = SerializeGhoul2Info ( buffer , mInfos [ i ] [ j ] ) ;
}
}
return static_cast < size_t > ( buffer - base ) ;
}
size_t Deserialize ( const char * buffer , size_t size )
{
const char * base = buffer ;
size_t count ;
// Free indices
count = * ( int * ) buffer ;
buffer + = sizeof ( int ) ;
mFreeIndecies . assign ( ( int * ) buffer , ( int * ) buffer + count ) ;
buffer + = sizeof ( int ) * count ;
// IDs
memcpy ( mIds , buffer , sizeof ( mIds ) ) ;
buffer + = sizeof ( mIds ) ;
// Ghoul2 infos
for ( size_t i = 0 ; i < MAX_G2_MODELS ; i + + )
{
mInfos [ i ] . clear ( ) ;
count = * ( int * ) buffer ;
buffer + = sizeof ( int ) ;
mInfos [ i ] . resize ( count ) ;
for ( size_t j = 0 ; j < count ; j + + )
{
buffer + = DeserializeGhoul2Info ( buffer , mInfos [ i ] [ j ] ) ;
}
}
return static_cast < size_t > ( buffer - base ) ;
}
~ Ghoul2InfoArray ( )
{
if ( mFreeIndecies . size ( ) < MAX_G2_MODELS )
{
# if G2API_DEBUG
char mess [ 1000 ] ;
sprintf ( mess , " ************************ \n Leaked %ld ghoul2info slots \n " , MAX_G2_MODELS - mFreeIndecies . size ( ) ) ;
Com_DPrintf ( mess ) ;
# endif
int i ;
for ( i = 0 ; i < MAX_G2_MODELS ; i + + )
{
std : : list < int > : : iterator j ;
for ( j = mFreeIndecies . begin ( ) ; j ! = mFreeIndecies . end ( ) ; + + j )
{
if ( * j = = i )
break ;
}
if ( j = = mFreeIndecies . end ( ) )
{
# if G2API_DEBUG
sprintf ( mess , " Leaked Info idx=%d id=%d sz=%ld \n " , i , mIds [ i ] , mInfos [ i ] . size ( ) ) ;
Com_DPrintf ( mess ) ;
if ( mInfos [ i ] . size ( ) )
{
sprintf ( mess , " %s \n " , mInfos [ i ] [ 0 ] . mFileName ) ;
Com_DPrintf ( mess ) ;
}
# endif
DeleteLow ( i ) ;
}
}
}
# if G2API_DEBUG
else
{
Com_DPrintf ( " 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 ) ;
}
}
std : : vector < CGhoul2Info > & Get ( int handle )
{
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
assert ( ! ( handle < = 0 | | ( handle & G2_INDEX_MASK ) < 0 | | ( handle & G2_INDEX_MASK ) > = MAX_G2_MODELS | | mIds [ handle & G2_INDEX_MASK ] ! = handle ) ) ;
return mInfos [ handle & G2_INDEX_MASK ] ;
}
const std : : 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
std : : vector < CGhoul2Info > & GetDebug ( int handle )
{
assert ( ! ( handle < = 0 | | ( handle & G2_INDEX_MASK ) < 0 | | ( handle & G2_INDEX_MASK ) > = MAX_G2_MODELS | | mIds [ handle & G2_INDEX_MASK ] ! = handle ) ) ;
return mInfos [ handle & G2_INDEX_MASK ] ;
}
void TestAllAnims ( )
{
for ( size_t j = 0 ; j < MAX_G2_MODELS ; j + + )
{
std : : vector < CGhoul2Info > & ghoul2 = mInfos [ j ] ;
for ( size_t 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 ;
}
# if G2API_DEBUG
std : : vector < CGhoul2Info > & DebugG2Info ( int handle )
{
return ( ( Ghoul2InfoArray * ) ( & TheGhoul2InfoArray ( ) ) ) - > GetDebug ( handle ) ;
}
CGhoul2Info & DebugG2InfoI ( int handle , int item )
{
return ( ( Ghoul2InfoArray * ) ( & TheGhoul2InfoArray ( ) ) ) - > GetDebug ( handle ) [ item ] ;
}
void TestAllGhoul2Anims ( )
{
( ( Ghoul2InfoArray * ) ( & TheGhoul2InfoArray ( ) ) ) - > TestAllAnims ( ) ;
}
# endif
# define PERSISTENT_G2DATA "g2infoarray"
void RestoreGhoul2InfoArray ( )
{
if ( singleton = = NULL )
{
// Create the ghoul2 info array
TheGhoul2InfoArray ( ) ;
size_t size ;
const void * data = ri . PD_Load ( PERSISTENT_G2DATA , & size ) ;
if ( data = = NULL )
{
return ;
}
# ifdef _DEBUG
size_t read =
# endif // _DEBUG
singleton - > Deserialize ( ( const char * ) data , size ) ;
R_Free ( ( void * ) data ) ;
# ifdef _DEBUG
assert ( read = = size ) ;
# endif
}
}
void SaveGhoul2InfoArray ( )
{
size_t size = singleton - > GetSerializedSize ( ) ;
void * data = R_Malloc ( size , TAG_GHOUL2 , qfalse ) ;
# ifdef _DEBUG
size_t written =
# endif // _DEBUG
singleton - > Serialize ( ( char * ) data ) ;
# ifdef _DEBUG
assert ( written = = size ) ;
# endif // _DEBUG
if ( ! ri . PD_Store ( PERSISTENT_G2DATA , data , size ) )
{
Com_Printf ( S_COLOR_RED " ERROR: Failed to store persistent renderer data. \n " ) ;
}
}
// this is the ONLY function to read entity states directly
void G2API_CleanGhoul2Models ( CGhoul2Info_v & ghoul2 )
{
# ifdef _G2_GORE
G2API_ClearSkinGore ( ghoul2 ) ;
# endif
ghoul2 . ~ CGhoul2Info_v ( ) ;
}
qhandle_t G2API_PrecacheGhoul2Model ( const char * fileName )
{
return RE_RegisterModel ( ( char * ) fileName ) ;
}
// initialise all that needs to be on a new Ghoul II model
int G2API_InitGhoul2Model ( CGhoul2Info_v & ghoul2 , const char * fileName , int , qhandle_t customSkin ,
qhandle_t customShader , int modelFlags , int lodBias )
{
int model = - 1 ;
G2ERROR ( fileName & & fileName [ 0 ] , " NULL filename " ) ;
if ( ! fileName | | ! fileName [ 0 ] )
{
assert ( fileName [ 0 ] ) ;
return - 1 ;
}
// 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 ( ) )
{
assert ( model < 8 ) ; //arb, just catching run-away models
CGhoul2Info info ;
Q_strncpyz ( info . mFileName , fileName , sizeof ( info . mFileName ) ) ;
info . mModelindex = 0 ;
if ( G2_TestModelPointers ( & info ) ) {
ghoul2 . push_back ( CGhoul2Info ( ) ) ;
} else {
return - 1 ;
}
}
Q_strncpyz ( ghoul2 [ model ] . mFileName , fileName , sizeof ( ghoul2 [ model ] . mFileName ) ) ;
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 , ghoul2 [ model ] . aHeader - > numBones ) ;
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 )
{
G2ERROR ( ghlInfo , " NULL ghlInfo " ) ;
if ( G2_SetupModelPointers ( ghlInfo ) )
{
ghlInfo - > mLodBias = lodBias ;
return qtrue ;
}
return qfalse ;
}
qboolean G2API_SetSkin ( CGhoul2Info * ghlInfo , qhandle_t customSkin , qhandle_t renderSkin )
{
G2ERROR ( ghlInfo , " NULL ghlInfo " ) ;
# ifdef JK2_MODE
if ( G2_SetupModelPointers ( ghlInfo ) )
{
ghlInfo - > mCustomSkin = customSkin ;
return qtrue ;
}
return qfalse ;
# else
if ( G2_SetupModelPointers ( ghlInfo ) )
{
ghlInfo - > mCustomSkin = customSkin ;
if ( renderSkin )
{ //this is going to set the surfs on/off matching the skin file
extern void G2API_SetSurfaceOnOffFromSkin ( CGhoul2Info * ghlInfo , qhandle_t renderSkin ) ; //tr_ghoul2.cpp
G2API_SetSurfaceOnOffFromSkin ( ghlInfo , renderSkin ) ;
}
return qtrue ;
}
# endif
return qfalse ;
}
qboolean G2API_SetShader ( CGhoul2Info * ghlInfo , qhandle_t customShader )
{
G2ERROR ( ghlInfo , " NULL ghlInfo " ) ;
if ( G2_SetupModelPointers ( ghlInfo ) )
{
ghlInfo - > mCustomShader = customShader ;
return qtrue ;
}
return qfalse ;
}
qboolean G2API_SetSurfaceOnOff ( CGhoul2Info * ghlInfo , const char * surfaceName , const int flags )
{
if ( G2_SetupModelPointers ( ghlInfo ) )
{
G2ERROR ( ! ( flags & ~ ( G2SURFACEFLAG_OFF | G2SURFACEFLAG_NODESCENDANTS ) ) , " G2API_SetSurfaceOnOff Illegal Flags " ) ;
// ensure we flush the cache
ghlInfo - > mMeshFrameNum = 0 ;
return G2_SetSurfaceOnOff ( ghlInfo , surfaceName , flags ) ;
}
return qfalse ;
}
qboolean G2API_SetRootSurface ( CGhoul2Info_v & ghlInfo , const int modelIndex , const char * surfaceName )
{
G2ERROR ( ghlInfo . IsValid ( ) , " Invalid ghlInfo " ) ;
G2ERROR ( surfaceName , " Invalid surfaceName " ) ;
if ( G2_SetupModelPointers ( ghlInfo ) )
{
G2ERROR ( modelIndex > = 0 & & modelIndex < ghlInfo . size ( ) , " Bad Model Index " ) ;
if ( modelIndex > = 0 & & modelIndex < ghlInfo . size ( ) )
{
return G2_SetRootSurface ( ghlInfo , 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 )
{
G2ERROR ( surfaceName , " Invalid surfaceName " ) ;
if ( G2_SetupModelPointers ( ghlInfo ) )
{
return G2_IsSurfaceRendered ( ghlInfo , surfaceName , ghlInfo - > mSlist ) ;
}
return - 1 ;
}
qboolean G2API_RemoveGhoul2Model ( CGhoul2Info_v & ghlInfo , const int modelIndex )
{
// sanity check
if ( ! ghlInfo . size ( ) | | ( ghlInfo . size ( ) < = modelIndex ) | | modelIndex < 0 | | ( ghlInfo [ modelIndex ] . mModelindex < 0 ) )
{
// 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.
G2ERROR ( 0 , " Remove Nonexistant Model " ) ;
assert ( 0 & & " remove non existing model " ) ;
return qfalse ;
}
# ifdef _G2_GORE
// Cleanup the gore attached to this model
if ( ghlInfo [ modelIndex ] . mGoreSetTag )
{
DeleteGoreSet ( ghlInfo [ modelIndex ] . mGoreSetTag ) ;
ghlInfo [ modelIndex ] . mGoreSetTag = 0 ;
}
# endif
RemoveBoneCache ( ghlInfo [ modelIndex ] . mBoneCache ) ;
ghlInfo [ modelIndex ] . mBoneCache = 0 ;
// set us to be the 'not active' state
ghlInfo [ modelIndex ] . mModelindex = - 1 ;
ghlInfo [ modelIndex ] . mFileName [ 0 ] = 0 ;
ghlInfo [ modelIndex ] = CGhoul2Info ( ) ;
return qtrue ;
}
//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
int G2API_GetAnimIndex ( CGhoul2Info * ghlInfo )
{
if ( ghlInfo )
{
return ghlInfo - > animModelIndexOffset ;
}
return 0 ;
}
qboolean G2API_SetAnimIndex ( CGhoul2Info * ghlInfo , const int index )
{
// Is This A Valid G2 Model?
//---------------------------
if ( ghlInfo )
{
// Is This A New Anim Index?
//---------------------------
if ( ghlInfo - > animModelIndexOffset ! = index )
{
ghlInfo - > animModelIndexOffset = index ;
ghlInfo - > currentAnimModelSize = 0 ; // Clear anim size so SetupModelPointers recalcs
// RemoveBoneCache(ghlInfo[0].mBoneCache);
// ghlInfo[0].mBoneCache=0;
// Kill All Existing Animation, Blending, Etc.
//---------------------------------------------
for ( size_t index = 0 ; index < ghlInfo - > mBlist . size ( ) ; index + + )
{
ghlInfo - > mBlist [ index ] . flags & = ~ ( BONE_ANIM_TOTAL ) ;
ghlInfo - > mBlist [ index ] . flags & = ~ ( BONE_ANGLES_TOTAL ) ;
// G2_Remove_Bone_Index(ghlInfo->mBlist, index);
}
}
return qtrue ;
}
return qfalse ;
}
qboolean G2API_SetBoneAnimIndex ( CGhoul2Info * ghlInfo , const int index , const int startFrame , const int endFrame , const int flags , const float animSpeed , const int AcurrentTime , const float setFrame , const int blendTime )
{
//rww - RAGDOLL_BEGIN
if ( ghlInfo & & ( ghlInfo - > mFlags & GHOUL2_RAG_STARTED ) )
{
return qfalse ;
}
//rww - RAGDOLL_END
qboolean ret = qfalse ;
if ( G2_SetupModelPointers ( ghlInfo ) )
{
G2ERROR ( startFrame > = 0 , " startframe<0 " ) ;
G2ERROR ( startFrame < ghlInfo - > aHeader - > numFrames , " startframe>=numframes " ) ;
G2ERROR ( endFrame > 0 , " endframe<=0 " ) ;
G2ERROR ( endFrame < = ghlInfo - > aHeader - > numFrames , " endframe>numframes " ) ;
G2ERROR ( setFrame < ghlInfo - > aHeader - > numFrames , " setframe>=numframes " ) ;
G2ERROR ( setFrame = = - 1.0f | | setFrame > = 0.0f , " setframe<0 but not -1 " ) ;
if ( startFrame < 0 | | startFrame > = ghlInfo - > aHeader - > numFrames )
{
* ( int * ) & startFrame = 0 ; // cast away const
}
if ( endFrame < = 0 | | endFrame > ghlInfo - > aHeader - > numFrames )
{
* ( int * ) & endFrame = 1 ;
}
if ( setFrame ! = - 1.0f & & ( setFrame < 0.0f | | setFrame > = ( float ) ghlInfo - > aHeader - > numFrames ) )
{
* ( float * ) & setFrame = 0.0f ;
}
ghlInfo - > mSkelFrameNum = 0 ;
G2ERROR ( index > = 0 & & index < ( int ) ghlInfo - > mBlist . size ( ) , va ( " Out of Range Bone Index (%s) " , ghlInfo - > mFileName ) ) ;
if ( index > = 0 & & index < ( int ) ghlInfo - > mBlist . size ( ) )
{
G2ERROR ( ghlInfo - > mBlist [ index ] . boneNumber > = 0 , va ( " Bone Index is not Active (%s) " , ghlInfo - > mFileName ) ) ;
int currentTime = G2API_GetTime ( AcurrentTime ) ;
#if 0
/*
if ( ge - > ValidateAnimRange ( startFrame , endFrame , animSpeed ) = = - 1 )
{
int wtf = 1 ;
}
*/
# endif
ret = G2_Set_Bone_Anim_Index ( ghlInfo - > mBlist , index , startFrame , endFrame , flags , animSpeed , currentTime , setFrame , blendTime , ghlInfo - > aHeader - > numFrames ) ;
G2ANIM ( ghlInfo , " G2API_SetBoneAnimIndex " ) ;
}
}
G2WARNING ( ret , va ( " G2API_SetBoneAnimIndex Failed (%s) " , ghlInfo - > mFileName ) ) ;
return ret ;
}
qboolean G2API_SetBoneAnim ( CGhoul2Info * ghlInfo , const char * boneName , const int startFrame , const int endFrame , const int flags , const float animSpeed , const int AcurrentTime , const float setFrame , const int blendTime )
{
//rww - RAGDOLL_BEGIN
if ( ghlInfo & & ghlInfo - > mFlags & GHOUL2_RAG_STARTED )
{
return qfalse ;
}
//rww - RAGDOLL_END
qboolean ret = qfalse ;
G2ERROR ( boneName , " NULL boneName " ) ;
if ( boneName & & G2_SetupModelPointers ( ghlInfo ) )
{
G2ERROR ( startFrame > = 0 , " startframe<0 " ) ;
G2ERROR ( startFrame < ghlInfo - > aHeader - > numFrames , " startframe>=numframes " ) ;
G2ERROR ( endFrame > 0 , " endframe<=0 " ) ;
G2ERROR ( endFrame < = ghlInfo - > aHeader - > numFrames , " endframe>numframes " ) ;
G2ERROR ( setFrame < ghlInfo - > aHeader - > numFrames , " setframe>=numframes " ) ;
G2ERROR ( setFrame = = - 1.0f | | setFrame > = 0.0f , " setframe<0 but not -1 " ) ;
if ( startFrame < 0 | | startFrame > = ghlInfo - > aHeader - > numFrames )
{
* ( int * ) & startFrame = 0 ; // cast away const
}
if ( endFrame < = 0 | | endFrame > ghlInfo - > aHeader - > numFrames )
{
* ( int * ) & endFrame = 1 ;
}
if ( setFrame ! = - 1.0f & & ( setFrame < 0.0f | | setFrame > = ( float ) ghlInfo - > aHeader - > numFrames ) )
{
* ( float * ) & setFrame = 0.0f ;
}
ghlInfo - > mSkelFrameNum = 0 ;
int currentTime = G2API_GetTime ( AcurrentTime ) ;
ret = G2_Set_Bone_Anim ( ghlInfo , ghlInfo - > mBlist , boneName , startFrame , endFrame , flags , animSpeed , currentTime , setFrame , blendTime ) ;
G2ANIM ( ghlInfo , " G2API_SetBoneAnim " ) ;
}
G2WARNING ( ret , " G2API_SetBoneAnim Failed " ) ;
return ret ;
}
qboolean G2API_GetBoneAnim ( CGhoul2Info * ghlInfo , const char * boneName , const int AcurrentTime , float * currentFrame ,
int * startFrame , int * endFrame , int * flags , float * animSpeed , int * )
{
qboolean ret = qfalse ;
G2ERROR ( boneName , " NULL boneName " ) ;
if ( G2_SetupModelPointers ( ghlInfo ) )
{
int currentTime = G2API_GetTime ( AcurrentTime ) ;
ret = G2_Get_Bone_Anim ( ghlInfo , ghlInfo - > mBlist , boneName , currentTime , currentFrame ,
startFrame , endFrame , flags , animSpeed ) ;
}
G2WARNING ( ret , " G2API_GetBoneAnim Failed " ) ;
return ret ;
}
qboolean G2API_GetBoneAnimIndex ( CGhoul2Info * ghlInfo , const int iBoneIndex , const int AcurrentTime , float * currentFrame ,
int * startFrame , int * endFrame , int * flags , float * animSpeed , int * )
{
qboolean ret = qfalse ;
if ( G2_SetupModelPointers ( ghlInfo ) )
{
int currentTime = G2API_GetTime ( AcurrentTime ) ;
G2NOTE ( iBoneIndex > = 0 & & iBoneIndex < ( int ) ghlInfo - > mBlist . size ( ) , va ( " Bad Bone Index (%d:%s) " , iBoneIndex , ghlInfo - > mFileName ) ) ;
if ( iBoneIndex > = 0 & & iBoneIndex < ( int ) ghlInfo - > mBlist . size ( ) )
{
G2NOTE ( ghlInfo - > mBlist [ iBoneIndex ] . flags & ( BONE_ANIM_OVERRIDE_LOOP | BONE_ANIM_OVERRIDE ) , " GetBoneAnim on non-animating bone. " ) ;
if ( ( ghlInfo - > mBlist [ iBoneIndex ] . flags & ( BONE_ANIM_OVERRIDE_LOOP | BONE_ANIM_OVERRIDE ) ) )
{
int sf , ef ;
ret = G2_Get_Bone_Anim_Index ( ghlInfo - > mBlist , // boneInfo_v &blist,
iBoneIndex , // const int index,
currentTime , // const int currentTime,
currentFrame , // float *currentFrame,
& sf , // int *startFrame,
& ef , // int *endFrame,
flags , // int *flags,
animSpeed , // float *retAnimSpeed,
ghlInfo - > aHeader - > numFrames
) ;
G2ERROR ( sf > = 0 , " returning startframe<0 " ) ;
G2ERROR ( sf < ghlInfo - > aHeader - > numFrames , " returning startframe>=numframes " ) ;
G2ERROR ( ef > 0 , " returning endframe<=0 " ) ;
G2ERROR ( ef < = ghlInfo - > aHeader - > numFrames , " returning endframe>numframes " ) ;
if ( currentFrame )
{
G2ERROR ( * currentFrame > = 0.0f , " returning currentframe<0 " ) ;
G2ERROR ( ( ( int ) ( * currentFrame ) ) < ghlInfo - > aHeader - > numFrames , " returning currentframe>=numframes " ) ;
}
if ( endFrame )
{
* endFrame = ef ;
}
if ( startFrame )
{
* startFrame = sf ;
}
G2ANIM ( ghlInfo , " G2API_GetBoneAnimIndex " ) ;
}
}
}
if ( ! ret )
{
* endFrame = 1 ;
* startFrame = 0 ;
* flags = 0 ;
* currentFrame = 0.0f ;
* animSpeed = 1.0f ;
}
G2NOTE ( ret , " G2API_GetBoneAnimIndex Failed " ) ;
return ret ;
}
qboolean G2API_GetAnimRange ( CGhoul2Info * ghlInfo , const char * boneName , int * startFrame , int * endFrame )
{
qboolean ret = qfalse ;
G2ERROR ( boneName , " NULL boneName " ) ;
if ( boneName & & G2_SetupModelPointers ( ghlInfo ) )
{
ret = G2_Get_Bone_Anim_Range ( ghlInfo , ghlInfo - > mBlist , boneName , startFrame , endFrame ) ;
G2ANIM ( ghlInfo , " G2API_GetAnimRange " ) ;
}
// looks like the game checks the return value
// G2WARNING(ret,"G2API_GetAnimRange Failed");
return ret ;
}
qboolean G2API_GetAnimRangeIndex ( CGhoul2Info * ghlInfo , const int boneIndex , int * startFrame , int * endFrame )
{
qboolean ret = qfalse ;
if ( G2_SetupModelPointers ( ghlInfo ) )
{
G2ERROR ( boneIndex > = 0 & & boneIndex < ( int ) ghlInfo - > mBlist . size ( ) , " Bad Bone Index " ) ;
if ( boneIndex > = 0 & & boneIndex < ( int ) ghlInfo - > mBlist . size ( ) )
{
ret = G2_Get_Bone_Anim_Range_Index ( ghlInfo - > mBlist , boneIndex , startFrame , endFrame ) ;
G2ANIM ( ghlInfo , " G2API_GetAnimRange " ) ;
}
}
// looks like the game checks the return value
// G2WARNING(ret,"G2API_GetAnimRangeIndex Failed");
return ret ;
}
qboolean G2API_PauseBoneAnim ( CGhoul2Info * ghlInfo , const char * boneName , const int AcurrentTime )
{
qboolean ret = qfalse ;
G2ERROR ( boneName , " NULL boneName " ) ;
if ( boneName & & G2_SetupModelPointers ( ghlInfo ) )
{
int currentTime = G2API_GetTime ( AcurrentTime ) ;
ret = G2_Pause_Bone_Anim ( ghlInfo , ghlInfo - > mBlist , boneName , currentTime ) ;
G2ANIM ( ghlInfo , " G2API_PauseBoneAnim " ) ;
}
G2NOTE ( ret , " G2API_PauseBoneAnim Failed " ) ;
return ret ;
}
qboolean G2API_PauseBoneAnimIndex ( CGhoul2Info * ghlInfo , const int boneIndex , const int AcurrentTime )
{
qboolean ret = qfalse ;
if ( G2_SetupModelPointers ( ghlInfo ) )
{
int currentTime = G2API_GetTime ( AcurrentTime ) ;
G2ERROR ( boneIndex > = 0 & & boneIndex < ( int ) ghlInfo - > mBlist . size ( ) , " Bad Bone Index " ) ;
if ( boneIndex > = 0 & & boneIndex < ( int ) ghlInfo - > mBlist . size ( ) )
{
ret = G2_Pause_Bone_Anim_Index ( ghlInfo - > mBlist , boneIndex , currentTime , ghlInfo - > aHeader - > numFrames ) ;
G2ANIM ( ghlInfo , " G2API_PauseBoneAnimIndex " ) ;
}
}
G2WARNING ( ret , " G2API_PauseBoneAnimIndex Failed " ) ;
return ret ;
}
qboolean G2API_IsPaused ( CGhoul2Info * ghlInfo , const char * boneName )
{
qboolean ret = qfalse ;
G2ERROR ( boneName , " NULL boneName " ) ;
if ( boneName & & G2_SetupModelPointers ( ghlInfo ) )
{
ret = G2_IsPaused ( ghlInfo , ghlInfo - > mBlist , boneName ) ;
}
G2WARNING ( ret , " G2API_IsPaused Failed " ) ;
return ret ;
}
qboolean G2API_StopBoneAnimIndex ( CGhoul2Info * ghlInfo , const int index )
{
qboolean ret = qfalse ;
G2ERROR ( ghlInfo , " NULL ghlInfo " ) ;
if ( G2_SetupModelPointers ( ghlInfo ) )
{
G2ERROR ( index > = 0 & & index < ( int ) ghlInfo - > mBlist . size ( ) , " Bad Bone Index " ) ;
if ( index > = 0 & & index < ( int ) ghlInfo - > mBlist . size ( ) )
{
ret = G2_Stop_Bone_Anim_Index ( ghlInfo - > mBlist , index ) ;
G2ANIM ( ghlInfo , " G2API_StopBoneAnimIndex " ) ;
}
}
//G2WARNING(ret,"G2API_StopBoneAnimIndex Failed");
return ret ;
}
qboolean G2API_StopBoneAnim ( CGhoul2Info * ghlInfo , const char * boneName )
{
qboolean ret = qfalse ;
G2ERROR ( boneName , " NULL boneName " ) ;
if ( boneName & & G2_SetupModelPointers ( ghlInfo ) )
{
ret = G2_Stop_Bone_Anim ( ghlInfo , ghlInfo - > mBlist , boneName ) ;
G2ANIM ( ghlInfo , " G2API_StopBoneAnim " ) ;
}
G2WARNING ( ret , " G2API_StopBoneAnim Failed " ) ;
return ret ;
}
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 * , int blendTime , int AcurrentTime )
{
//rww - RAGDOLL_BEGIN
if ( ghlInfo & & ghlInfo - > mFlags & GHOUL2_RAG_STARTED )
{
return qfalse ;
}
//rww - RAGDOLL_END
qboolean ret = qfalse ;
if ( G2_SetupModelPointers ( ghlInfo ) )
{
int currentTime = G2API_GetTime ( AcurrentTime ) ;
// ensure we flush the cache
ghlInfo - > mSkelFrameNum = 0 ;
G2ERROR ( index > = 0 & & index < ( int ) ghlInfo - > mBlist . size ( ) , " G2API_SetBoneAnglesIndex:Invalid bone index " ) ;
if ( index > = 0 & & index < ( int ) ghlInfo - > mBlist . size ( ) )
{
ret = G2_Set_Bone_Angles_Index ( ghlInfo , ghlInfo - > mBlist , index , angles , flags , yaw , pitch , roll , blendTime , currentTime ) ;
}
}
G2WARNING ( ret , " G2API_SetBoneAnglesIndex Failed " ) ;
return ret ;
}
qboolean G2API_SetBoneAngles ( CGhoul2Info * ghlInfo , const char * boneName , const vec3_t angles , const int flags ,
const Eorientations up , const Eorientations left , const Eorientations forward ,
qhandle_t * , int blendTime , int AcurrentTime )
{
//rww - RAGDOLL_BEGIN
if ( ghlInfo & & ghlInfo - > mFlags & GHOUL2_RAG_STARTED )
{
return qfalse ;
}
//rww - RAGDOLL_END
qboolean ret = qfalse ;
G2ERROR ( boneName , " NULL boneName " ) ;
if ( boneName & & G2_SetupModelPointers ( ghlInfo ) )
{
int currentTime = G2API_GetTime ( AcurrentTime ) ;
// ensure we flush the cache
ghlInfo - > mSkelFrameNum = 0 ;
ret = G2_Set_Bone_Angles ( ghlInfo , ghlInfo - > mBlist , boneName , angles , flags , up , left , forward , blendTime , currentTime ) ;
}
G2WARNING ( ret , " G2API_SetBoneAngles Failed " ) ;
return ret ;
}
qboolean G2API_SetBoneAnglesMatrixIndex ( CGhoul2Info * ghlInfo , const int index , const mdxaBone_t & matrix ,
const int flags , qhandle_t * , int blendTime , int AcurrentTime )
{
qboolean ret = qfalse ;
if ( G2_SetupModelPointers ( ghlInfo ) )
{
int currentTime = G2API_GetTime ( AcurrentTime ) ;
// ensure we flush the cache
ghlInfo - > mSkelFrameNum = 0 ;
G2ERROR ( index > = 0 & & index < ( int ) ghlInfo - > mBlist . size ( ) , " Bad Bone Index " ) ;
if ( index > = 0 & & index < ( int ) ghlInfo - > mBlist . size ( ) )
{
ret = G2_Set_Bone_Angles_Matrix_Index ( ghlInfo - > mBlist , index , matrix , flags , blendTime , currentTime ) ;
}
}
G2WARNING ( ret , " G2API_SetBoneAnglesMatrixIndex Failed " ) ;
return ret ;
}
qboolean G2API_SetBoneAnglesMatrix ( CGhoul2Info * ghlInfo , const char * boneName , const mdxaBone_t & matrix ,
const int flags , qhandle_t * modelList , int blendTime , int AcurrentTime )
{
qboolean ret = qfalse ;
G2ERROR ( boneName , " NULL boneName " ) ;
if ( boneName & & G2_SetupModelPointers ( ghlInfo ) )
{
int currentTime = G2API_GetTime ( AcurrentTime ) ;
// ensure we flush the cache
ghlInfo - > mSkelFrameNum = 0 ;
ret = G2_Set_Bone_Angles_Matrix ( ghlInfo , ghlInfo - > mBlist , boneName , matrix , flags , blendTime , currentTime ) ;
}
G2WARNING ( ret , " G2API_SetBoneAnglesMatrix Failed " ) ;
return ret ;
}
qboolean G2API_StopBoneAnglesIndex ( CGhoul2Info * ghlInfo , const int index )
{
qboolean ret = qfalse ;
if ( G2_SetupModelPointers ( ghlInfo ) )
{
// ensure we flush the cache
ghlInfo - > mSkelFrameNum = 0 ;
G2ERROR ( index > = 0 & & index < ( int ) ghlInfo - > mBlist . size ( ) , " Bad Bone Index " ) ;
if ( index > = 0 & & index < ( int ) ghlInfo - > mBlist . size ( ) )
{
ret = G2_Stop_Bone_Angles_Index ( ghlInfo - > mBlist , index ) ;
}
}
G2WARNING ( ret , " G2API_StopBoneAnglesIndex Failed " ) ;
return ret ;
}
qboolean G2API_StopBoneAngles ( CGhoul2Info * ghlInfo , const char * boneName )
{
qboolean ret = qfalse ;
G2ERROR ( boneName , " NULL boneName " ) ;
if ( boneName & & G2_SetupModelPointers ( ghlInfo ) )
{
// ensure we flush the cache
ghlInfo - > mSkelFrameNum = 0 ;
ret = G2_Stop_Bone_Angles ( ghlInfo , ghlInfo - > mBlist , boneName ) ;
}
G2WARNING ( ret , " G2API_StopBoneAngles Failed " ) ;
return ret ;
}
//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 ) ;
}
//rww - RAGDOLL_END
qboolean G2API_RemoveBone ( CGhoul2Info * ghlInfo , const char * boneName )
{
qboolean ret = qfalse ;
G2ERROR ( boneName , " NULL boneName " ) ;
if ( boneName & & G2_SetupModelPointers ( ghlInfo ) )
{
// ensure we flush the cache
ghlInfo - > mSkelFrameNum = 0 ;
ret = G2_Remove_Bone ( ghlInfo , ghlInfo - > mBlist , boneName ) ;
G2ANIM ( ghlInfo , " G2API_RemoveBone " ) ;
}
G2WARNING ( ret , " G2API_RemoveBone Failed " ) ;
return ret ;
}
//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
// Com_Printf("Rag trace time: %i (%i STARTSOLID, %i TOTAL)\n", ragTraceTime, ragSSCount, ragTraceCount);
// assert(ragTraceTime < 15);
//assert(ragTraceCount < 600);
# 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 )
{
qboolean ret = qfalse ;
if ( G2_SetupModelPointers ( ghlInfo ) )
{
ret = G2_Remove_Bolt ( ghlInfo - > mBltlist , index ) ;
}
G2WARNING ( ret , " G2API_RemoveBolt Failed " ) ;
return ret ;
}
int G2API_AddBolt ( CGhoul2Info * ghlInfo , const char * boneName )
{
int ret = - 1 ;
G2ERROR ( boneName , " NULL boneName " ) ;
if ( boneName & & G2_SetupModelPointers ( ghlInfo ) )
{
ret = G2_Add_Bolt ( ghlInfo , ghlInfo - > mBltlist , ghlInfo - > mSlist , boneName ) ;
G2NOTE ( ret > = 0 , va ( " G2API_AddBolt Failed (%s:%s) " , boneName , ghlInfo - > mFileName ) ) ;
}
return ret ;
}
int G2API_AddBoltSurfNum ( CGhoul2Info * ghlInfo , const int surfIndex )
{
int ret = - 1 ;
if ( G2_SetupModelPointers ( ghlInfo ) )
{
ret = G2_Add_Bolt_Surf_Num ( ghlInfo , ghlInfo - > mBltlist , ghlInfo - > mSlist , surfIndex ) ;
}
G2WARNING ( ret > = 0 , " G2API_AddBoltSurfNum Failed " ) ;
return ret ;
}
qboolean G2API_AttachG2Model ( CGhoul2Info * ghlInfo , CGhoul2Info * ghlInfoTo , int toBoltIndex , int toModel )
{
qboolean ret = qfalse ;
if ( G2_SetupModelPointers ( ghlInfo ) & & G2_SetupModelPointers ( ghlInfoTo ) )
{
G2ERROR ( toBoltIndex > = 0 & & toBoltIndex < ( int ) ghlInfoTo - > mBltlist . size ( ) , " Invalid Bolt Index " ) ;
G2ERROR ( ghlInfoTo - > mBltlist . size ( ) > 0 , " Empty Bolt List " ) ;
assert ( toBoltIndex > = 0 ) ;
if ( toBoltIndex > = 0 & & ghlInfoTo - > mBltlist . size ( ) )
{
// make sure we have a model to attach, a model to attach to, and a bolt on that model
if ( ( ( ghlInfoTo - > mBltlist [ toBoltIndex ] . boneNumber ! = - 1 ) | | ( ghlInfoTo - > mBltlist [ toBoltIndex ] . surfaceNumber ! = - 1 ) ) )
{
// encode the bolt address into the model bolt link
toModel & = MODEL_AND ;
toBoltIndex & = BOLT_AND ;
ghlInfo - > mModelBoltLink = ( toModel < < MODEL_SHIFT ) | ( toBoltIndex < < BOLT_SHIFT ) ;
ret = qtrue ;
}
}
}
G2WARNING ( ret , " G2API_AttachG2Model Failed " ) ;
return ret ;
}
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 )
{
qboolean ret = qfalse ;
G2ERROR ( boltInfo , " NULL boltInfo " ) ;
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 ) ;
ret = qtrue ;
}
}
G2WARNING ( ret , " G2API_AttachEnt Failed " ) ;
return ret ;
}
void G2API_DetachEnt ( int * boltInfo )
{
G2ERROR ( boltInfo , " NULL boltInfo " ) ;
if ( boltInfo )
{
* boltInfo = 0 ;
}
}
bool G2_NeedsRecalc ( CGhoul2Info * ghlInfo , int frameNum ) ;
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 )
{
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 frameNum = G2API_GetTime ( AframeNum ) ;
CGhoul2Info * ghlInfo = & ghoul2 [ modelIndex ] ;
G2ERROR ( boltIndex > = 0 & & ( boltIndex < ( int ) ghlInfo - > mBltlist . size ( ) ) , va ( " Invalid Bolt Index (%d:%s) " , boltIndex , ghlInfo - > mFileName ) ) ;
if ( boltIndex > = 0 & & ghlInfo & & ( boltIndex < ( int ) ghlInfo - > mBltlist . size ( ) ) )
{
mdxaBone_t bolt ;
if ( G2_NeedsRecalc ( ghlInfo , frameNum ) )
{
G2_ConstructGhoulSkeleton ( ghoul2 , frameNum , true , scale ) ;
}
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 ( ! Q_isnan ( matrix - > matrix [ i ] [ j ] ) ) ;
}
}
# endif // _DEBUG
G2ANIM ( ghlInfo , " G2API_GetBoltMatrix " ) ;
return qtrue ;
}
}
}
else
{
G2WARNING ( 0 , " G2API_GetBoltMatrix Failed on empty or bad model " ) ;
}
Multiply_3x4Matrix ( matrix , & worldMatrix , & 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 )
{
return ( qboolean ) ghoul2 . IsValid ( ) ;
}
// 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 )
{
G2ERROR ( ghoul2 . IsValid ( ) , " Invalid ghlInfo " ) ;
int i ;
for ( i = 0 ; i < ghoul2 . size ( ) ; i + + )
{
if ( ghoul2 [ i ] . mModelindex ! = - 1 )
{
ghoul2 [ i ] . mSkin = skinList [ ghoul2 [ i ] . mCustomSkin ] ;
}
}
}
char * G2API_GetAnimFileNameIndex ( qhandle_t modelIndex )
{
model_t * mod_m = R_GetModelByHandle ( modelIndex ) ;
G2ERROR ( mod_m & & mod_m - > mdxm , " Bad Model " ) ;
if ( mod_m & & mod_m - > mdxm )
{
return mod_m - > mdxm - > animName ;
}
return " " ;
}
// as above, but gets the internal embedded name, not the name of the disk file.
// This is needed for some unfortunate jiggery-hackery to do with frameskipping & the animevents.cfg file
//
char * G2API_GetAnimFileInternalNameIndex ( qhandle_t modelIndex )
{
model_t * mod_a = R_GetModelByHandle ( modelIndex ) ;
G2ERROR ( mod_a & & mod_a - > mdxa , " Bad Model " ) ;
if ( mod_a & & mod_a - > mdxa )
{
return mod_a - > mdxa - > name ;
}
return " " ;
}
/************************************************************************************************
* 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 )
{
qboolean ret = qfalse ;
if ( G2_SetupModelPointers ( ghlInfo ) )
{
ret = G2_GetAnimFileName ( ghlInfo - > mFileName , filename ) ;
}
G2WARNING ( ret , " G2API_GetAnimFileName Failed " ) ;
return ret ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = =
SV_QsortEntityNumbers
= = = = = = = = = = = = = = = = = = = = = = =
*/
static int QDECL QsortDistance ( const void * a , const void * b ) {
const float & ea = ( ( CCollisionRecord * ) a ) - > mDistance ;
const float & eb = ( ( CCollisionRecord * ) b ) - > mDistance ;
if ( ea < eb ) {
return - 1 ;
}
return 1 ;
}
void G2API_CollisionDetect ( CCollisionRecord * collRecMap , CGhoul2Info_v & ghoul2 , const vec3_t angles , const vec3_t position ,
int AframeNumber , int entNum , vec3_t rayStart , vec3_t rayEnd , vec3_t scale , CMiniHeap * ,
EG2_Collision eG2TraceType , int useLod , float fRadius )
{
G2ERROR ( ghoul2 . IsValid ( ) , " Invalid ghlInfo " ) ;
G2ERROR ( collRecMap , " NULL Collision Rec " ) ;
if ( G2_SetupModelPointers ( ghoul2 ) & & collRecMap )
{
int frameNumber = G2API_GetTime ( AframeNumber ) ;
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 ) ;
ri . GetG2VertSpaceServer ( ) - > ResetHeap ( ) ;
// now having done that, time to build the model
# ifdef _G2_GORE
G2_TransformModel ( ghoul2 , frameNumber , scale , ri . GetG2VertSpaceServer ( ) , useLod , false ) ;
# else
G2_TransformModel ( ghoul2 , frameNumber , scale , ri . GetG2VertSpaceServer ( ) , 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 , eG2TraceType , useLod , fRadius , 0 , 0 , 0 , 0 , 0 , qfalse ) ;
# else
G2_TraceModels ( ghoul2 , transRayStart , transRayEnd , collRecMap , entNum , eG2TraceType , useLod , fRadius ) ;
# endif
ri . GetG2VertSpaceServer ( ) - > ResetHeap ( ) ;
// now sort the resulting array of collision records so they are distance ordered
qsort ( collRecMap , MAX_G2_COLLISIONS ,
sizeof ( CCollisionRecord ) , QsortDistance ) ;
G2ANIM ( ghoul2 , " G2API_CollisionDetect " ) ;
}
}
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 ;
}
}
// copy a model from one ghoul2 instance to another, and reset the root surface on the new model if need be
// NOTE if modelIndex = -1 then copy all the models
void G2API_CopyGhoul2Instance ( CGhoul2Info_v & ghoul2From , CGhoul2Info_v & ghoul2To , int modelIndex )
{
//Ensiform: I'm commenting this out because modelIndex appears unused and legitimately set in gamecode
//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 ( ghoul2From . IsValid ( ) )
{
ghoul2To . DeepCopy ( ghoul2From ) ;
# ifdef _G2_GORE //check through gore stuff then, as well.
int model = 0 ;
//(since we are sharing this gore set with the copied instance we will have to increment
//the reference count - if the goreset is "removed" while the refcount is > 0, the refcount
//is decremented to avoid giving other instances an invalid pointer -rww)
while ( model < ghoul2To . size ( ) )
{
if ( ghoul2To [ model ] . mGoreSetTag )
{
CGoreSet * gore = FindGoreSet ( ghoul2To [ model ] . mGoreSetTag ) ;
assert ( gore ) ;
if ( gore )
{
gore - > mRefCount + + ;
}
}
model + + ;
}
# endif
G2ANIM ( ghoul2From , " G2API_CopyGhoul2Instance (source) " ) ;
G2ANIM ( ghoul2To , " G2API_CopyGhoul2Instance (dest) " ) ;
}
}
char * G2API_GetSurfaceName ( CGhoul2Info * ghlInfo , int surfNumber )
{
static char noSurface [ 1 ] = " " ;
if ( G2_SetupModelPointers ( ghlInfo ) )
{
mdxmSurface_t * surf = 0 ;
mdxmSurfHierarchy_t * surfInfo = 0 ;
surf = ( mdxmSurface_t * ) G2_FindSurface ( ghlInfo - > currentModel , surfNumber , 0 ) ;
if ( surf )
{
assert ( G2_MODEL_OK ( ghlInfo ) ) ;
mdxmHierarchyOffsets_t * surfIndexes = ( mdxmHierarchyOffsets_t * ) ( ( byte * ) ghlInfo - > currentModel - > mdxm + sizeof ( mdxmHeader_t ) ) ;
surfInfo = ( mdxmSurfHierarchy_t * ) ( ( byte * ) surfIndexes + surfIndexes - > offsets [ surf - > thisSurfaceIndex ] ) ;
return surfInfo - > name ;
}
}
G2WARNING ( 0 , " Surface Not Found " ) ;
return noSurface ;
}
int G2API_GetSurfaceIndex ( CGhoul2Info * ghlInfo , const char * surfaceName )
{
int ret = - 1 ;
G2ERROR ( surfaceName , " NULL surfaceName " ) ;
if ( surfaceName & & G2_SetupModelPointers ( ghlInfo ) )
{
ret = G2_GetSurfaceIndex ( ghlInfo , surfaceName ) ;
}
G2WARNING ( ret > = 0 , " G2API_GetSurfaceIndex Failed " ) ;
return ret ;
}
char * G2API_GetGLAName ( CGhoul2Info * ghlInfo )
{
if ( G2_SetupModelPointers ( ghlInfo ) )
{
assert ( G2_MODEL_OK ( ghlInfo ) ) ;
return ( char * ) ghlInfo - > aHeader - > name ;
//return ghlInfo->currentModel->mdxm->animName;
}
return 0 ;
}
qboolean G2API_SetNewOrigin ( CGhoul2Info * ghlInfo , const int boltIndex )
{
if ( G2_SetupModelPointers ( ghlInfo ) )
{
G2ERROR ( boltIndex > = 0 & & boltIndex < ( int ) ghlInfo - > mBltlist . size ( ) , " invalid boltIndex " ) ;
if ( boltIndex > = 0 & & boltIndex < ( int ) ghlInfo - > mBltlist . size ( ) )
{
ghlInfo - > mNewOrigin = boltIndex ;
ghlInfo - > mFlags | = GHOUL2_NEWORIGIN ;
}
return qtrue ;
}
return qfalse ;
}
int G2API_GetBoneIndex ( CGhoul2Info * ghlInfo , const char * boneName , qboolean bAddIfNotFound )
{
int ret = - 1 ;
G2ERROR ( boneName , " NULL boneName " ) ;
if ( boneName & & G2_SetupModelPointers ( ghlInfo ) )
{
ret = G2_Get_Bone_Index ( ghlInfo , boneName , bAddIfNotFound ) ;
G2ANIM ( ghlInfo , " G2API_GetBoneIndex " ) ;
}
G2NOTE ( ret > = 0 , " G2API_GetBoneIndex Failed " ) ;
return ret ;
}
void G2API_SaveGhoul2Models ( CGhoul2Info_v & ghoul2 )
{
G2ANIM ( ghoul2 , " G2API_SaveGhoul2Models " ) ;
G2_SaveGhoul2Models ( ghoul2 ) ;
}
void G2API_LoadGhoul2Models ( CGhoul2Info_v & ghoul2 , char * buffer )
{
G2_LoadGhoul2Model ( ghoul2 , buffer ) ;
G2ANIM ( ghoul2 , " G2API_LoadGhoul2Models " ) ;
// G2ERROR(ghoul2.IsValid(),"Invalid ghlInfo after load");
}
// 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 )
{
ghoul2 . ~ CGhoul2Info_v ( ) ; // so I can load junk over it then memset to 0 without orphaning
}
# ifdef _G2_GORE
void ResetGoreTag ( ) ; // put here to reduce coupling
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 ;
}
}
}
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 ) ;
if ( ! gore . useTheta )
{
vec3_t t ;
VectorCopy ( gore . uaxis , t ) ;
TransformPoint ( t , gore . uaxis , & worldMatrixInv ) ;
}
int lod ;
ResetGoreTag ( ) ;
2023-08-08 19:29:41 +00:00
const int lodbias = Com_Clamp ( 0 , 2 , G2_DecideTraceLod ( ghoul2 [ 0 ] , r_lodbias - > integer ) ) ;
2022-09-18 15:37:21 +00:00
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
ri . GetG2VertSpaceServer ( ) - > ResetHeap ( ) ;
G2_TransformModel ( ghoul2 , gore . currentTime , gore . scale , ri . GetG2VertSpaceServer ( ) , lod , true , & gore ) ;
// now walk each model and compute new texture coordinates
G2_TraceModels ( ghoul2 , transHitLocation , transRayDirection , 0 , gore . entNum , G2_NOCOLLIDE , lod , 1.0f , gore . SSize , gore . TSize , gore . theta , gore . shader , & gore , qtrue ) ;
}
}
# else
void G2API_ClearSkinGore ( CGhoul2Info_v & ghoul2 )
{
}
void G2API_AddSkinGore ( CGhoul2Info_v & ghoul2 , SSkinGoreData & gore )
{
}
# endif
bool G2_TestModelPointers ( CGhoul2Info * ghlInfo ) // returns true if the model is properly set up
{
G2ERROR ( ghlInfo , " NULL ghlInfo " ) ;
if ( ! ghlInfo )
{
return false ;
}
ghlInfo - > mValid = false ;
if ( ghlInfo - > mModelindex ! = - 1 )
{
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 + ghlInfo - > animModelIndexOffset ) ;
if ( ghlInfo - > animModel )
{
ghlInfo - > aHeader = ghlInfo - > animModel - > mdxa ;
G2ERROR ( ghlInfo - > aHeader , va ( " Model has no mdxa (gla) %s " , ghlInfo - > mFileName ) ) ;
if ( ! ghlInfo - > aHeader )
{
Com_Error ( ERR_DROP , " Ghoul2 Model has no mdxa (gla) %s " , ghlInfo - > mFileName ) ;
}
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 ghlInfo - > mValid ;
}
bool G2_SetupModelPointers ( CGhoul2Info * ghlInfo ) // returns true if the model is properly set up
{
G2ERROR ( ghlInfo , " NULL ghlInfo " ) ;
if ( ! ghlInfo )
{
return false ;
}
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 " ) ;
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 + ghlInfo - > animModelIndexOffset ) ;
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 )
{
Com_Error ( ERR_DROP , " Ghoul2 Model has no mdxa (gla) %s " , ghlInfo - > mFileName ) ;
}
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 ;
}
return ghlInfo - > mValid ;
}
bool 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 + + )
{
bool r = G2_SetupModelPointers ( & ghoul2 [ i ] ) ;
ret = ret | | r ;
}
return ret ;
}