From 48a5819afa77db49b348f9bdb58150d5d89c4edf Mon Sep 17 00:00:00 2001 From: Julia Nechaevskaya Date: Wed, 10 Jan 2024 21:34:14 +0300 Subject: [PATCH] Heretic: update P_GroupLines and (re-)create BLOCKMAP if necessary (#1136) * Update P_GroupLines * (Re-)create BLOCKMAP if necessary --- src/heretic/CMakeLists.txt | 1 + src/heretic/Makefile.am | 1 + src/heretic/doomdef.h | 3 + src/heretic/p_blockmap.c | 194 +++++++++++++++++++++++++++++++++++++ src/heretic/p_setup.c | 73 +++++++++++--- 5 files changed, 258 insertions(+), 14 deletions(-) create mode 100644 src/heretic/p_blockmap.c diff --git a/src/heretic/CMakeLists.txt b/src/heretic/CMakeLists.txt index 181c628aab..123ac246e1 100644 --- a/src/heretic/CMakeLists.txt +++ b/src/heretic/CMakeLists.txt @@ -21,6 +21,7 @@ add_library(heretic STATIC m_random.c m_random.h mn_menu.c p_action.h + p_blockmap.c p_ceilng.c p_doors.c p_enemy.c diff --git a/src/heretic/Makefile.am b/src/heretic/Makefile.am index d6a5709b85..0939543c50 100644 --- a/src/heretic/Makefile.am +++ b/src/heretic/Makefile.am @@ -32,6 +32,7 @@ in_lude.c \ m_random.c m_random.h \ mn_menu.c \ p_action.h \ +p_blockmap.c \ p_ceilng.c \ p_doors.c \ p_enemy.c \ diff --git a/src/heretic/doomdef.h b/src/heretic/doomdef.h index ead1bfb346..be87e31049 100644 --- a/src/heretic/doomdef.h +++ b/src/heretic/doomdef.h @@ -763,6 +763,9 @@ void P_Ticker(void); // can call G_PlayerExited // carries out all thinking of monsters and players +// [crispy] (re-)create BLOCKMAP if necessary +void P_CreateBlockMap(void); + void P_SetupLevel(int episode, int map, int playermask, skill_t skill); // called by W_Ticker diff --git a/src/heretic/p_blockmap.c b/src/heretic/p_blockmap.c new file mode 100644 index 0000000000..eb725ac074 --- /dev/null +++ b/src/heretic/p_blockmap.c @@ -0,0 +1,194 @@ +// +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 1999 id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman +// Copyright(C) 2005-2014 Simon Howard +// Copyright(C) 2017 Fabian Greffrath +// +// 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: +// [crispy] Create Blockmap +// + +#include +#include "i_system.h" +#include "p_local.h" +#include "z_zone.h" + +// [crispy] taken from mbfsrc/P_SETUP.C:547-707, slightly adapted + +void P_CreateBlockMap(void) +{ + register int i; + fixed_t minx = INT_MAX, miny = INT_MAX, maxx = INT_MIN, maxy = INT_MIN; + + // First find limits of map + + for (i=0; i> FRACBITS < minx) + minx = vertexes[i].x >> FRACBITS; + else + if (vertexes[i].x >> FRACBITS > maxx) + maxx = vertexes[i].x >> FRACBITS; + if (vertexes[i].y >> FRACBITS < miny) + miny = vertexes[i].y >> FRACBITS; + else + if (vertexes[i].y >> FRACBITS > maxy) + maxy = vertexes[i].y >> FRACBITS; + } + +#if 0 + // [crispy] doombsp/DRAWING.M:175-178 + minx -= 8; miny -= 8; + maxx += 8; maxy += 8; +#endif + + // Save blockmap parameters + + bmaporgx = minx << FRACBITS; + bmaporgy = miny << FRACBITS; + bmapwidth = ((maxx-minx) >> MAPBTOFRAC) + 1; + bmapheight = ((maxy-miny) >> MAPBTOFRAC) + 1; + + // Compute blockmap, which is stored as a 2d array of variable-sized lists. + // + // Pseudocode: + // + // For each linedef: + // + // Map the starting and ending vertices to blocks. + // + // Starting in the starting vertex's block, do: + // + // Add linedef to current block's list, dynamically resizing it. + // + // If current block is the same as the ending vertex's block, exit loop. + // + // Move to an adjacent block by moving towards the ending block in + // either the x or y direction, to the block which contains the linedef. + + { + typedef struct { int n, nalloc, *list; } bmap_t; // blocklist structure + unsigned tot = bmapwidth * bmapheight; // size of blockmap + bmap_t *bmap = calloc(sizeof *bmap, tot); // array of blocklists + int x, y, adx, ady, bend; + + for (i=0; i < numlines; i++) + { + int dx, dy, diff, b; + + // starting coordinates + x = (lines[i].v1->x >> FRACBITS) - minx; + y = (lines[i].v1->y >> FRACBITS) - miny; + + // x-y deltas + adx = lines[i].dx >> FRACBITS, dx = adx < 0 ? -1 : 1; + ady = lines[i].dy >> FRACBITS, dy = ady < 0 ? -1 : 1; + + // difference in preferring to move across y (>0) instead of x (<0) + diff = !adx ? 1 : !ady ? -1 : + (((x >> MAPBTOFRAC) << MAPBTOFRAC) + + (dx > 0 ? MAPBLOCKUNITS-1 : 0) - x) * (ady = abs(ady)) * dx - + (((y >> MAPBTOFRAC) << MAPBTOFRAC) + + (dy > 0 ? MAPBLOCKUNITS-1 : 0) - y) * (adx = abs(adx)) * dy; + + // starting block, and pointer to its blocklist structure + b = (y >> MAPBTOFRAC)*bmapwidth + (x >> MAPBTOFRAC); + + // ending block + bend = (((lines[i].v2->y >> FRACBITS) - miny) >> MAPBTOFRAC) * + bmapwidth + (((lines[i].v2->x >> FRACBITS) - minx) >> MAPBTOFRAC); + + // delta for pointer when moving across y + dy *= bmapwidth; + + // deltas for diff inside the loop + adx <<= MAPBTOFRAC; + ady <<= MAPBTOFRAC; + + // Now we simply iterate block-by-block until we reach the end block. + while ((unsigned) b < tot) // failsafe -- should ALWAYS be true + { + // Increase size of allocated list if necessary + if (bmap[b].n >= bmap[b].nalloc) + bmap[b].list = I_Realloc(bmap[b].list, + (bmap[b].nalloc = bmap[b].nalloc ? + bmap[b].nalloc*2 : 8)*sizeof*bmap->list); + + // Add linedef to end of list + bmap[b].list[bmap[b].n++] = i; + + // If we have reached the last block, exit + if (b == bend) + break; + + // Move in either the x or y direction to the next block + if (diff < 0) + diff += ady, b += dx; + else + diff -= adx, b += dy; + } + } + + // Compute the total size of the blockmap. + // + // Compression of empty blocks is performed by reserving two offset words + // at tot and tot+1. + // + // 4 words, unused if this routine is called, are reserved at the start. + + { + int count = tot+6; // we need at least 1 word per block, plus reserved's + + for (i = 0; i < tot; i++) + if (bmap[i].n) + count += bmap[i].n + 2; // 1 header word + 1 trailer word + blocklist + + // Allocate blockmap lump with computed count + blockmaplump = Z_Malloc(sizeof(*blockmaplump) * count, PU_LEVEL, 0); + } + + // Now compress the blockmap. + { + int ndx = tot += 4; // Advance index to start of linedef lists + bmap_t *bp = bmap; // Start of uncompressed blockmap + + blockmaplump[ndx++] = 0; // Store an empty blockmap list at start + blockmaplump[ndx++] = -1; // (Used for compression) + + for (i = 4; i < tot; i++, bp++) + if (bp->n) // Non-empty blocklist + { + blockmaplump[blockmaplump[i] = ndx++] = 0; // Store index & header + do + blockmaplump[ndx++] = bp->list[--bp->n]; // Copy linedef list + while (bp->n); + blockmaplump[ndx++] = -1; // Store trailer + free(bp->list); // Free linedef list + } + else // Empty blocklist: point to reserved empty blocklist + blockmaplump[i] = tot; + + free(bmap); // Free uncompressed blockmap + } + } + + // [crispy] copied over from P_LoadBlockMap() + { + int count = sizeof(*blocklinks) * bmapwidth * bmapheight; + blocklinks = Z_Malloc(count, PU_LEVEL, 0); + memset(blocklinks, 0, count); + blockmap = blockmaplump+4; + } + + printf("P_CreateBlockMap: BLOCKMAP recreated.\n"); +} diff --git a/src/heretic/p_setup.c b/src/heretic/p_setup.c index c5ecaa0e4f..28a03458da 100644 --- a/src/heretic/p_setup.c +++ b/src/heretic/p_setup.c @@ -515,15 +515,20 @@ void P_LoadSideDefs(int lump) ================= */ -void P_LoadBlockMap(int lump) +boolean P_LoadBlockMap(int lump) { int i, count; int lumplen; short *wadblockmaplump; - lumplen = W_LumpLength(lump); - - count = lumplen / 2; // [crispy] remove BLOCKMAP limit + // [crispy] (re-)create BLOCKMAP if necessary + if (M_CheckParm("-blockmap") || + lump >= numlumps || + (lumplen = W_LumpLength(lump)) < 8 || + (count = lumplen / 2) >= 0x10000) + { + return false; + } // [crispy] remove BLOCKMAP limit wadblockmaplump = Z_Malloc(lumplen, PU_LEVEL, NULL); @@ -556,6 +561,9 @@ void P_LoadBlockMap(int lump) count = sizeof(*blocklinks) * bmapwidth * bmapheight; blocklinks = Z_Malloc(count, PU_LEVEL, 0); memset(blocklinks, 0, count); + + // [crispy] (re-)create BLOCKMAP if necessary + return true; } @@ -568,6 +576,8 @@ void P_LoadBlockMap(int lump) = = Builds sector line lists and subsector sector numbers = Finds block bounding boxes for sectors += [crispy] updated old Doom 1.2 code with actual implementation of P_GroupLines += from Chocolate Doom for better handling and faster loading of complex levels ================= */ @@ -606,23 +616,51 @@ void P_GroupLines(void) // build line tables for each sector linebuffer = Z_Malloc(total * sizeof(line_t *), PU_LEVEL, 0); + for (i = 0; i < numsectors; ++i) + { + // Assign the line buffer for this sector + sectors[i].lines = linebuffer; + linebuffer += sectors[i].linecount; + + // Reset linecount to zero so in the next stage we can count + // lines into the list. + sectors[i].linecount = 0; + } + +// [crispy] assign lines to sectors + for (i = 0; i < numlines; ++i) + { + li = &lines[i]; + + if (li->frontsector != NULL) + { + sector = li->frontsector; + + sector->lines[sector->linecount] = li; + ++sector->linecount; + } + + if (li->backsector != NULL && li->frontsector != li->backsector) + { + sector = li->backsector; + + sector->lines[sector->linecount] = li; + ++sector->linecount; + } + } + +// [crispy] generate bounding boxes for sectors sector = sectors; for (i = 0; i < numsectors; i++, sector++) { M_ClearBox(bbox); - sector->lines = linebuffer; - li = lines; - for (j = 0; j < numlines; j++, li++) + for (j = 0; j < sector->linecount; j++) { - if (li->frontsector == sector || li->backsector == sector) - { - *linebuffer++ = li; + li = sector->lines[j]; + M_AddToBox(bbox, li->v1->x, li->v1->y); M_AddToBox(bbox, li->v2->x, li->v2->y); - } } - if (linebuffer - sector->lines != sector->linecount) - I_Error("P_GroupLines: miscounted"); // set the degenmobj_t to the middle of the bounding box sector->soundorg.x = (bbox[BOXRIGHT] + bbox[BOXLEFT]) / 2; @@ -720,6 +758,7 @@ void P_SetupLevel(int episode, int map, int playermask, skill_t skill) char lumpname[9]; int lumpnum; mobj_t *mobj; + boolean crispy_validblockmap; mapformat_t crispy_mapformat; totalkills = totalitems = totalsecret = 0; @@ -763,13 +802,19 @@ void P_SetupLevel(int episode, int map, int playermask, skill_t skill) maplumpinfo = lumpinfo[lumpnum]; // note: most of this ordering is important - P_LoadBlockMap(lumpnum + ML_BLOCKMAP); + crispy_validblockmap = P_LoadBlockMap(lumpnum + ML_BLOCKMAP); // [crispy] (re-)create BLOCKMAP if necessary P_LoadVertexes(lumpnum + ML_VERTEXES); P_LoadSectors(lumpnum + ML_SECTORS); P_LoadSideDefs(lumpnum + ML_SIDEDEFS); P_LoadLineDefs(lumpnum + ML_LINEDEFS); + // [crispy] (re-)create BLOCKMAP if necessary + if (!crispy_validblockmap) + { + P_CreateBlockMap(); + } + if (crispy_mapformat & (MFMT_ZDBSPX | MFMT_ZDBSPZ)) { P_LoadNodes_ZDBSP(lumpnum + ML_NODES, crispy_mapformat & MFMT_ZDBSPZ);