mirror of
https://github.com/ZDoom/raze-gles.git
synced 2024-12-26 03:30:46 +00:00
- merged most of Blood's resource manager into the file system
This commit is contained in:
parent
261af9e401
commit
8ef40c5083
6 changed files with 399 additions and 857 deletions
|
@ -29,9 +29,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
#include "crc32_.h"
|
#include "crc32_.h"
|
||||||
#include "compat.h"
|
#include "compat.h"
|
||||||
#include "cache1d.h"
|
#include "cache1d.h"
|
||||||
#ifdef WITHKPLIB
|
|
||||||
#include "kplib.h"
|
|
||||||
#endif
|
|
||||||
#include "common_game.h"
|
#include "common_game.h"
|
||||||
|
|
||||||
#include "misc.h"
|
#include "misc.h"
|
||||||
|
@ -46,858 +43,88 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
BEGIN_BLD_NS
|
BEGIN_BLD_NS
|
||||||
|
|
||||||
CACHENODE Resource::purgeHead = { NULL, &purgeHead, &purgeHead, 0 };
|
|
||||||
|
|
||||||
#ifdef USE_QHEAP
|
|
||||||
QHeap *Resource::heap;
|
|
||||||
#endif
|
|
||||||
Resource::Resource(void)
|
|
||||||
{
|
|
||||||
dict = NULL;
|
|
||||||
indexName = NULL;
|
|
||||||
indexId = NULL;
|
|
||||||
buffSize = 0;
|
|
||||||
count = 0;
|
|
||||||
handle = -1;
|
|
||||||
crypt = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Resource::~Resource(void)
|
|
||||||
{
|
|
||||||
if (dict)
|
|
||||||
{
|
|
||||||
for (unsigned int i = 0; i < count; i++)
|
|
||||||
{
|
|
||||||
if (dict[i].type)
|
|
||||||
Free(dict[i].type);
|
|
||||||
if (dict[i].name)
|
|
||||||
Free(dict[i].name);
|
|
||||||
if (dict[i].path)
|
|
||||||
Free(dict[i].path);
|
|
||||||
}
|
|
||||||
Free(dict);
|
|
||||||
dict = NULL;
|
|
||||||
buffSize = 0;
|
|
||||||
count = 0;
|
|
||||||
}
|
|
||||||
if (handle != -1)
|
|
||||||
{
|
|
||||||
kclose(handle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Resource::Init(const char *filename)
|
|
||||||
{
|
|
||||||
RFFHeader header;
|
|
||||||
#ifdef USE_QHEAP
|
|
||||||
dassert(heap != NULL);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (filename)
|
|
||||||
{
|
|
||||||
handle = kopen4loadfrommod(filename, 0);
|
|
||||||
if (handle != -1)
|
|
||||||
{
|
|
||||||
int nFileLength = kfilelength(handle);
|
|
||||||
dassert(nFileLength != -1);
|
|
||||||
if (kread(handle, &header, sizeof(RFFHeader)) != sizeof(RFFHeader)
|
|
||||||
|| memcmp(header.sign, "RFF\x1a", 4))
|
|
||||||
{
|
|
||||||
ThrowError("RFF header corrupted");
|
|
||||||
}
|
|
||||||
#if B_BIG_ENDIAN == 1
|
#if B_BIG_ENDIAN == 1
|
||||||
header.version = B_LITTLE16(header.version);
|
// Todo: Hook these up with the resource loader
|
||||||
header.offset = B_LITTLE32(header.offset);
|
void ByteSwapQAV(void *p)
|
||||||
header.filenum = B_LITTLE32(header.filenum);
|
{
|
||||||
#endif
|
QAV *qav = (QAV*)p;
|
||||||
switch (header.version & 0xff00)
|
qav->nFrames = B_LITTLE32(qav->nFrames);
|
||||||
{
|
qav->ticksPerFrame = B_LITTLE32(qav->ticksPerFrame);
|
||||||
case 0x200:
|
qav->at10 = B_LITTLE32(qav->at10);
|
||||||
crypt = 0;
|
qav->x = B_LITTLE32(qav->x);
|
||||||
break;
|
qav->y = B_LITTLE32(qav->y);
|
||||||
case 0x300:
|
qav->nSprite = B_LITTLE32(qav->nSprite);
|
||||||
crypt = 1;
|
for (int i = 0; i < qav->nFrames; i++)
|
||||||
break;
|
{
|
||||||
default:
|
FRAMEINFO *pFrame = &qav->frames[i];
|
||||||
ThrowError("Unknown RFF version");
|
SOUNDINFO *pSound = &pFrame->sound;
|
||||||
break;
|
pFrame->nCallbackId = B_LITTLE32(pFrame->nCallbackId);
|
||||||
}
|
pSound->sound = B_LITTLE32(pSound->sound);
|
||||||
count = header.filenum;
|
for (int j = 0; j < 8; j++)
|
||||||
if (count)
|
{
|
||||||
{
|
TILE_FRAME *pTile = &pFrame->tiles[j];
|
||||||
buffSize = 1;
|
pTile->picnum = B_LITTLE32(pTile->picnum);
|
||||||
while (count * 2 >= buffSize)
|
pTile->x = B_LITTLE32(pTile->x);
|
||||||
{
|
pTile->y = B_LITTLE32(pTile->y);
|
||||||
buffSize *= 2;
|
pTile->z = B_LITTLE32(pTile->z);
|
||||||
}
|
pTile->stat = B_LITTLE32(pTile->stat);
|
||||||
dict = (DICTNODE*)Alloc(buffSize * sizeof(DICTNODE));
|
pTile->angle = B_LITTLE16(pTile->angle);
|
||||||
memset(dict, 0, buffSize * sizeof(DICTNODE));
|
}
|
||||||
DICTNODE_FILE *tdict = (DICTNODE_FILE*)Alloc(count*sizeof(DICTNODE_FILE));
|
}
|
||||||
int r = klseek(handle, header.offset, SEEK_SET);
|
|
||||||
dassert(r != -1);
|
|
||||||
if ((uint32_t)kread(handle, tdict, count * sizeof(DICTNODE_FILE)) != count*sizeof(DICTNODE_FILE))
|
|
||||||
{
|
|
||||||
ThrowError("RFF dictionary corrupted");
|
|
||||||
}
|
|
||||||
if (crypt)
|
|
||||||
{
|
|
||||||
Crypt(tdict, count * sizeof(DICTNODE_FILE),
|
|
||||||
header.offset + (header.version & 0xff) * header.offset);
|
|
||||||
}
|
|
||||||
for (unsigned int i = 0; i < count; i++)
|
|
||||||
{
|
|
||||||
dict[i].offset = B_LITTLE32(tdict[i].offset);
|
|
||||||
dict[i].size = B_LITTLE32(tdict[i].size);
|
|
||||||
dict[i].flags = tdict[i].flags;
|
|
||||||
int nTypeLength = strnlen(tdict[i].type, 3);
|
|
||||||
int nNameLength = strnlen(tdict[i].name, 8);
|
|
||||||
dict[i].type = (char*)Alloc(nTypeLength+1);
|
|
||||||
dict[i].name = (char*)Alloc(nNameLength+1);
|
|
||||||
strncpy(dict[i].type, tdict[i].type, min(3, nTypeLength));
|
|
||||||
strncpy(dict[i].name, tdict[i].name, min(8, nNameLength));
|
|
||||||
dict[i].path = NULL;
|
|
||||||
dict[i].type[nTypeLength] = 0;
|
|
||||||
dict[i].name[nNameLength] = 0;
|
|
||||||
dict[i].id = B_LITTLE32(tdict[i].id);
|
|
||||||
dict[i].buffer = NULL;
|
|
||||||
}
|
|
||||||
Free(tdict);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!dict)
|
|
||||||
{
|
|
||||||
buffSize = 16;
|
|
||||||
dict = (DICTNODE*)Alloc(buffSize * sizeof(DICTNODE));
|
|
||||||
memset(dict, 0, buffSize * sizeof(DICTNODE));
|
|
||||||
}
|
|
||||||
Reindex();
|
|
||||||
for (unsigned int i = 0; i < count; i++)
|
|
||||||
{
|
|
||||||
if (dict[i].flags & DICT_LOCK)
|
|
||||||
{
|
|
||||||
Lock(&dict[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (unsigned int i = 0; i < count; i++)
|
|
||||||
{
|
|
||||||
if (dict[i].flags & DICT_LOAD)
|
|
||||||
{
|
|
||||||
Load(&dict[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Resource::Flush(CACHENODE *h)
|
void ByteSwapSEQ(void *p)
|
||||||
{
|
{
|
||||||
if (h->ptr)
|
Seq *pSeq = (Seq*)p;
|
||||||
{
|
pSeq->version = B_LITTLE16(pSeq->version);
|
||||||
#ifdef USE_QHEAP
|
pSeq->nFrames = B_LITTLE16(pSeq->nFrames);
|
||||||
heap->Free(h->ptr);
|
pSeq->at8 = B_LITTLE16(pSeq->at8);
|
||||||
#else
|
pSeq->ata = B_LITTLE16(pSeq->ata);
|
||||||
delete[] (char*)h->ptr;
|
pSeq->atc = B_LITTLE32(pSeq->atc);
|
||||||
|
for (int i = 0; i < pSeq->nFrames; i++)
|
||||||
|
{
|
||||||
|
SEQFRAME *pFrame = &pSeq->frames[i];
|
||||||
|
BitReader bitReader((char *)pFrame, sizeof(SEQFRAME));
|
||||||
|
SEQFRAME swapFrame;
|
||||||
|
swapFrame.tile = bitReader.readUnsigned(12);
|
||||||
|
swapFrame.at1_4 = bitReader.readBit();
|
||||||
|
swapFrame.at1_5 = bitReader.readBit();
|
||||||
|
swapFrame.at1_6 = bitReader.readBit();
|
||||||
|
swapFrame.at1_7 = bitReader.readBit();
|
||||||
|
swapFrame.at2_0 = bitReader.readUnsigned(8);
|
||||||
|
swapFrame.at3_0 = bitReader.readUnsigned(8);
|
||||||
|
swapFrame.at4_0 = bitReader.readSigned(8);
|
||||||
|
swapFrame.at5_0 = bitReader.readUnsigned(5);
|
||||||
|
swapFrame.at5_5 = bitReader.readBit();
|
||||||
|
swapFrame.at5_6 = bitReader.readBit();
|
||||||
|
swapFrame.at5_7 = bitReader.readBit();
|
||||||
|
swapFrame.at6_0 = bitReader.readBit();
|
||||||
|
swapFrame.at6_1 = bitReader.readBit();
|
||||||
|
swapFrame.at6_2 = bitReader.readBit();
|
||||||
|
swapFrame.at6_3 = bitReader.readBit();
|
||||||
|
swapFrame.at6_4 = bitReader.readBit();
|
||||||
|
swapFrame.tile2 = bitReader.readUnsigned(4);
|
||||||
|
swapFrame.soundRange = bitReader.readUnsigned(4);
|
||||||
|
swapFrame.surfaceSound = bitReader.readBit();
|
||||||
|
swapFrame.reserved = bitReader.readUnsigned(2);
|
||||||
|
*pFrame = swapFrame;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ByteSwapSFX(void *p)
|
||||||
|
{
|
||||||
|
SFX *pSFX = (SFX*)p;
|
||||||
|
pSFX->relVol = B_LITTLE32(pSFX->relVol);
|
||||||
|
pSFX->pitch = B_LITTLE32(pSFX->pitch);
|
||||||
|
pSFX->pitchRange = B_LITTLE32(pSFX->pitchRange);
|
||||||
|
pSFX->format = B_LITTLE32(pSFX->format);
|
||||||
|
pSFX->loopStart = B_LITTLE32(pSFX->loopStart);
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
h->ptr = NULL;
|
|
||||||
if (h->lockCount == 0)
|
|
||||||
{
|
|
||||||
RemoveMRU(h);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
h->lockCount = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Resource::Purge(void)
|
|
||||||
{
|
|
||||||
for (unsigned int i = 0; i < count; i++)
|
|
||||||
{
|
|
||||||
if (dict[i].ptr)
|
|
||||||
{
|
|
||||||
Flush((CACHENODE *)&dict[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DICTNODE **Resource::Probe(const char *fname, const char *type)
|
|
||||||
{
|
|
||||||
char name[BMAX_PATH];
|
|
||||||
dassert(indexName != NULL);
|
|
||||||
memset(name, 0, sizeof(name));
|
|
||||||
strcpy(name, type);
|
|
||||||
strcat(name, fname);
|
|
||||||
dassert(dict != NULL);
|
|
||||||
unsigned int hash = Bcrc32(name, strlen(name), 0) & (buffSize - 1);
|
|
||||||
unsigned int i = hash;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
if (!indexName[i])
|
|
||||||
{
|
|
||||||
return &indexName[i];
|
|
||||||
}
|
|
||||||
if (!strcmp((*indexName[i]).type, type)
|
|
||||||
&& !strcmp((*indexName[i]).name, fname))
|
|
||||||
{
|
|
||||||
return &indexName[i];
|
|
||||||
}
|
|
||||||
if (++i == buffSize)
|
|
||||||
{
|
|
||||||
i = 0;
|
|
||||||
}
|
|
||||||
} while (i != hash);
|
|
||||||
ThrowError("Linear probe failed to find match or unused node!");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
DICTNODE **Resource::Probe(unsigned int id, const char *type)
|
|
||||||
{
|
|
||||||
struct {
|
|
||||||
int id;
|
|
||||||
char type[BMAX_PATH];
|
|
||||||
} name;
|
|
||||||
dassert(indexName != NULL);
|
|
||||||
memset(&name, 0, sizeof(name));
|
|
||||||
strcpy(name.type, type);
|
|
||||||
name.id = id;
|
|
||||||
dassert(dict != NULL);
|
|
||||||
unsigned int hash = Bcrc32(&name, strlen(name.type)+sizeof(name.id), 0) & (buffSize - 1);
|
|
||||||
unsigned int i = hash;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
if (!indexId[i])
|
|
||||||
{
|
|
||||||
return &indexId[i];
|
|
||||||
}
|
|
||||||
if (!strcmp((*indexId[i]).type, type)
|
|
||||||
&& (*indexId[i]).id == id)
|
|
||||||
{
|
|
||||||
return &indexId[i];
|
|
||||||
}
|
|
||||||
if (++i == buffSize)
|
|
||||||
{
|
|
||||||
i = 0;
|
|
||||||
}
|
|
||||||
} while (i != hash);
|
|
||||||
ThrowError("Linear probe failed to find match or unused node!");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Resource::Reindex(void)
|
|
||||||
{
|
|
||||||
if (indexName)
|
|
||||||
{
|
|
||||||
Free(indexName);
|
|
||||||
}
|
|
||||||
indexName = (DICTNODE **)Alloc(buffSize * sizeof(DICTNODE*));
|
|
||||||
memset(indexName, 0, buffSize * sizeof(DICTNODE*));
|
|
||||||
for (unsigned int i = 0; i < count; i++)
|
|
||||||
{
|
|
||||||
DICTNODE **node = Probe(dict[i].name, dict[i].type);
|
|
||||||
*node = &dict[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (indexId)
|
|
||||||
{
|
|
||||||
Free(indexId);
|
|
||||||
}
|
|
||||||
indexId = (DICTNODE **)Alloc(buffSize * sizeof(DICTNODE*));
|
|
||||||
memset(indexId, 0, buffSize * sizeof(DICTNODE*));
|
|
||||||
for (unsigned int i = 0; i < count; i++)
|
|
||||||
{
|
|
||||||
if (dict[i].flags & DICT_ID)
|
|
||||||
{
|
|
||||||
DICTNODE **node = Probe(dict[i].id, dict[i].type);
|
|
||||||
*node = &dict[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Resource::Grow(void)
|
|
||||||
{
|
|
||||||
buffSize *= 2;
|
|
||||||
void *p = Alloc(buffSize * sizeof(DICTNODE));
|
|
||||||
memset(p, 0, buffSize * sizeof(DICTNODE));
|
|
||||||
memcpy(p, dict, count * sizeof(DICTNODE));
|
|
||||||
Free(dict);
|
|
||||||
dict = (DICTNODE*)p;
|
|
||||||
Reindex();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Resource::AddExternalResource(const char *name, const char *type, int id, int flags, const char *pzDirectory)
|
|
||||||
{
|
|
||||||
char name2[BMAX_PATH], type2[BMAX_PATH], filename[BMAX_PATH], path[BMAX_PATH];
|
|
||||||
|
|
||||||
if (Bstrlen(type) > 0)
|
|
||||||
Bsnprintf(filename, BMAX_PATH-1, "%s.%s", name, type);
|
|
||||||
else
|
|
||||||
Bsnprintf(filename, BMAX_PATH-1, "%s", name);
|
|
||||||
|
|
||||||
if (pzDirectory)
|
|
||||||
Bsnprintf(path, BMAX_PATH-1, "%s/%s", pzDirectory, filename);
|
|
||||||
else
|
|
||||||
Bstrncpy(path, filename, BMAX_PATH-1);
|
|
||||||
|
|
||||||
int fhandle = kopen4loadfrommod(filename, 0);
|
|
||||||
if (fhandle == -1)
|
|
||||||
return;
|
|
||||||
int size = kfilelength(fhandle);
|
|
||||||
kclose(fhandle);
|
|
||||||
strcpy(name2, name);
|
|
||||||
strcpy(type2, type);
|
|
||||||
Bstrupr(name2);
|
|
||||||
Bstrupr(type2);
|
|
||||||
dassert(dict != NULL);
|
|
||||||
DICTNODE **index = Probe(name2, type2);
|
|
||||||
dassert(index != NULL);
|
|
||||||
DICTNODE *node = *index;
|
|
||||||
if (node && (node->flags & DICT_EXTERNAL))
|
|
||||||
return;
|
|
||||||
if (!node)
|
|
||||||
{
|
|
||||||
if (2 * count >= buffSize)
|
|
||||||
{
|
|
||||||
Grow();
|
|
||||||
}
|
|
||||||
node = &dict[count++];
|
|
||||||
index = Probe(name2, type2);
|
|
||||||
*index = node;
|
|
||||||
if (node->type)
|
|
||||||
{
|
|
||||||
Free(node->type);
|
|
||||||
node->type = NULL;
|
|
||||||
}
|
|
||||||
if (node->name)
|
|
||||||
{
|
|
||||||
Free(node->name);
|
|
||||||
node->name = NULL;
|
|
||||||
}
|
|
||||||
if (node->path)
|
|
||||||
{
|
|
||||||
Free(node->path);
|
|
||||||
node->path = NULL;
|
|
||||||
}
|
|
||||||
int nTypeLength = strlen(type2);
|
|
||||||
int nNameLength = strlen(name2);
|
|
||||||
int nPathLength = strlen(path);
|
|
||||||
node->type = (char*)Alloc(nTypeLength+1);
|
|
||||||
node->name = (char*)Alloc(nNameLength+1);
|
|
||||||
node->path = (char*)Alloc(nPathLength+1);
|
|
||||||
strcpy(node->type, type2);
|
|
||||||
strcpy(node->name, name2);
|
|
||||||
strcpy(node->path, path);
|
|
||||||
}
|
|
||||||
node->size = size;
|
|
||||||
node->flags = DICT_EXTERNAL | flags;
|
|
||||||
node->buffer = NULL;
|
|
||||||
Flush(node);
|
|
||||||
if (id >= 0)
|
|
||||||
{
|
|
||||||
index = Probe(id, type2);
|
|
||||||
dassert(index != NULL);
|
|
||||||
DICTNODE *node = *index;
|
|
||||||
if (!node)
|
|
||||||
{
|
|
||||||
if (2 * count >= buffSize)
|
|
||||||
{
|
|
||||||
Grow();
|
|
||||||
}
|
|
||||||
node = &dict[count++];
|
|
||||||
index = Probe(id, type2);
|
|
||||||
*index = node;
|
|
||||||
}
|
|
||||||
if (node->type)
|
|
||||||
{
|
|
||||||
Free(node->type);
|
|
||||||
node->type = NULL;
|
|
||||||
}
|
|
||||||
if (node->name)
|
|
||||||
{
|
|
||||||
Free(node->name);
|
|
||||||
node->name = NULL;
|
|
||||||
}
|
|
||||||
if (node->path)
|
|
||||||
{
|
|
||||||
Free(node->path);
|
|
||||||
node->path = NULL;
|
|
||||||
}
|
|
||||||
int nTypeLength = strlen(type2);
|
|
||||||
int nNameLength = strlen(name2);
|
|
||||||
int nPathLength = strlen(path);
|
|
||||||
node->type = (char*)Alloc(nTypeLength+1);
|
|
||||||
node->name = (char*)Alloc(nNameLength+1);
|
|
||||||
node->path = (char*)Alloc(nPathLength+1);
|
|
||||||
strcpy(node->type, type2);
|
|
||||||
strcpy(node->name, name2);
|
|
||||||
strcpy(node->path, path);
|
|
||||||
node->id = id;
|
|
||||||
node->size = size;
|
|
||||||
node->flags = DICT_EXTERNAL | flags;
|
|
||||||
node->buffer = NULL;
|
|
||||||
Flush(node);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Resource::AddFromBuffer(const char* name, const char* type, char* data, int size, int id, int flags)
|
|
||||||
{
|
|
||||||
char name2[BMAX_PATH], type2[BMAX_PATH];
|
|
||||||
|
|
||||||
char *pHeapData = (char*)Alloc(size);
|
|
||||||
if (!pHeapData)
|
|
||||||
return;
|
|
||||||
Bmemcpy(pHeapData, data, size);
|
|
||||||
strcpy(name2, name);
|
|
||||||
strcpy(type2, type);
|
|
||||||
Bstrupr(name2);
|
|
||||||
Bstrupr(type2);
|
|
||||||
dassert(dict != NULL);
|
|
||||||
DICTNODE **index = Probe(name2, type2);
|
|
||||||
dassert(index != NULL);
|
|
||||||
DICTNODE *node = *index;
|
|
||||||
if (!node)
|
|
||||||
{
|
|
||||||
if (2 * count >= buffSize)
|
|
||||||
{
|
|
||||||
Grow();
|
|
||||||
}
|
|
||||||
node = &dict[count++];
|
|
||||||
index = Probe(name2, type2);
|
|
||||||
*index = node;
|
|
||||||
if (node->type)
|
|
||||||
{
|
|
||||||
Free(node->type);
|
|
||||||
node->type = NULL;
|
|
||||||
}
|
|
||||||
if (node->name)
|
|
||||||
{
|
|
||||||
Free(node->name);
|
|
||||||
node->name = NULL;
|
|
||||||
}
|
|
||||||
if (node->path)
|
|
||||||
{
|
|
||||||
Free(node->path);
|
|
||||||
node->path = NULL;
|
|
||||||
}
|
|
||||||
int nTypeLength = strlen(type2);
|
|
||||||
int nNameLength = strlen(name2);
|
|
||||||
node->type = (char*)Alloc(nTypeLength+1);
|
|
||||||
node->name = (char*)Alloc(nNameLength+1);
|
|
||||||
strcpy(node->type, type2);
|
|
||||||
strcpy(node->name, name2);
|
|
||||||
}
|
|
||||||
node->size = size;
|
|
||||||
node->flags = DICT_BUFFER | flags;
|
|
||||||
node->buffer = pHeapData;
|
|
||||||
Flush(node);
|
|
||||||
if (id >= 0)
|
|
||||||
{
|
|
||||||
index = Probe(id, type2);
|
|
||||||
dassert(index != NULL);
|
|
||||||
DICTNODE *node = *index;
|
|
||||||
if (!node)
|
|
||||||
{
|
|
||||||
if (2 * count >= buffSize)
|
|
||||||
{
|
|
||||||
Grow();
|
|
||||||
}
|
|
||||||
node = &dict[count++];
|
|
||||||
index = Probe(id, type2);
|
|
||||||
*index = node;
|
|
||||||
}
|
|
||||||
if (node->type)
|
|
||||||
{
|
|
||||||
Free(node->type);
|
|
||||||
node->type = NULL;
|
|
||||||
}
|
|
||||||
if (node->name)
|
|
||||||
{
|
|
||||||
Free(node->name);
|
|
||||||
node->name = NULL;
|
|
||||||
}
|
|
||||||
if (node->path)
|
|
||||||
{
|
|
||||||
Free(node->path);
|
|
||||||
node->path = NULL;
|
|
||||||
}
|
|
||||||
int nTypeLength = strlen(type2);
|
|
||||||
int nNameLength = strlen(name2);
|
|
||||||
node->type = (char*)Alloc(nTypeLength+1);
|
|
||||||
node->name = (char*)Alloc(nNameLength+1);
|
|
||||||
strcpy(node->type, type2);
|
|
||||||
strcpy(node->name, name2);
|
|
||||||
node->id = id;
|
|
||||||
node->size = size;
|
|
||||||
node->flags = DICT_BUFFER | flags;
|
|
||||||
node->buffer = pHeapData;
|
|
||||||
Flush(node);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void *Resource::Alloc(int nSize)
|
|
||||||
{
|
|
||||||
#ifdef USE_QHEAP
|
|
||||||
dassert(heap != NULL);
|
|
||||||
dassert(nSize != 0);
|
|
||||||
void *p = heap->Alloc(nSize);
|
|
||||||
if (p)
|
|
||||||
{
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
for (CACHENODE *node = purgeHead.next; node != &purgeHead; node = node->next)
|
|
||||||
{
|
|
||||||
dassert(node->lockCount == 0);
|
|
||||||
dassert(node->ptr != NULL);
|
|
||||||
int nFree = heap->Free(node->ptr);
|
|
||||||
node->ptr = NULL;
|
|
||||||
RemoveMRU(node);
|
|
||||||
if (nSize <= nFree)
|
|
||||||
{
|
|
||||||
p = Alloc(nSize);
|
|
||||||
dassert(p != NULL);
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ThrowError("Out of memory!");
|
|
||||||
return NULL;
|
|
||||||
#else
|
|
||||||
dassert(nSize != 0);
|
|
||||||
void* p = new char[nSize];
|
|
||||||
if (p)
|
|
||||||
{
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
for (CACHENODE *node = purgeHead.next; node != &purgeHead; node = node->next)
|
|
||||||
{
|
|
||||||
dassert(node->lockCount == 0);
|
|
||||||
dassert(node->ptr != NULL);
|
|
||||||
delete[] (char*)node->ptr;
|
|
||||||
node->ptr = NULL;
|
|
||||||
RemoveMRU(node);
|
|
||||||
p = new char[nSize];
|
|
||||||
if (p)
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
ThrowError("Out of memory!");
|
|
||||||
return NULL;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void Resource::Free(void *p)
|
|
||||||
{
|
|
||||||
#ifdef USE_QHEAP
|
|
||||||
dassert(heap != NULL);
|
|
||||||
dassert(p != NULL);
|
|
||||||
heap->Free(p);
|
|
||||||
#else
|
|
||||||
dassert(p != NULL);
|
|
||||||
delete[] (char*)p;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
DICTNODE *Resource::Lookup(const char *name, const char *type)
|
|
||||||
{
|
|
||||||
char name2[BMAX_PATH], type2[BMAX_PATH];
|
|
||||||
dassert(name != NULL);
|
|
||||||
dassert(type != NULL);
|
|
||||||
//if (strlen(name) > 8 || strlen(type) > 3) return NULL;
|
|
||||||
// Try to load external resource first
|
|
||||||
AddExternalResource(name, type);
|
|
||||||
strcpy(name2, name);
|
|
||||||
strcpy(type2, type);
|
|
||||||
Bstrupr(type2);
|
|
||||||
Bstrupr(name2);
|
|
||||||
return *Probe(name2, type2);
|
|
||||||
}
|
|
||||||
|
|
||||||
DICTNODE *Resource::Lookup(unsigned int id, const char *type)
|
|
||||||
{
|
|
||||||
char type2[BMAX_PATH];
|
|
||||||
dassert(type != NULL);
|
|
||||||
//if (strlen(type) > 3) return NULL;
|
|
||||||
strcpy(type2, type);
|
|
||||||
Bstrupr(type2);
|
|
||||||
return *Probe(id, type2);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Resource::Read(DICTNODE *n)
|
|
||||||
{
|
|
||||||
dassert(n != NULL);
|
|
||||||
Read(n, n->ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Resource::Read(DICTNODE *n, void *p)
|
|
||||||
{
|
|
||||||
char filename[BMAX_PATH];
|
|
||||||
dassert(n != NULL);
|
|
||||||
if (n->flags & DICT_EXTERNAL)
|
|
||||||
{
|
|
||||||
if (n->path)
|
|
||||||
Bstrncpy(filename, n->path, BMAX_PATH-1);
|
|
||||||
else
|
|
||||||
Bsnprintf(filename, BMAX_PATH-1, "%s.%s", n->name, n->type);
|
|
||||||
int fhandle = kopen4loadfrommod(filename, 0);
|
|
||||||
if (fhandle == -1 || (uint32_t)kread(fhandle, p, n->size) != n->size)
|
|
||||||
{
|
|
||||||
ThrowError("Error reading external resource (%i)", errno);
|
|
||||||
}
|
|
||||||
kclose(fhandle);
|
|
||||||
}
|
|
||||||
else if (n->flags & DICT_BUFFER)
|
|
||||||
{
|
|
||||||
Bmemcpy(p, n->buffer, n->size);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int r = klseek(handle, n->offset, SEEK_SET);
|
|
||||||
if (r == -1)
|
|
||||||
{
|
|
||||||
ThrowError("Error seeking to resource!");
|
|
||||||
}
|
|
||||||
if ((uint32_t)kread(handle, p, n->size) != n->size)
|
|
||||||
{
|
|
||||||
ThrowError("Error loading resource!");
|
|
||||||
}
|
|
||||||
if (n->flags & DICT_CRYPT)
|
|
||||||
{
|
|
||||||
int size;
|
|
||||||
if (n->size > 0x100)
|
|
||||||
{
|
|
||||||
size = 0x100;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
size = n->size;
|
|
||||||
}
|
|
||||||
Crypt(n->ptr, size, 0);
|
|
||||||
}
|
|
||||||
#if B_BIG_ENDIAN == 1
|
|
||||||
if (!Bstrcmp(n->type, "QAV"))
|
|
||||||
{
|
|
||||||
QAV *qav = (QAV*)p;
|
|
||||||
qav->nFrames = B_LITTLE32(qav->nFrames);
|
|
||||||
qav->ticksPerFrame = B_LITTLE32(qav->ticksPerFrame);
|
|
||||||
qav->at10 = B_LITTLE32(qav->at10);
|
|
||||||
qav->x = B_LITTLE32(qav->x);
|
|
||||||
qav->y = B_LITTLE32(qav->y);
|
|
||||||
qav->nSprite = B_LITTLE32(qav->nSprite);
|
|
||||||
for (int i = 0; i < qav->nFrames; i++)
|
|
||||||
{
|
|
||||||
FRAMEINFO *pFrame = &qav->frames[i];
|
|
||||||
SOUNDINFO *pSound = &pFrame->sound;
|
|
||||||
pFrame->nCallbackId = B_LITTLE32(pFrame->nCallbackId);
|
|
||||||
pSound->sound = B_LITTLE32(pSound->sound);
|
|
||||||
for (int j = 0; j < 8; j++)
|
|
||||||
{
|
|
||||||
TILE_FRAME *pTile = &pFrame->tiles[j];
|
|
||||||
pTile->picnum = B_LITTLE32(pTile->picnum);
|
|
||||||
pTile->x = B_LITTLE32(pTile->x);
|
|
||||||
pTile->y = B_LITTLE32(pTile->y);
|
|
||||||
pTile->z = B_LITTLE32(pTile->z);
|
|
||||||
pTile->stat = B_LITTLE32(pTile->stat);
|
|
||||||
pTile->angle = B_LITTLE16(pTile->angle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (!Bstrcmp(n->type, "SEQ"))
|
|
||||||
{
|
|
||||||
Seq *pSeq = (Seq*)p;
|
|
||||||
pSeq->version = B_LITTLE16(pSeq->version);
|
|
||||||
pSeq->nFrames = B_LITTLE16(pSeq->nFrames);
|
|
||||||
pSeq->at8 = B_LITTLE16(pSeq->at8);
|
|
||||||
pSeq->ata = B_LITTLE16(pSeq->ata);
|
|
||||||
pSeq->atc = B_LITTLE32(pSeq->atc);
|
|
||||||
for (int i = 0; i < pSeq->nFrames; i++)
|
|
||||||
{
|
|
||||||
SEQFRAME *pFrame = &pSeq->frames[i];
|
|
||||||
BitReader bitReader((char *)pFrame, sizeof(SEQFRAME));
|
|
||||||
SEQFRAME swapFrame;
|
|
||||||
swapFrame.tile = bitReader.readUnsigned(12);
|
|
||||||
swapFrame.at1_4 = bitReader.readBit();
|
|
||||||
swapFrame.at1_5 = bitReader.readBit();
|
|
||||||
swapFrame.at1_6 = bitReader.readBit();
|
|
||||||
swapFrame.at1_7 = bitReader.readBit();
|
|
||||||
swapFrame.at2_0 = bitReader.readUnsigned(8);
|
|
||||||
swapFrame.at3_0 = bitReader.readUnsigned(8);
|
|
||||||
swapFrame.at4_0 = bitReader.readSigned(8);
|
|
||||||
swapFrame.at5_0 = bitReader.readUnsigned(5);
|
|
||||||
swapFrame.at5_5 = bitReader.readBit();
|
|
||||||
swapFrame.at5_6 = bitReader.readBit();
|
|
||||||
swapFrame.at5_7 = bitReader.readBit();
|
|
||||||
swapFrame.at6_0 = bitReader.readBit();
|
|
||||||
swapFrame.at6_1 = bitReader.readBit();
|
|
||||||
swapFrame.at6_2 = bitReader.readBit();
|
|
||||||
swapFrame.at6_3 = bitReader.readBit();
|
|
||||||
swapFrame.at6_4 = bitReader.readBit();
|
|
||||||
swapFrame.tile2 = bitReader.readUnsigned(4);
|
|
||||||
swapFrame.soundRange = bitReader.readUnsigned(4);
|
|
||||||
swapFrame.surfaceSound = bitReader.readBit();
|
|
||||||
swapFrame.reserved = bitReader.readUnsigned(2);
|
|
||||||
*pFrame = swapFrame;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (!Bstrcmp(n->type, "SFX"))
|
|
||||||
{
|
|
||||||
SFX *pSFX = (SFX*)p;
|
|
||||||
pSFX->relVol = B_LITTLE32(pSFX->relVol);
|
|
||||||
pSFX->pitch = B_LITTLE32(pSFX->pitch);
|
|
||||||
pSFX->pitchRange = B_LITTLE32(pSFX->pitchRange);
|
|
||||||
pSFX->format = B_LITTLE32(pSFX->format);
|
|
||||||
pSFX->loopStart = B_LITTLE32(pSFX->loopStart);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void *Resource::Load(DICTNODE *h)
|
|
||||||
{
|
|
||||||
dassert(h != NULL);
|
|
||||||
if (h->ptr)
|
|
||||||
{
|
|
||||||
if (!h->lockCount)
|
|
||||||
{
|
|
||||||
RemoveMRU(h);
|
|
||||||
|
|
||||||
h->prev = purgeHead.prev;
|
|
||||||
purgeHead.prev->next = h;
|
|
||||||
h->next = &purgeHead;
|
|
||||||
purgeHead.prev = h;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
h->ptr = Alloc(h->size);
|
|
||||||
Read(h);
|
|
||||||
|
|
||||||
h->prev = purgeHead.prev;
|
|
||||||
purgeHead.prev->next = h;
|
|
||||||
h->next = &purgeHead;
|
|
||||||
purgeHead.prev = h;
|
|
||||||
}
|
|
||||||
return h->ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *Resource::Load(DICTNODE *h, void *p)
|
|
||||||
{
|
|
||||||
dassert(h != NULL);
|
|
||||||
if (p)
|
|
||||||
{
|
|
||||||
Read(h, p);
|
|
||||||
}
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *Resource::Lock(DICTNODE *h)
|
|
||||||
{
|
|
||||||
dassert(h != NULL);
|
|
||||||
if (h->ptr)
|
|
||||||
{
|
|
||||||
if (h->lockCount == 0)
|
|
||||||
{
|
|
||||||
RemoveMRU(h);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
h->ptr = Alloc(h->size);
|
|
||||||
Read(h);
|
|
||||||
}
|
|
||||||
|
|
||||||
h->lockCount++;
|
|
||||||
return h->ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Resource::Unlock(DICTNODE *h)
|
|
||||||
{
|
|
||||||
dassert(h != NULL);
|
|
||||||
dassert(h->ptr != NULL);
|
|
||||||
if (h->lockCount > 0)
|
|
||||||
{
|
|
||||||
h->lockCount--;
|
|
||||||
if (h->lockCount == 0)
|
|
||||||
{
|
|
||||||
h->prev = purgeHead.prev;
|
|
||||||
purgeHead.prev->next = h;
|
|
||||||
h->next = &purgeHead;
|
|
||||||
purgeHead.prev = h;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Resource::Crypt(void *p, int length, unsigned short key)
|
|
||||||
{
|
|
||||||
char *cp = (char*)p;
|
|
||||||
for (int i = 0; i < length; i++, key++)
|
|
||||||
{
|
|
||||||
cp[i] ^= (key >> 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Resource::RemoveMRU(CACHENODE *h)
|
|
||||||
{
|
|
||||||
h->prev->next = h->next;
|
|
||||||
h->next->prev = h->prev;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Resource::FNAddFiles(fnlist_t * fnlist, const char *pattern)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void Resource::PurgeCache(void)
|
|
||||||
{
|
|
||||||
#ifndef USE_QHEAP
|
|
||||||
for (CACHENODE *node = purgeHead.next; node != &purgeHead; node = node->next)
|
|
||||||
{
|
|
||||||
DICTNODE *pDict = (DICTNODE*)node;
|
|
||||||
if (!(pDict->flags & DICT_LOAD))
|
|
||||||
{
|
|
||||||
dassert(pDict->lockCount == 0);
|
|
||||||
dassert(pDict->ptr != NULL);
|
|
||||||
Free(pDict->ptr);
|
|
||||||
pDict->ptr = NULL;
|
|
||||||
RemoveMRU(pDict);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void Resource::PrecacheSounds(void)
|
|
||||||
{
|
|
||||||
for (unsigned int i = 0; i < count; i++)
|
|
||||||
{
|
|
||||||
DICTNODE *pNode = &dict[i];
|
|
||||||
if ((!strcmp(pNode->type, "RAW") || !strcmp(pNode->type, "SFX")) && !pNode->ptr)
|
|
||||||
{
|
|
||||||
Load(pNode);
|
|
||||||
gameHandleEvents();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Resource::RemoveNode(DICTNODE* pNode)
|
|
||||||
{
|
|
||||||
Flush(pNode);
|
|
||||||
if (pNode->name)
|
|
||||||
{
|
|
||||||
Free(pNode->name);
|
|
||||||
pNode->name = NULL;
|
|
||||||
}
|
|
||||||
if (pNode->type)
|
|
||||||
{
|
|
||||||
Free(pNode->type);
|
|
||||||
pNode->type = NULL;
|
|
||||||
}
|
|
||||||
if (pNode->path)
|
|
||||||
{
|
|
||||||
Free(pNode->path);
|
|
||||||
pNode->path = NULL;
|
|
||||||
}
|
|
||||||
*pNode = dict[--count];
|
|
||||||
Bmemset(&dict[count], 0, sizeof(DICTNODE));
|
|
||||||
if (pNode->ptr && !pNode->lockCount)
|
|
||||||
{
|
|
||||||
pNode->prev->next = pNode;
|
|
||||||
pNode->next->prev = pNode;
|
|
||||||
}
|
|
||||||
Reindex();
|
|
||||||
}
|
|
||||||
|
|
||||||
END_BLD_NS
|
END_BLD_NS
|
||||||
|
|
|
@ -64,8 +64,6 @@ void qloadvoxel(int32_t nVoxel)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CACHENODE tileNode[kMaxTiles];
|
|
||||||
|
|
||||||
bool artLoaded = false;
|
bool artLoaded = false;
|
||||||
int nTileFiles = 0;
|
int nTileFiles = 0;
|
||||||
|
|
||||||
|
|
138
source/common/filesystem/cache.cpp
Normal file
138
source/common/filesystem/cache.cpp
Normal file
|
@ -0,0 +1,138 @@
|
||||||
|
CACHENODE Resource::purgeHead = { NULL, &purgeHead, &purgeHead, 0 };
|
||||||
|
|
||||||
|
|
||||||
|
void *Resource::Lock(DICTNODE *h)
|
||||||
|
{
|
||||||
|
dassert(h != NULL);
|
||||||
|
if (h->ptr)
|
||||||
|
{
|
||||||
|
if (h->lockCount == 0)
|
||||||
|
{
|
||||||
|
RemoveMRU(h);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
h->ptr = Alloc(h->size);
|
||||||
|
Read(h);
|
||||||
|
}
|
||||||
|
|
||||||
|
h->lockCount++;
|
||||||
|
return h->ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Resource::Unlock(DICTNODE *h)
|
||||||
|
{
|
||||||
|
dassert(h != NULL);
|
||||||
|
dassert(h->ptr != NULL);
|
||||||
|
if (h->lockCount > 0)
|
||||||
|
{
|
||||||
|
h->lockCount--;
|
||||||
|
if (h->lockCount == 0)
|
||||||
|
{
|
||||||
|
h->prev = purgeHead.prev;
|
||||||
|
purgeHead.prev->next = h;
|
||||||
|
h->next = &purgeHead;
|
||||||
|
purgeHead.prev = h;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Resource::Flush(CACHENODE *h)
|
||||||
|
{
|
||||||
|
if (h->ptr)
|
||||||
|
{
|
||||||
|
#ifdef USE_QHEAP
|
||||||
|
heap->Free(h->ptr);
|
||||||
|
#else
|
||||||
|
delete[] (char*)h->ptr;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
h->ptr = NULL;
|
||||||
|
if (h->lockCount == 0)
|
||||||
|
{
|
||||||
|
RemoveMRU(h);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
h->lockCount = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Resource::Purge(void)
|
||||||
|
{
|
||||||
|
for (unsigned int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
if (dict[i].ptr)
|
||||||
|
{
|
||||||
|
Flush((CACHENODE *)&dict[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Resource::PurgeCache(void)
|
||||||
|
{
|
||||||
|
#ifndef USE_QHEAP
|
||||||
|
for (CACHENODE *node = purgeHead.next; node != &purgeHead; node = node->next)
|
||||||
|
{
|
||||||
|
DICTNODE *pDict = (DICTNODE*)node;
|
||||||
|
if (!(pDict->flags & DICT_LOAD))
|
||||||
|
{
|
||||||
|
dassert(pDict->lockCount == 0);
|
||||||
|
dassert(pDict->ptr != NULL);
|
||||||
|
Free(pDict->ptr);
|
||||||
|
pDict->ptr = NULL;
|
||||||
|
RemoveMRU(pDict);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void *Resource::Load(DICTNODE *h)
|
||||||
|
{
|
||||||
|
dassert(h != NULL);
|
||||||
|
if (h->ptr)
|
||||||
|
{
|
||||||
|
if (!h->lockCount)
|
||||||
|
{
|
||||||
|
RemoveMRU(h);
|
||||||
|
|
||||||
|
h->prev = purgeHead.prev;
|
||||||
|
purgeHead.prev->next = h;
|
||||||
|
h->next = &purgeHead;
|
||||||
|
purgeHead.prev = h;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
h->ptr = Alloc(h->size);
|
||||||
|
Read(h);
|
||||||
|
|
||||||
|
h->prev = purgeHead.prev;
|
||||||
|
purgeHead.prev->next = h;
|
||||||
|
h->next = &purgeHead;
|
||||||
|
purgeHead.prev = h;
|
||||||
|
}
|
||||||
|
return h->ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Resource::RemoveMRU(CACHENODE *h)
|
||||||
|
{
|
||||||
|
h->prev->next = h->next;
|
||||||
|
h->next->prev = h->prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Resource::PrecacheSounds(void)
|
||||||
|
{
|
||||||
|
for (unsigned int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
DICTNODE *pNode = &dict[i];
|
||||||
|
if ((!strcmp(pNode->type, "RAW") || !strcmp(pNode->type, "SFX")) && !pNode->ptr)
|
||||||
|
{
|
||||||
|
Load(pNode);
|
||||||
|
gameHandleEvents();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -79,9 +79,14 @@ FileSystem::~FileSystem ()
|
||||||
|
|
||||||
void FileSystem::DeleteAll ()
|
void FileSystem::DeleteAll ()
|
||||||
{
|
{
|
||||||
FileInfo.Clear();
|
|
||||||
NumEntries = 0;
|
NumEntries = 0;
|
||||||
|
|
||||||
|
// explicitly delete all manually added lumps.
|
||||||
|
for (auto &frec : FileInfo)
|
||||||
|
{
|
||||||
|
if (frec.rfnum == -1) delete frec.lump;
|
||||||
|
}
|
||||||
|
FileInfo.Clear();
|
||||||
for (int i = Files.Size() - 1; i >= 0; --i)
|
for (int i = Files.Size() - 1; i >= 0; --i)
|
||||||
{
|
{
|
||||||
delete Files[i];
|
delete Files[i];
|
||||||
|
@ -428,6 +433,26 @@ void FileSystem::InitHashChains (void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FileSystem::AddLump(FResourceLump *lump)
|
||||||
|
{
|
||||||
|
FileRecord rec = { -1, lump};
|
||||||
|
FileInfo.Push(rec);
|
||||||
|
|
||||||
|
for (int l = 0; l < NumLookupModes; l++)
|
||||||
|
{
|
||||||
|
int hash;
|
||||||
|
if (l != (int)ELookupMode::IdWithType && lump->LumpName[l] != NAME_None)
|
||||||
|
{
|
||||||
|
hash = int(lump->LumpName[l]) % NumEntries;
|
||||||
|
}
|
||||||
|
else if (lump->ResourceId > 0)
|
||||||
|
{
|
||||||
|
hash = int(lump->ResourceId) % NumEntries;
|
||||||
|
}
|
||||||
|
NextFileIndex[l][hash] = FirstFileIndex[l][hash];
|
||||||
|
FirstFileIndex[l][hash] = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
|
@ -649,6 +674,27 @@ const void *FileSystem::Get(int lump)
|
||||||
return lump->Get();
|
return lump->Get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// Stand-ins for Blood's resource class
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
void *FileSystem::Lock(FResourceLump *lump)
|
||||||
|
{
|
||||||
|
if (lump) return lump->Lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileSystem::Unlock(FResourceLump *lump)
|
||||||
|
{
|
||||||
|
if (lump) return lump->Unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileSystem::Load(FResourceLump *lump)
|
||||||
|
{
|
||||||
|
if (lump) return lump->Get();
|
||||||
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
// ReadFile - variant 2
|
// ReadFile - variant 2
|
||||||
|
@ -801,6 +847,95 @@ const char *FileSystem::GetResourceFileFullName (int rfnum) const noexcept
|
||||||
return Files[rfnum]->FileName;
|
return Files[rfnum]->FileName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// AddFromBuffer
|
||||||
|
//
|
||||||
|
// Adds an in-memory resource to the virtual directory
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
void FileSystem::AddFromBuffer(const char* name, const char* type, char* data, int size, int id, int flags)
|
||||||
|
{
|
||||||
|
FStringf fullname("%s.%s", name, type);
|
||||||
|
auto newlump = new FMemoryLump(data, size);
|
||||||
|
newlump->LumpNameSetup(fullname);
|
||||||
|
newlump->ResourceId = id;
|
||||||
|
AddLump(newlump);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// Read
|
||||||
|
//
|
||||||
|
// Reads lump into buffer (simulate Blood interface)
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
void FileSystem::Read(FResourceLump *n, void *p)
|
||||||
|
{
|
||||||
|
if (!n || !p) return;
|
||||||
|
auto r = n->Get();
|
||||||
|
memcpy(p, r, n->Size());
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// Blood style lookup functions
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
FResourceLump *FileSystem::Lookup(const char *name, const char *type)
|
||||||
|
{
|
||||||
|
FStringf fname("%s.%s", name, type);
|
||||||
|
auto lump = FindFile(fname);
|
||||||
|
if (lump >= 0) return FileInfo[lump].lump;
|
||||||
|
}
|
||||||
|
|
||||||
|
FResourceLump *FileSystem::Lookup(unsigned int id, const char *type)
|
||||||
|
{
|
||||||
|
auto lump = FindResource(id, type);
|
||||||
|
auto lump = FindFile(fname);
|
||||||
|
if (lump >= 0) return FileInfo[lump].lump;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// Clones an existing resource with different properties
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
void FileSystem::AddExternalResource(const char *name, const char *type, int id, int flags, const char *pzDirectory)
|
||||||
|
{
|
||||||
|
FString name2, type2, filename, path;
|
||||||
|
|
||||||
|
if (strlen(type) > 0)
|
||||||
|
filename.Format("%s.%s", name, type);
|
||||||
|
else
|
||||||
|
filename.Format("%s", name);
|
||||||
|
|
||||||
|
if (pzDirectory)
|
||||||
|
path.Format("%s/%s", pzDirectory, filename);
|
||||||
|
else
|
||||||
|
path = filename;
|
||||||
|
|
||||||
|
// The old code said 'filename' and ignored the path, this looked like a bug.
|
||||||
|
auto lump = FindFile(path);
|
||||||
|
if (lump < 0) return; // Does not exist.
|
||||||
|
|
||||||
|
// Check if a lump with this name already exists.
|
||||||
|
// Blood does not allow re-replacing external resources.
|
||||||
|
auto prevlump = FindFile(filename);
|
||||||
|
if (prevlump >= 0 && FileInfo[prevlump].rfnum == -1) return;
|
||||||
|
|
||||||
|
// Create a clone of the resource to give it new lookup properties.
|
||||||
|
auto newlump = new FClonedLump(FileInfo[lump].lump);
|
||||||
|
newlump->LumpNameSetup(filename);
|
||||||
|
newlump->ResourceId = id;
|
||||||
|
if (flags & DICT_LOCK) newlump->Lock();
|
||||||
|
else if (flags & DICT_LOAD) newlump->Get();
|
||||||
|
AddLump(newlump);
|
||||||
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
|
|
|
@ -49,6 +49,11 @@ struct FolderEntry
|
||||||
unsigned lumpnum;
|
unsigned lumpnum;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum DICTFLAGS {
|
||||||
|
DICT_LOAD = 4,
|
||||||
|
DICT_LOCK = 8,
|
||||||
|
};
|
||||||
|
|
||||||
enum class ELookupMode // Todo: Merge with FResourceLump::ENameType
|
enum class ELookupMode // Todo: Merge with FResourceLump::ENameType
|
||||||
{
|
{
|
||||||
FullName,
|
FullName,
|
||||||
|
@ -94,6 +99,8 @@ public:
|
||||||
int FindResource (int resid, const char *type, int filenum = -1) const noexcept;
|
int FindResource (int resid, const char *type, int filenum = -1) const noexcept;
|
||||||
int GetResource (int resid, const char *type, int filenum = -1) const; // Like FindFile, but throws an exception when it cannot find what it looks for.
|
int GetResource (int resid, const char *type, int filenum = -1) const; // Like FindFile, but throws an exception when it cannot find what it looks for.
|
||||||
|
|
||||||
|
void AddFromBuffer(const char* name, const char* type, char* data, int size, int id, int flags);
|
||||||
|
|
||||||
|
|
||||||
TArray<uint8_t> GetFileData(int file, int pad = 0); // reads file into a writable buffer and optionally adds some padding at the end. (FileData isn't writable!)
|
TArray<uint8_t> GetFileData(int file, int pad = 0); // reads file into a writable buffer and optionally adds some padding at the end. (FileData isn't writable!)
|
||||||
FileData ReadFile (int file);
|
FileData ReadFile (int file);
|
||||||
|
@ -103,6 +110,16 @@ public:
|
||||||
void Unlock(bool mayfree = false);
|
void Unlock(bool mayfree = false);
|
||||||
void *Get(int lump);
|
void *Get(int lump);
|
||||||
|
|
||||||
|
// These are designed to be stand-ins for Blood's resource class.
|
||||||
|
static void *Lock(FResourceLump *lump);
|
||||||
|
static void Unlock(FResourceLump *lump);
|
||||||
|
static void *Load(FResourceLump *lump);
|
||||||
|
static void Read(FResourceLump *lump) { Load(lump); }
|
||||||
|
static void Read(FResourceLump *n, void *p);
|
||||||
|
FResourceLump *Lookup(const char *name, const char *type);
|
||||||
|
FResourceLump *Lookup(unsigned int id, const char *type);
|
||||||
|
void AddExternalResource(const char *name, const char *type, int id, int flags, const char *pzDirectory);
|
||||||
|
|
||||||
FileReader OpenFileReader(int file); // opens a reader that redirects to the containing file's one.
|
FileReader OpenFileReader(int file); // opens a reader that redirects to the containing file's one.
|
||||||
FileReader ReopenFileReader(int file, bool alwayscache = false); // opens an independent reader.
|
FileReader ReopenFileReader(int file, bool alwayscache = false); // opens an independent reader.
|
||||||
|
|
||||||
|
@ -138,7 +155,7 @@ protected:
|
||||||
uint32_t *NextFileIndex[NumLookupModes];
|
uint32_t *NextFileIndex[NumLookupModes];
|
||||||
|
|
||||||
uint32_t NumFiles = 0; // Not necessarily the same as FileInfo.Size()
|
uint32_t NumFiles = 0; // Not necessarily the same as FileInfo.Size()
|
||||||
uint32_t NumEntries;
|
uint32_t NumEntries; // Hash modulus. Can be smaller than NumFiles if things get added at run time.
|
||||||
|
|
||||||
void InitHashChains (); // [RH] Set up the lumpinfo hashing
|
void InitHashChains (); // [RH] Set up the lumpinfo hashing
|
||||||
|
|
||||||
|
|
|
@ -74,9 +74,9 @@ struct FResourceLump
|
||||||
void LumpNameSetup(FString iname);
|
void LumpNameSetup(FString iname);
|
||||||
virtual FCompressedBuffer GetRawData();
|
virtual FCompressedBuffer GetRawData();
|
||||||
|
|
||||||
void *Lock(); // validates the cache and increases the refcount.
|
virtual void *Lock(); // validates the cache and increases the refcount.
|
||||||
void Unlock(bool freeunrefd = false); // recreases the refcount and optionally frees the buffer
|
virtual void Unlock(bool freeunrefd = false); // recreases the refcount and optionally frees the buffer
|
||||||
void *Get(); // validates the cache and returns a pointer without locking
|
virtual void *Get(); // validates the cache and returns a pointer without locking
|
||||||
|
|
||||||
// Wrappers for emulating Blood's resource system
|
// Wrappers for emulating Blood's resource system
|
||||||
unsigned Size() const{ return LumpSize; }
|
unsigned Size() const{ return LumpSize; }
|
||||||
|
@ -165,6 +165,33 @@ struct FExternalLump : public FResourceLump
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct FMemoryLump : public FResourceLump
|
||||||
|
{
|
||||||
|
FMemoryLump(const void *data, int length)
|
||||||
|
{
|
||||||
|
Cache.Resize(length);
|
||||||
|
memcpy(Cache.Data(), data, length);
|
||||||
|
}
|
||||||
|
virtual int ValidateCache() override
|
||||||
|
{
|
||||||
|
RefCount = INT_MAX / 2; // Make sure it never counts down to 0 by resetting it to something high each time it is used.
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct FClonedLump : public FResourceLump
|
||||||
|
{
|
||||||
|
FResourceLump *parent;
|
||||||
|
FClonedLump(FResourceLump *lump)
|
||||||
|
{
|
||||||
|
parent = lump;
|
||||||
|
}
|
||||||
|
void *Lock() { return parent->Lock(); }
|
||||||
|
void Unlock(bool mayfree) override { parent->Unlock(mayfree); }
|
||||||
|
void *Get() { return parent->Get(); }
|
||||||
|
void ValidateCache() override { parent->ValidateCache(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue