mirror of
https://github.com/ZDoom/Raze.git
synced 2025-02-04 06:01:01 +00:00
fbc7e626e9
- also removed the legacy fog modes because their implementation did not mix well with the texture system - they are also not really useful to begin with. The last fog mode will most likely also be removed once true color shading is working but that one is less of an issue.
798 lines
21 KiB
C++
798 lines
21 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);
|
|
#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];
|
|
picanm[tile] = {};
|
|
}
|
|
|
|
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;
|
|
|
|
if ((fil = kopen4loadfrommod(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);
|
|
|
|
if (cache1d_file_fromzip(fil))
|
|
{
|
|
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);
|
|
}
|
|
}
|
|
|
|
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
|
|
//
|
|
|
|
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]);
|
|
|
|
|
|
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);
|
|
|
|
artfil = kopen4loadfrommod(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;
|
|
}
|
|
|
|
|
|
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;
|
|
}
|
|
|
|
//
|
|
// 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);
|
|
picanm[tilenume] = {};
|
|
|
|
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;
|
|
}
|
|
}
|
|
tileInvalidate(tilenume2, -1, -1);
|
|
}
|
|
|
|
void Buninitart(void)
|
|
{
|
|
if (artfil != buildvfs_kfd_invalid)
|
|
kclose(artfil);
|
|
|
|
ALIGNED_FREE_AND_NULL(pic);
|
|
}
|