openmohaa/code/tiki/tiki_files.cpp

1085 lines
24 KiB
C++
Raw Normal View History

2016-03-27 11:49:47 +02:00
/*
===========================================================================
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;
2016-03-27 11:49:47 +02:00
typedef struct {
char path[100];
skelAnimDataGameHeader_t* data;
2016-03-27 11:49:47 +02:00
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];
2016-03-27 11:49:47 +02:00
InitSkelCache InitSkelCache::init;
MEM_TempAlloc TIKI_allocator;
/*
===============
InitSkelCache::InitSkelCache
===============
*/
InitSkelCache::InitSkelCache()
{
int i;
for (i = 0; i < 4095; i++)
2016-03-27 11:49:47 +02:00
{
m_cachedData[i].lookup = -1;
2016-03-27 11:49:47 +02:00
}
}
/*
===============
TIKI_FreeStorage
===============
*/
void TIKI_FreeStorage(dloaddef_t* ld)
2016-03-27 11:49:47 +02:00
{
TIKI_allocator.FreeAll();
ld->tikiFile.Close();
}
/*
===============
TIKI_AllocateLoadData
===============
*/
void* TIKI_AllocateLoadData(size_t length)
2016-03-27 11:49:47 +02:00
{
return TIKI_allocator.Alloc(length);
2016-03-27 11:49:47 +02:00
}
/*
===============
TIKI_CopyString
===============
*/
char* TIKI_CopyString(const char* s)
2016-03-27 11:49:47 +02:00
{
char* result = (char*)TIKI_AllocateLoadData(strlen(s) + 1);
strcpy(result, s);
2016-03-27 11:49:47 +02:00
return result;
}
/*
===============
TIKI_LoadTikiAnim
===============
*/
qboolean loadtikicommands = true;
dtikianim_t* TIKI_LoadTikiAnim(const char* path)
2016-03-27 11:49:47 +02:00
{
dloaddef_t loaddef;
dtikianim_t* tiki = NULL;
const char* token;
float tempVec[3];
2016-03-27 11:49:47 +02:00
msg_t modelBuf;
str s;
char tempName[257];
2016-03-27 11:49:47 +02:00
memset(&loaddef, 0, sizeof(dloaddef_t));
2016-03-27 11:49:47 +02:00
loaddef.modelBuf = &modelBuf;
TIKI_InitSetup(&loaddef);
2016-03-27 11:49:47 +02:00
if (loaddef.tikiFile.LoadFile(path, qfalse))
2016-03-27 11:49:47 +02:00
{
loaddef.path = path;
token = loaddef.tikiFile.GetToken(true);
if (strcmp(token, "TIKI"))
2016-03-27 11:49:47 +02:00
{
TIKI_Error("TIKI_LoadTIKIfile: def file %s has wrong header (%s should be TIKI)\n", loaddef.tikiFile.Filename(), token);
2016-03-27 11:49:47 +02:00
loaddef.tikiFile.Close();
return NULL;
}
loaddef.numanims = 0;
loaddef.numserverinitcmds = 0;
loaddef.numclientinitcmds = 0;
loaddef.bInIncludesSection = false;
while (loaddef.tikiFile.TokenAvailable(true))
2016-03-27 11:49:47 +02:00
{
token = loaddef.tikiFile.GetToken(true);
2016-03-27 11:49:47 +02:00
if (!stricmp(token, "setup"))
2016-03-27 11:49:47 +02:00
{
if (!TIKI_ParseSetup(&loaddef))
2016-03-27 11:49:47 +02:00
{
TIKI_FreeStorage(&loaddef);
2016-03-27 11:49:47 +02:00
return NULL;
}
}
else if (!stricmp(token, "init"))
2016-03-27 11:49:47 +02:00
{
TIKI_ParseInit(&loaddef);
2016-03-27 11:49:47 +02:00
}
else if (!stricmp(token, "animations"))
2016-03-27 11:49:47 +02:00
{
TIKI_ParseAnimations(&loaddef);
2016-03-27 11:49:47 +02:00
}
else if (!stricmp(token, "includes"))
2016-03-27 11:49:47 +02:00
{
if (!loaddef.bInIncludesSection)
2016-03-27 11:49:47 +02:00
{
loaddef.bInIncludesSection = TIKI_ParseIncludes(&loaddef);
2016-03-27 11:49:47 +02:00
}
else
{
TIKI_Error("TIKI_LoadTIKIfile: Nested Includes section in %s on line %d, the animations will be fubar\n",
2016-03-27 11:49:47 +02:00
token,
loaddef.tikiFile.GetLineNumber(),
loaddef.tikiFile.Filename());
2016-03-27 11:49:47 +02:00
}
}
else if (!stricmp(token, "}") && loaddef.bInIncludesSection)
2016-03-27 11:49:47 +02:00
{
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());
2016-03-27 11:49:47 +02:00
// skip the current line
while (loaddef.tikiFile.TokenAvailable(false)) {
loaddef.tikiFile.GetToken(false);
2016-03-27 11:49:47 +02:00
}
}
}
if (loaddef.bInIncludesSection)
2016-03-27 11:49:47 +02:00
{
TIKI_Error("TIKI_LoadTIKIfile: Include section in %s did not terminate\n", loaddef.tikiFile.Filename());
2016-03-27 11:49:47 +02:00
}
if (loaddef.numanims)
2016-03-27 11:49:47 +02:00
{
sprintf(tempName, "a%s", path);
UI_LoadResource(tempName);
2016-03-27 11:49:47 +02:00
tiki = TIKI_FillTIKIStructureSkel(&loaddef);
if (tiki)
2016-03-27 11:49:47 +02:00
{
sprintf(tempName, "b%s", path);
UI_LoadResource(tempName);
sprintf(tempName, "c%s", path);
UI_LoadResource(tempName);
2016-03-27 11:49:47 +02:00
VectorSubtract(tiki->maxs, tiki->mins, tempVec);
if (VectorLength(tempVec) > 100000.0f)
2016-03-27 11:49:47 +02:00
{
VectorSet(tiki->mins, -4.0f, -4.0f, -4.0f);
VectorSet(tiki->maxs, 4.0f, 4.0f, 4.0f);
2016-03-27 11:49:47 +02:00
}
TIKI_FreeStorage(&loaddef);
sprintf(tempName, "d%s", path);
UI_LoadResource(tempName);
2016-03-27 11:49:47 +02:00
}
else
{
TIKI_FreeStorage(&loaddef);
2016-03-27 11:49:47 +02:00
}
}
else
{
TIKI_Error("TIKI_LoadTIKIfile: No valid animations found in %s.\n", loaddef.tikiFile.Filename());
TIKI_FreeStorage(&loaddef);
2016-03-27 11:49:47 +02:00
}
}
else
{
loaddef.tikiFile.Close();
}
return tiki;
}
/*
===============
TIKI_LoadTikiModel
===============
*/
dtiki_t* TIKI_LoadTikiModel(dtikianim_t* tikianim, const char* name, con_map<str, str>* keyValues)
2016-03-27 11:49:47 +02:00
{
dtiki_t* tiki;
2016-03-27 11:49:47 +02:00
//byte *start_ptr;
//byte *ptr;
int i, j, k;
char* strptr;
2016-03-27 11:49:47 +02:00
size_t defsize;
struct {
dtiki_t tiki;
short int buffer[1000];
2016-03-27 11:49:47 +02:00
} temp;
//int skel;
dloadsurface_t loadsurfaces[24];
2016-03-27 11:49:47 +02:00
int numSurfacesSetUp;
dtikisurface_t* tikiSurf;
dloadsurface_t* loadsurf;
2016-03-27 11:49:47 +02:00
int mesh;
skelHeaderGame_t* skelmodel;
skelSurfaceGame_t* surf;
2016-03-27 11:49:47 +02:00
int surfOffset;
qboolean found;
2023-02-02 23:49:06 +01:00
byte* start_ptr, *max_ptr, *ptr;
2016-03-27 11:49:47 +02:00
TIKI_LoadSetup(&temp.tiki, tikianim->name, loadsurfaces, &numSurfacesSetUp, tikianim->modelData, tikianim->modelDataSize, keyValues);
if (!temp.tiki.numMeshes)
2016-03-27 11:49:47 +02:00
{
Com_Printf("^~^~^ Model '%s' has no skelmodel\n", tikianim->name);
2016-03-27 11:49:47 +02:00
return NULL;
}
2023-05-15 16:50:19 +02:00
defsize = sizeof(dtiki_t) - sizeof(tiki->mesh);
defsize += temp.tiki.numMeshes * sizeof(short);
2023-02-02 23:49:06 +01:00
defsize += strlen(name) + 1;
defsize = PAD(defsize, sizeof(void*));
defsize += temp.tiki.num_surfaces * sizeof(dtikisurface_t);
tiki = (dtiki_t*)TIKI_Alloc(defsize);
memset(tiki, 0, defsize);
2023-02-02 23:49:06 +01:00
start_ptr = (byte*)tiki;
max_ptr = start_ptr + defsize;
2023-05-15 16:50:19 +02:00
ptr = start_ptr + sizeof(dtiki_t) - sizeof(tiki->mesh) + temp.tiki.numMeshes * sizeof(tiki->mesh[0]);
2023-02-02 23:49:06 +01:00
2016-03-27 11:49:47 +02:00
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;
2023-02-02 23:49:06 +01:00
tiki->name = (char*)ptr;
strcpy(tiki->name, name);
2023-02-02 23:49:06 +01:00
ptr += strlen(tiki->name) + 1;
ptr = (byte*)PADP(ptr, sizeof(void*));
tikiSurf = (dtikisurface_t*)ptr;
2016-03-27 11:49:47 +02:00
tiki->m_boneList.ZeroChannels();
2023-05-15 16:50:19 +02:00
assert((byte*)(tikiSurf + temp.tiki.num_surfaces) <= max_ptr);
for (i = 0; i < temp.tiki.numMeshes; i++)
2016-03-27 11:49:47 +02:00
{
mesh = temp.tiki.mesh[i];
tiki->mesh[i] = mesh;
skelmodel = skelcache[mesh].skel;
skelcache[mesh].numuses++;
2016-03-27 11:49:47 +02:00
for (j = 0; j < skelmodel->numBones; j++)
2016-03-27 11:49:47 +02:00
{
tiki->m_boneList.AddChannel(skelmodel->pBones[j].channel);
2016-03-27 11:49:47 +02:00
}
}
tiki->m_boneList.PackChannels();
VectorCopy(temp.tiki.light_offset, tiki->light_offset);
VectorCopy(temp.tiki.load_origin, tiki->load_origin);
2016-03-27 11:49:47 +02:00
tiki->surfaces = tikiSurf;
for (i = 0; i < numSurfacesSetUp; i++)
2016-03-27 11:49:47 +02:00
{
loadsurf = &loadsurfaces[i];
2016-03-27 11:49:47 +02:00
found = false;
strptr = strchr(loadsurf->name, '*');
2016-03-27 11:49:47 +02:00
surfOffset = 0;
if (strptr || !stricmp(loadsurf->name, "all"))
2016-03-27 11:49:47 +02:00
{
for (j = 0; j < temp.tiki.numMeshes; j++)
2016-03-27 11:49:47 +02:00
{
mesh = temp.tiki.mesh[j];
skelmodel = TIKI_GetSkel(mesh);
2016-03-27 11:49:47 +02:00
surf = skelmodel->pSurfaces;
for (k = 0; k < skelmodel->numSurfaces; k++)
2016-03-27 11:49:47 +02:00
{
2023-05-15 16:50:19 +02:00
tikiSurf = &tiki->surfaces[surfOffset + k];
2016-03-27 11:49:47 +02:00
if ((strptr
2016-03-27 11:49:47 +02:00
&& strptr != loadsurf->name
&& !strnicmp(loadsurf->name, surf->name, strptr - loadsurf->name))
|| !stricmp(loadsurf->name, "all"))
2016-03-27 11:49:47 +02:00
{
TIKI_SetupIndividualSurface(tikianim->name, tikiSurf, surf->name, loadsurf);
2016-03-27 11:49:47 +02:00
found = true;
}
surf = surf->pNext;
}
surfOffset += skelmodel->numSurfaces;
}
}
else
{
for (j = 0; j < temp.tiki.numMeshes; j++)
2016-03-27 11:49:47 +02:00
{
mesh = temp.tiki.mesh[j];
skelmodel = TIKI_GetSkel(mesh);
2016-03-27 11:49:47 +02:00
surf = skelmodel->pSurfaces;
tikiSurf = &tiki->surfaces[surfOffset];
2016-03-27 11:49:47 +02:00
for (k = 0; k < skelmodel->numSurfaces; k++)
2016-03-27 11:49:47 +02:00
{
if (!stricmp(loadsurf->name, surf->name))
2016-03-27 11:49:47 +02:00
{
TIKI_SetupIndividualSurface(tikianim->name, tikiSurf, surf->name, loadsurf);
if (!tikiSurf->name[0])
2016-03-27 11:49:47 +02:00
{
TIKI_Warning("TIKI_InitTiki: Surface %i in %s(referenced in %s) has no name! Please investigate and fix\n", k, skelmodel->name, name);
2016-03-27 11:49:47 +02:00
}
found = true;
}
surf = surf->pNext;
tikiSurf++;
}
surfOffset += skelmodel->numSurfaces;
}
}
if (!found)
2016-03-27 11:49:47 +02:00
{
TIKI_Warning("TIKI_InitTiki: could not find surface '%s' in '%s' (check referenced skb/skd files).\n", loadsurf->name, tikianim->name);
2016-03-27 11:49:47 +02:00
}
}
2023-08-27 17:28:25 +02:00
if (!tiki->radius)
2016-03-27 11:49:47 +02:00
{
TIKI_CalcRadius(tiki);
2016-03-27 11:49:47 +02:00
}
return tiki;
}
/*
===============
TIKI_CalcRadius
===============
*/
void TIKI_CalcRadius(dtiki_t* tiki)
2016-03-27 11:49:47 +02:00
{
int j;
float radius;
float tmpVec[3];
float* bounds[2];
2016-03-27 11:49:47 +02:00
tiki->radius = 0.0f;
bounds[0] = &tiki->a->mins[0];
bounds[1] = &tiki->a->maxs[0];
2016-03-27 11:49:47 +02:00
for (j = 0; j < 4; j++)
2016-03-27 11:49:47 +02:00
{
tmpVec[0] = bounds[j & 1][0];
tmpVec[1] = bounds[j & 1][1];
tmpVec[2] = bounds[j & 1][2];
2016-03-27 11:49:47 +02:00
radius = VectorLength(tmpVec);
if (radius > tiki->radius) {
2016-03-27 11:49:47 +02:00
tiki->radius = radius;
}
}
radius = tiki->radius * 0.7f;
tiki->radius = radius * tiki->lod_scale;
}
/*
===============
SkeletorCacheFileCallback
===============
*/
skelAnimDataGameHeader_t* SkeletorCacheFileCallback(const char* path)
2016-03-27 11:49:47 +02:00
{
skelAnimDataFileHeader_t* pHeader;
2016-03-27 11:49:47 +02:00
int iBuffLength;
char tempName[100];
char extension[100];
skelAnimDataGameHeader_t* finishedHeader;
char* buffer;
char npath[256];
2016-03-27 11:49:47 +02:00
Skel_ExtractFileExtension(path, extension);
2016-03-27 11:49:47 +02:00
if (strcmp(extension, "skc"))
2016-03-27 11:49:47 +02:00
{
Com_Printf("Skeletor CacheAnimSkel: %s: File extension unknown. Attempting to open as skc file\n", path);
2016-03-27 11:49:47 +02:00
}
strcpy(npath, "newanim/");
strcat(npath, path);
2016-03-27 11:49:47 +02:00
iBuffLength = TIKI_ReadFileEx(npath, (void**)&buffer, qtrue);
if (iBuffLength > 0)
2016-03-27 11:49:47 +02:00
{
finishedHeader = skeletor_c::LoadProcessedAnim(npath, buffer, iBuffLength, path);
TIKI_FreeFile(buffer);
2016-03-27 11:49:47 +02:00
}
else
{
iBuffLength = TIKI_ReadFileEx(path, (void**)&pHeader, qtrue);
if (iBuffLength <= 0)
2016-03-27 11:49:47 +02:00
{
Com_Printf("Skeletor CacheAnimSkel: Could not open binary file %s\n", path);
2016-03-27 11:49:47 +02:00
return NULL;
}
int ident = LittleLong(pHeader->ident);
int version = LittleLong(pHeader->version);
if (LittleLong(ident) != TIKI_SKC_HEADER_IDENT || (version != TIKI_SKC_HEADER_OLD_VERSION && version != TIKI_SKC_HEADER_VERSION))
2016-03-27 11:49:47 +02:00
{
Com_Printf("Skeletor CacheAnimSkel: anim %s has wrong header ([ident,version] = [%i,%i] should be [%i,%i])\n", path,
ident, version,
TIKI_SKC_HEADER_IDENT, TIKI_SKC_HEADER_VERSION);
TIKI_FreeFile(pHeader);
2016-03-27 11:49:47 +02:00
return NULL;
}
if (version == TIKI_SKC_HEADER_OLD_VERSION)
2016-03-27 11:49:47 +02:00
{
Com_Printf("WARNING- DOWNGRADING TO OLD ANIMATION FORMAT FOR FILE: %s\n", path);
finishedHeader = skeletor_c::ConvertSkelFileToGame(pHeader, iBuffLength, path);
if (convertAnims && convertAnims->integer)
2016-08-13 18:32:13 +02:00
{
skeletor_c::SaveProcessedAnim(finishedHeader, path, pHeader);
2016-08-13 18:32:13 +02:00
}
}
else
{
// looks like SKC version 14 and above are processed animations
// points the buffer to the animation data
buffer = (char*)pHeader + sizeof(int) + sizeof(int);
iBuffLength -= sizeof(int) + sizeof(int);
2016-08-13 18:32:13 +02:00
// loads the processed animation
finishedHeader = skeletor_c::LoadProcessedAnimEx(path, buffer, iBuffLength, path);
2016-03-27 11:49:47 +02:00
}
TIKI_FreeFile(pHeader);
2016-03-27 11:49:47 +02:00
}
if (dumploadedanims && dumploadedanims->integer)
2016-03-27 11:49:47 +02:00
{
Com_Printf("+loadanim: %s\n", path);
2016-03-27 11:49:47 +02:00
}
2023-02-01 00:28:40 +01:00
Com_sprintf(tempName, sizeof(tempName), "g%s", path);
UI_LoadResource(tempName);
2016-03-27 11:49:47 +02:00
return finishedHeader;
}
/*
===============
SkeletorCacheGetData
===============
*/
skelAnimDataGameHeader_t* SkeletorCacheGetData(int index)
2016-03-27 11:49:47 +02:00
{
if (index < 0)
2017-02-19 21:12:43 +01:00
{
return NULL;
}
skelAnimDataGameHeader_t* data = m_cachedData[index].data;
if (!data)
2016-03-27 11:49:47 +02:00
{
data = SkeletorCacheFileCallback(m_cachedData[index].path);
m_cachedData[index].data = data;
2016-03-27 11:49:47 +02:00
}
return data;
}
/*
===============
SkeletorCacheFindFilename
===============
*/
bool SkeletorCacheFindFilename(const char* path, int* indexPtr)
2016-03-27 11:49:47 +02:00
{
int sortValue;
int lowerBound;
int upperBound;
int index;
lowerBound = 0;
upperBound = m_numInCache - 1;
while (lowerBound <= upperBound)
2016-03-27 11:49:47 +02:00
{
index = (lowerBound + upperBound) / 2;
sortValue = stricmp(path, m_cachedData[m_cachedDataLookup[index]].path);
if (!sortValue)
2016-03-27 11:49:47 +02:00
{
if (indexPtr)
2016-03-27 11:49:47 +02:00
*indexPtr = index;
return true;
}
if (sortValue < 0)
2016-03-27 11:49:47 +02:00
{
upperBound = index - 1;
}
else
{
lowerBound = index + 1;
}
}
if (indexPtr)
2016-03-27 11:49:47 +02:00
*indexPtr = lowerBound;
return false;
}
/*
===============
SkeletorCacheLoadData
===============
*/
bool SkeletorCacheLoadData(const char* path, bool precache, int newIndex)
2016-03-27 11:49:47 +02:00
{
int i;
skelAnimDataGameHeader_t* data;
2016-03-27 11:49:47 +02:00
int lookup;
if (m_numInCache >= 4095)
2016-03-27 11:49:47 +02:00
{
Com_Printf("Skeletor CacheData, Cache full, can't load %s\n", path);
2016-03-27 11:49:47 +02:00
return false;
}
if (strlen(path) >= 100)
2016-03-27 11:49:47 +02:00
{
Com_Printf("^~^~^ SkeletorCache: File name over %i characters will be ignored.\n(%s)\n", 99, path);
2016-03-27 11:49:47 +02:00
return false;
}
if (precache)
2016-03-27 11:49:47 +02:00
{
data = SkeletorCacheFileCallback(path);
if (!data) {
2016-03-27 11:49:47 +02:00
return false;
}
}
else
{
data = 0;
}
for (lookup = 0; lookup < 4095; lookup++)
2016-03-27 11:49:47 +02:00
{
if (m_cachedData[lookup].lookup == -1) {
2016-03-27 11:49:47 +02:00
break;
}
}
for (i = m_numInCache - 1; i >= newIndex; i--)
2016-03-27 11:49:47 +02:00
{
m_cachedData[m_cachedDataLookup[i]].lookup = i + 1;
m_cachedDataLookup[i + 1] = m_cachedDataLookup[i];
2016-03-27 11:49:47 +02:00
}
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;
2016-03-27 11:49:47 +02:00
m_numInCache++;
return true;
}
/*
===============
SkeletorCacheUnloadData
===============
*/
void SkeletorCacheUnloadData(int index)
2016-03-27 11:49:47 +02:00
{
int i;
m_numInCache--;
if (dumploadedanims && dumploadedanims->integer)
2016-03-27 11:49:47 +02:00
{
2023-02-01 00:28:40 +01:00
Com_Printf("-loadanim: %s\n", m_cachedData[m_cachedDataLookup[index]].path);
2016-03-27 11:49:47 +02:00
}
if (m_cachedData[m_cachedDataLookup[index]].data) {
skelAnimDataGameHeader_s::DeallocAnimData(m_cachedData[m_cachedDataLookup[index]].data);
m_cachedData[m_cachedDataLookup[index]].data = NULL;
2016-03-27 11:49:47 +02:00
}
m_cachedData[m_cachedDataLookup[index]].lookup = -1;
for (i = index + 1; i < m_numInCache; i++)
2016-03-27 11:49:47 +02:00
{
m_cachedDataLookup[i - 1] = m_cachedDataLookup[i];
m_cachedData[m_cachedDataLookup[i]].lookup = i - 1;
2016-03-27 11:49:47 +02:00
}
}
/*
===============
SkeletorCacheCleanCache
===============
*/
void SkeletorCacheCleanCache()
{
int i;
for (i = m_numInCache - 1; i >= 0; i--)
2016-03-27 11:49:47 +02:00
{
if (!m_cachedData[m_cachedDataLookup[i]].numusers) {
SkeletorCacheUnloadData(i);
2016-03-27 11:49:47 +02:00
}
}
}
/*
===============
TikiAddToBounds
===============
*/
void TikiAddToBounds(dtikianim_t* tiki, SkelVec3* newBounds)
2016-03-27 11:49:47 +02:00
{
int i;
for (i = 0; i < 3; i++)
2016-03-27 11:49:47 +02:00
{
if (newBounds[0].val[i] < tiki->mins[i]) {
tiki->mins[i] = newBounds[0].val[i];
2016-03-27 11:49:47 +02:00
}
if (newBounds[1].val[i] > tiki->maxs[i]) {
tiki->maxs[i] = newBounds[1].val[i];
2016-03-27 11:49:47 +02:00
}
}
}
/*
===============
TIKI_AnimList_f
===============
*/
void TIKI_AnimList_f()
{
skeletorCacheEntry_t* entry;
2016-03-27 11:49:47 +02:00
int i;
Com_Printf("\nanimlist:\n");
for (i = 0; i < m_numInCache; i++)
2016-03-27 11:49:47 +02:00
{
entry = &m_cachedData[m_cachedDataLookup[i]];
if (!entry) {
Com_Printf("*** NOT CACHED: ");
2016-03-27 11:49:47 +02:00
}
if (m_cachedData[i].path[0])
2016-03-27 11:49:47 +02:00
{
Com_Printf("%s\n", m_cachedData[i].path);
2016-03-27 11:49:47 +02:00
}
else
{
Com_Printf("*** EMPTY PATH ERROR\n");
2016-03-27 11:49:47 +02:00
}
}
for (; i < 4095; i++)
2016-03-27 11:49:47 +02:00
{
if (m_cachedData[m_cachedDataLookup[i]].path[0]) {
Com_Printf("*** CORRUPTED ENTRY\n");
2016-03-27 11:49:47 +02:00
}
}
}
/*
===============
TIKI_FixFrameNum
===============
*/
void TIKI_FixFrameNum(dtikianim_t* ptiki, skelAnimDataGameHeader_t* animData, dtikicmd_t* cmd, const char* alias)
2016-03-27 11:49:47 +02:00
{
if (cmd->frame_num >= TIKI_FRAME_LAST && cmd->frame_num < animData->numFrames)
2016-03-27 11:49:47 +02:00
{
if (cmd->frame_num <= TIKI_FRAME_END) {
2016-03-27 11:49:47 +02:00
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);
2016-03-27 11:49:47 +02:00
cmd->frame_num = 0;
}
}
/*
===============
TIKI_LoadAnim
===============
*/
void TIKI_LoadAnim(dtikianim_t* ptiki)
2016-03-27 11:49:47 +02:00
{
int i, j;
dtikianimdef_t* panim;
skelAnimDataGameHeader_t* animData;
2016-03-27 11:49:47 +02:00
for (i = 0; i < ptiki->num_anims; i++)
2016-03-27 11:49:47 +02:00
{
animData = SkeletorCacheGetData(ptiki->m_aliases[i]);
if (animData)
2016-03-27 11:49:47 +02:00
{
panim = ptiki->animdefs[i];
for (j = 0; j < panim->num_server_cmds; j++)
2016-03-27 11:49:47 +02:00
{
TIKI_FixFrameNum(ptiki, animData, &ptiki->animdefs[i]->server_cmds[j], ptiki->animdefs[i]->alias);
2016-03-27 11:49:47 +02:00
}
for (j = 0; j < panim->num_client_cmds; j++)
2016-03-27 11:49:47 +02:00
{
TIKI_FixFrameNum(ptiki, animData, &ptiki->animdefs[i]->client_cmds[j], ptiki->animdefs[i]->alias);
2016-03-27 11:49:47 +02:00
}
}
}
}
/*
===============
TIKI_InitTiki
===============
*/
dtikianim_t* TIKI_InitTiki(dloaddef_t* ld, size_t defsize)
2016-03-27 11:49:47 +02:00
{
byte* ptr;
byte* start_ptr;
byte* max_ptr;
dtikicmd_t* pcmds;
2016-03-27 11:49:47 +02:00
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;
2016-03-27 11:49:47 +02:00
qboolean bModelBoundsSet = false;
bool bPrecache;
int index;
char tempName[257];
int order[4095];
short temp_aliases[4095];
2016-03-27 11:49:47 +02:00
panim = (dtikianim_t*)TIKI_Alloc(defsize);
start_ptr = (byte*)panim;
max_ptr = start_ptr + defsize;
ptr = start_ptr;
memset(panim, 0, defsize);
ClearBounds(panim->mins, panim->maxs);
2016-03-27 11:49:47 +02:00
panim->num_client_initcmds = ld->numclientinitcmds;
panim->num_server_initcmds = ld->numserverinitcmds;
panim->bIsCharacter = ld->bIsCharacter;
ptr += sizeof(dtikianim_t) - sizeof(dtikianimdef_t*) + sizeof(dtikianimdef_t*) * ld->numanims;
panim->name = (char*)ptr;
strcpy(panim->name, ld->path);
ptr += strlen(ld->path) + 1;
ptr = (byte*)PADP(ptr, sizeof(void*));
panim->server_initcmds = (dtikicmd_t*)ptr;
ptr += sizeof(*panim->server_initcmds) * panim->num_server_initcmds;
2016-03-27 11:49:47 +02:00
// Process server init commands
for (i = 0; i < ld->numserverinitcmds; i++)
2016-03-27 11:49:47 +02:00
{
pcmds = &panim->server_initcmds[i];
pcmds->num_args = ld->loadserverinitcmds[i]->num_args;
pcmds->args = (char**)ptr;
2016-03-27 11:49:47 +02:00
2023-05-12 00:01:26 +02:00
ptr += sizeof(*pcmds->args) * pcmds->num_args;
2016-03-27 11:49:47 +02:00
for (j = 0; j < ld->loadserverinitcmds[i]->num_args; j++)
2016-03-27 11:49:47 +02:00
{
pcmds->args[j] = (char*)ptr;
size = strlen(ld->loadserverinitcmds[i]->args[j]) + 1;
memcpy(pcmds->args[j], ld->loadserverinitcmds[i]->args[j], size);
2016-03-27 11:49:47 +02:00
ptr += size;
}
ptr = (byte*)PADP(ptr, sizeof(void*));
2016-03-27 11:49:47 +02:00
}
panim->client_initcmds = (dtikicmd_t*)ptr;
2016-03-27 11:49:47 +02:00
ptr += sizeof(*panim->client_initcmds) * ld->numclientinitcmds;
2016-03-27 11:49:47 +02:00
// Process client init commands
for (i = 0; i < ld->numclientinitcmds; i++)
2016-03-27 11:49:47 +02:00
{
pcmds = &panim->client_initcmds[i];
pcmds->num_args = ld->loadclientinitcmds[i]->num_args;
pcmds->args = (char**)ptr;
2016-03-27 11:49:47 +02:00
2023-05-12 00:01:26 +02:00
ptr += sizeof(*pcmds->args) * pcmds->num_args;
2016-03-27 11:49:47 +02:00
for (j = 0; j < ld->loadclientinitcmds[i]->num_args; j++)
2016-03-27 11:49:47 +02:00
{
pcmds->args[j] = (char*)ptr;
size = strlen(ld->loadclientinitcmds[i]->args[j]) + 1;
memcpy(pcmds->args[j], ld->loadclientinitcmds[i]->args[j], size);
2016-03-27 11:49:47 +02:00
ptr += size;
}
ptr = (byte*)PADP(ptr, sizeof(void*));
2016-03-27 11:49:47 +02:00
}
2023-02-01 00:28:40 +01:00
TIKI_GetAnimOrder(ld, order);
Com_sprintf(tempName, sizeof(tempName), "e%s", ld->path);
UI_LoadResource(tempName);
2016-03-27 11:49:47 +02:00
panim->m_aliases = temp_aliases;
assert(ptr <= max_ptr);
2016-03-27 11:49:47 +02:00
// Process anim commands
for (i = 0; i < ld->numanims; i++)
2016-03-27 11:49:47 +02:00
{
anim = ld->loadanims[order[i]];
if (!SkeletorCacheFindFilename(anim->name, &index))
2016-03-27 11:49:47 +02:00
{
bPrecache = false;
if ((!low_anim_memory && ld->numanims <= 49) || !low_anim_memory || !low_anim_memory->integer)
2016-03-27 11:49:47 +02:00
{
bPrecache = true;
}
if (!SkeletorCacheLoadData(anim->name, bPrecache, index))
2016-03-27 11:49:47 +02:00
{
TIKI_Error("TIKI_InitTiki: Failed to load animation '%s' at %s\n", anim->name, anim->location);
panim->m_aliases[i] = -1;
2016-03-27 11:49:47 +02:00
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);
2016-03-27 11:49:47 +02:00
panimdef->weight = anim->weight;
panimdef->flags = anim->flags;
if (!Q_stricmp(panimdef->alias, "idle"))
2016-03-27 11:49:47 +02:00
{
data = SkeletorCacheGetData(alias_index);
if (data)
2016-03-27 11:49:47 +02:00
{
VectorCopy(data->bounds[0].val, panim->mins);
VectorCopy(data->bounds[1].val, panim->maxs);
2016-03-27 11:49:47 +02:00
bModelBoundsSet = true;
}
}
if (anim->flags & TAF_RANDOM)
2016-03-27 11:49:47 +02:00
{
j = strlen(panimdef->alias);
if (isdigit(panimdef->alias[j - 1]))
2016-03-27 11:49:47 +02:00
{
do
{
j--;
} while (isdigit(panimdef->alias[j - 1]));
2016-03-27 11:49:47 +02:00
panimdef->alias[j] = 0;
2016-03-27 11:49:47 +02:00
}
else
{
TIKI_DPrintf("TIKI_InitTiki: Random animation name '%s' should end with a number\n", panimdef->alias);
2016-03-27 11:49:47 +02:00
}
}
panimdef->blendtime = anim->blendtime;
if (loadtikicommands)
2016-03-27 11:49:47 +02:00
{
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 = (byte*)(panimdef->server_cmds + anim->num_server_cmds);
2016-03-27 11:49:47 +02:00
// Process server anim commands
for (j = 0; j < anim->num_server_cmds; j++)
2016-03-27 11:49:47 +02:00
{
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;
2016-03-27 11:49:47 +02:00
2023-05-12 00:01:26 +02:00
ptr += pcmds->num_args * sizeof(*pcmds->args);
2016-03-27 11:49:47 +02:00
for (k = 0; k < anim->loadservercmds[j]->num_args; k++)
2016-03-27 11:49:47 +02:00
{
pcmds->args[k] = (char*)ptr;
size = strlen(anim->loadservercmds[j]->args[k]) + 1;
memcpy(pcmds->args[k], anim->loadservercmds[j]->args[k], size);
2016-03-27 11:49:47 +02:00
ptr += size;
}
ptr = (byte*)PADP(ptr, sizeof(void*));
2016-03-27 11:49:47 +02:00
}
panimdef->client_cmds = (dtikicmd_t*)ptr;
ptr += anim->num_client_cmds * sizeof(dtikicmd_t);
2016-03-27 11:49:47 +02:00
// Process client anim commands
for (j = 0; j < anim->num_client_cmds; j++)
2016-03-27 11:49:47 +02:00
{
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;
2016-03-27 11:49:47 +02:00
2023-05-12 00:01:26 +02:00
ptr += pcmds->num_args * sizeof(*pcmds->args);
2016-03-27 11:49:47 +02:00
for (k = 0; k < anim->loadclientcmds[j]->num_args; k++)
2016-03-27 11:49:47 +02:00
{
pcmds->args[k] = (char*)ptr;
size = strlen(anim->loadclientcmds[j]->args[k]) + 1;
memcpy(pcmds->args[k], anim->loadclientcmds[j]->args[k], size);
2016-03-27 11:49:47 +02:00
ptr += size;
}
ptr = (byte*)PADP(ptr, sizeof(void*));
2016-03-27 11:49:47 +02:00
}
assert(ptr <= max_ptr);
2016-03-27 11:49:47 +02:00
}
panim->m_aliases = NULL;
if (i)
2016-03-27 11:49:47 +02:00
{
if (!bModelBoundsSet)
2016-03-27 11:49:47 +02:00
{
TIKI_DPrintf("TIKI_InitTiki: no 'idle' animation found, model bounds not set for %s\n", ld->path);
2016-03-27 11:49:47 +02:00
}
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));
2016-03-27 11:49:47 +02:00
panim->modelData = ptr;
panim->modelDataSize = ld->modelBuf->cursize;
memcpy(panim->modelData, ld->modelData, panim->modelDataSize);
2016-03-27 11:49:47 +02:00
ptr += panim->modelDataSize;
size = strlen(ld->headmodels) + 1;
panim->headmodels = (char*)ptr;
memcpy(panim->headmodels, ld->headmodels, size);
2016-03-27 11:49:47 +02:00
ptr += size;
size = strlen(ld->headskins) + 1;
panim->headskins = (char*)ptr;
memcpy(panim->headskins, ld->headskins, size);
2016-03-27 11:49:47 +02:00
ptr += size;
sprintf(tempName, "h%s", ld->path);
UI_LoadResource(tempName);
2016-03-27 11:49:47 +02:00
if (low_anim_memory && (!low_anim_memory->integer || !tiki_loading))
2016-03-27 11:49:47 +02:00
{
TIKI_LoadAnim(panim);
2016-03-27 11:49:47 +02:00
}
}
else
{
TIKI_Error("TIKI_InitTiki: No valid animations found in %s.\n", ld->path);
2016-03-27 11:49:47 +02:00
panim = NULL;
}
assert(ptr <= max_ptr);
2016-03-27 11:49:47 +02:00
return panim;
}
/*
===============
TIKI_RemoveTiki
===============
*/
void TIKI_RemoveTiki(dtikianim_t* ptiki)
2016-03-27 11:49:47 +02:00
{
int i;
int alias_index;
for (i = 0; i < ptiki->num_anims; i++)
2016-03-27 11:49:47 +02:00
{
alias_index = ptiki->m_aliases[i];
m_cachedData[alias_index].numusers--;
2016-03-27 11:49:47 +02:00
}
}