diff --git a/Makefile b/Makefile index 62a14ae..7107ca8 100644 --- a/Makefile +++ b/Makefile @@ -21,11 +21,13 @@ IPU_OBJ = $(addprefix build/ipu_obj/, \ r_bsp.gp \ r_codelets.gp \ r_draw.gp \ + r_data.gp \ r_main.gp \ r_plane.gp \ r_segs.gp \ tables.gp \ v_video.gp \ + w_wad.gp \ doomstat.gp \ ) @@ -33,7 +35,7 @@ IPU_OBJ = $(addprefix build/ipu_obj/, \ CPU_FLAGS = -I src -I /usr/local/include/SDL2 -I/usr/include/libpng16 -I/opt/poplar/include \ -D_REENTRANT -lSDL2 -lSDL2_mixer -lSDL2_net -lpng16 -lz -lpoplar \ -Wall -Werror \ - -O2 # -m32 + -O2 -g IPU_FLAGS = -I src/ipu \ --target=ipu2 \ diff --git a/README.md b/README.md index e134361..2d5d198 100644 --- a/README.md +++ b/README.md @@ -27,13 +27,14 @@ Activity Log: - [x] IPU interacts with host to load and unpack all level geometry from disk whenever a level is loaded - [x] Implement all methods used by the automap (vector rendering, sprite rendering, AM event responder). Automap is now disabled on CPU, renders entirely on IPU. - ![automap](https://static.wikia.nocookie.net/doom/images/9/9c/Automap.png) +![automap](https://static.wikia.nocookie.net/doom/images/9/9c/Automap.png) -- [x] Implement BinarySpacePartion search (stackless recursion version for IPU), solidseg occlusion and floor/ceiling clipping to get (untextured) rendering of vertical walls running on the IPU. CPU still renders everything else.![gameplay gif](README_imgs/flats.gif) +- [x] Implement BinarySpacePartion search (stackless recursion version for IPU), solidseg occlusion and floor/ceiling clipping to get (untextured) rendering of vertical walls running on the IPU. CPU still renders everything else. +![gameplay gif](README_imgs/flats.gif) Immediate next steps: -- [ ] Port visplane system to get IPU rendering floors and ceilings? -- [ ] Textures are too large to fit on a singe tile, so devise a mechanism for tiles to cooperate on texturing wall. +- [ ] Textures are too large to fit on a singe tile, so devise a mechanism for tiles to cooperate on texturing wall, probably by JIT-fetching textures +- [ ] Port visplane system to get IPU rendering floors and ceilings Longer term next steps: diff --git a/src/d_main.c b/src/d_main.c index a33c661..9ba0d78 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -401,7 +401,7 @@ void D_DoomLoop(void) { I_GraphicsCheckCommandLine(); I_SetGrabMouseCallback(D_GrabMouseCallback); I_InitGraphics(); - IPU_Init(); + IPU_MiscSetup(); TryRunTics(); @@ -1246,6 +1246,9 @@ void D_DoomMain(void) { startloadgame = -1; } + printf("IPU_Init: Init hardware... "); + IPU_Init(); + printf("M_Init: Init miscellaneous info.\n"); M_Init(); diff --git a/src/ipu/ipu_interface.h b/src/ipu/ipu_interface.h index 39b3556..db78f66 100644 --- a/src/ipu/ipu_interface.h +++ b/src/ipu/ipu_interface.h @@ -20,7 +20,7 @@ extern "C" { #define IPUMAPPEDLINEUPDATES (2) #define IPUFIRSTRENDERTILE (0) -#define IPUNUMRENDERTILES (8) +#define IPUNUMRENDERTILES (32) #define IPUCOLSPERRENDERTILE (SCREENWIDTH / IPUNUMRENDERTILES) @@ -50,7 +50,6 @@ typedef struct { int mappedline_updates[IPUMAPPEDLINEUPDATES]; } G_Ticker_MiscValues_t; - typedef struct { event_t events[IPUMAXEVENTSPERTIC]; unsigned char num_ev; @@ -62,12 +61,15 @@ typedef struct { int dummy; // just so struct is not empty } R_RenderPlayerView_MiscValues_t; - typedef struct { int setblocks; int setdetail; } R_ExecuteSetViewSize_MiscValues_t; +typedef struct { + int dummy; // Nothing here yet... maybe ever? +} R_Init_MiscValues_t; + #ifdef __cplusplus } diff --git a/src/ipu/ipu_malloc.c b/src/ipu/ipu_malloc.c index ddbd405..193f770 100644 --- a/src/ipu/ipu_malloc.c +++ b/src/ipu/ipu_malloc.c @@ -2,27 +2,38 @@ #include "ipu_malloc.h" #include "print.h" - -#define IPUMALLOC_MAXMAPSIZE 200000 +#include "r_main.h" #define ALIGN32(x) (((x) + 3) & (~3)) -static unsigned char PU_LEVEL_pool[IPUMALLOC_MAXMAPSIZE]; -static int PU_LEVEL_size = 0; +// #define IPUMALLOC_DEBUGPRINT 0 + +enum { + PU_STATIC_max_size = 10000, + PU_LEVEL_max_size = 200000, + PU_TMP_max_size = 512 // This is a category I made up, for fleeting allocations +}; + +static unsigned PU_STATIC_size = 0; +static unsigned PU_LEVEL_size = 0; +static unsigned PU_TMP_size = 0; +static unsigned char PU_STATIC_pool[PU_STATIC_max_size]; +static unsigned char PU_LEVEL_pool[PU_LEVEL_max_size]; +static unsigned char PU_TMP_pool[PU_TMP_max_size]; void* IPU_level_malloc(int size, const char* name) { void* ret = (void*)(&PU_LEVEL_pool[PU_LEVEL_size]); PU_LEVEL_size = ALIGN32(PU_LEVEL_size + size); - if (0) { // Enable for debug - printf("LEVEL_ALLOC: %s = %dK, total = %dK\n", - name, size / 1000, PU_LEVEL_size / 1000); - } +#ifdef IPUMALLOC_DEBUGPRINT + if (tileID == IPUMALLOC_DEBUGPRINT) + printf("LEVEL_ALLOC: %s = %dK, total = %dK\n", name, size / 1000, PU_LEVEL_size / 1000); +#endif - if (PU_LEVEL_size > IPUMALLOC_MAXMAPSIZE) { - printf("ERROR: IPUMALLOC_MAXMAPSIZE is %d, but IPU_level_malloc wants %d\n", - IPUMALLOC_MAXMAPSIZE, PU_LEVEL_size); + if (PU_LEVEL_size > PU_LEVEL_max_size) { + printf("### ERROR ###: PU_LEVEL_max_size is %d, but IPU_level_malloc wants %d\n", + PU_LEVEL_max_size, PU_LEVEL_size); // exit(1701); } return ret; @@ -30,4 +41,64 @@ void* IPU_level_malloc(int size, const char* name) { void IPU_level_free() { PU_LEVEL_size = 0; -} \ No newline at end of file +} + +void* IPU_static_malloc(int size, const char* name) { + void* ret = (void*)(&PU_STATIC_pool[PU_STATIC_size]); + PU_STATIC_size = ALIGN32(PU_STATIC_size + size); + +#ifdef IPUMALLOC_DEBUGPRINT + if (tileID == IPUMALLOC_DEBUGPRINT) + printf("STATIC_ALLOC: %s = %d, total = %dK\n", name, size, PU_STATIC_size / 1000); +#endif + + if (PU_STATIC_size > PU_STATIC_max_size) { + printf("### ERROR ###: PU_STATIC_max_size is %d, but IPU_static_malloc wants %d\n", + PU_STATIC_max_size, PU_STATIC_size); + } + return ret; +} + // There is no IPU_static_free :) + + +static unsigned PU_TMP_count = 0; +void* IPU_tmp_malloc(int size, const char* name) { + void* ret = (void*)(&PU_TMP_pool[PU_TMP_size]); + PU_TMP_size = ALIGN32(PU_TMP_size + size); + +#ifdef IPUMALLOC_DEBUGPRINT + if (tileID == IPUMALLOC_DEBUGPRINT) + printf("TMP_ALLOC: %s = %dK, total = %dK\n", name, size / 1000, PU_TMP_size / 1000); +#endif + + if (PU_TMP_size > PU_TMP_max_size) { + printf("### ERROR ###: PU_TMP_max_size is %d, but IPU_tmp_malloc wants %d\n", + PU_TMP_max_size, PU_TMP_size); + } + + PU_TMP_count += 1; + return ret; +} + + +void IPU_tmp_free(void* ptr) { + (void) ptr; + PU_TMP_count -= 1; + if (PU_TMP_count == 0) { + PU_TMP_size = 0; + } +} + + +void IPU_summarise_malloc() { + if (tileID != 0) + return; + + printf( + "IPU Dynamic Allocation Summary:\n" + "Static: %dK/%dK, Level: %dK/%dK, Tmp: %d/%d\n", + PU_STATIC_size / 1000, PU_STATIC_max_size / 1000, + PU_LEVEL_size / 1000, PU_LEVEL_size/ 1000, + PU_TMP_size / 1000, PU_TMP_size/ 1000 + ); +} diff --git a/src/ipu/ipu_malloc.h b/src/ipu/ipu_malloc.h index df7c809..663c704 100644 --- a/src/ipu/ipu_malloc.h +++ b/src/ipu/ipu_malloc.h @@ -4,9 +4,18 @@ extern "C" { #endif + +void* IPU_static_malloc(int size, const char* name); +// There is no IPU_static_free() :D + void* IPU_level_malloc(int size, const char* name); void IPU_level_free(void); +void* IPU_tmp_malloc(int size, const char* name); +void IPU_tmp_free(void* ptr); + +void IPU_summarise_malloc(void); + #ifdef __cplusplus } diff --git a/src/ipu/ipu_vertices.cpp b/src/ipu/ipu_vertices.cpp index 6e6f240..13a8268 100644 --- a/src/ipu/ipu_vertices.cpp +++ b/src/ipu/ipu_vertices.cpp @@ -13,6 +13,7 @@ typedef uint8_t pixel_t; extern "C" { void AM_LevelInit(void); void AM_Drawer(pixel_t*); + void IPU_Setup_UnpackMarkNums(const unsigned char* buf); }; @@ -37,14 +38,13 @@ class AM_Drawer_Vertex : public poplar::Vertex { }; +// ------ Happens before most CPU setup is done ------------- // + struct IPU_Init_Vertex : public poplar::SupervisorVertex { - poplar::InOut> frame; __attribute__((target("supervisor"))) void compute() { - I_VideoBuffer = &frame[0]; - // Deduce logical tile ID int physical = __builtin_ipu_get_tile_id(); int row = physical / 64; @@ -59,4 +59,27 @@ struct IPU_Init_Vertex : public poplar::SupervisorVertex { tileID = logical; } +}; + + +// ------ Happens after most CPU setup is done ------------- // + +struct IPU_MiscSetup_Vertex : public poplar::SupervisorVertex { + poplar::InOut> frame; + + __attribute__((target("supervisor"))) + void compute() { + + I_VideoBuffer = &frame[0]; + + } +}; + +struct IPU_UnpackMarknumSprites_Vertex : public poplar::Vertex { + poplar::Input> buf; + + void compute() { + IPU_Setup_UnpackMarkNums(&buf[0]); + return; + } }; \ No newline at end of file diff --git a/src/ipu/p_setup.c b/src/ipu/p_setup.c index b1f27fe..daf175b 100644 --- a/src/ipu/p_setup.c +++ b/src/ipu/p_setup.c @@ -324,9 +324,9 @@ void P_LoadSideDefs(const unsigned char *buf) { for (i = 0; i < numsides; i++, msd++, sd++) { sd->textureoffset = SHORT(msd->textureoffset) << FRACBITS; sd->rowoffset = SHORT(msd->rowoffset) << FRACBITS; - sd->toptexture = msd->toptexture[0] != '-'; // LATER: R_TextureNumForName(msd->toptexture); - sd->bottomtexture = msd->bottomtexture[0] != '-'; // LATER: R_TextureNumForName(msd->bottomtexture); - sd->midtexture = msd->midtexture[0] != '-'; // LATER: R_TextureNumForName(msd->midtexture); + sd->toptexture = R_TextureNumForName(msd->toptexture); + sd->bottomtexture = R_TextureNumForName(msd->bottomtexture); + sd->midtexture = R_TextureNumForName(msd->midtexture); sd->sector = §ors[SHORT(msd->sector)]; } } diff --git a/src/ipu/p_setup_codelets.cpp b/src/ipu/p_setup_codelets.cpp index 41f2173..5407d5f 100644 --- a/src/ipu/p_setup_codelets.cpp +++ b/src/ipu/p_setup_codelets.cpp @@ -21,36 +21,12 @@ extern "C" { void P_LoadSegs(const unsigned char *buf); void P_LoadThings(const unsigned char *buf); void P_GroupLines(const unsigned char *buf); - void IPU_Setup_UnpackMarkNums(const unsigned char* buf); }; // --------------- P_Setup ----------------- // -// struct P_SetupLevel_SubFunc { -// void (*func)(const unsigned char*); -// int lump_num; -// }; -// static P_SetupLevel_SubFunc setupLevelSubfuncs[14] = { -// {P_SetupLevel_pt0, 0}, -// {P_LoadBlockMap, ML_BLOCKMAP}, -// {P_LoadVertexes, ML_VERTEXES}, -// {P_LoadSectors, ML_SECTORS}, -// {P_LoadSideDefs, ML_SIDEDEFS}, -// {P_LoadLineDefs, ML_LINEDEFS}, -// {P_LoadSubsectors, ML_SSECTORS}, -// {P_LoadNodes, ML_NODES}, -// {P_LoadSegs, ML_SEGS}, -// // {P_GroupLines, ML_SEGS}, -// // {P_LoadReject, ML_REJECT}, -// {P_LoadThings, ML_THINGS}, -// // {P_SpawnSpecials, 0} -// {NULL, 0}, /* SENTINEL */ -// }; - -// DEF_FUNC_CALL_PTRS("__runCodelet_P_SetupLevel_Vertex", -// "P_LoadBlockMap,P_LoadVertexes,P_LoadSectors,P_LoadSideDefs,P_LoadLineDefs,P_LoadSubsectors"); class P_SetupLevel_Vertex : public poplar::Vertex { poplar::Input> lumpBuf; @@ -62,20 +38,20 @@ class P_SetupLevel_Vertex : public poplar::Vertex { // Switch statements are bonkers switch (step++) { next = 0; case 0: P_SetupLevel_pt0(&lumpBuf[0]); - next = ML_BLOCKMAP; break; case 1: P_LoadBlockMap( &lumpBuf[0]); - next = ML_VERTEXES; break; case 2: P_LoadVertexes( &lumpBuf[0]); - next = ML_SECTORS; break; case 3: P_LoadSectors( &lumpBuf[0]); - next = ML_SIDEDEFS; break; case 4: P_LoadSideDefs( &lumpBuf[0]); - next = ML_LINEDEFS; break; case 5: P_LoadLineDefs( &lumpBuf[0]); + next = ML_BLOCKMAP; break; case 1: P_LoadBlockMap (&lumpBuf[0]); + next = ML_VERTEXES; break; case 2: P_LoadVertexes (&lumpBuf[0]); + next = ML_SECTORS; break; case 3: P_LoadSectors (&lumpBuf[0]); + next = ML_SIDEDEFS; break; case 4: P_LoadSideDefs (&lumpBuf[0]); + next = ML_LINEDEFS; break; case 5: P_LoadLineDefs (&lumpBuf[0]); next = ML_SSECTORS; break; case 6: P_LoadSubsectors(&lumpBuf[0]); - next = ML_NODES; break; case 7: P_LoadNodes( &lumpBuf[0]); - next = ML_SEGS; break; case 8: P_LoadSegs( &lumpBuf[0]); - next = 0; break; case 9: P_GroupLines( &lumpBuf[0]); - // P_LoadReject // TODO - next = ML_THINGS; break; case 10: P_LoadThings( &lumpBuf[0]); - // P_SpawnSpecials // TODO - // R_PrecacheLevel // TODO - next = -1; break; + next = ML_NODES; break; case 7: P_LoadNodes (&lumpBuf[0]); + next = ML_SEGS; break; case 8: P_LoadSegs (&lumpBuf[0]); + next = 0; break; case 9: P_GroupLines (&lumpBuf[0]); + // P_LoadReject // TODO + next = ML_THINGS; break; case 10: P_LoadThings (&lumpBuf[0]); + // P_SpawnSpecials // TODO + // R_PrecacheLevel // TODO + next = -1; break; } *lumpNum = gamelumpnum + next; if (next == -1) { @@ -86,16 +62,3 @@ class P_SetupLevel_Vertex : public poplar::Vertex { return true; } }; - - -// ------------ IPU_Setup ------------ // - -struct IPU_Setup_UnpackMarknumSprites_Vertex : public poplar::Vertex { - poplar::Input> buf; - - void compute() { - IPU_Setup_UnpackMarkNums(&buf[0]); - - return; - } -}; \ No newline at end of file diff --git a/src/ipu/r_codelets.cpp b/src/ipu/r_codelets.cpp index f51faad..f8b3541 100644 --- a/src/ipu/r_codelets.cpp +++ b/src/ipu/r_codelets.cpp @@ -10,12 +10,36 @@ extern "C" { + void R_InitTextures(int* maptex, R_Init_MiscValues_t* miscVals); void R_RenderPlayerView(player_t *player); void R_ExecuteSetViewSize(void); }; -// --------------- P_Setup ----------------- // +struct R_Init_Vertex: public poplar::Vertex { + + poplar::Input> miscValues; + poplar::Input> lumpBuf; + poplar::Output lumpNum; + + void compute() { + static int step = 0; + + switch (step++) { + case 0: + *lumpNum = 105; + + break; case 1: + R_InitTextures((int*)&lumpBuf[0], (R_Init_MiscValues_t*)&miscValues[0]); + + + *lumpNum = 0; + step = 0; + } + + } +}; + struct R_RenderPlayerView_Vertex : public poplar::Vertex { poplar::Input> miscValues; diff --git a/src/ipu/r_data.c b/src/ipu/r_data.c new file mode 100644 index 0000000..38b9426 --- /dev/null +++ b/src/ipu/r_data.c @@ -0,0 +1,856 @@ +// +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// DESCRIPTION: +// Preparation of data for rendering, +// generation of lookups, caching, retrieval by name. +// + +#include "doomstat.h" +#include "i_swap.h" +#include "m_fixed.h" +#include "r_data.h" +#include "r_defs.h" +#include "r_state.h" +#include "w_wad.h" + +/* +#include +#include +#include + +#include "d_think.h" +#include "i_system.h" +#include "m_misc.h" +#include "p_local.h" +#include "p_mobj.h" +#include "r_sky.h" +#include "v_patch.h" +#include "z_zone.h" +*/ + +#include +#include "ipu_transfer.h" +#include "ipu_malloc.h" + + +struct texture_s; + +// +// Graphics. +// DOOM graphics for walls and sprites +// is stored in vertical runs of opaque pixels (posts). +// A column is composed of zero or more posts, +// a patch or sprite is composed of zero or more columns. +// + +// +// Texture definition. +// Each texture is composed of one or more patches, +// with patches being lumps stored in the WAD. +// The lumps are referenced by number, and patched +// into the rectangular texture space using origin +// and possibly other attributes. +// +typedef PACKED_STRUCT({ + short originx; + short originy; + short patch; + short stepdir; + short colormap; +}) mappatch_t; + +// +// Texture definition. +// A DOOM wall texture is a list of patches +// which are to be combined in a predefined order. +// +typedef PACKED_STRUCT({ + char name[8]; + int masked; + short width; + short height; + int obsolete; + short patchcount; + mappatch_t patches[1]; +}) maptexture_t; + +// A single patch from a texture definition, +// basically a rectangular area within +// the texture rectangle. +typedef struct { + // Block origin (allways UL), + // which has allready accounted + // for the internal origin of the patch. + short originx; + short originy; + int patch; +} texpatch_t; + +// A maptexturedef_t describes a rectangular texture, +// which is composed of one or more mappatch_t structures +// that arrange graphic patches. + +typedef struct texture_s texture_t; + +struct texture_s { + // Keep name for switch changing, etc. + char name[8]; + short width; + short height; + + // Index in textures list + + int index; + + // Next in hash table chain + + texture_t *next; + + // All the patches[patchcount] + // are drawn back to front into the cached texture. + short patchcount; + texpatch_t patches[1]; +}; + +typedef struct IPUpatchlesstexture_s IPUpatchlesstexture_t; + +struct IPUpatchlesstexture_s { + // Keep name for switch changing, etc. + char name[8]; + short width; + short height; + + // Index in textures list + int index; + + // Next in hash table chain + IPUpatchlesstexture_t *next; +}; + +int firstflat; +int lastflat; +int numflats; + +int firstpatch; +int lastpatch; +int numpatches; + +int firstspritelump; +int lastspritelump; +int numspritelumps; + +int numtextures; +IPUpatchlesstexture_t *patchlesstextures; // JOSEF +IPUpatchlesstexture_t **textures_hashtable; // JOSEF + +int *texturewidthmask; +// needed for texture pegging +fixed_t *textureheight; +int *texturecompositesize; +short **texturecolumnlump; +unsigned short **texturecolumnofs; +byte **texturecomposite; + +// for global animation +int *flattranslation; +int *texturetranslation; + +// needed for pre rendering +fixed_t *spritewidth; +fixed_t *spriteoffset; +fixed_t *spritetopoffset; + +lighttable_t *colormaps; + +/* +// +// MAPTEXTURE_T CACHING +// When a texture is first needed, +// it counts the number of composite columns +// required in the texture and allocates space +// for a column directory and any new columns. +// The directory will simply point inside other patches +// if there is only one patch in a given column, +// but any columns with multiple patches +// will have new column_ts generated. +// + +// +// R_DrawColumnInCache +// Clip and draw a column +// from a patch into a cached post. +// +void R_DrawColumnInCache(column_t *patch, byte *cache, int originy, + int cacheheight) { + int count; + int position; + byte *source; + + while (patch->topdelta != 0xff) { + source = (byte *)patch + 3; + count = patch->length; + position = originy + patch->topdelta; + + if (position < 0) { + count += position; + position = 0; + } + + if (position + count > cacheheight) + count = cacheheight - position; + + if (count > 0) + memcpy(cache + position, source, count); + + patch = (column_t *)((byte *)patch + patch->length + 4); + } +} + +// +// R_GenerateComposite +// Using the texture definition, +// the composite texture is created from the patches, +// and each column is cached. +// +void R_GenerateComposite(int texnum) { + byte *block; + texture_t *texture; + texpatch_t *patch; + patch_t *realpatch; + int x; + int x1; + int x2; + int i; + column_t *patchcol; + short *collump; + unsigned short *colofs; + + texture = textures[texnum]; + + block = Z_Malloc(texturecompositesize[texnum], PU_STATIC, + &texturecomposite[texnum]); + + collump = texturecolumnlump[texnum]; + colofs = texturecolumnofs[texnum]; + + // Composite the columns together. + patch = texture->patches; + + for (i = 0, patch = texture->patches; i < texture->patchcount; i++, patch++) { + realpatch = W_CacheLumpNum(patch->patch, PU_CACHE); + x1 = patch->originx; + x2 = x1 + SHORT(realpatch->width); + + if (x1 < 0) + x = 0; + else + x = x1; + + if (x2 > texture->width) + x2 = texture->width; + + for (; x < x2; x++) { + // Column does not have multiple patches? + if (collump[x] >= 0) + continue; + + patchcol = + (column_t *)((byte *)realpatch + LONG(realpatch->columnofs[x - x1])); + R_DrawColumnInCache(patchcol, block + colofs[x], patch->originy, + texture->height); + } + } + + // Now that the texture has been built in column cache, + // it is purgable from zone memory. + Z_ChangeTag(block, PU_CACHE); +} + +// +// R_GenerateLookup +// +void R_GenerateLookup(int texnum) { + texture_t *texture; + byte *patchcount; // patchcount[texture->width] + texpatch_t *patch; + patch_t *realpatch; + int x; + int x1; + int x2; + int i; + short *collump; + unsigned short *colofs; + + texture = textures[texnum]; + + // Composited texture not created yet. + texturecomposite[texnum] = 0; + + texturecompositesize[texnum] = 0; + collump = texturecolumnlump[texnum]; + colofs = texturecolumnofs[texnum]; + + // Now count the number of columns + // that are covered by more than one patch. + // Fill in the lump / offset, so columns + // with only a single patch are all done. + patchcount = (byte *)Z_Malloc(texture->width, PU_STATIC, &patchcount); + memset(patchcount, 0, texture->width); + patch = texture->patches; + + for (i = 0, patch = texture->patches; i < texture->patchcount; i++, patch++) { + realpatch = W_CacheLumpNum(patch->patch, PU_CACHE); + x1 = patch->originx; + x2 = x1 + SHORT(realpatch->width); + + if (x1 < 0) + x = 0; + else + x = x1; + + if (x2 > texture->width) + x2 = texture->width; + for (; x < x2; x++) { + patchcount[x]++; + collump[x] = patch->patch; + colofs[x] = LONG(realpatch->columnofs[x - x1]) + 3; + } + } + + for (x = 0; x < texture->width; x++) { + if (!patchcount[x]) { + printf("R_GenerateLookup: column without a patch (%s)\n", texture->name); + return; + } + // I_Error ("R_GenerateLookup: column without a patch"); + + if (patchcount[x] > 1) { + // Use the cached block. + collump[x] = -1; + colofs[x] = texturecompositesize[texnum]; + + if (texturecompositesize[texnum] > 0x10000 - texture->height) { + I_Error("R_GenerateLookup: texture %i is >64k", texnum); + } + + texturecompositesize[texnum] += texture->height; + } + } + + Z_Free(patchcount); +} + +// +// R_GetColumn +// +byte *R_GetColumn(int tex, int col) { + int lump; + int ofs; + + col &= texturewidthmask[tex]; + lump = texturecolumnlump[tex][col]; + ofs = texturecolumnofs[tex][col]; + + if (lump > 0) + return (byte *)W_CacheLumpNum(lump, PU_CACHE) + ofs; + + if (!texturecomposite[tex]) + R_GenerateComposite(tex); + + return texturecomposite[tex] + ofs; +} +*/ + +static void GenerateTextureHashTable(void) { + IPUpatchlesstexture_t **rover; + int i; + int key; + + textures_hashtable = IPU_static_malloc( + sizeof(IPUpatchlesstexture_t *) * numtextures, + "textures_hashtable" + ); + + memset(textures_hashtable, 0, sizeof(IPUpatchlesstexture_t *) * numtextures); + + // Add all textures to hash table + + for (i = 0; i < numtextures; ++i) { + // Store index + + patchlesstextures[i].index = i; + + // Vanilla Doom does a linear search of the texures array + // and stops at the first entry it finds. If there are two + // entries with the same name, the first one in the array + // wins. The new entry must therefore be added at the end + // of the hash chain, so that earlier entries win. + key = W_LumpNameHash(patchlesstextures[i].name) % numtextures; + + rover = &textures_hashtable[key]; + + while (*rover != NULL) { + rover = &(*rover)->next; + } + + // Hook into hash table + + patchlesstextures[i].next = NULL; + *rover = &patchlesstextures[i]; + } +} + +// +// R_InitTextures +// Initializes the texture list +// with the textures from the world map. +// +void R_InitTextures(int* maptex, R_Init_MiscValues_t* miscVals) { + maptexture_t *mtexture; + IPUpatchlesstexture_t *texture; + mappatch_t *mpatch; + texpatch_t *patch; + + int i; + int j; + + // int *maptex; // JOSEF + int *maptex2; + int *maptex1; + + char name[9]; + char *names; + char *name_p; + + int *patchlookup; + + int totalwidth; + int nummappatches; + int offset; + int maxoff; + int maxoff2; + int numtextures1; + int numtextures2; + + int *directory; + + int temp1; + int temp2; + int temp3; + + // Load the patch names from pnames.lmp. + name[8] = 0; + + // JOSEF : Don't need patch info on the render tiles? + // names = W_CacheLumpName(("PNAMES"), PU_STATIC); + // nummappatches = LONG(*((int *)names)); + // name_p = names + 4; + // patchlookup = Z_Malloc(nummappatches * sizeof(*patchlookup), PU_STATIC, NULL); + + // for (i = 0; i < nummappatches; i++) { + // M_StringCopy(name, name_p + i * 8, sizeof(name)); + // patchlookup[i] = W_CheckNumForName(name); + // } + // W_ReleaseLumpName(("PNAMES")); + // END JOSEF + + + // Load the map texture definitions from textures.lmp. + // The data is contained in one or two lumps, + // TEXTURE1 for shareware, plus TEXTURE2 for commercial. + + // maptex = maptex1 = W_CacheLumpName(("TEXTURE1"), PU_STATIC); // JOSEF + maxoff = *maptex++; // W_LumpLength(W_GetNumForName(("TEXTURE1"))); // JOSEF + numtextures1 = LONG(*maptex); + directory = maptex + 1; + + // JOSEF: Only support shareware version + // if (W_CheckNumForName(("TEXTURE2")) != -1) { + // maptex2 = W_CacheLumpName(("TEXTURE2"), PU_STATIC); + // numtextures2 = LONG(*maptex2); + // maxoff2 = W_LumpLength(W_GetNumForName(("TEXTURE2"))); + // } else { + maptex2 = NULL; + numtextures2 = 0; + maxoff2 = 0; + // } + numtextures = numtextures1 + numtextures2; + + patchlesstextures = IPU_static_malloc(numtextures * sizeof(IPUpatchlesstexture_t), "patchlesstextures"); + // LATER: texturecolumnlump = IPU_static_malloc(numtextures * sizeof(*texturecolumnlump), "texturecolumnlump"); + // LATER: texturecolumnofs = IPU_static_malloc(numtextures * sizeof(*texturecolumnofs), "texturecolumnofs"); + // LATER: texturecomposite = IPU_static_malloc(numtextures * sizeof(*texturecomposite), "texturecomposite"); + // LATER: texturecompositesize = IPU_static_malloc(numtextures * sizeof(*texturecompositesize), "texturecompositesize"); + texturewidthmask = IPU_static_malloc(numtextures * sizeof(*texturewidthmask), "texturewidthmask"); + textureheight = IPU_static_malloc(numtextures * sizeof(*textureheight), "textureheight"); + + // totalwidth = 0; // JOSEF: Unused? + + // Really complex printing shit... + // JOSEF: Printing disabled + // temp1 = W_GetNumForName(("S_START")); // P_??????? + // temp2 = W_GetNumForName(("S_END")) - 1; + // temp3 = ((temp2 - temp1 + 63) / 64) + ((numtextures + 63) / 64); + + // If stdout is a real console, use the classic vanilla "filling + // up the box" effect, which uses backspace to "step back" inside + // the box. If stdout is a file, don't draw the box. + + // if (I_ConsoleStdout()) { // JOSEF: Printing Disabled + // printf("["); + // for (i = 0; i < temp3 + 9; i++) + // printf(" "); + // printf("]"); + // for (i = 0; i < temp3 + 10; i++) + // printf("\b"); + // } + for (i = 0; i < numtextures; i++, directory++) { + // if (!(i & 63)) // JOSEF + // printf("."); + + if (i == numtextures1) { + // Start looking in second texture file. + maptex = maptex2; + maxoff = maxoff2; + directory = maptex + 1; + } + + offset = LONG(*directory); + + if (offset > maxoff) + printf("R_InitTextures: bad texture directory\n"); + + mtexture = (maptexture_t *)((byte *)maptex + offset); + + texture = &patchlesstextures[i]; + // texture = patchlesstextures[i] = IPU_static_malloc( + // sizeof(texture_t) + sizeof(texpatch_t) * (SHORT(mtexture->patchcount) - 1), + // "textures[i]" + // ); + + texture->width = SHORT(mtexture->width); + texture->height = SHORT(mtexture->height); + // texture->patchcount = SHORT(mtexture->patchcount); // JOSEF + + // memcpy(texture->name, mtexture->name, sizeof(texture->name)); // JOSEF + ((unsigned*)texture->name)[0] = ((unsigned*)mtexture->name)[0]; // JOSEF + ((unsigned*)texture->name)[1] = ((unsigned*)mtexture->name)[1]; + + // JOSEF: patches unneeded for render tiles (?) + // mpatch = &mtexture->patches[0]; + // patch = &texture->patches[0]; + // for (j = 0; j < texture->patchcount; j++, mpatch++, patch++) { + // patch->originx = SHORT(mpatch->originx); + // patch->originy = SHORT(mpatch->originy); + // patch->patch = patchlookup[SHORT(mpatch->patch)]; + // if (patch->patch == -1) { + // I_Error("R_InitTextures: Missing patch in texture %s", texture->name); + // } + // } + + // JOSEF: Later, if needed at all + // texturecolumnlump[i] = + // Z_Malloc(texture->width * sizeof(**texturecolumnlump), PU_STATIC, 0); + // texturecolumnofs[i] = + // Z_Malloc(texture->width * sizeof(**texturecolumnofs), PU_STATIC, 0); + + j = 1; + while (j * 2 <= texture->width) + j <<= 1; + + texturewidthmask[i] = j - 1; + textureheight[i] = texture->height << FRACBITS; + + // totalwidth += texture->width; // JOSEF: Unused? + } + + // JOSEF + // Z_Free(patchlookup); + // W_ReleaseLumpName(("TEXTURE1")); + // if (maptex2) + // W_ReleaseLumpName(("TEXTURE2")); + + // Precalculate whatever possible. + // for (i = 0; i < numtextures; i++) // JOSEF + // R_GenerateLookup(i); + + // Create translation table for global animation. + // texturetranslation = // JOSEF + // Z_Malloc((numtextures + 1) * sizeof(*texturetranslation), PU_STATIC, 0); + // for (i = 0; i < numtextures; i++) + // texturetranslation[i] = i; + + GenerateTextureHashTable(); +} + + +/* +// +// R_InitFlats +// +void R_InitFlats(void) { + int i; + + firstflat = W_GetNumForName(("F_START")) + 1; + lastflat = W_GetNumForName(("F_END")) - 1; + numflats = lastflat - firstflat + 1; + + // Create translation table for global animation. + flattranslation = + Z_Malloc((numflats + 1) * sizeof(*flattranslation), PU_STATIC, 0); + + for (i = 0; i < numflats; i++) + flattranslation[i] = i; +} + +// +// R_InitSpriteLumps +// Finds the width and hoffset of all sprites in the wad, +// so the sprite does not need to be cached completely +// just for having the header info ready during rendering. +// +void R_InitSpriteLumps(void) { + int i; + patch_t *patch; + + firstspritelump = W_GetNumForName(("S_START")) + 1; + lastspritelump = W_GetNumForName(("S_END")) - 1; + + numspritelumps = lastspritelump - firstspritelump + 1; + spritewidth = Z_Malloc(numspritelumps * sizeof(*spritewidth), PU_STATIC, 0); + spriteoffset = Z_Malloc(numspritelumps * sizeof(*spriteoffset), PU_STATIC, 0); + spritetopoffset = + Z_Malloc(numspritelumps * sizeof(*spritetopoffset), PU_STATIC, 0); + + for (i = 0; i < numspritelumps; i++) { + if (!(i & 63)) + printf("."); + + patch = W_CacheLumpNum(firstspritelump + i, PU_CACHE); + spritewidth[i] = SHORT(patch->width) << FRACBITS; + spriteoffset[i] = SHORT(patch->leftoffset) << FRACBITS; + spritetopoffset[i] = SHORT(patch->topoffset) << FRACBITS; + } +} + +// +// R_InitColormaps +// +void R_InitColormaps(void) { + int lump; + + // Load in the light tables, + // 256 byte align tables. + lump = W_GetNumForName(("COLORMAP")); + colormaps = W_CacheLumpNum(lump, PU_STATIC); +} + +// +// R_InitData +// Locates all the lumps +// that will be used by all views +// Must be called after W_Init. +// +void R_InitData(void) { + R_InitTextures(); + printf("."); + R_InitFlats(); + printf("."); + R_InitSpriteLumps(); + printf("."); + R_InitColormaps(); +} + +// +// R_FlatNumForName +// Retrieval, get a flat number for a flat name. +// +int R_FlatNumForName(char *name) { + int i; + char namet[9]; + + i = W_CheckNumForName(name); + + if (i == -1) { + namet[8] = 0; + memcpy(namet, name, 8); + I_Error("R_FlatNumForName: %s not found", namet); + } + return i - firstflat; +} +*/ + +int JOSEFstrsame(const char* restrict a, const char* restrict b) { + for (int i = 0; i < 8; ++i) { + char c_a = JOSEFtoupper(a[i]), c_b = JOSEFtoupper(b[i]); + if (c_a != c_b) return 0; + if (c_a == '\0' || c_b == '\0') return 1; + } + return 1; +} + +// +// R_CheckTextureNumForName +// Check whether texture is available. +// Filter out NoTexture indicator. +// +int R_CheckTextureNumForName(char *name) { + IPUpatchlesstexture_t *texture; + int key; + + // "NoTexture" marker. + if (name[0] == '-') + return 0; + + key = W_LumpNameHash(name) % numtextures; + + texture = textures_hashtable[key]; + + while (texture != NULL) { + // if (!strncasecmp(texture->name, name, 8)) // JOSEF + if (JOSEFstrsame(texture->name, name)) + return texture->index; + + texture = texture->next; + } + + return -1; +} + +// +// R_TextureNumForName +// Calls R_CheckTextureNumForName, +// aborts with error message. +// +int R_TextureNumForName(char *name) { + int i; + + i = R_CheckTextureNumForName(name); + + if (i == -1) { + printf("# # ERROR # # : R_TextureNumForName: %s not found\n", name); + } + return i; +} + +/* +// +// R_PrecacheLevel +// Preloads all relevant graphics for the level. +// +int flatmemory; +int texturememory; +int spritememory; + +void R_PrecacheLevel(void) { + char *flatpresent; + char *texturepresent; + char *spritepresent; + + int i; + int j; + int k; + int lump; + + texture_t *texture; + thinker_t *th; + spriteframe_t *sf; + + if (demoplayback) + return; + + // Precache flats. + flatpresent = Z_Malloc(numflats, PU_STATIC, NULL); + memset(flatpresent, 0, numflats); + + for (i = 0; i < numsectors; i++) { + flatpresent[sectors[i].floorpic] = 1; + flatpresent[sectors[i].ceilingpic] = 1; + } + + flatmemory = 0; + + for (i = 0; i < numflats; i++) { + if (flatpresent[i]) { + lump = firstflat + i; + flatmemory += lumpinfo[lump]->size; + W_CacheLumpNum(lump, PU_CACHE); + } + } + + Z_Free(flatpresent); + + // Precache textures. + texturepresent = Z_Malloc(numtextures, PU_STATIC, NULL); + memset(texturepresent, 0, numtextures); + + for (i = 0; i < numsides; i++) { + texturepresent[sides[i].toptexture] = 1; + texturepresent[sides[i].midtexture] = 1; + texturepresent[sides[i].bottomtexture] = 1; + } + + // Sky texture is always present. + // Note that F_SKY1 is the name used to + // indicate a sky floor/ceiling as a flat, + // while the sky texture is stored like + // a wall texture, with an episode dependend + // name. + texturepresent[skytexture] = 1; + + texturememory = 0; + for (i = 0; i < numtextures; i++) { + if (!texturepresent[i]) + continue; + + texture = textures[i]; + + for (j = 0; j < texture->patchcount; j++) { + lump = texture->patches[j].patch; + texturememory += lumpinfo[lump]->size; + W_CacheLumpNum(lump, PU_CACHE); + } + } + + Z_Free(texturepresent); + + // Precache sprites. + spritepresent = Z_Malloc(numsprites, PU_STATIC, NULL); + memset(spritepresent, 0, numsprites); + + for (th = thinkercap.next; th != &thinkercap; th = th->next) { + if (th->function.acp1 == (actionf_p1)P_MobjThinker) + spritepresent[((mobj_t *)th)->sprite] = 1; + } + + spritememory = 0; + for (i = 0; i < numsprites; i++) { + if (!spritepresent[i]) + continue; + + for (j = 0; j < sprites[i].numframes; j++) { + sf = &sprites[i].spriteframes[j]; + for (k = 0; k < 8; k++) { + lump = firstspritelump + sf->lump[k]; + spritememory += lumpinfo[lump]->size; + W_CacheLumpNum(lump, PU_CACHE); + } + } + } + + Z_Free(spritepresent); +} + +*/ \ No newline at end of file diff --git a/src/ipu/r_main.c b/src/ipu/r_main.c index 6523023..3a28a36 100644 --- a/src/ipu/r_main.c +++ b/src/ipu/r_main.c @@ -676,31 +676,34 @@ void R_ExecuteSetViewSize(void) { */ } -/* // // R_Init // void R_Init(void) { R_InitData(); - // printf("."); // JOSEF + + /* LATER + // printf("."); R_InitPointToAngle(); - // printf("."); // JOSEF + // printf("."); R_InitTables(); // viewwidth / viewheight / detailLevel are set by the defaults - // printf("."); // JOSEF + // printf("."); R_SetViewSize(screenblocks, detailLevel); R_InitPlanes(); - // printf("."); // JOSEF + // printf("."); R_InitLightTables(); - // printf("."); // JOSEF + // printf("."); R_InitSkyMap(); R_InitTranslationTables(); - // printf("."); // JOSEF + // printf("."); + */ framecount = 0; } +/* // // R_PointInSubsector diff --git a/src/ipu/w_file.h b/src/ipu/w_file.h index 8ffebe6..2931ec8 100644 --- a/src/ipu/w_file.h +++ b/src/ipu/w_file.h @@ -20,7 +20,7 @@ #ifndef __W_FILE__ #define __W_FILE__ -#include +// #include #include "doomtype.h" diff --git a/src/ipu/w_wad.c b/src/ipu/w_wad.c new file mode 100644 index 0000000..edf6146 --- /dev/null +++ b/src/ipu/w_wad.c @@ -0,0 +1,631 @@ +// +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// DESCRIPTION: +// Handles WAD file header, directory, lump I/O. +// + + + +/* +#include +#include +#include +#include +#include + +#include "doomtype.h" +#include "i_swap.h" +#include "i_system.h" +#include "m_misc.h" +#include "w_wad.h" +#include "z_zone.h" + +typedef PACKED_STRUCT ( +{ + // Should be "IWAD" or "PWAD". + char identification[4]; + int numlumps; + int infotableofs; +}) wadinfo_t; + + +typedef PACKED_STRUCT ( +{ + int filepos; + int size; + char name[8]; +}) filelump_t; + +// +// GLOBALS +// + +// Location of each lump on disk. +lumpinfo_t **lumpinfo; +unsigned int numlumps = 0; + +// Hash table for fast lookups +static lumpindex_t *lumphash; + +// Variables for the reload hack: filename of the PWAD to reload, and the +// lumps from WADs before the reload file, so we can resent numlumps and +// load the file again. +static wad_file_t *reloadhandle = NULL; +static lumpinfo_t *reloadlumps = NULL; +static char *reloadname = NULL; +static int reloadlump = -1; +*/ + +char JOSEFtoupper(const char c) { + if (c < 97 || c > 122) return c; + return c ^ 0x20; +} + +// Hash function used for lump names. +unsigned int W_LumpNameHash(const char *s) +{ + // This is the djb2 string hash function, modded to work on strings + // that have a maximum length of 8. + + unsigned int result = 5381; + unsigned int i; + + for (i=0; i < 8 && s[i] != '\0'; ++i) + { + // result = ((result << 5) ^ result ) ^ toupper(s[i]); // JOSEF + result = ((result << 5) ^ result ) ^ JOSEFtoupper(s[i]); + } + + return result; +} +/* + +// +// LUMP BASED ROUTINES. +// + +// +// W_AddFile +// All files are optional, but at least one file must be +// found (PWAD, if all required lumps are present). +// Files with a .wad extension are wadlink files +// with multiple lumps. +// Other files are single lumps with the base filename +// for the lump name. + +wad_file_t *W_AddFile (char *filename) +{ + wadinfo_t header; + lumpindex_t i; + wad_file_t *wad_file; + int length; + int startlump; + filelump_t *fileinfo; + filelump_t *filerover; + lumpinfo_t *filelumps; + int numfilelumps; + + // If the filename begins with a ~, it indicates that we should use the + // reload hack. + if (filename[0] == '~') + { + if (reloadname != NULL) + { + I_Error("Prefixing a WAD filename with '~' indicates that the " + "WAD should be reloaded\n" + "on each level restart, for use by level authors for " + "rapid development. You\n" + "can only reload one WAD file, and it must be the last " + "file in the -file list."); + } + + reloadname = strdup(filename); + reloadlump = numlumps; + ++filename; + } + + // Open the file and add to directory + wad_file = W_OpenFile(filename); + + if (wad_file == NULL) + { + printf (" couldn't open %s\n", filename); + return NULL; + } + + if (strcasecmp(filename+strlen(filename)-3 , "wad" ) ) + { + // single lump file + + // fraggle: Swap the filepos and size here. The WAD directory + // parsing code expects a little-endian directory, so will swap + // them back. Effectively we're constructing a "fake WAD directory" + // here, as it would appear on disk. + + fileinfo = Z_Malloc(sizeof(filelump_t), PU_STATIC, 0); + fileinfo->filepos = LONG(0); + fileinfo->size = LONG(wad_file->length); + + // Name the lump after the base of the filename (without the + // extension). + + M_ExtractFileBase (filename, fileinfo->name); + numfilelumps = 1; + } + else + { + // WAD file + W_Read(wad_file, 0, &header, sizeof(header)); + + if (strncmp(header.identification,"IWAD",4)) + { + // Homebrew levels? + if (strncmp(header.identification,"PWAD",4)) + { + W_CloseFile(wad_file); + I_Error ("Wad file %s doesn't have IWAD " + "or PWAD id\n", filename); + } + + // ???modifiedgame = true; + } + + header.numlumps = LONG(header.numlumps); + + // Vanilla Doom doesn't like WADs with more than 4046 lumps + // https://www.doomworld.com/vb/post/1010985 + if (!strncmp(header.identification,"PWAD",4) && header.numlumps > 4046) + { + W_CloseFile(wad_file); + I_Error ("Error: Vanilla limit for lumps in a WAD is 4046, " + "PWAD %s has %d", filename, header.numlumps); + } + + header.infotableofs = LONG(header.infotableofs); + length = header.numlumps*sizeof(filelump_t); + fileinfo = Z_Malloc(length, PU_STATIC, 0); + + W_Read(wad_file, header.infotableofs, fileinfo, length); + numfilelumps = header.numlumps; + } + + // Increase size of numlumps array to accomodate the new file. + filelumps = calloc(numfilelumps, sizeof(lumpinfo_t)); + if (filelumps == NULL) + { + W_CloseFile(wad_file); + I_Error("Failed to allocate array for lumps from new file."); + } + + startlump = numlumps; + numlumps += numfilelumps; + lumpinfo = realloc(lumpinfo, numlumps * sizeof(lumpinfo_t *)); + if (lumpinfo == NULL) + { + W_CloseFile(wad_file); + I_Error("Failed to increase lumpinfo[] array size."); + } + + filerover = fileinfo; + + for (i = startlump; i < numlumps; ++i) + { + lumpinfo_t *lump_p = &filelumps[i - startlump]; + lump_p->wad_file = wad_file; + lump_p->position = LONG(filerover->filepos); + lump_p->size = LONG(filerover->size); + lump_p->cache = NULL; + strncpy(lump_p->name, filerover->name, 8); + lumpinfo[i] = lump_p; + + ++filerover; + } + + Z_Free(fileinfo); + + if (lumphash != NULL) + { + Z_Free(lumphash); + lumphash = NULL; + } + + // If this is the reload file, we need to save some details about the + // file so that we can close it later on when we do a reload. + if (reloadname) + { + reloadhandle = wad_file; + reloadlumps = filelumps; + } + + return wad_file; +} + + + +// +// W_NumLumps +// +int W_NumLumps (void) +{ + return numlumps; +} + + + +// +// W_CheckNumForName +// Returns -1 if name not found. +// + +lumpindex_t W_CheckNumForName(char* name) +{ + lumpindex_t i; + + // Do we have a hash table yet? + + if (lumphash != NULL) + { + int hash; + + // We do! Excellent. + + hash = W_LumpNameHash(name) % numlumps; + + for (i = lumphash[hash]; i != -1; i = lumpinfo[i]->next) + { + if (!strncasecmp(lumpinfo[i]->name, name, 8)) + { + return i; + } + } + } + else + { + // We don't have a hash table generate yet. Linear search :-( + // + // scan backwards so patch lump files take precedence + + for (i = numlumps - 1; i >= 0; --i) + { + if (!strncasecmp(lumpinfo[i]->name, name, 8)) + { + return i; + } + } + } + + // TFB. Not found. + + return -1; +} + + + + +// +// W_GetNumForName +// Calls W_CheckNumForName, but bombs out if not found. +// +lumpindex_t W_GetNumForName(char* name) +{ + lumpindex_t i; + + i = W_CheckNumForName (name); + + if (i < 0) + { + I_Error ("W_GetNumForName: %s not found!", name); + } + + return i; +} + + +// +// W_LumpLength +// Returns the buffer size needed to load the given lump. +// +int W_LumpLength(lumpindex_t lump) +{ + if (lump >= numlumps) + { + I_Error ("W_LumpLength: %i >= numlumps", lump); + } + + return lumpinfo[lump]->size; +} + + + +// +// W_ReadLump +// Loads the lump into the given buffer, +// which must be >= W_LumpLength(). +// +void W_ReadLump(lumpindex_t lump, void *dest) +{ + int c; + lumpinfo_t *l; + + if (lump >= numlumps) + { + I_Error ("W_ReadLump: %i >= numlumps", lump); + } + + l = lumpinfo[lump]; + + c = W_Read(l->wad_file, l->position, dest, l->size); + + if (c < l->size) + { + I_Error("W_ReadLump: only read %i of %i on lump %i", + c, l->size, lump); + } +} + + + + +// +// W_CacheLumpNum +// +// Load a lump into memory and return a pointer to a buffer containing +// the lump data. +// +// 'tag' is the type of zone memory buffer to allocate for the lump +// (usually PU_STATIC or PU_CACHE). If the lump is loaded as +// PU_STATIC, it should be released back using W_ReleaseLumpNum +// when no longer needed (do not use Z_ChangeTag). +// + +void *W_CacheLumpNum(lumpindex_t lumpnum, int tag) +{ + byte *result; + lumpinfo_t *lump; + + if ((unsigned)lumpnum >= numlumps) + { + I_Error ("W_CacheLumpNum: %i >= numlumps", lumpnum); + } + + lump = lumpinfo[lumpnum]; + + // Get the pointer to return. If the lump is in a memory-mapped + // file, we can just return a pointer to within the memory-mapped + // region. If the lump is in an ordinary file, we may already + // have it cached; otherwise, load it into memory. + + if (lump->wad_file->mapped != NULL) + { + // Memory mapped file, return from the mmapped region. + + result = lump->wad_file->mapped + lump->position; + } + else if (lump->cache != NULL) + { + // Already cached, so just switch the zone tag. + + result = lump->cache; + Z_ChangeTag(lump->cache, tag); + } + else + { + // Not yet loaded, so load it now + + lump->cache = Z_Malloc(W_LumpLength(lumpnum), tag, &lump->cache); + W_ReadLump (lumpnum, lump->cache); + result = lump->cache; + } + + return result; +} + + + +// +// W_CacheLumpName +// +void *W_CacheLumpName(char *name, int tag) +{ + return W_CacheLumpNum(W_GetNumForName(name), tag); +} + +// +// Release a lump back to the cache, so that it can be reused later +// without having to read from disk again, or alternatively, discarded +// if we run out of memory. +// +// Back in Vanilla Doom, this was just done using Z_ChangeTag +// directly, but now that we have WAD mmap, things are a bit more +// complicated ... +// + +void W_ReleaseLumpNum(lumpindex_t lumpnum) +{ + lumpinfo_t *lump; + + if ((unsigned)lumpnum >= numlumps) + { + I_Error ("W_ReleaseLumpNum: %i >= numlumps", lumpnum); + } + + lump = lumpinfo[lumpnum]; + + if (lump->wad_file->mapped != NULL) + { + // Memory-mapped file, so nothing needs to be done here. + } + else + { + Z_ChangeTag(lump->cache, PU_CACHE); + } +} + +void W_ReleaseLumpName(char *name) +{ + W_ReleaseLumpNum(W_GetNumForName(name)); +} + +#if 0 + +// +// W_Profile +// +int info[2500][10]; +int profilecount; + +void W_Profile (void) +{ + int i; + memblock_t* block; + void* ptr; + char ch; + FILE* f; + int j; + char name[9]; + + + for (i=0 ; itag < PU_PURGELEVEL) + ch = 'S'; + else + ch = 'P'; + } + info[i][profilecount] = ch; + } + profilecount++; + + f = fopen ("waddump.txt","w"); + name[8] = 0; + + for (i=0 ; i 0) + { + lumphash = Z_Malloc(sizeof(lumpindex_t) * numlumps, PU_STATIC, NULL); + + for (i = 0; i < numlumps; ++i) + { + lumphash[i] = -1; + } + + for (i = 0; i < numlumps; ++i) + { + unsigned int hash; + + hash = W_LumpNameHash(lumpinfo[i]->name) % numlumps; + + // Hook into the hash table + + lumpinfo[i]->next = lumphash[hash]; + lumphash[hash] = i; + } + } + + // All done! +} + +// The Doom reload hack. The idea here is that if you give a WAD file to -file +// prefixed with the ~ hack, that WAD file will be reloaded each time a new +// level is loaded. This lets you use a level editor in parallel and make +// incremental changes to the level you're working on without having to restart +// the game after every change. +// But: the reload feature is a fragile hack... +void W_Reload(void) +{ + char *filename; + lumpindex_t i; + + if (reloadname == NULL) + { + return; + } + + // We must free any lumps being cached from the PWAD we're about to reload: + for (i = reloadlump; i < numlumps; ++i) + { + if (lumpinfo[i]->cache != NULL) + { + Z_Free(lumpinfo[i]->cache); + } + } + + // Reset numlumps to remove the reload WAD file: + numlumps = reloadlump; + + // Now reload the WAD file. + filename = reloadname; + + W_CloseFile(reloadhandle); + free(reloadlumps); + + reloadname = NULL; + reloadlump = -1; + reloadhandle = NULL; + W_AddFile(filename); + free(filename); + + // The WAD directory has changed, so we have to regenerate the + // fast lookup hashtable: + W_GenerateHashTable(); +} + +*/ \ No newline at end of file diff --git a/src/ipu/w_wad.h b/src/ipu/w_wad.h index c836f4f..ad860ca 100644 --- a/src/ipu/w_wad.h +++ b/src/ipu/w_wad.h @@ -71,4 +71,6 @@ extern unsigned int W_LumpNameHash(const char *s); void W_ReleaseLumpNum(lumpindex_t lump); void W_ReleaseLumpName(char *name); +char JOSEFtoupper(const char c); + #endif diff --git a/src/ipu_host.cpp b/src/ipu_host.cpp index c10cb91..a311858 100644 --- a/src/ipu_host.cpp +++ b/src/ipu_host.cpp @@ -9,6 +9,8 @@ #include #include #include +#include +#include #include "i_video.h" #include "ipu/ipu_interface.h" @@ -44,7 +46,9 @@ class IpuDoom { void run_AM_Drawer(); void run_R_RenderPlayerView(); void run_R_ExecuteSetViewSize(); - void run_IPU_Setup(); + void run_R_Init(); + void run_IPU_Init(); + void run_IPU_MiscSetup(); void run_G_DoLoadLevel(); void run_G_Ticker(); void run_G_Responder(G_Responder_MiscValues_t* buf); @@ -140,6 +144,33 @@ void IpuDoom::buildIpuGraph() { })), }); + // -------- R_Init ------ // + + poplar::ComputeSet R_Init_CS = m_ipuGraph.addComputeSet("R_Init_CS"); + for (int renderTile = 0; renderTile < IPUNUMRENDERTILES; ++renderTile) { + vtx = m_ipuGraph.addVertex(R_Init_CS, "R_Init_Vertex", { + {"lumpNum", m_lumpNum[renderTile]}, {"lumpBuf", lumpBuf}, {"miscValues", m_miscValuesBuf}}); + m_ipuGraph.setTileMapping(vtx, renderTile + IPUFIRSTRENDERTILE); + m_ipuGraph.setPerfEstimate(vtx, 100); + } + + poplar::HostFunction requestLumpFromHost = m_ipuGraph.addHostFunction( + "requestLumpFromHost", + {poplar::Graph::HostFunctionArgument{poplar::INT, 1}}, + {poplar::Graph::HostFunctionArgument{poplar::UNSIGNED_CHAR, IPUMAXLUMPBYTES}} + ); + + poplar::program::Sequence R_Init_prog({ + poplar::program::Copy(miscValuesStream, m_miscValuesBuf), + poplar::program::Repeat(2, poplar::program::Sequence({ // <- number of R_Init_CS steps + poplar::program::Execute(R_Init_CS), + // poplar::program::Copy(m_lumpNum[0], lumpNumStream), // Only listen to first tile's requests + // poplar::program::Sync(poplar::SyncType::GLOBAL), // lumpnum must arrive before lump is loaded + // poplar::program::Copy(lumpBufStream, lumpBuf), + poplar::program::Call(requestLumpFromHost, {m_lumpNum[0]}, {lumpBuf}), + })), + }); + // ---------------- G_Ticker --------------// @@ -172,12 +203,24 @@ void IpuDoom::buildIpuGraph() { }); - // -------------- IPU state setup ------------// - + // -------------- IPU Init setup (Happens after most CPU setup) ------------// poplar::ComputeSet IPU_Init_CS = m_ipuGraph.addComputeSet("IPU_Init_CS"); for (int renderTile = 0; renderTile < IPUNUMRENDERTILES; ++renderTile) { - vtx = m_ipuGraph.addVertex(IPU_Init_CS, "IPU_Init_Vertex", + vtx = m_ipuGraph.addVertex(IPU_Init_CS, "IPU_Init_Vertex"); + m_ipuGraph.setTileMapping(vtx, renderTile + IPUFIRSTRENDERTILE); + m_ipuGraph.setPerfEstimate(vtx, 10000); + } + poplar::program::Sequence IPU_Init_Prog({ + poplar::program::Execute(IPU_Init_CS), + }); + + + // -------------- IPU misc state setup (Happens after most CPU setup) ------------// + + poplar::ComputeSet IPU_MiscSetup_CS = m_ipuGraph.addComputeSet("IPU_MiscSetup_CS"); + for (int renderTile = 0; renderTile < IPUNUMRENDERTILES; ++renderTile) { + vtx = m_ipuGraph.addVertex(IPU_MiscSetup_CS, "IPU_MiscSetup_Vertex", {{"frame", ipuFrameSlices[renderTile]}}); m_ipuGraph.setTileMapping(vtx, renderTile + IPUFIRSTRENDERTILE); m_ipuGraph.setPerfEstimate(vtx, 10000); @@ -188,18 +231,18 @@ void IpuDoom::buildIpuGraph() { auto marknumSpriteBufStream = m_ipuGraph.addHostToDeviceFIFO("marknumSpriteBuf-stream", poplar::UNSIGNED_CHAR, IPUAMMARKBUFSIZE); - poplar::ComputeSet IPU_Setup_UnpackMarknumSprites_CS = m_ipuGraph.addComputeSet("IPU_Setup_UnpackMarknumSprites_CS"); + poplar::ComputeSet IPU_UnpackMarknumSprites_CS = m_ipuGraph.addComputeSet("IPU_UnpackMarknumSprites_CS"); for (int renderTile = 0; renderTile < IPUNUMRENDERTILES; ++renderTile) { - vtx = m_ipuGraph.addVertex(IPU_Setup_UnpackMarknumSprites_CS, "IPU_Setup_UnpackMarknumSprites_Vertex", + vtx = m_ipuGraph.addVertex(IPU_UnpackMarknumSprites_CS, "IPU_UnpackMarknumSprites_Vertex", {{"buf", marknumSpriteBuf}}); m_ipuGraph.setTileMapping(vtx, renderTile + IPUFIRSTRENDERTILE); m_ipuGraph.setPerfEstimate(vtx, IPUAMMARKBUFSIZE * 100); } - poplar::program::Sequence IPU_Init_Prog({ - poplar::program::Execute(IPU_Init_CS), + poplar::program::Sequence IPU_MiscSetup_Prog({ + poplar::program::Execute(IPU_MiscSetup_CS), poplar::program::Copy(marknumSpriteBufStream, marknumSpriteBuf), - poplar::program::Execute(IPU_Setup_UnpackMarknumSprites_CS), + poplar::program::Execute(IPU_UnpackMarknumSprites_CS), }); @@ -236,26 +279,33 @@ void IpuDoom::buildIpuGraph() { // ---------------- Final prog --------------// - printf("Creating engine...\n"); m_ipuEngine = std::make_unique(std::move(poplar::Engine( m_ipuGraph, { - IPU_Init_Prog, + IPU_MiscSetup_Prog, G_DoLoadLevel_prog, G_Ticker_prog, G_Responder_prog, AM_Drawer_prog, R_RenderPlayerView_prog, R_ExecuteSetViewSize_prog, + R_Init_prog, + IPU_Init_Prog, }))); - m_ipuEngine->connectStream("frame-instream", I_VideoBuffer); - m_ipuEngine->connectStream("frame-outstream", I_VideoBuffer); m_ipuEngine->connectStream("miscValues-stream", m_miscValuesBuf_h); m_ipuEngine->connectStream("lumpNum-stream", &m_lumpNum_h); + // Connect frame-instream/outstream later in run_IPU_MiscSetup because + // I_VideoBuffer is initialised quite late m_ipuEngine->connectStreamToCallback("lumpBuf-stream", [this](void* p) { IPU_LoadLumpForTransfer(m_lumpNum_h, (byte*) p); }); + m_ipuEngine->connectHostFunction( + "requestLumpFromHost", 0, [](poplar::ArrayRef inputs, poplar::ArrayRef outputs) { + const int* _lumpNum = static_cast(inputs[0]); + unsigned char* _lumpBuf = static_cast(outputs[0]); + IPU_LoadLumpForTransfer(*_lumpNum, _lumpBuf); + }); m_ipuEngine->connectStreamToCallback("marknumSpriteBuf-stream", [this](void* p) { IPU_Setup_PackMarkNums(p); }); @@ -264,7 +314,10 @@ void IpuDoom::buildIpuGraph() { } // --- Internal interface from class IpuDoom to m_ipuEngine --- // -void IpuDoom::run_IPU_Setup() { + +void IpuDoom::run_IPU_MiscSetup() { + m_ipuEngine->connectStream("frame-instream", I_VideoBuffer); + m_ipuEngine->connectStream("frame-outstream", I_VideoBuffer); m_ipuEngine->run(0); } void IpuDoom::run_G_DoLoadLevel() { @@ -290,20 +343,29 @@ void IpuDoom::run_R_ExecuteSetViewSize() { IPU_R_ExecuteSetViewSize_PackMiscValues(m_miscValuesBuf_h); m_ipuEngine->run(6); } +void IpuDoom::run_R_Init() { + IPU_R_Init_PackMiscValues(m_miscValuesBuf_h); + m_ipuEngine->run(7); +} +void IpuDoom::run_IPU_Init() { + m_ipuEngine->run(8); +} static std::unique_ptr ipuDoomInstance = nullptr; -// --- External interface from C to class IpuDoom --- // +// --- External interface from C to the singleton IpuDoom object --- // extern "C" { -void IPU_Init() { - ipuDoomInstance = std::make_unique(); - ipuDoomInstance->run_IPU_Setup(); -} -void IPU_AM_Drawer() { ipuDoomInstance->run_AM_Drawer(); } -void IPU_R_RenderPlayerView() { ipuDoomInstance->run_R_RenderPlayerView(); } -void IPU_G_DoLoadLevel() { ipuDoomInstance->run_G_DoLoadLevel(); } -void IPU_G_Ticker() { ipuDoomInstance->run_G_Ticker(); } -void IPU_G_Responder(G_Responder_MiscValues_t* buf) { ipuDoomInstance->run_G_Responder(buf); } -void IPU_R_ExecuteSetViewSize() { ipuDoomInstance->run_R_ExecuteSetViewSize(); } + void IPU_Init() { + ipuDoomInstance = std::make_unique(); + ipuDoomInstance->run_IPU_Init(); + } + void IPU_MiscSetup() { ipuDoomInstance->run_IPU_MiscSetup(); } + void IPU_AM_Drawer() { ipuDoomInstance->run_AM_Drawer(); } + void IPU_R_RenderPlayerView() { ipuDoomInstance->run_R_RenderPlayerView(); } + void IPU_G_DoLoadLevel() { ipuDoomInstance->run_G_DoLoadLevel(); } + void IPU_G_Ticker() { ipuDoomInstance->run_G_Ticker(); } + void IPU_G_Responder(G_Responder_MiscValues_t* buf) { ipuDoomInstance->run_G_Responder(buf); } + void IPU_R_ExecuteSetViewSize() { ipuDoomInstance->run_R_ExecuteSetViewSize(); } + void IPU_R_Init() { ipuDoomInstance->run_R_Init(); } } diff --git a/src/ipu_host.h b/src/ipu_host.h index dd089a8..3d8d6a9 100644 --- a/src/ipu_host.h +++ b/src/ipu_host.h @@ -10,7 +10,9 @@ extern "C" { void IPU_Init(void); +void IPU_MiscSetup(void); void IPU_AM_Drawer(void); +void IPU_R_Init(void); void IPU_R_RenderPlayerView(void); void IPU_R_ExecuteSetViewSize(void); diff --git a/src/ipu_transfer.c b/src/ipu_transfer.c index cb6de0c..2d79731 100644 --- a/src/ipu_transfer.c +++ b/src/ipu_transfer.c @@ -108,6 +108,13 @@ void IPU_R_ExecuteSetViewSize_PackMiscValues(void* buf) { pack->setdetail = setdetail; } +void IPU_R_Init_PackMiscValues(void* buf) { + assert(sizeof(R_Init_MiscValues_t) <= IPUMISCVALUESSIZE); + // R_Init_MiscValues_t* pack = buf; + // pack->TEXTURE1lumplength = W_LumpLength(W_GetNumForName(("TEXTURE1"))); + // Nothing to pack? Todo: Remove me later +} + void IPU_Setup_PackMarkNums(void* buf) { int bufpos = 10 * sizeof(short); char namebuf[9] = "AMMNUM0\0"; diff --git a/src/ipu_transfer.h b/src/ipu_transfer.h index aa76f62..65ca0e8 100644 --- a/src/ipu_transfer.h +++ b/src/ipu_transfer.h @@ -14,6 +14,7 @@ void IPU_G_Ticker_PackMiscValues(void* buf); void IPU_G_Responder_PackMiscValues(void* src_buf, void* dst_buf); void IPU_R_RenderPlayerView_PackMiscValues(void* buf); void IPU_R_ExecuteSetViewSize_PackMiscValues(void* buf); +void IPU_R_Init_PackMiscValues(void* buf); void IPU_LoadLumpForTransfer(int lumpnum, byte* buf); void IPU_Setup_PackMarkNums(void* buf); void IPU_NotifyLineMapped(line_t *line); diff --git a/src/r_data.c b/src/r_data.c index e82c74d..8bc416c 100644 --- a/src/r_data.c +++ b/src/r_data.c @@ -489,6 +489,8 @@ void R_InitTextures(void) { printf("\b"); } + int totaltexturesize = 0; // JOSEF TMP + for (i = 0; i < numtextures; i++, directory++) { if (!(i & 63)) printf("."); @@ -516,6 +518,8 @@ void R_InitTextures(void) { texture->height = SHORT(mtexture->height); texture->patchcount = SHORT(mtexture->patchcount); + totaltexturesize += texture->width * texture->height; // JOSEF TMP + memcpy(texture->name, mtexture->name, sizeof(texture->name)); mpatch = &mtexture->patches[0]; patch = &texture->patches[0]; @@ -543,6 +547,12 @@ void R_InitTextures(void) { totalwidth += texture->width; } + printf("\n JOSEF: Total Texture Size = %d bytes (%dKb), numtextures = %d\n", + totaltexturesize, + totaltexturesize / 1000, + numtextures + ); + Z_Free(patchlookup); W_ReleaseLumpName(("TEXTURE1")); diff --git a/src/r_main.c b/src/r_main.c index c6c2364..1710951 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -646,6 +646,8 @@ void R_ExecuteSetViewSize(void) { // void R_Init(void) { + IPU_R_Init(); + R_InitData(); printf("."); R_InitPointToAngle();