mirror of
https://github.com/ZDoom/raze-gles.git
synced 2024-12-25 19:20:46 +00:00
891 lines
24 KiB
C++
891 lines
24 KiB
C++
// "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman
|
|
// Ken Silverman's official web site: "http://www.advsys.net/ken"
|
|
// See the included license file "BUILDLIC.TXT" for license info.
|
|
//
|
|
// This file has been modified from Ken Silverman's original release
|
|
// by Jonathon Fowler (jf@jonof.id.au)
|
|
// by the EDuke32 team (development@voidpoint.com)
|
|
|
|
#include "compat.h"
|
|
#include "build.h"
|
|
#include "baselayer.h"
|
|
#include "engine_priv.h"
|
|
#include "cache1d.h"
|
|
#include "lz4.h"
|
|
#include "crc32.h"
|
|
|
|
#include "vfs.h"
|
|
|
|
void *pic = NULL;
|
|
|
|
// The tile file number (tilesXXX <- this) of each tile:
|
|
// 0 <= . < MAXARTFILES_BASE: tile is in a "base" ART file
|
|
// MAXARTFILES_BASE <= . < MAXARTFILES_TOTAL: tile is in a map-specific ART file
|
|
static uint8_t tilefilenum[MAXTILES];
|
|
EDUKE32_STATIC_ASSERT(MAXARTFILES_TOTAL <= 256);
|
|
|
|
static int32_t tilefileoffs[MAXTILES];
|
|
|
|
// Backup tilefilenum[] and tilefileoffs[]. These get allocated only when
|
|
// necessary (have per-map ART files).
|
|
static uint8_t *g_bakTileFileNum;
|
|
static int32_t *g_bakTileFileOffs;
|
|
static vec2_16_t *g_bakTileSiz;
|
|
static char *g_bakPicSiz;
|
|
static char *g_bakWalock;
|
|
static intptr_t *g_bakWaloff;
|
|
static picanm_t *g_bakPicAnm;
|
|
static char * g_bakFakeTile;
|
|
static char ** g_bakFakeTileData;
|
|
// NOTE: picsiz[] is not backed up, but recalculated when necessary.
|
|
|
|
//static int32_t artsize = 0;
|
|
static int32_t cachesize = 0;
|
|
|
|
static char artfilename[BMAX_PATH];
|
|
static char artfilenameformat[BMAX_PATH];
|
|
static char mapartfilename[BMAX_PATH]; // map-specific ART file name
|
|
static int32_t mapartfnXXofs; // byte offset to 'XX' (the number part) in the above
|
|
static int32_t artfilnum, artfilplc;
|
|
static buildvfs_kfd artfil;
|
|
|
|
////////// Per-map ART file loading //////////
|
|
|
|
// Some forward declarations.
|
|
static const char *artGetIndexedFileName(int32_t tilefilei);
|
|
static int32_t artReadIndexedFile(int32_t tilefilei);
|
|
|
|
static inline void artClearMapArtFilename(void)
|
|
{
|
|
Bmemset(mapartfilename, 0, sizeof(mapartfilename));
|
|
mapartfnXXofs = 0;
|
|
}
|
|
|
|
static inline void artUpdateManifest(void)
|
|
{
|
|
for (bssize_t i=0; i<MAXTILES; i++)
|
|
tileUpdatePicSiz(i);
|
|
}
|
|
|
|
template <typename origar_t, typename bakar_t>
|
|
static inline void RESTORE_MAPART_ARRAY(origar_t & origar, bakar_t & bakar)
|
|
{
|
|
EDUKE32_STATIC_ASSERT(sizeof(origar[0]) == sizeof(bakar[0]));
|
|
Bmemcpy(origar, bakar, ARRAY_SIZE(origar) * sizeof(origar[0]));
|
|
DO_FREE_AND_NULL(bakar);
|
|
}
|
|
|
|
template <typename origar_t, typename bakar_t>
|
|
static inline void ALLOC_MAPART_ARRAY(origar_t & origar, bakar_t & bakar)
|
|
{
|
|
bakar = (bakar_t) Xmalloc(ARRAY_SIZE(origar) * sizeof(origar[0]));
|
|
Bmemcpy(bakar, origar, ARRAY_SIZE(origar) * sizeof(origar[0]));
|
|
}
|
|
|
|
void artClearMapArt(void)
|
|
{
|
|
if (g_bakTileFileNum == NULL)
|
|
return; // per-map ART N/A
|
|
|
|
artClearMapArtFilename();
|
|
|
|
if (artfilnum >= MAXARTFILES_BASE)
|
|
{
|
|
kclose(artfil);
|
|
|
|
artfil = buildvfs_kfd_invalid;
|
|
artfilnum = -1;
|
|
artfilplc = 0L;
|
|
}
|
|
|
|
for (bssize_t i=0; i<MAXTILES; i++)
|
|
{
|
|
if (tilefilenum[i] >= MAXARTFILES_BASE)
|
|
{
|
|
// XXX: OK way to free it? Better: cache1d API. CACHE1D_FREE
|
|
walock[i] = 1;
|
|
waloff[i] = 0;
|
|
}
|
|
}
|
|
|
|
// Restore original per-tile arrays
|
|
RESTORE_MAPART_ARRAY(tilefilenum, g_bakTileFileNum);
|
|
RESTORE_MAPART_ARRAY(tilefileoffs, g_bakTileFileOffs);
|
|
RESTORE_MAPART_ARRAY(tilesiz, g_bakTileSiz);
|
|
RESTORE_MAPART_ARRAY(picsiz, g_bakPicSiz);
|
|
RESTORE_MAPART_ARRAY(walock, g_bakWalock);
|
|
RESTORE_MAPART_ARRAY(waloff, g_bakWaloff);
|
|
RESTORE_MAPART_ARRAY(picanm, g_bakPicAnm);
|
|
RESTORE_MAPART_ARRAY(faketile, g_bakFakeTile);
|
|
|
|
for (size_t i = 0; i < MAXUSERTILES; ++i)
|
|
{
|
|
if (faketiledata[i] != g_bakFakeTileData[i])
|
|
{
|
|
free(faketiledata[i]);
|
|
faketiledata[i] = g_bakFakeTileData[i];
|
|
}
|
|
}
|
|
DO_FREE_AND_NULL(g_bakFakeTileData);
|
|
|
|
artUpdateManifest();
|
|
#ifdef USE_OPENGL
|
|
//POGOTODO: review this to ensure we're not invalidating more than we have to
|
|
gltexinvalidatetype(INVALIDATE_ART);
|
|
# ifdef POLYMER
|
|
if (videoGetRenderMode() == REND_POLYMER)
|
|
polymer_texinvalidate();
|
|
# endif
|
|
#endif
|
|
}
|
|
|
|
void artSetupMapArt(const char *filename)
|
|
{
|
|
artClearMapArt();
|
|
|
|
if (Bstrlen(filename) + 7 >= sizeof(mapartfilename))
|
|
return;
|
|
|
|
Bstrcpy(mapartfilename, filename);
|
|
append_ext_UNSAFE(mapartfilename, "_XX.art");
|
|
mapartfnXXofs = Bstrlen(mapartfilename) - 6;
|
|
|
|
// Check for first per-map ART file: if that one doesn't exist, don't load any.
|
|
buildvfs_kfd fil = kopen4load(artGetIndexedFileName(MAXARTFILES_BASE), 0);
|
|
|
|
if (fil == buildvfs_kfd_invalid)
|
|
{
|
|
artClearMapArtFilename();
|
|
return;
|
|
}
|
|
|
|
kclose(fil);
|
|
|
|
// Allocate backup arrays.
|
|
ALLOC_MAPART_ARRAY(tilefilenum, g_bakTileFileNum);
|
|
ALLOC_MAPART_ARRAY(tilefileoffs, g_bakTileFileOffs);
|
|
ALLOC_MAPART_ARRAY(tilesiz, g_bakTileSiz);
|
|
ALLOC_MAPART_ARRAY(picsiz, g_bakPicSiz);
|
|
ALLOC_MAPART_ARRAY(walock, g_bakWalock);
|
|
ALLOC_MAPART_ARRAY(waloff, g_bakWaloff);
|
|
ALLOC_MAPART_ARRAY(picanm, g_bakPicAnm);
|
|
ALLOC_MAPART_ARRAY(faketile, g_bakFakeTile);
|
|
ALLOC_MAPART_ARRAY(faketiledata, g_bakFakeTileData);
|
|
|
|
for (bssize_t i=MAXARTFILES_BASE; i<MAXARTFILES_TOTAL; i++)
|
|
{
|
|
int ret = artReadIndexedFile(i);
|
|
|
|
if (ret != 0)
|
|
{
|
|
// NOTE: i == MAXARTFILES_BASE && ret == -1 can only have happened
|
|
// if the file was deleted between the above file existence check
|
|
// and now. Very cornerly... but I like my code to be prepared to
|
|
// any eventuality.
|
|
if (i == MAXARTFILES_BASE || ret != -1)
|
|
artClearMapArt();
|
|
break;
|
|
}
|
|
}
|
|
|
|
artUpdateManifest();
|
|
#ifdef USE_OPENGL
|
|
//POGOTODO: review this to ensure we're not invalidating more than we have to
|
|
gltexinvalidatetype(INVALIDATE_ART);
|
|
# ifdef POLYMER
|
|
if (videoGetRenderMode() == REND_POLYMER)
|
|
polymer_texinvalidate();
|
|
# endif
|
|
#endif
|
|
}
|
|
|
|
//
|
|
// ART loading
|
|
//
|
|
|
|
void tileSetupDummy(int32_t const tile)
|
|
{
|
|
faketile[tile>>3] |= pow2char[tile&7];
|
|
DO_FREE_AND_NULL(faketiledata[tile]);
|
|
}
|
|
|
|
static void tileSetDataSafe(int32_t const tile, int32_t tsiz, char const * const buffer)
|
|
{
|
|
int const compressed_tsiz = LZ4_compressBound(tsiz);
|
|
char * newtile = (char *) Xmalloc(compressed_tsiz);
|
|
|
|
if ((tsiz = LZ4_compress_default(buffer, newtile, tsiz, compressed_tsiz)) != -1)
|
|
{
|
|
faketiledata[tile] = (char *) Xrealloc(newtile, tsiz);
|
|
faketile[tile>>3] |= pow2char[tile&7];
|
|
tilefilenum[tile] = MAXARTFILES_TOTAL;
|
|
}
|
|
else
|
|
{
|
|
free(newtile);
|
|
}
|
|
}
|
|
|
|
void tileSetData(int32_t const tile, int32_t tsiz, char const * const buffer)
|
|
{
|
|
int const compressed_tsiz = LZ4_compressBound(tsiz);
|
|
faketiledata[tile] = (char *) Xrealloc(faketiledata[tile], compressed_tsiz);
|
|
|
|
if ((tsiz = LZ4_compress_default(buffer, faketiledata[tile], tsiz, compressed_tsiz)) != -1)
|
|
{
|
|
faketiledata[tile] = (char *) Xrealloc(faketiledata[tile], tsiz);
|
|
faketile[tile>>3] |= pow2char[tile&7];
|
|
tilefilenum[tile] = MAXARTFILES_TOTAL;
|
|
}
|
|
else
|
|
{
|
|
DO_FREE_AND_NULL(faketiledata[tile]);
|
|
faketile[tile>>3] &= ~pow2char[tile&7];
|
|
}
|
|
}
|
|
|
|
static void tileSoftDelete(int32_t const tile)
|
|
{
|
|
tilesiz[tile].x = 0;
|
|
tilesiz[tile].y = 0;
|
|
picsiz[tile] = 0;
|
|
|
|
// CACHE1D_FREE
|
|
walock[tile] = 1;
|
|
waloff[tile] = 0;
|
|
|
|
faketile[tile>>3] &= ~pow2char[tile&7];
|
|
|
|
Bmemset(&picanm[tile], 0, sizeof(picanm_t));
|
|
}
|
|
|
|
void tileDelete(int32_t const tile)
|
|
{
|
|
tileSoftDelete(tile);
|
|
|
|
DO_FREE_AND_NULL(faketiledata[tile]);
|
|
|
|
vox_undefine(tile);
|
|
|
|
#ifdef USE_OPENGL
|
|
for (ssize_t i=MAXPALOOKUPS-1; i>=0; --i)
|
|
hicclearsubst(tile, i);
|
|
|
|
md_undefinetile(tile);
|
|
#endif
|
|
}
|
|
|
|
void tileUpdatePicSiz(int32_t picnum)
|
|
{
|
|
int j = 15;
|
|
|
|
while ((j > 1) && (pow2long[j] > tilesiz[picnum].x))
|
|
j--;
|
|
picsiz[picnum] = j;
|
|
|
|
j = 15;
|
|
while ((j > 1) && (pow2long[j] > tilesiz[picnum].y))
|
|
j--;
|
|
picsiz[picnum] |= j<<4;
|
|
}
|
|
|
|
void tileSetSize(int32_t picnum, int16_t dasizx, int16_t dasizy)
|
|
{
|
|
tilesiz[picnum].x = dasizx;
|
|
tilesiz[picnum].y = dasizy;
|
|
|
|
tileUpdatePicSiz(picnum);
|
|
}
|
|
|
|
int32_t artReadHeader(buildvfs_kfd const fil, char const * const fn, artheader_t * const local)
|
|
{
|
|
int32_t artversion;
|
|
kread(fil, &artversion, 4); artversion = B_LITTLE32(artversion);
|
|
|
|
if (artversion == B_LITTLE32(0x4c495542))
|
|
{
|
|
kread(fil, &artversion, 4); artversion = B_LITTLE32(artversion);
|
|
if (artversion == B_LITTLE32(0x54524144))
|
|
{
|
|
kread(fil, &artversion, 4); artversion = B_LITTLE32(artversion);
|
|
}
|
|
else
|
|
{
|
|
initprintf("loadpics: Invalid art file, %s\n", fn);
|
|
kclose(fil);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
if (artversion != 1)
|
|
{
|
|
initprintf("loadpics: Invalid art file version in %s\n", fn);
|
|
kclose(fil);
|
|
return 1;
|
|
}
|
|
|
|
int32_t numtiles_dummy;
|
|
kread(fil, &numtiles_dummy, 4);
|
|
|
|
kread(fil, &local->tilestart, 4); local->tilestart = B_LITTLE32(local->tilestart);
|
|
kread(fil, &local->tileend, 4); local->tileend = B_LITTLE32(local->tileend);
|
|
|
|
if ((uint32_t) local->tilestart >= MAXUSERTILES || (uint32_t) local->tileend >= MAXUSERTILES)
|
|
{
|
|
initprintf("loadpics: Invalid localtilestart or localtileend in %s\n", fn);
|
|
kclose(fil);
|
|
return 1;
|
|
}
|
|
if (local->tileend < local->tilestart)
|
|
{
|
|
initprintf("loadpics: localtileend < localtilestart in %s\n", fn);
|
|
kclose(fil);
|
|
return 1;
|
|
}
|
|
|
|
local->numtiles = (local->tileend-local->tilestart+1);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int32_t artReadHeaderFromBuffer(uint8_t const * const buf, artheader_t * const local)
|
|
{
|
|
int const artversion = B_LITTLE32(B_UNBUF32(&buf[0]));
|
|
if (EDUKE32_PREDICT_FALSE(artversion != 1))
|
|
{
|
|
initprintf("loadpics: Invalid art file version\n");
|
|
return 1;
|
|
}
|
|
|
|
local->tilestart = B_LITTLE32(B_UNBUF32(&buf[8]));
|
|
local->tileend = B_LITTLE32(B_UNBUF32(&buf[12]));
|
|
|
|
if (EDUKE32_PREDICT_FALSE((unsigned) local->tilestart >= MAXUSERTILES || (unsigned) local->tileend >= MAXUSERTILES))
|
|
{
|
|
initprintf("loadpics: Invalid localtilestart or localtileend\n");
|
|
return 1;
|
|
}
|
|
if (EDUKE32_PREDICT_FALSE(local->tileend < local->tilestart))
|
|
{
|
|
initprintf("loadpics: localtileend < localtilestart\n");
|
|
return 1;
|
|
}
|
|
|
|
local->numtiles = (local->tileend-local->tilestart+1);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int32_t artCheckUnitFileHeader(uint8_t const * const buf, int32_t length)
|
|
{
|
|
if (EDUKE32_PREDICT_FALSE(length <= ARTv1_UNITOFFSET))
|
|
return -1;
|
|
|
|
artheader_t local;
|
|
if (EDUKE32_PREDICT_FALSE(artReadHeaderFromBuffer(buf, &local) != 0))
|
|
return -2;
|
|
|
|
if (EDUKE32_PREDICT_FALSE(local.numtiles != 1))
|
|
return -3;
|
|
|
|
return 0;
|
|
}
|
|
|
|
void tileConvertAnimFormat(int32_t const picnum, int32_t const picanmdisk)
|
|
{
|
|
EDUKE32_STATIC_ASSERT(PICANM_ANIMTYPE_MASK == 192);
|
|
|
|
// Unpack a 4 byte packed anim descriptor into the internal 5 byte format.
|
|
picanm_t* const thispicanm = &picanm[picnum];
|
|
thispicanm->num = picanmdisk & 63;
|
|
thispicanm->xofs = (picanmdisk >> 8) & 255;
|
|
thispicanm->yofs = (picanmdisk >> 16) & 255;
|
|
thispicanm->sf = ((picanmdisk >> 24) & 15) | (picanmdisk & 192);
|
|
thispicanm->extra = (picanmdisk >> 28) & 15;
|
|
}
|
|
|
|
void artReadManifest(int32_t const fil, artheader_t const* const local)
|
|
{
|
|
int16_t* tilesizx = (int16_t*)Xmalloc(local->numtiles * sizeof(int16_t));
|
|
int16_t* tilesizy = (int16_t*)Xmalloc(local->numtiles * sizeof(int16_t));
|
|
kread(fil, tilesizx, local->numtiles * sizeof(int16_t));
|
|
kread(fil, tilesizy, local->numtiles * sizeof(int16_t));
|
|
|
|
for (bssize_t i = local->tilestart; i <= local->tileend; i++)
|
|
{
|
|
int32_t picanmdisk;
|
|
|
|
tilesiz[i].x = B_LITTLE16(tilesizx[i - local->tilestart]);
|
|
tilesiz[i].y = B_LITTLE16(tilesizy[i - local->tilestart]);
|
|
|
|
kread(fil, &picanmdisk, sizeof(int32_t));
|
|
picanmdisk = B_LITTLE32(picanmdisk);
|
|
|
|
tileConvertAnimFormat(i, picanmdisk);
|
|
}
|
|
|
|
DO_FREE_AND_NULL(tilesizx);
|
|
DO_FREE_AND_NULL(tilesizy);
|
|
}
|
|
|
|
void artPreloadFile(buildvfs_kfd const fil, artheader_t const * const local)
|
|
{
|
|
char *buffer = NULL;
|
|
int32_t buffersize = 0;
|
|
|
|
for (bssize_t i=local->tilestart; i<=local->tileend; i++)
|
|
{
|
|
int const dasiz = tilesiz[i].x * tilesiz[i].y;
|
|
|
|
if (dasiz == 0)
|
|
{
|
|
tileDelete(i);
|
|
continue;
|
|
}
|
|
|
|
maybe_grow_buffer(&buffer, &buffersize, dasiz);
|
|
kread(fil, buffer, dasiz);
|
|
tileSetData(i, dasiz, buffer);
|
|
}
|
|
|
|
DO_FREE_AND_NULL(buffer);
|
|
}
|
|
|
|
static void artPreloadFileSafe(buildvfs_kfd const fil, artheader_t const * const local)
|
|
{
|
|
char *buffer = NULL;
|
|
int32_t buffersize = 0;
|
|
|
|
for (bssize_t i=local->tilestart; i<=local->tileend; i++)
|
|
{
|
|
int const dasiz = tilesiz[i].x * tilesiz[i].y;
|
|
|
|
if (dasiz == 0)
|
|
{
|
|
tileSoftDelete(i);
|
|
continue;
|
|
}
|
|
|
|
maybe_grow_buffer(&buffer, &buffersize, dasiz);
|
|
kread(fil, buffer, dasiz);
|
|
tileSetDataSafe(i, dasiz, buffer);
|
|
}
|
|
|
|
DO_FREE_AND_NULL(buffer);
|
|
}
|
|
|
|
static const char *artGetIndexedFileName(int32_t tilefilei)
|
|
{
|
|
if (tilefilei >= MAXARTFILES_BASE)
|
|
{
|
|
int32_t o = mapartfnXXofs;
|
|
tilefilei -= MAXARTFILES_BASE;
|
|
|
|
mapartfilename[o+1] = '0' + tilefilei%10;
|
|
mapartfilename[o+0] = '0' + (tilefilei/10)%10;
|
|
|
|
return mapartfilename;
|
|
}
|
|
else
|
|
{
|
|
Bsnprintf(artfilename, sizeof(artfilename), artfilenameformat, tilefilei);
|
|
|
|
return artfilename;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Returns:
|
|
// 0: successfully read ART file
|
|
// >0: error with the ART file
|
|
// -1: ART file does not exist
|
|
//<-1: per-map ART issue
|
|
static int32_t artReadIndexedFile(int32_t tilefilei)
|
|
{
|
|
const char *fn = artGetIndexedFileName(tilefilei);
|
|
const int32_t permap = (tilefilei >= MAXARTFILES_BASE); // is it a per-map ART file?
|
|
buildvfs_kfd fil;
|
|
|
|
auto kopen4loadfunc = bloodhack == 2 ? kopen4loadfrommod : kopen4load;
|
|
|
|
if ((fil = kopen4loadfunc(fn, 0)) != buildvfs_kfd_invalid)
|
|
{
|
|
artheader_t local;
|
|
int const headerval = artReadHeader(fil, fn, &local);
|
|
if (headerval != 0)
|
|
{
|
|
kclose(fil);
|
|
return headerval;
|
|
}
|
|
|
|
if (permap)
|
|
{
|
|
// Check whether we can evict existing tiles to make place for
|
|
// per-map ART ones.
|
|
for (int i=local.tilestart; i<=local.tileend; i++)
|
|
{
|
|
// Tiles having dummytile replacements or those that are
|
|
// cache1d-locked can't be replaced.
|
|
if (faketile[i>>3] & pow2char[i&7] || walock[i] >= 200)
|
|
{
|
|
initprintf("loadpics: per-map ART file \"%s\": "
|
|
"tile %d has dummytile or is locked\n", fn, i);
|
|
kclose(fil);
|
|
return -3;
|
|
}
|
|
}
|
|
|
|
// Free existing tiles from the cache1d. CACHE1D_FREE
|
|
Bmemset(&waloff[local.tilestart], 0, local.numtiles*sizeof(intptr_t));
|
|
Bmemset(&walock[local.tilestart], 1, local.numtiles*sizeof(walock[0]));
|
|
}
|
|
|
|
artReadManifest(fil, &local);
|
|
|
|
#ifndef USE_PHYSFS
|
|
if (cache1d_file_fromzip(fil))
|
|
#else
|
|
if (1)
|
|
#endif
|
|
{
|
|
if (permap)
|
|
artPreloadFileSafe(fil, &local);
|
|
else
|
|
artPreloadFile(fil, &local);
|
|
}
|
|
else
|
|
{
|
|
int offscount = ktell(fil);
|
|
|
|
for (bssize_t i=local.tilestart; i<=local.tileend; ++i)
|
|
{
|
|
int const dasiz = tilesiz[i].x * tilesiz[i].y;
|
|
|
|
tilefilenum[i] = tilefilei;
|
|
tilefileoffs[i] = offscount;
|
|
|
|
offscount += dasiz;
|
|
// artsize += ((dasiz+15)&0xfffffff0);
|
|
}
|
|
}
|
|
|
|
#ifdef DEBUGGINGAIDS
|
|
if (permap)
|
|
initprintf("Read in per-map ART file \"%s\"\n", fn);
|
|
#endif
|
|
kclose(fil);
|
|
return 0;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
//
|
|
// loadpics
|
|
//
|
|
int32_t artLoadFiles(const char *filename, int32_t askedsize)
|
|
{
|
|
Bstrncpyz(artfilenameformat, filename, sizeof(artfilenameformat));
|
|
|
|
Bmemset(&tilesiz[0], 0, sizeof(vec2_16_t) * MAXTILES);
|
|
Bmemset(picanm, 0, sizeof(picanm));
|
|
|
|
for (auto &rot : rottile)
|
|
rot = { -1, -1 };
|
|
|
|
// artsize = 0;
|
|
|
|
for (int tilefilei=0; tilefilei<MAXARTFILES_BASE; tilefilei++)
|
|
artReadIndexedFile(tilefilei);
|
|
|
|
Bmemset(gotpic, 0, sizeof(gotpic));
|
|
|
|
//cachesize = min((int32_t)((Bgetsysmemsize()/100)*60),max(artsize,askedsize));
|
|
cachesize = (Bgetsysmemsize() <= (uint32_t)askedsize) ? (int32_t)((Bgetsysmemsize() / 100) * 60) : askedsize;
|
|
pic = Xaligned_alloc(Bgetpagesize(), cachesize);
|
|
cacheInitBuffer((intptr_t) pic, cachesize);
|
|
|
|
artUpdateManifest();
|
|
|
|
artfil = buildvfs_kfd_invalid;
|
|
artfilnum = -1;
|
|
artfilplc = 0L;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
//
|
|
// loadtile
|
|
//
|
|
static void tilePostLoad(int16_t tilenume);
|
|
|
|
bool tileLoad(int16_t tileNum)
|
|
{
|
|
if ((unsigned) tileNum >= (unsigned) MAXTILES) return 0;
|
|
int const dasiz = tilesiz[tileNum].x*tilesiz[tileNum].y;
|
|
if (dasiz <= 0) return 0;
|
|
|
|
// Allocate storage if necessary.
|
|
if (waloff[tileNum] == 0)
|
|
{
|
|
walock[tileNum] = 199;
|
|
cacheAllocateBlock(&waloff[tileNum], dasiz, &walock[tileNum]);
|
|
}
|
|
|
|
tileLoadData(tileNum, dasiz, (char *) waloff[tileNum]);
|
|
|
|
/*
|
|
#ifdef USE_OPENGL
|
|
if (videoGetRenderMode() >= REND_POLYMOST &&
|
|
in3dmode())
|
|
{
|
|
//POGOTODO: this type stuff won't be necessary down the line -- review this
|
|
int type;
|
|
for (type = 0; type <= 1; ++type)
|
|
{
|
|
gltexinvalidate(tileNum, 0, (type ? DAMETH_CLAMPED : DAMETH_MASK) | PTH_INDEXED);
|
|
texcache_fetch(tileNum, 0, 0, (type ? DAMETH_CLAMPED : DAMETH_MASK) | PTH_INDEXED);
|
|
}
|
|
}
|
|
#endif
|
|
*/
|
|
|
|
tilePostLoad(tileNum);
|
|
|
|
return (waloff[tileNum] != 0 && tilesiz[tileNum].x > 0 && tilesiz[tileNum].y > 0);
|
|
}
|
|
|
|
void tileMaybeRotate(int16_t tilenume)
|
|
{
|
|
auto &rot = rottile[tilenume];
|
|
auto &siz = tilesiz[rot.owner];
|
|
|
|
auto src = (char *)waloff[rot.owner];
|
|
auto dst = (char *)waloff[tilenume];
|
|
|
|
// the engine has a squarerotatetile() we could call, but it mirrors at the same time
|
|
for (int x = 0; x < siz.x; ++x)
|
|
{
|
|
int const xofs = siz.x - x - 1;
|
|
int const yofs = siz.y * x;
|
|
|
|
for (int y = 0; y < siz.y; ++y)
|
|
*(dst + y * siz.x + xofs) = *(src + y + yofs);
|
|
}
|
|
|
|
tileSetSize(tilenume, siz.y, siz.x);
|
|
}
|
|
|
|
void tileLoadData(int16_t tilenume, int32_t dasiz, char *buffer)
|
|
{
|
|
int const owner = rottile[tilenume].owner;
|
|
|
|
if (owner != -1)
|
|
{
|
|
if (!waloff[owner])
|
|
tileLoad(owner);
|
|
|
|
if (waloff[tilenume])
|
|
tileMaybeRotate(tilenume);
|
|
|
|
return;
|
|
}
|
|
|
|
int const tfn = tilefilenum[tilenume];
|
|
|
|
// dummy tiles for highres replacements and tilefromtexture definitions
|
|
if (faketile[tilenume>>3] & pow2char[tilenume&7])
|
|
{
|
|
if (faketiledata[tilenume] != NULL)
|
|
LZ4_decompress_fast(faketiledata[tilenume], buffer, dasiz);
|
|
|
|
faketimerhandler();
|
|
return;
|
|
}
|
|
|
|
// Potentially switch open ART file.
|
|
if (tfn != artfilnum)
|
|
{
|
|
if (artfil != buildvfs_kfd_invalid)
|
|
kclose(artfil);
|
|
|
|
char const *fn = artGetIndexedFileName(tfn);
|
|
|
|
auto kopen4loadfunc = bloodhack == 2 ? kopen4loadfrommod : kopen4load;
|
|
|
|
artfil = kopen4loadfunc(fn, 0);
|
|
|
|
if (artfil == buildvfs_kfd_invalid)
|
|
{
|
|
initprintf("Failed opening ART file \"%s\"!\n", fn);
|
|
engineUnInit();
|
|
Bexit(11);
|
|
}
|
|
|
|
artfilnum = tfn;
|
|
artfilplc = 0L;
|
|
|
|
faketimerhandler();
|
|
}
|
|
|
|
// Seek to the right position.
|
|
if (artfilplc != tilefileoffs[tilenume])
|
|
{
|
|
klseek(artfil, tilefileoffs[tilenume], BSEEK_SET);
|
|
faketimerhandler();
|
|
}
|
|
|
|
kread(artfil, buffer, dasiz);
|
|
faketimerhandler();
|
|
artfilplc = tilefileoffs[tilenume]+dasiz;
|
|
}
|
|
|
|
static void tilePostLoad(int16_t tilenume)
|
|
{
|
|
#if !defined DEBUG_TILESIZY_512 && !defined DEBUG_TILEOFFSETS
|
|
UNREFERENCED_PARAMETER(tilenume);
|
|
#endif
|
|
#ifdef DEBUG_TILESIZY_512
|
|
if (tilesizy[tilenume] >= 512)
|
|
{
|
|
int32_t i;
|
|
char *p = (char *) waloff[tilenume];
|
|
for (i=0; i<tilesizx[tilenume]*tilesizy[tilenume]; i++)
|
|
p[i] = i;
|
|
}
|
|
#endif
|
|
#ifdef DEBUG_TILEOFFSETS
|
|
// Add some dark blue marker lines to STEAM and CEILINGSTEAM.
|
|
// See test_tileoffsets.map.
|
|
if (tilenume==1250 || tilenume==1255)
|
|
{
|
|
char *p = (char *) waloff[tilenume];
|
|
p[0] = p[1] = p[2] = p[3] = 254;
|
|
}
|
|
|
|
// Add some offset to the cocktail glass neon sign. It's more asymmetric
|
|
// than the steam, and thus more suited to debugging the spatial
|
|
// orientation of drawn sprites.
|
|
if (tilenume==1008)
|
|
{
|
|
picanm[tilenume].xofs = 8;
|
|
picanm[tilenume].yofs = 12;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
int32_t tileCRC(int16_t tileNum)
|
|
{
|
|
char *data;
|
|
|
|
if ((unsigned)tileNum >= (unsigned)MAXTILES)
|
|
return 0;
|
|
int const dasiz = tilesiz[tileNum].x * tilesiz[tileNum].y;
|
|
if (dasiz <= 0)
|
|
return 0;
|
|
|
|
data = (char *)Xmalloc(dasiz);
|
|
tileLoadData(tileNum, dasiz, data);
|
|
|
|
int32_t crc = Bcrc32((unsigned char *)data, (unsigned int)dasiz, 0);
|
|
|
|
Xfree(data);
|
|
|
|
return crc;
|
|
}
|
|
|
|
// Assumes pic has been initialized to zero.
|
|
void artConvertRGB(palette_t * const pic, uint8_t const * const buf, int32_t const bufsizx, int32_t const sizx, int32_t const sizy)
|
|
{
|
|
for (bssize_t y = 0; y < sizy; ++y)
|
|
{
|
|
palette_t * const picrow = &pic[bufsizx * y];
|
|
|
|
for (bssize_t x = 0; x < sizx; ++x)
|
|
{
|
|
uint8_t index = buf[sizy * x + y];
|
|
|
|
if (index == 255)
|
|
continue;
|
|
|
|
index *= 3;
|
|
|
|
// pic is BGRA
|
|
picrow[x].r = palette[index+2];
|
|
picrow[x].g = palette[index+1];
|
|
picrow[x].b = palette[index];
|
|
picrow[x].f = 255;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// allocatepermanenttile
|
|
//
|
|
intptr_t tileCreate(int16_t tilenume, int32_t xsiz, int32_t ysiz)
|
|
{
|
|
if (xsiz <= 0 || ysiz <= 0 || (unsigned) tilenume >= MAXTILES)
|
|
return 0;
|
|
|
|
int const dasiz = xsiz*ysiz;
|
|
|
|
walock[tilenume] = 255;
|
|
cacheAllocateBlock(&waloff[tilenume], dasiz, &walock[tilenume]);
|
|
|
|
tileSetSize(tilenume, xsiz, ysiz);
|
|
Bmemset(&picanm[tilenume], 0, sizeof(picanm_t));
|
|
|
|
return waloff[tilenume];
|
|
}
|
|
|
|
//
|
|
// copytilepiece
|
|
//
|
|
void tileCopySection(int32_t tilenume1, int32_t sx1, int32_t sy1, int32_t xsiz, int32_t ysiz,
|
|
int32_t tilenume2, int32_t sx2, int32_t sy2)
|
|
{
|
|
char *ptr1, *ptr2, dat;
|
|
int32_t xsiz1, ysiz1, xsiz2, ysiz2, i, j, x1, y1, x2, y2;
|
|
|
|
xsiz1 = tilesiz[tilenume1].x; ysiz1 = tilesiz[tilenume1].y;
|
|
xsiz2 = tilesiz[tilenume2].x; ysiz2 = tilesiz[tilenume2].y;
|
|
if ((xsiz1 > 0) && (ysiz1 > 0) && (xsiz2 > 0) && (ysiz2 > 0))
|
|
{
|
|
if (waloff[tilenume1] == 0) tileLoad(tilenume1);
|
|
if (waloff[tilenume2] == 0) tileLoad(tilenume2);
|
|
|
|
x1 = sx1;
|
|
for (i=0; i<xsiz; i++)
|
|
{
|
|
y1 = sy1;
|
|
for (j=0; j<ysiz; j++)
|
|
{
|
|
x2 = sx2+i;
|
|
y2 = sy2+j;
|
|
if ((x2 >= 0) && (y2 >= 0) && (x2 < xsiz2) && (y2 < ysiz2))
|
|
{
|
|
ptr1 = (char *) (waloff[tilenume1] + x1*ysiz1 + y1);
|
|
ptr2 = (char *) (waloff[tilenume2] + x2*ysiz2 + y2);
|
|
dat = *ptr1;
|
|
if (dat != 255)
|
|
*ptr2 = *ptr1;
|
|
}
|
|
|
|
y1++; if (y1 >= ysiz1) y1 = 0;
|
|
}
|
|
x1++; if (x1 >= xsiz1) x1 = 0;
|
|
}
|
|
}
|
|
if (playing_rr)
|
|
tileInvalidate(tilenume2, -1, -1);
|
|
}
|
|
|
|
void Buninitart(void)
|
|
{
|
|
if (artfil != buildvfs_kfd_invalid)
|
|
kclose(artfil);
|
|
|
|
ALIGNED_FREE_AND_NULL(pic);
|
|
}
|