mirror of
https://github.com/openmoh/openmohaa.git
synced 2025-04-28 21:57:57 +03:00
1030 lines
24 KiB
C++
1030 lines
24 KiB
C++
/*
|
|
===========================================================================
|
|
Copyright (C) 2015 the OpenMoHAA team
|
|
|
|
This file is part of OpenMoHAA source code.
|
|
|
|
OpenMoHAA source code is free software; you can redistribute it
|
|
and/or modify it under the terms of the GNU General Public License as
|
|
published by the Free Software Foundation; either version 2 of the License,
|
|
or (at your option) any later version.
|
|
|
|
OpenMoHAA source code is distributed in the hope that it will be
|
|
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with OpenMoHAA source code; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
===========================================================================
|
|
*/
|
|
|
|
// tiki_files.cpp : TIKI File Loader
|
|
|
|
#include "q_shared.h"
|
|
#include "qcommon.h"
|
|
#include "../skeletor/skeletor.h"
|
|
#include "../skeletor/tokenizer.h"
|
|
#include "../client/client.h"
|
|
#include <tiki.h>
|
|
#include <mem_tempalloc.h>
|
|
|
|
qboolean tiki_loading;
|
|
cvar_t *dumploadedanims;
|
|
cvar_t *low_anim_memory;
|
|
cvar_t *showLoad;
|
|
cvar_t *convertAnims;
|
|
|
|
typedef struct {
|
|
char path[ 100 ];
|
|
skelAnimDataGameHeader_t *data;
|
|
int numusers;
|
|
int lookup;
|
|
} skeletorCacheEntry_t;
|
|
|
|
static int m_numInCache;
|
|
class InitSkelCache {
|
|
public:
|
|
static class InitSkelCache init;
|
|
|
|
InitSkelCache();
|
|
};
|
|
|
|
static int m_cachedDataLookup[ 4095 ];
|
|
static skeletorCacheEntry_t m_cachedData[ 4095 ];
|
|
InitSkelCache InitSkelCache::init;
|
|
MEM_TempAlloc TIKI_allocator;
|
|
dloaddef_t loaddef;
|
|
|
|
/*
|
|
===============
|
|
InitSkelCache::InitSkelCache
|
|
===============
|
|
*/
|
|
InitSkelCache::InitSkelCache()
|
|
{
|
|
int i;
|
|
|
|
for( i = 0; i < 4095; i++ )
|
|
{
|
|
m_cachedData[ i ].lookup = -1;
|
|
}
|
|
}
|
|
|
|
/*
|
|
===============
|
|
TIKI_FreeStorage
|
|
===============
|
|
*/
|
|
void TIKI_FreeStorage( dloaddef_t *ld )
|
|
{
|
|
TIKI_allocator.FreeAll();
|
|
ld->tikiFile.Close();
|
|
}
|
|
|
|
/*
|
|
===============
|
|
TIKI_AllocateLoadData
|
|
===============
|
|
*/
|
|
void *TIKI_AllocateLoadData( size_t length )
|
|
{
|
|
return TIKI_allocator.Alloc( length );
|
|
}
|
|
|
|
/*
|
|
===============
|
|
TIKI_CopyString
|
|
===============
|
|
*/
|
|
char *TIKI_CopyString( const char *s )
|
|
{
|
|
char *result = ( char * )TIKI_AllocateLoadData( strlen( s ) + 1 );
|
|
strcpy( result, s );
|
|
return result;
|
|
}
|
|
|
|
/*
|
|
===============
|
|
TIKI_LoadTikiAnim
|
|
===============
|
|
*/
|
|
qboolean loadtikicommands = true;
|
|
dtikianim_t *TIKI_LoadTikiAnim( const char *path )
|
|
{
|
|
dtikianim_t *tiki = NULL;
|
|
const char *token;
|
|
float tempVec[ 3 ];
|
|
msg_t modelBuf;
|
|
str s;
|
|
char tempName[ 257 ];
|
|
|
|
memset( &loaddef, 0, sizeof( dloaddef_t ) );
|
|
loaddef.modelBuf = &modelBuf;
|
|
|
|
TIKI_InitSetup( &loaddef );
|
|
|
|
if( loaddef.tikiFile.LoadFile( path, qfalse ) )
|
|
{
|
|
loaddef.path = path;
|
|
|
|
token = loaddef.tikiFile.GetToken( true );
|
|
if( strcmp( token, "TIKI" ) )
|
|
{
|
|
TIKI_Error( "TIKI_LoadTIKIfile: def file %s has wrong header (%s should be TIKI)\n", loaddef.tikiFile.Filename() );
|
|
loaddef.tikiFile.Close();
|
|
return NULL;
|
|
}
|
|
|
|
loaddef.numanims = 0;
|
|
loaddef.numserverinitcmds = 0;
|
|
loaddef.numclientinitcmds = 0;
|
|
loaddef.bInIncludesSection = false;
|
|
|
|
while( loaddef.tikiFile.TokenAvailable( true ) )
|
|
{
|
|
token = loaddef.tikiFile.GetToken( true );
|
|
|
|
if( !stricmp( token, "setup" ) )
|
|
{
|
|
if( !TIKI_ParseSetup( &loaddef ) )
|
|
{
|
|
TIKI_FreeStorage( &loaddef );
|
|
return NULL;
|
|
}
|
|
}
|
|
else if( !stricmp( token, "init" ) )
|
|
{
|
|
TIKI_ParseInit( &loaddef );
|
|
}
|
|
else if( !stricmp( token, "animations" ) )
|
|
{
|
|
TIKI_ParseAnimations( &loaddef );
|
|
}
|
|
else if( !stricmp( token, "includes" ) )
|
|
{
|
|
if( !loaddef.bInIncludesSection )
|
|
{
|
|
loaddef.bInIncludesSection = TIKI_ParseIncludes( &loaddef );
|
|
}
|
|
else
|
|
{
|
|
TIKI_Error( "TIKI_LoadTIKIfile: Nested Includes section in %s on line %d, the animations will be fubar\n",
|
|
token,
|
|
loaddef.tikiFile.GetLineNumber(),
|
|
loaddef.tikiFile.Filename() );
|
|
}
|
|
}
|
|
else if( !stricmp( token, "}" ) && loaddef.bInIncludesSection )
|
|
{
|
|
loaddef.bInIncludesSection = false;
|
|
}
|
|
else
|
|
{
|
|
TIKI_Error( "TIKI_LoadTIKIfile: unknown section %s in %s online %d, skipping line.\n", token, loaddef.tikiFile.Filename(), loaddef.tikiFile.GetLineNumber() );
|
|
|
|
// skip the current line
|
|
while( loaddef.tikiFile.TokenAvailable( false ) ) {
|
|
loaddef.tikiFile.GetToken( false );
|
|
}
|
|
}
|
|
}
|
|
|
|
if( loaddef.bInIncludesSection )
|
|
{
|
|
TIKI_Error( "TIKI_LoadTIKIfile: Include section in %s did not terminate\n", loaddef.tikiFile.Filename() );
|
|
}
|
|
|
|
if( loaddef.numanims )
|
|
{
|
|
sprintf( tempName, "a%s", path );
|
|
UI_LoadResource( tempName );
|
|
|
|
tiki = TIKI_FillTIKIStructureSkel( &loaddef );
|
|
if( tiki )
|
|
{
|
|
sprintf( tempName, "b%s", path );
|
|
UI_LoadResource( tempName );
|
|
sprintf( tempName, "c%s", path );
|
|
UI_LoadResource( tempName );
|
|
|
|
VectorSubtract( tiki->maxs, tiki->mins, tempVec );
|
|
if( VectorLength( tempVec ) > 100000.0f )
|
|
{
|
|
VectorSet( tiki->mins, -4.0f, -4.0f, -4.0f );
|
|
VectorSet( tiki->maxs, 4.0f, 4.0f, 4.0f );
|
|
}
|
|
|
|
TIKI_FreeStorage( &loaddef );
|
|
sprintf( tempName, "d%s", path );
|
|
UI_LoadResource( tempName );
|
|
}
|
|
else
|
|
{
|
|
TIKI_FreeStorage( &loaddef );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TIKI_Error( "TIKI_LoadTIKIfile: No valid animations found in %s.\n", loaddef.tikiFile.Filename() );
|
|
TIKI_FreeStorage( &loaddef );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
loaddef.tikiFile.Close();
|
|
}
|
|
|
|
return tiki;
|
|
}
|
|
|
|
/*
|
|
===============
|
|
TIKI_LoadTikiModel
|
|
===============
|
|
*/
|
|
dtiki_t *TIKI_LoadTikiModel( dtikianim_t *tikianim, const char *name, con_map<str, str> *keyValues )
|
|
{
|
|
dtiki_t *tiki;
|
|
//byte *start_ptr;
|
|
//byte *ptr;
|
|
int i, j, k;
|
|
char *strptr;
|
|
size_t defsize;
|
|
struct {
|
|
dtiki_t tiki;
|
|
short int buffer[ 1000 ];
|
|
} temp;
|
|
//int skel;
|
|
dloadsurface_t loadsurfaces[ 24 ];
|
|
int numSurfacesSetUp;
|
|
dtikisurface_t *tikiSurf;
|
|
dloadsurface_t *loadsurf;
|
|
int mesh;
|
|
skelHeaderGame_t *skelmodel;
|
|
skelSurfaceGame_t *surf;
|
|
int surfOffset;
|
|
qboolean found;
|
|
|
|
TIKI_LoadSetup( &temp.tiki, tikianim->name, loadsurfaces, &numSurfacesSetUp, tikianim->modelData, tikianim->modelDataSize, keyValues );
|
|
if( !temp.tiki.numMeshes )
|
|
{
|
|
Com_Printf( "^~^~^ Model '%s' has no skelmodel\n", tikianim->name );
|
|
return NULL;
|
|
}
|
|
|
|
defsize = sizeof( dtiki_t ) + strlen( name ) + 1 + temp.tiki.num_surfaces * sizeof( dtikisurface_t ) + temp.tiki.numMeshes * sizeof( short );
|
|
tiki = ( dtiki_t * )TIKI_Alloc( defsize );
|
|
memset( tiki, 0, defsize );
|
|
tiki->a = tikianim;
|
|
tiki->m_boneList.InitChannels();
|
|
tiki->skeletor = NULL;
|
|
tiki->load_scale = temp.tiki.load_scale;
|
|
tiki->lod_scale = temp.tiki.lod_scale;
|
|
tiki->lod_bias = temp.tiki.lod_bias;
|
|
tiki->num_surfaces = temp.tiki.num_surfaces;
|
|
tiki->numMeshes = temp.tiki.numMeshes;
|
|
tiki->radius = temp.tiki.radius;
|
|
tiki->name = ( char * )( ( char * )tiki + sizeof( dtiki_t ) + ( temp.tiki.numMeshes - 1 ) * sizeof( short ) );
|
|
strcpy( tiki->name, name );
|
|
tikiSurf = ( dtikisurface_t * )( ( byte * )tiki->name + strlen( tiki->name ) + 1 );
|
|
tiki->m_boneList.ZeroChannels();
|
|
|
|
for( i = 0; i < temp.tiki.numMeshes; i++ )
|
|
{
|
|
mesh = temp.tiki.mesh[ i ];
|
|
tiki->mesh[ i ] = mesh;
|
|
skelmodel = skelcache[ mesh ].skel;
|
|
skelcache[ mesh ].numuses++;
|
|
|
|
for( j = 0; j < skelmodel->numBones; j++ )
|
|
{
|
|
tiki->m_boneList.AddChannel( skelmodel->pBones[ j ].channel );
|
|
}
|
|
}
|
|
|
|
tiki->m_boneList.PackChannels();
|
|
VectorCopy( temp.tiki.light_offset, tiki->light_offset );
|
|
VectorCopy( temp.tiki.load_origin, tiki->load_origin );
|
|
tiki->surfaces = tikiSurf;
|
|
|
|
for( i = 0; i < numSurfacesSetUp; i++ )
|
|
{
|
|
loadsurf = &loadsurfaces[ i ];
|
|
found = false;
|
|
strptr = strchr( loadsurf->name, '*' );
|
|
|
|
surfOffset = 0;
|
|
|
|
if( strptr || !stricmp( loadsurf->name, "all" ) )
|
|
{
|
|
for( j = 0; j < temp.tiki.numMeshes; j++ )
|
|
{
|
|
mesh = temp.tiki.mesh[ j ];
|
|
skelmodel = TIKI_GetSkel( mesh );
|
|
surf = skelmodel->pSurfaces;
|
|
|
|
tikiSurf = &tiki->surfaces[ surfOffset ];
|
|
|
|
for( k = 0; k < skelmodel->numSurfaces; k++ )
|
|
{
|
|
tikiSurf = &tiki->surfaces[ surfOffset ];
|
|
|
|
if( ( strptr
|
|
&& strptr != loadsurf->name
|
|
&& !strnicmp( loadsurf->name, surf->name, strptr - loadsurf->name ) )
|
|
|| !stricmp( loadsurf->name, "all" ) )
|
|
{
|
|
TIKI_SetupIndividualSurface( tikianim->name, tikiSurf, surf->name, loadsurf );
|
|
found = true;
|
|
}
|
|
|
|
surf = surf->pNext;
|
|
tikiSurf++;
|
|
}
|
|
|
|
surfOffset += skelmodel->numSurfaces;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for( j = 0; j < temp.tiki.numMeshes; j++ )
|
|
{
|
|
mesh = temp.tiki.mesh[ j ];
|
|
skelmodel = TIKI_GetSkel( mesh );
|
|
surf = skelmodel->pSurfaces;
|
|
|
|
tikiSurf = &tiki->surfaces[ surfOffset ];
|
|
|
|
for( k = 0; k < skelmodel->numSurfaces; k++ )
|
|
{
|
|
if( !stricmp( loadsurf->name, surf->name ) )
|
|
{
|
|
TIKI_SetupIndividualSurface( tikianim->name, tikiSurf, surf->name, loadsurf );
|
|
if( !tikiSurf->name[ 0 ] )
|
|
{
|
|
TIKI_Warning( "TIKI_InitTiki: Surface %i in %s(referenced in %s) has no name! Please investigate and fix\n", k, skelmodel->name, name );
|
|
}
|
|
found = true;
|
|
}
|
|
|
|
surf = surf->pNext;
|
|
tikiSurf++;
|
|
}
|
|
|
|
surfOffset += skelmodel->numSurfaces;
|
|
}
|
|
}
|
|
|
|
if( !found )
|
|
{
|
|
TIKI_Warning( "TIKI_InitTiki: could not find surface '%s' in '%s' (check referenced skb/skd files).\n", loadsurf, tikianim->name );
|
|
}
|
|
}
|
|
|
|
if( tiki->radius != 0.0f )
|
|
{
|
|
TIKI_CalcRadius( tiki );
|
|
}
|
|
|
|
return tiki;
|
|
}
|
|
|
|
/*
|
|
===============
|
|
TIKI_CalcRadius
|
|
===============
|
|
*/
|
|
void TIKI_CalcRadius( dtiki_t *tiki )
|
|
{
|
|
int j;
|
|
float radius;
|
|
float tmpVec[ 3 ];
|
|
float *bounds[ 2 ];
|
|
|
|
tiki->radius = 0.0f;
|
|
|
|
bounds[ 0 ] = &tiki->a->mins[ 0 ];
|
|
bounds[ 1 ] = &tiki->a->maxs[ 0 ];
|
|
|
|
for( j = 0; j < 4; j++ )
|
|
{
|
|
tmpVec[ 0 ] = bounds[ j & 1 ][ 0 ];
|
|
tmpVec[ 1 ] = bounds[ j & 1 ][ 1 ];
|
|
tmpVec[ 2 ] = bounds[ j & 1 ][ 2 ];
|
|
|
|
radius = VectorLength( tmpVec );
|
|
if( radius > tiki->radius ) {
|
|
tiki->radius = radius;
|
|
}
|
|
}
|
|
|
|
radius = tiki->radius * 0.7f;
|
|
tiki->radius = radius * tiki->lod_scale;
|
|
}
|
|
|
|
/*
|
|
===============
|
|
SkeletorCacheFileCallback
|
|
===============
|
|
*/
|
|
skelAnimDataGameHeader_t *SkeletorCacheFileCallback( const char *path )
|
|
{
|
|
skelAnimDataFileHeader_t *pHeader;
|
|
int iBuffLength;
|
|
char tempName[ 100 ];
|
|
char extension[ 100 ];
|
|
skelAnimDataGameHeader_t *finishedHeader;
|
|
void *buffer;
|
|
char npath[ 256 ];
|
|
|
|
Skel_ExtractFileExtension( path, extension );
|
|
|
|
if( strcmp( extension, "skc" ) )
|
|
{
|
|
Com_Printf( "Skeletor CacheAnimSkel: %s: File extension unknown. Attempting to open as skc file\n", path );
|
|
}
|
|
|
|
strcpy( npath, "newanim/" );
|
|
strcat( npath, path );
|
|
|
|
iBuffLength = TIKI_ReadFileEx( npath, ( void ** )&buffer, qtrue );
|
|
if( iBuffLength > 0 )
|
|
{
|
|
finishedHeader = skeletor_c::LoadProcessedAnim( npath, buffer, iBuffLength, path );
|
|
TIKI_FreeFile( buffer );
|
|
}
|
|
else
|
|
{
|
|
iBuffLength = TIKI_ReadFileEx( path, ( void ** )&pHeader, qtrue );
|
|
if( iBuffLength <= 0 )
|
|
{
|
|
Com_Printf( "Skeletor CacheAnimSkel: Could not open binary file %s\n", path );
|
|
return NULL;
|
|
}
|
|
|
|
if( pHeader->ident != TIKI_SKC_HEADER_IDENT || pHeader->version != TIKI_SKC_HEADER_VERSION )
|
|
{
|
|
Com_Printf( "Skeletor CacheAnimSkel: anim %s has wrong header ([ident,version] = [%i,%i] should be [%i,%i])\n", path,
|
|
pHeader->ident, pHeader->version,
|
|
TIKI_SKC_HEADER_IDENT, TIKI_SKC_HEADER_VERSION );
|
|
TIKI_FreeFile( pHeader );
|
|
return NULL;
|
|
}
|
|
|
|
Com_Printf( "WARNING- DOWNGRADING TO OLD ANIMATION FORMAT FOR FILE: %s\n", path );
|
|
finishedHeader = skeletor_c::ConvertSkelFileToGame( pHeader, iBuffLength, path );
|
|
if( convertAnims && convertAnims->integer )
|
|
{
|
|
skeletor_c::SaveProcessedAnim( finishedHeader, path, pHeader );
|
|
}
|
|
|
|
TIKI_FreeFile( pHeader );
|
|
}
|
|
|
|
if( dumploadedanims && dumploadedanims->integer )
|
|
{
|
|
Com_Printf( "+loadanim: %s\n", path );
|
|
}
|
|
|
|
sprintf( tempName, "g%s", path );
|
|
UI_LoadResource( tempName );
|
|
|
|
return finishedHeader;
|
|
}
|
|
|
|
/*
|
|
===============
|
|
SkeletorCacheGetData
|
|
===============
|
|
*/
|
|
skelAnimDataGameHeader_t *SkeletorCacheGetData( int index )
|
|
{
|
|
skelAnimDataGameHeader_t *data = m_cachedData[ index ].data;
|
|
if( !data )
|
|
{
|
|
data = SkeletorCacheFileCallback( m_cachedData[ index ].path );
|
|
m_cachedData[ index ].data = data;
|
|
}
|
|
|
|
return data;
|
|
}
|
|
|
|
/*
|
|
===============
|
|
SkeletorCacheFindFilename
|
|
===============
|
|
*/
|
|
bool SkeletorCacheFindFilename( const char *path, int *indexPtr )
|
|
{
|
|
int sortValue;
|
|
int lowerBound;
|
|
int upperBound;
|
|
int index;
|
|
|
|
lowerBound = 0;
|
|
upperBound = m_numInCache - 1;
|
|
while( lowerBound <= upperBound )
|
|
{
|
|
index = ( lowerBound + upperBound ) / 2;
|
|
sortValue = stricmp( path, m_cachedData[ m_cachedDataLookup[ index ] ].path );
|
|
if( !sortValue )
|
|
{
|
|
if( indexPtr )
|
|
*indexPtr = index;
|
|
return true;
|
|
}
|
|
if( sortValue < 0 )
|
|
{
|
|
upperBound = index - 1;
|
|
}
|
|
else
|
|
{
|
|
lowerBound = index + 1;
|
|
}
|
|
}
|
|
|
|
if( indexPtr )
|
|
*indexPtr = lowerBound;
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
===============
|
|
SkeletorCacheLoadData
|
|
===============
|
|
*/
|
|
bool SkeletorCacheLoadData( const char *path, bool precache, int newIndex )
|
|
{
|
|
int i;
|
|
skelAnimDataGameHeader_t *data;
|
|
int lookup;
|
|
|
|
if( m_numInCache >= 4095 )
|
|
{
|
|
Com_Printf( "Skeletor CacheData, Cache full, can't load %s\n", path );
|
|
return false;
|
|
}
|
|
|
|
if( strlen( path ) >= 100 )
|
|
{
|
|
Com_Printf( "^~^~^ SkeletorCache: File name over %i characters will be ignored.\n(%s)\n", 99, path );
|
|
return false;
|
|
}
|
|
|
|
if( precache )
|
|
{
|
|
data = SkeletorCacheFileCallback( path );
|
|
if( !data ) {
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
data = 0;
|
|
}
|
|
|
|
for( lookup = 0; lookup < 4095; lookup++ )
|
|
{
|
|
if( m_cachedData[ lookup ].lookup == -1 ) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
for( i = m_numInCache - 1; i >= newIndex; i-- )
|
|
{
|
|
m_cachedData[ m_cachedDataLookup[ i ] ].lookup = i + 1;
|
|
m_cachedDataLookup[ i + 1 ] = m_cachedDataLookup[ i ];
|
|
}
|
|
|
|
m_cachedDataLookup[ newIndex ] = lookup;
|
|
m_cachedData[ lookup ].lookup = newIndex;
|
|
m_cachedData[ lookup ].data = data;
|
|
strcpy( m_cachedData[ lookup ].path, path );
|
|
m_cachedData[ lookup ].numusers = 0;
|
|
m_numInCache++;
|
|
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
===============
|
|
SkeletorCacheUnloadData
|
|
===============
|
|
*/
|
|
void SkeletorCacheUnloadData( int index )
|
|
{
|
|
int i;
|
|
|
|
m_numInCache--;
|
|
|
|
if( dumploadedanims && dumploadedanims->integer )
|
|
{
|
|
Com_Printf( "-loadanim: %s\n", m_cachedData[ m_cachedDataLookup[ index ] ] );
|
|
}
|
|
|
|
if( m_cachedData[ m_cachedDataLookup[ index ] ].data ) {
|
|
skelAnimDataGameHeader_s::DeallocAnimData( m_cachedData[ m_cachedDataLookup[ index ] ].data );
|
|
m_cachedData[ m_cachedDataLookup[ index ] ].data = NULL;
|
|
}
|
|
|
|
m_cachedData[ m_cachedDataLookup[ index ] ].lookup = -1;
|
|
for( i = index + 1; i < m_numInCache; i++ )
|
|
{
|
|
m_cachedDataLookup[ i - 1 ] = m_cachedDataLookup[ i ];
|
|
m_cachedData[ m_cachedDataLookup[ i ] ].lookup = i - 1;
|
|
}
|
|
}
|
|
|
|
/*
|
|
===============
|
|
SkeletorCacheCleanCache
|
|
===============
|
|
*/
|
|
void SkeletorCacheCleanCache()
|
|
{
|
|
int i;
|
|
|
|
for( i = 0; i < m_numInCache; i++ )
|
|
{
|
|
if( !m_cachedData[ m_cachedDataLookup[ i ] ].numusers ) {
|
|
SkeletorCacheUnloadData( i );
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
===============
|
|
TikiAddToBounds
|
|
===============
|
|
*/
|
|
void TikiAddToBounds( dtikianim_t *tiki, SkelVec3 *newBounds )
|
|
{
|
|
int i;
|
|
|
|
for( i = 0; i < 3; i++ )
|
|
{
|
|
if( newBounds[ 0 ].val[ i ] < tiki->mins[ i ] ) {
|
|
tiki->mins[ i ] = newBounds[ 0 ].val[ i ];
|
|
}
|
|
|
|
if( newBounds[ 1 ].val[ i ] > tiki->maxs[ i ] ) {
|
|
tiki->maxs[ i ] = newBounds[ 1 ].val[ i ];
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
===============
|
|
TIKI_AnimList_f
|
|
===============
|
|
*/
|
|
void TIKI_AnimList_f()
|
|
{
|
|
skeletorCacheEntry_t *entry;
|
|
int i;
|
|
|
|
Com_Printf( "\nanimlist:\n" );
|
|
for( i = 0; i < m_numInCache; i++ )
|
|
{
|
|
entry = &m_cachedData[ m_cachedDataLookup[ i ] ];
|
|
if( !entry ) {
|
|
Com_Printf( "*** NOT CACHED: " );
|
|
}
|
|
|
|
if( m_cachedData[ i ].path[ 0 ] )
|
|
{
|
|
Com_Printf( "%s\n", m_cachedData[ i ].path );
|
|
}
|
|
else
|
|
{
|
|
Com_Printf( "*** EMPTY PATH ERROR\n" );
|
|
}
|
|
}
|
|
|
|
for( ; i < 4095; i++ )
|
|
{
|
|
if( m_cachedData[ m_cachedDataLookup[ i ] ].path[ 0 ] ) {
|
|
Com_Printf( "*** CORRUPTED ENTRY\n" );
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
===============
|
|
TIKI_FixFrameNum
|
|
===============
|
|
*/
|
|
void TIKI_FixFrameNum( dtikianim_t *ptiki, skelAnimDataGameHeader_t *animData, dtikicmd_t *cmd, const char *alias )
|
|
{
|
|
if( cmd->frame_num >= TIKI_FRAME_LAST && cmd->frame_num < animData->numFrames )
|
|
{
|
|
if( cmd->frame_num <= TIKI_FRAME_END ) {
|
|
cmd->frame_num = animData->numFrames - 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TIKI_Error( "TIKI_FixFrameNum: illegal frame number %d (total: %d) in anim '%s' in '%s'\n", cmd->frame_num, animData->numFrames, alias, ptiki->name );
|
|
cmd->frame_num = 0;
|
|
}
|
|
}
|
|
|
|
/*
|
|
===============
|
|
TIKI_LoadAnim
|
|
===============
|
|
*/
|
|
void TIKI_LoadAnim( dtikianim_t *ptiki )
|
|
{
|
|
int i, j;
|
|
dtikianimdef_t *panim;
|
|
skelAnimDataGameHeader_t *animData;
|
|
|
|
for( i = 0; i < ptiki->num_anims; i++ )
|
|
{
|
|
animData = SkeletorCacheGetData( ptiki->m_aliases[ i ] );
|
|
if( animData )
|
|
{
|
|
panim = ptiki->animdefs[ i ];
|
|
for( j = 0; j < panim->num_server_cmds; j++ )
|
|
{
|
|
TIKI_FixFrameNum( ptiki, animData, &ptiki->animdefs[ i ]->server_cmds[ j ], ptiki->animdefs[ i ]->alias );
|
|
}
|
|
|
|
for( j = 0; j < panim->num_client_cmds; j++ )
|
|
{
|
|
TIKI_FixFrameNum( ptiki, animData, &ptiki->animdefs[ i ]->client_cmds[ j ], ptiki->animdefs[ i ]->alias );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
===============
|
|
TIKI_InitTiki
|
|
===============
|
|
*/
|
|
dtikianim_t *TIKI_InitTiki( dloaddef_t *ld, size_t defsize )
|
|
{
|
|
byte *ptr;
|
|
byte *start_ptr;
|
|
dtikicmd_t *pcmds;
|
|
int i, k;
|
|
size_t j;
|
|
size_t size;
|
|
//int anim_index;
|
|
int alias_index;
|
|
dtikianim_t *panim;
|
|
dtikianimdef_t *panimdef;
|
|
dloadanim_t *anim;
|
|
skelAnimDataGameHeader_t *data;
|
|
qboolean bModelBoundsSet = false;
|
|
bool bPrecache;
|
|
int index;
|
|
char tempName[ 257 ];
|
|
int order[ 4095 ];
|
|
short temp_aliases[ 4095 ];
|
|
|
|
panim = ( dtikianim_t * )TIKI_Alloc( defsize );
|
|
memset( panim, 0, defsize );
|
|
ClearBounds( panim->mins, panim->maxs );
|
|
panim->num_client_initcmds = ld->numclientinitcmds;
|
|
panim->num_server_initcmds = ld->numserverinitcmds;
|
|
panim->bIsCharacter = ld->bIsCharacter;
|
|
panim->name = ( char * )( ( char * )panim + sizeof( dtikianim_t ) + ( ld->numanims - 1 ) * sizeof( dtikianimdef_t * ) );
|
|
strcpy( panim->name, ld->path );
|
|
panim->server_initcmds = ( dtikicmd_t * )( ( char * )panim->name + strlen( ld->path ) + 1 );
|
|
|
|
start_ptr = ( byte * )( ( char * )panim->server_initcmds + ld->numserverinitcmds * sizeof( dtikicmd_t ) );
|
|
ptr = start_ptr;
|
|
|
|
// Process server init commands
|
|
for( i = 0; i < ld->numserverinitcmds; i++ )
|
|
{
|
|
pcmds = &panim->server_initcmds[ i ];
|
|
pcmds->num_args = ld->loadserverinitcmds[ i ]->num_args;
|
|
pcmds->args = ( char ** )ptr;
|
|
|
|
ptr += pcmds->num_args * sizeof( char ** );
|
|
|
|
for( j = 0; j < ld->loadserverinitcmds[ i ]->num_args; j++ )
|
|
{
|
|
pcmds->args[ j ] = ( char * )ptr;
|
|
size = strlen( ld->loadserverinitcmds[ i ]->args[ j ] ) + 1;
|
|
memcpy( pcmds->args[ j ], ld->loadserverinitcmds[ i ]->args[ j ], size );
|
|
|
|
ptr += size;
|
|
}
|
|
}
|
|
|
|
panim->client_initcmds = ( dtikicmd_t * )ptr;
|
|
|
|
start_ptr = ( byte * )( ( char * )panim->client_initcmds + ld->numclientinitcmds * sizeof( dtikicmd_t ) );
|
|
ptr = start_ptr;
|
|
|
|
// Process client init commands
|
|
for( i = 0; i < ld->numclientinitcmds; i++ )
|
|
{
|
|
pcmds = &panim->client_initcmds[ i ];
|
|
pcmds->num_args = ld->loadclientinitcmds[ i ]->num_args;
|
|
pcmds->args = ( char ** )ptr;
|
|
|
|
ptr += pcmds->num_args * sizeof( char ** );
|
|
|
|
for( j = 0; j < ld->loadclientinitcmds[ i ]->num_args; j++ )
|
|
{
|
|
pcmds->args[ j ] = ( char * )ptr;
|
|
size = strlen( ld->loadclientinitcmds[ i ]->args[ j ] ) + 1;
|
|
memcpy( pcmds->args[ j ], ld->loadclientinitcmds[ i ]->args[ j ], size );
|
|
|
|
ptr += size;
|
|
}
|
|
}
|
|
|
|
TIKI_GetAnimOrder( ld, order );
|
|
sprintf( tempName, "e%s", ld->path );
|
|
UI_LoadResource( tempName );
|
|
|
|
panim->m_aliases = temp_aliases;
|
|
|
|
// Process anim commands
|
|
for( i = 0; i < ld->numanims; i++ )
|
|
{
|
|
anim = ld->loadanims[ order[ i ] ];
|
|
if( !SkeletorCacheFindFilename( anim->name, &index ) )
|
|
{
|
|
bPrecache = false;
|
|
|
|
if( ( !low_anim_memory && ld->numanims <= 49 ) || !low_anim_memory || !low_anim_memory->integer )
|
|
{
|
|
bPrecache = true;
|
|
}
|
|
|
|
if( !SkeletorCacheLoadData( anim->name, bPrecache, index ) )
|
|
{
|
|
TIKI_Error( "TIKI_InitTiki: Failed to load animation '%s' at %s\n", anim->name, anim->location );
|
|
panim->m_aliases[ i ] = -1;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
alias_index = m_cachedDataLookup[ index ];
|
|
m_cachedData[ alias_index ].numusers++;
|
|
panimdef = ( dtikianimdef_t * )ptr;
|
|
ptr += sizeof( dtikianimdef_t );
|
|
panim->animdefs[ i ] = panimdef;
|
|
panim->m_aliases[ i ] = alias_index;
|
|
strcpy( panimdef->alias, anim->alias );
|
|
panimdef->weight = anim->weight;
|
|
panimdef->flags = anim->flags;
|
|
|
|
if( !Q_stricmp( panimdef->alias, "idle" ) )
|
|
{
|
|
data = SkeletorCacheGetData( alias_index );
|
|
if( data )
|
|
{
|
|
VectorCopy( data->bounds[ 0 ].val, panim->mins );
|
|
VectorCopy( data->bounds[ 1 ].val, panim->maxs );
|
|
bModelBoundsSet = true;
|
|
}
|
|
}
|
|
|
|
|
|
if( anim->flags & TAF_RANDOM )
|
|
{
|
|
j = strlen( panimdef->alias );
|
|
if( isdigit( panimdef->alias[ j - 1 ] ) )
|
|
{
|
|
do
|
|
{
|
|
j--;
|
|
} while( isdigit( panimdef->alias[ j - 1 ] ) );
|
|
|
|
panimdef->alias[ j ] = 0;
|
|
}
|
|
else
|
|
{
|
|
TIKI_DPrintf( "TIKI_InitTiki: Random animation name '%s' should end with a number\n", panimdef->alias );
|
|
}
|
|
}
|
|
|
|
panimdef->blendtime = anim->blendtime;
|
|
if( loadtikicommands )
|
|
{
|
|
panimdef->num_server_cmds = anim->num_server_cmds;
|
|
panimdef->num_client_cmds = anim->num_client_cmds;
|
|
}
|
|
else
|
|
{
|
|
panimdef->num_server_cmds = 0;
|
|
panimdef->num_client_cmds = 0;
|
|
}
|
|
|
|
panimdef->server_cmds = ( dtikicmd_t * )ptr;
|
|
ptr += anim->num_server_cmds * sizeof( dtikicmd_t );
|
|
|
|
// Process server anim commands
|
|
for( j = 0; j < anim->num_server_cmds; j++ )
|
|
{
|
|
pcmds = &panimdef->server_cmds[ j ];
|
|
pcmds->num_args = anim->loadservercmds[ j ]->num_args;
|
|
pcmds->frame_num = anim->loadservercmds[ j ]->frame_num;
|
|
pcmds->args = ( char ** )ptr;
|
|
|
|
ptr += pcmds->num_args * sizeof( char * );
|
|
|
|
for( k = 0; k < anim->loadservercmds[ j ]->num_args; k++ )
|
|
{
|
|
pcmds->args[ k ] = ( char * )ptr;
|
|
size = strlen( anim->loadservercmds[ j ]->args[ k ] ) + 1;
|
|
memcpy( pcmds->args[ k ], anim->loadservercmds[ j ]->args[ k ], size );
|
|
|
|
ptr += size;
|
|
}
|
|
}
|
|
|
|
panimdef->client_cmds = ( dtikicmd_t * )ptr;
|
|
ptr += anim->num_client_cmds * sizeof( dtikicmd_t );
|
|
|
|
// Process client anim commands
|
|
for( j = 0; j < anim->num_client_cmds; j++ )
|
|
{
|
|
pcmds = &panimdef->client_cmds[ j ];
|
|
pcmds->num_args = anim->loadclientcmds[ j ]->num_args;
|
|
pcmds->frame_num = anim->loadclientcmds[ j ]->frame_num;
|
|
pcmds->args = ( char ** )ptr;
|
|
|
|
ptr += pcmds->num_args * sizeof( char * );
|
|
|
|
for( k = 0; k < anim->loadclientcmds[ j ]->num_args; k++ )
|
|
{
|
|
pcmds->args[ k ] = ( char * )ptr;
|
|
size = strlen( anim->loadclientcmds[ j ]->args[ k ] ) + 1;
|
|
memcpy( pcmds->args[ k ], anim->loadclientcmds[ j ]->args[ k ], size );
|
|
|
|
ptr += size;
|
|
}
|
|
}
|
|
}
|
|
|
|
panim->m_aliases = NULL;
|
|
if( i )
|
|
{
|
|
if( !bModelBoundsSet )
|
|
{
|
|
TIKI_DPrintf( "TIKI_InitTiki: no 'idle' animation found, model bounds not set for %s\n", ld->path );
|
|
}
|
|
|
|
panim->num_anims = i;
|
|
panim->m_aliases = ( short * )TIKI_Alloc( panim->num_anims * sizeof( short ) );
|
|
memcpy( panim->m_aliases, temp_aliases, panim->num_anims * sizeof( short ) );
|
|
panim->modelData = ptr;
|
|
panim->modelDataSize = ld->modelBuf->cursize;
|
|
memcpy( panim->modelData, ld->modelData, panim->modelDataSize );
|
|
ptr += panim->modelDataSize;
|
|
|
|
size = strlen( ld->headmodels ) + 1;
|
|
panim->headmodels = ( char * )ptr;
|
|
memcpy( panim->headmodels, ld->headmodels, size );
|
|
ptr += size;
|
|
|
|
size = strlen( ld->headskins ) + 1;
|
|
panim->headskins = ( char * )ptr;
|
|
memcpy( panim->headskins, ld->headskins, size );
|
|
ptr += size;
|
|
|
|
sprintf( tempName, "h%s", ld->path );
|
|
UI_LoadResource( tempName );
|
|
|
|
if( low_anim_memory && ( !low_anim_memory->integer || !tiki_loading ) )
|
|
{
|
|
TIKI_LoadAnim( panim );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TIKI_Error( "TIKI_InitTiki: No valid animations found in %s.\n", ld->path );
|
|
panim = NULL;
|
|
}
|
|
|
|
return panim;
|
|
}
|
|
|
|
/*
|
|
===============
|
|
TIKI_RemoveTiki
|
|
===============
|
|
*/
|
|
void TIKI_RemoveTiki( dtikianim_t *ptiki )
|
|
{
|
|
int i;
|
|
int alias_index;
|
|
|
|
for( i = 0; i < ptiki->num_anims; i++ )
|
|
{
|
|
alias_index = ptiki->m_aliases[ i ];
|
|
m_cachedData[ i ].numusers--;
|
|
}
|
|
}
|