mirror of
https://github.com/openmoh/openmohaa.git
synced 2025-04-28 13:47:58 +03:00

This was using an uninitialized buffer to find the cached TIKI, in most configurations it always returned false, but when compiled with GCC it would return true
499 lines
11 KiB
C++
499 lines
11 KiB
C++
/*
|
|
===========================================================================
|
|
Copyright (C) 2024 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_cache.cpp : TIKI's fast implementation
|
|
|
|
#include "q_shared.h"
|
|
#include "qcommon.h"
|
|
#include "../skeletor/skeletor.h"
|
|
#include <mem_blockalloc.h>
|
|
#include <con_set.h>
|
|
#include "tiki_files.h"
|
|
#include "tiki_skel.h"
|
|
|
|
struct pchar {
|
|
const char *m_Value;
|
|
|
|
pchar() { m_Value = NULL; }
|
|
|
|
pchar(const char *value) { m_Value = value; }
|
|
|
|
friend bool operator==(const pchar& l, const pchar& r) { return !strcmp(l.m_Value, r.m_Value); }
|
|
};
|
|
|
|
con_map<pchar, dtikianim_t *> *tikianimcache;
|
|
con_map<pchar, dtiki_t *> *tikicache;
|
|
static skeletor_c *skel_entity_cache[TIKI_MAX_ENTITY_CACHE];
|
|
|
|
template<>
|
|
int HashCode<pchar>(const pchar& key)
|
|
{
|
|
return HashCode<const char *>(key.m_Value);
|
|
}
|
|
|
|
/*
|
|
===============
|
|
TIKI_FindTikiAnim
|
|
===============
|
|
*/
|
|
dtikianim_t *TIKI_FindTikiAnim(const char *path)
|
|
{
|
|
char filename[1024];
|
|
|
|
if (tikianimcache) {
|
|
dtikianim_t **t;
|
|
|
|
t = tikianimcache->find(filename);
|
|
if (t) {
|
|
return *t;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
===============
|
|
TIKI_FindTiki
|
|
===============
|
|
*/
|
|
dtiki_t *TIKI_FindTiki(const char *path)
|
|
{
|
|
char filename[1024];
|
|
|
|
if (tikicache) {
|
|
dtiki_t **t;
|
|
|
|
Q_strncpyz(filename, path, sizeof(filename));
|
|
FS_CanonicalFilename(filename);
|
|
|
|
t = tikicache->find(filename);
|
|
if (t) {
|
|
return *t;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
===============
|
|
TIKI_RegisterTikiAnimFlags
|
|
===============
|
|
*/
|
|
dtikianim_t *TIKI_RegisterTikiAnimFlags(const char *path, qboolean use)
|
|
{
|
|
dtikianim_t *tiki;
|
|
char filename[1024];
|
|
|
|
Q_strncpyz(filename, path, sizeof(filename));
|
|
FS_CanonicalFilename(filename);
|
|
|
|
if (tikianimcache) {
|
|
dtikianim_t **t;
|
|
|
|
t = tikianimcache->find(filename);
|
|
if (t) {
|
|
return *t;
|
|
}
|
|
} else {
|
|
tikianimcache = new con_map<pchar, dtikianim_t *>;
|
|
}
|
|
|
|
tiki = TIKI_LoadTikiAnim(filename);
|
|
if (tiki) {
|
|
if (use) {
|
|
Com_DPrintf("^~^~^ Add the following line to the *_precache.scr map script:\n");
|
|
Com_DPrintf("cache %s\n", filename);
|
|
}
|
|
|
|
(*tikianimcache)[tiki->name] = tiki;
|
|
}
|
|
|
|
return tiki;
|
|
}
|
|
|
|
/*
|
|
===============
|
|
TIKI_RegisterTikiAnim
|
|
===============
|
|
*/
|
|
dtikianim_t *TIKI_RegisterTikiAnim(const char *path)
|
|
{
|
|
return TIKI_RegisterTikiAnimFlags(path, qfalse);
|
|
}
|
|
|
|
/*
|
|
===============
|
|
TIKI_RegisterTikiFlags
|
|
===============
|
|
*/
|
|
dtiki_t *TIKI_RegisterTikiFlags(const char *path, qboolean use)
|
|
{
|
|
dtiki_t *tiki = NULL;
|
|
dtikianim_t *tikianim = NULL;
|
|
con_map<str, str> keyValues;
|
|
const char *next_path;
|
|
str key;
|
|
str value;
|
|
const char *name;
|
|
char filename[1024];
|
|
char full_filename[1024];
|
|
|
|
full_filename[0] = 0;
|
|
|
|
name = path;
|
|
for (next_path = strstr(name, "|"); next_path; next_path = strstr(name, "|")) {
|
|
key = name;
|
|
key[next_path - name] = 0;
|
|
|
|
name = next_path + 1;
|
|
next_path = strstr(name, "|");
|
|
if (!next_path) {
|
|
break;
|
|
}
|
|
|
|
value = name;
|
|
value[next_path - name] = 0;
|
|
name = next_path + 1;
|
|
|
|
// add it to the entry
|
|
keyValues[key] = value;
|
|
|
|
strcat(full_filename, key.c_str());
|
|
strcat(full_filename, "|");
|
|
strcat(full_filename, value.c_str());
|
|
strcat(full_filename, "|");
|
|
}
|
|
|
|
Q_strncpyz(filename, name, sizeof(filename));
|
|
FS_CanonicalFilename(filename);
|
|
Q_strcat(full_filename, sizeof(full_filename), filename);
|
|
|
|
if (!tikicache) {
|
|
tikicache = new con_map<pchar, dtiki_t *>;
|
|
} else {
|
|
dtiki_t **t;
|
|
|
|
t = tikicache->find(full_filename);
|
|
if (t) {
|
|
return *t;
|
|
}
|
|
}
|
|
|
|
tikianim = TIKI_RegisterTikiAnimFlags(filename, use);
|
|
if (tikianim) {
|
|
tiki = TIKI_LoadTikiModel(tikianim, full_filename, &keyValues);
|
|
if (tiki) {
|
|
// cache the tiki
|
|
(*tikicache)[tiki->name] = tiki;
|
|
}
|
|
}
|
|
|
|
return tiki;
|
|
}
|
|
|
|
/*
|
|
===============
|
|
TIKI_RegisterTiki
|
|
===============
|
|
*/
|
|
dtiki_t *TIKI_RegisterTiki(const char *path)
|
|
{
|
|
return TIKI_RegisterTikiFlags(path, qfalse);
|
|
}
|
|
|
|
/*
|
|
===============
|
|
TIKI_FreeAll
|
|
===============
|
|
*/
|
|
void TIKI_FreeAll()
|
|
{
|
|
dtiki_t **entry;
|
|
dtikianim_t **entryanim;
|
|
dtiki_t *tiki;
|
|
dtikianim_t *tikianim;
|
|
int i;
|
|
|
|
if (tikicache) {
|
|
con_map_enum<pchar, dtiki_t *> en = *tikicache;
|
|
|
|
for (entry = en.NextValue(); entry != NULL; entry = en.NextValue()) {
|
|
skeletor_c *skeletor;
|
|
|
|
tiki = *entry;
|
|
skeletor = (skeletor_c *)tiki->skeletor;
|
|
if (skeletor) {
|
|
delete skeletor;
|
|
}
|
|
|
|
tiki->m_boneList.CleanUpChannels();
|
|
// Fixed in OPM
|
|
// It's better to free aliases when actually clearing the anim cache
|
|
/*
|
|
if (tiki->a->m_aliases) {
|
|
TIKI_Free(tiki->a->m_aliases);
|
|
tiki->a->m_aliases = NULL;
|
|
tiki->a->num_anims = 0;
|
|
}
|
|
*/
|
|
|
|
TIKI_Free(tiki);
|
|
}
|
|
|
|
tikicache->clear();
|
|
}
|
|
|
|
if (tikianimcache) {
|
|
con_map_enum<pchar, dtikianim_t *> en = *tikianimcache;
|
|
|
|
for (entryanim = en.NextValue(); entryanim != NULL; entryanim = en.NextValue()) {
|
|
tikianim = *entryanim;
|
|
|
|
TIKI_RemoveTiki(tikianim);
|
|
|
|
// Fixed in OPM
|
|
// Each tikianim should free their aliases
|
|
if (tikianim->m_aliases) {
|
|
TIKI_Free(tikianim->m_aliases);
|
|
tikianim->m_aliases = NULL;
|
|
tikianim->num_anims = 0;
|
|
}
|
|
|
|
TIKI_Free(tikianim);
|
|
}
|
|
|
|
tikianimcache->clear();
|
|
}
|
|
|
|
tiki_loading = true;
|
|
|
|
for (i = 0; i < cache_maxskel; i++) {
|
|
if (skelcache[i].skel) {
|
|
TIKI_FreeSkel(i);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
===============
|
|
TIKI_GetSkeletor
|
|
===============
|
|
*/
|
|
static qboolean tiki_started;
|
|
|
|
void *TIKI_GetSkeletor(dtiki_t *tiki, int entnum)
|
|
{
|
|
skeletor_c *skel;
|
|
int i;
|
|
int index;
|
|
|
|
if (entnum == ENTITYNUM_NONE) {
|
|
if (!tiki->skeletor) {
|
|
tiki->skeletor = new skeletor_c(tiki);
|
|
}
|
|
skel = (skeletor_c *)tiki->skeletor;
|
|
} else {
|
|
// Added in 2.30
|
|
// Multiple caches per entity
|
|
for (i = 0; i < TIKI_MAX_ENTITY_CACHE_PER_ENT; i++) {
|
|
index = ((entnum % TIKI_MAX_ENTITIES) * TIKI_MAX_ENTITY_CACHE_PER_ENT) + i;
|
|
|
|
skel = skel_entity_cache[index];
|
|
if (!skel) {
|
|
break;
|
|
}
|
|
|
|
if (skel->m_Tiki == tiki) {
|
|
return skel;
|
|
}
|
|
}
|
|
|
|
if (i == TIKI_MAX_ENTITY_CACHE_PER_ENT) {
|
|
i = 0;
|
|
}
|
|
|
|
index = ((entnum % TIKI_MAX_ENTITIES) * TIKI_MAX_ENTITY_CACHE_PER_ENT) + i;
|
|
skel = skel_entity_cache[index];
|
|
|
|
if (skel) {
|
|
delete skel;
|
|
}
|
|
|
|
skel = new skeletor_c(tiki);
|
|
skel_entity_cache[index] = skel;
|
|
}
|
|
|
|
return skel;
|
|
}
|
|
|
|
/*
|
|
===============
|
|
TIKI_DeleteSkeletor
|
|
===============
|
|
*/
|
|
static void TIKI_DeleteSkeletor(int entnum)
|
|
{
|
|
skeletor_c *skel;
|
|
int i;
|
|
|
|
if (entnum == ENTITYNUM_NONE) {
|
|
return;
|
|
}
|
|
|
|
for (i = 0; i < TIKI_MAX_ENTITY_CACHE_PER_ENT; i++) {
|
|
skel = skel_entity_cache[entnum * TIKI_MAX_ENTITY_CACHE_PER_ENT + i];
|
|
if (skel) {
|
|
delete skel;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
===============
|
|
TIKI_Begin
|
|
===============
|
|
*/
|
|
void TIKI_Begin(void)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < TIKI_MAX_ENTITY_CACHE; i++) {
|
|
skel_entity_cache[i] = 0;
|
|
}
|
|
|
|
tiki_started = true;
|
|
}
|
|
|
|
/*
|
|
===============
|
|
TIKI_End
|
|
===============
|
|
*/
|
|
void TIKI_End(void)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < MAX_GENTITIES; i++) {
|
|
TIKI_DeleteSkeletor(i);
|
|
}
|
|
|
|
tiki_started = false;
|
|
}
|
|
|
|
/*
|
|
===============
|
|
TIKI_FinishLoad
|
|
===============
|
|
*/
|
|
void TIKI_FinishLoad(void)
|
|
{
|
|
con_map_enum<pchar, dtikianim_t *> en;
|
|
dtikianim_t **entry;
|
|
|
|
if (!tiki_loading) {
|
|
return;
|
|
}
|
|
|
|
tiki_loading = false;
|
|
SkeletorCacheCleanCache();
|
|
|
|
if (!low_anim_memory || !low_anim_memory->integer) {
|
|
return;
|
|
}
|
|
|
|
if (tikianimcache) {
|
|
en = *tikianimcache;
|
|
for (entry = en.NextValue(); entry != NULL; entry = en.NextValue()) {
|
|
TIKI_LoadAnim(*entry);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
===============
|
|
TIKI_FreeImages
|
|
===============
|
|
*/
|
|
void TIKI_FreeImages(void)
|
|
{
|
|
dtikisurface_t *dsurf;
|
|
dtiki_t *tiki;
|
|
int j, k;
|
|
dtiki_t **entry;
|
|
con_map_enum<pchar, dtiki_t *> en;
|
|
|
|
if (!tikicache) {
|
|
return;
|
|
}
|
|
|
|
en = *tikicache;
|
|
for (entry = en.NextValue(); entry != NULL; entry = en.NextValue()) {
|
|
tiki = *entry;
|
|
for (k = 0; k < tiki->num_surfaces; k++) {
|
|
dsurf = &tiki->surfaces[k];
|
|
|
|
for (j = 0; j < dsurf->numskins; j++) {
|
|
dsurf->hShader[j] = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
===============
|
|
TIKI_TikiAnimList_f
|
|
===============
|
|
*/
|
|
void TIKI_TikiAnimList_f(void)
|
|
{
|
|
con_map_enum<pchar, dtikianim_t *> en;
|
|
dtikianim_t **entry;
|
|
|
|
Com_Printf("\ntikianimlist:\n");
|
|
if (tikicache) {
|
|
en = *tikianimcache;
|
|
for (entry = en.NextValue(); entry != NULL; entry = en.NextValue()) {
|
|
Com_Printf("%s\n", (*entry)->name);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
===============
|
|
TIKI_TikiList_f
|
|
===============
|
|
*/
|
|
void TIKI_TikiList_f(void)
|
|
{
|
|
con_map_enum<pchar, dtiki_t *> en;
|
|
dtiki_t **entry;
|
|
|
|
Com_Printf("\ntikilist:\n");
|
|
if (tikicache) {
|
|
en = *tikicache;
|
|
for (entry = en.NextValue(); entry != NULL; entry = en.NextValue()) {
|
|
Com_Printf("%s\n", (*entry)->name);
|
|
}
|
|
}
|
|
}
|