From 4881a13f99a7bf467e6cc3ea3a20ef57bd3c8d10 Mon Sep 17 00:00:00 2001 From: helixhorned Date: Sun, 12 Jan 2014 14:54:36 +0000 Subject: [PATCH] Engine-side per-map ART file support. When a map named .map is loaded ( may also contain directory separators), the engine checks for existence of _XX.art in the virtual file system, where XX is a 0-padded number from 00 to 19. It loads a consecutive sequence of these ART files, i.e. aborts whenever a number in the sequence isn't found (in contrast to normal ART loading). Restrictions: - the per-map ART files must not reside in ZIP files - if a tile number is attempted to be overridden that has a dummytile or is cache1d-locked, per-map ART loading fails On failure, the map is still loaded, but a diagnostic message is output to the log/OSD. Loaded per-map ART data are cleared whenever the map is "left". In particular: - whenever another map is loaded - in the editor: when a new map is started - in the game: after the bonus ending screen of a finished level, after going to the title screen via the menu A final note: file names are supposed to be looked up and compared case-sensitively. That is, must match EXACTLY between the map's and per-map ART one; 'art' must be lowercase. Otherwise, the cookie monster will come and eat you! BUILD_LUNATIC. git-svn-id: https://svn.eduke32.com/eduke32@4257 1a8010ca-5511-0410-912e-c29ae57300e0 --- polymer/eduke32/build/include/build.h | 2 + polymer/eduke32/build/src/build.c | 2 +- polymer/eduke32/build/src/engine.c | 411 ++++++++++++++++++------ polymer/eduke32/build/src/engine_priv.h | 3 +- polymer/eduke32/source/game.c | 4 + polymer/eduke32/source/menus.c | 1 + polymer/eduke32/source/premap.c | 2 +- polymer/eduke32/source/savegame.c | 1 + 8 files changed, 322 insertions(+), 104 deletions(-) diff --git a/polymer/eduke32/build/include/build.h b/polymer/eduke32/build/include/build.h index 717aa3442..f9be79e6f 100644 --- a/polymer/eduke32/build/include/build.h +++ b/polymer/eduke32/build/include/build.h @@ -1060,6 +1060,8 @@ int32_t saveboard(const char *filename, const vec3_t *dapos, int16_t daang, in void set_tilesiz(int32_t picnum, int16_t dasizx, int16_t dasizy); int32_t tile_exists(int32_t picnum); int32_t loadpics(const char *filename, int32_t askedsize); +void E_MapArt_Clear(void); +void E_MapArt_Setup(const char *filename); void loadtile(int16_t tilenume); int32_t qloadkvx(int32_t voxindex, const char *filename); intptr_t allocatepermanenttile(int16_t tilenume, int32_t xsiz, int32_t ysiz); diff --git a/polymer/eduke32/build/src/build.c b/polymer/eduke32/build/src/build.c index a175e8b0f..051874fb5 100644 --- a/polymer/eduke32/build/src/build.c +++ b/polymer/eduke32/build/src/build.c @@ -433,7 +433,7 @@ static void reset_default_mapstate(void) initspritelists(); taglab_init(); - + E_MapArt_Clear(); #ifdef YAX_ENABLE yax_resetbunchnums(); #endif diff --git a/polymer/eduke32/build/src/engine.c b/polymer/eduke32/build/src/engine.c index 5ff890531..dfbde3cf6 100644 --- a/polymer/eduke32/build/src/engine.c +++ b/polymer/eduke32/build/src/engine.c @@ -186,20 +186,31 @@ static intptr_t slopalookup[16384]; // was 2048 palette_t palookupfog[MAXPALOOKUPS]; #endif -static int32_t artversion; static 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(MAXTILEFILES <= 256); +EDUKE32_STATIC_ASSERT(MAXARTFILES_TOTAL <= 256); static int32_t tilefileoffs[MAXTILES]; static int32_t lastageclock; -static int32_t artsize = 0, cachesize = 0; +// 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 int16_t *g_bakTileSizX; +static int16_t *g_bakTileSizY; +static picanm_t *g_bakPicAnm; +// NOTE: picsiz[] is not backed up, but recalculated when necessary. + +//static int32_t artsize = 0; +static int32_t cachesize = 0; // Whole ART file contents loaded from ZIPs in memory. -static char *artptrs[MAXTILEFILES]; +static char *artptrs[MAXARTFILES_TOTAL]; static int32_t no_radarang2 = 0; static int16_t radarang[1280], radarang2[MAXXDIM]; @@ -2422,6 +2433,8 @@ int16_t searchbottomwall, searchisbottom; double msens = 1.0; static char artfilename[20]; +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 artfil = -1, artfilnum, artfilplc; char inpreparemirror = 0; @@ -8716,7 +8729,7 @@ void uninitengine(void) kclose(artfil); // this leaves a bunch of invalid pointers in waloff... fixme? - for (i=0; i= MAXARTFILES_BASE) + { + kclose(artfil); + + artfil = -1; + artfilnum = -1; + artfilplc = 0L; + } + + for (i=0; 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(tilesizx, g_bakTileSizX); + RESTORE_MAPART_ARRAY(tilesizy, g_bakTileSizY); + RESTORE_MAPART_ARRAY(picanm, g_bakPicAnm); + + E_RecalcPicSiz(); +} + +void E_MapArt_Setup(const char *filename) +{ + int32_t i; + + if (Bstrlen(filename) + 7 >= sizeof(mapartfilename)) + return; + + E_MapArt_Clear(); + + 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. + { + int32_t fil = kopen4load(E_GetArtFileName(MAXARTFILES_BASE), 0); + + if (fil == -1) + { + clearmapartfilename(); + return; + } + + kclose(fil); + } + + // Allocate backup arrays. + ALLOC_MAPART_ARRAY(tilefilenum, g_bakTileFileNum); + ALLOC_MAPART_ARRAY(tilefileoffs, g_bakTileFileOffs); + ALLOC_MAPART_ARRAY(tilesizx, g_bakTileSizX); + ALLOC_MAPART_ARRAY(tilesizy, g_bakTileSizY); + ALLOC_MAPART_ARRAY(picanm, g_bakPicAnm); + + for (i=MAXARTFILES_BASE; i 0 && tilesizy[picnum] > 0); } -static void artfilename_setnumber(int32_t tilefilei) +static const char *E_GetArtFileName(int32_t tilefilei) { - artfilename[7] = '0' + tilefilei%10; - artfilename[6] = '0' + (tilefilei/10)%10; - artfilename[5] = '0' + (tilefilei/100)%10; + 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 + { + artfilename[7] = '0' + tilefilei%10; + artfilename[6] = '0' + (tilefilei/10)%10; + artfilename[5] = '0' + (tilefilei/100)%10; + + 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 E_ReadArtFile(int32_t tilefilei) +{ + int32_t fil; + + const char *fn = E_GetArtFileName(tilefilei); + const int32_t permap = (tilefilei >= MAXARTFILES_BASE); // is it a per-map ART file? + + if ((fil = kopen4load(fn,0)) != -1) + { + int32_t localtilestart, localtileend, localnumtiles; + int32_t i, offscount, numtiles_dummy, artversion; +#ifdef WITHKPLIB + if (permap && cache1d_file_fromzip(fil)) + { + initprintf("loadpics: per-map ART file \"%s\": can't be read from a ZIP file\n", fn); + kclose(fil); + return -2; + } +#endif + kread(fil,&artversion,4); artversion = B_LITTLE32(artversion); + if (artversion != 1) + { + initprintf("loadpics: Invalid art file version in %s\n", fn); + kclose(fil); + return 1; + } + + kread(fil,&numtiles_dummy,4); + kread(fil,&localtilestart,4); localtilestart = B_LITTLE32(localtilestart); + kread(fil,&localtileend,4); localtileend = B_LITTLE32(localtileend); + + if ((uint32_t)localtilestart >= MAXUSERTILES || (uint32_t)localtileend >= MAXUSERTILES) + { + initprintf("loadpics: Invalid localtilestart or localtileend in %s\n", fn); + kclose(fil); + return 1; + } + if (localtileend <= localtilestart) + { + initprintf("loadpics: localtileend <= localtilestart in %s\n", fn); + kclose(fil); + return 1; + } + + localnumtiles = (localtileend-localtilestart+1); + + if (permap) + { + // Check whether we can evict existing tiles to make place for + // per-map ART ones. + for (i=localtilestart; i<=localtileend; i++) + { + // Tiles having dummytile replacements or those that are + // cache1d-locked can't be replaced. + if (faketilesiz[i] || 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[localtilestart], 0, localnumtiles*sizeof(intptr_t)); + Bmemset(&walock[localtilestart], 1, localnumtiles*sizeof(walock[0])); + } + + kread(fil, &tilesizx[localtilestart], localnumtiles*sizeof(int16_t)); + kread(fil, &tilesizy[localtilestart], localnumtiles*sizeof(int16_t)); + kread(fil, &picanm[localtilestart], localnumtiles*sizeof(picanm_t)); + + for (i=localtilestart; i<=localtileend; i++) + { + EDUKE32_STATIC_ASSERT(sizeof(picanm_t) == 4); + EDUKE32_STATIC_ASSERT(PICANM_ANIMTYPE_MASK == 192); + + tilesizx[i] = B_LITTLE16(tilesizx[i]); + tilesizy[i] = B_LITTLE16(tilesizy[i]); + + // Old on-disk format: anim type is in the 2 highest bits of the lowest byte. + picanm[i].sf &= ~192; + picanm[i].sf |= picanm[i].num&192; + picanm[i].num &= ~192; + + // don't allow setting texhitscan/nofullbright from ART (yet?) + picanm[i].sf &= ~PICANM_MISC_MASK; + } + + offscount = 4+4+4+4+(localnumtiles<<3); + for (i=localtilestart; i<=localtileend; i++) + { + int32_t dasiz = tilesizx[i]*tilesizy[i]; + + tilefilenum[i] = tilefilei; + tilefileoffs[i] = offscount; + + offscount += dasiz; +// artsize += ((dasiz+15)&0xfffffff0); + } + +#ifdef WITHKPLIB + if (cache1d_file_fromzip(fil)) // from zip + { + i = kfilelength(fil); + artptrs[tilefilei] = (char *)Brealloc(artptrs[tilefilei], i); + klseek(fil, 0, BSEEK_SET); + kread(fil, artptrs[tilefilei], i); + } +#endif +#ifdef DEBUGGINGAIDS + if (permap) + initprintf("Read in per-map ART file \"%s\"\n", fn); +#endif + kclose(fil); + return 0; + } + + return -1; } // @@ -11000,7 +11281,7 @@ static void artfilename_setnumber(int32_t tilefilei) // int32_t loadpics(const char *filename, int32_t askedsize) { - int32_t i, tilefilei; + int32_t tilefilei; Bstrncpyz(artfilename, filename, sizeof(artfilename)); @@ -11008,91 +11289,10 @@ int32_t loadpics(const char *filename, int32_t askedsize) Bmemset(tilesizy, 0, sizeof(tilesizy)); Bmemset(picanm, 0, sizeof(picanm)); - artsize = 0; +// artsize = 0; - for (tilefilei=0; tilefilei= MAXUSERTILES || (uint32_t)localtileend >= MAXUSERTILES) - { - initprintf("loadpics: Invalid localtilestart or localtileend in %s\n", artfilename); - kclose(fil); - continue; - } - if (localtileend <= localtilestart) - { - initprintf("loadpics: localtileend <= localtilestart in %s\n", artfilename); - kclose(fil); - continue; - } - - localnumtiles = (localtileend-localtilestart+1); - - kread(fil,&tilesizx[localtilestart], localnumtiles<<1); - kread(fil,&tilesizy[localtilestart], localnumtiles<<1); - kread(fil,&picanm[localtilestart], localnumtiles<<2); - - for (i=localtilestart; i<=localtileend; i++) - { - EDUKE32_STATIC_ASSERT(sizeof(picanm_t) == 4); - EDUKE32_STATIC_ASSERT(PICANM_ANIMTYPE_MASK == 192); - - tilesizx[i] = B_LITTLE16(tilesizx[i]); - tilesizy[i] = B_LITTLE16(tilesizy[i]); - - // Old on-disk format: anim type is in the 2 highest bits of the lowest byte. - picanm[i].sf &= ~192; - picanm[i].sf |= picanm[i].num&192; - picanm[i].num &= ~192; - - // don't allow setting texhitscan/nofullbright from ART (yet?) - picanm[i].sf &= ~PICANM_MISC_MASK; - } - - offscount = 4+4+4+4+(localnumtiles<<3); - for (i=localtilestart; i<=localtileend; i++) - { - int32_t dasiz = tilesizx[i]*tilesizy[i]; - - tilefilenum[i] = tilefilei; - tilefileoffs[i] = offscount; - - offscount += dasiz; - artsize += ((dasiz+15)&0xfffffff0); - } - -#ifdef WITHKPLIB - if (cache1d_file_fromzip(fil)) // from zip - { - i = kfilelength(fil); - artptrs[tilefilei] = (char *)Brealloc(artptrs[tilefilei], i); - klseek(fil, 0, BSEEK_SET); - kread(fil, artptrs[tilefilei], i); - } -#endif - kclose(fil); - } - } + for (tilefilei=0; tilefilei>7) #define MAXNODESPERLINE (MAXYSAVES/MAXYDIM) // 307 diff --git a/polymer/eduke32/source/game.c b/polymer/eduke32/source/game.c index 92e4241ec..1315c39c3 100644 --- a/polymer/eduke32/source/game.c +++ b/polymer/eduke32/source/game.c @@ -11005,6 +11005,10 @@ static int32_t G_EndOfLevel(void) ud.screen_size = i; G_BonusScreen(0); } + + // Clear potentially loaded per-map ART only after the bonus screens. + E_MapArt_Clear(); + if (ud.eog) { ud.eog = 0; diff --git a/polymer/eduke32/source/menus.c b/polymer/eduke32/source/menus.c index 89e8dd3c0..ac81583a0 100644 --- a/polymer/eduke32/source/menus.c +++ b/polymer/eduke32/source/menus.c @@ -5031,6 +5031,7 @@ VOLUME_ALL_40x: g_player[myconnectindex].ps->gm = MODE_DEMO; if (ud.recstat == 1) G_CloseDemoWrite(); + E_MapArt_Clear(); M_ChangeMenu(MENU_MAIN); } diff --git a/polymer/eduke32/source/premap.c b/polymer/eduke32/source/premap.c index 62be6655a..6e32ee966 100644 --- a/polymer/eduke32/source/premap.c +++ b/polymer/eduke32/source/premap.c @@ -548,7 +548,7 @@ void G_CacheMapData(void) } } - clearbufbyte(gotpic,sizeof(gotpic),0L); + Bmemset(gotpic, 0, sizeof(gotpic)); endtime = getticks(); OSD_Printf("Cache time: %dms\n", endtime-starttime); diff --git a/polymer/eduke32/source/savegame.c b/polymer/eduke32/source/savegame.c index e98785e94..f21d1930f 100644 --- a/polymer/eduke32/source/savegame.c +++ b/polymer/eduke32/source/savegame.c @@ -282,6 +282,7 @@ int32_t G_LoadPlayer(int32_t spot) ud.m_player_skill = h.skill; Bstrcpy(boardfilename, h.boardfn); + E_MapArt_Setup(h.boardfn); // XXX: Better after the following filename tweaking? if (boardfilename[0]) Bstrcpy(currentboardfilename, boardfilename);