Skip to content

Commit

Permalink
Heretic: update P_GroupLines and (re-)create BLOCKMAP if necessary (#…
Browse files Browse the repository at this point in the history
…1136)

* Update P_GroupLines

* (Re-)create BLOCKMAP if necessary
  • Loading branch information
JNechaevsky authored Jan 10, 2024
1 parent 3d66f1f commit 48a5819
Show file tree
Hide file tree
Showing 5 changed files with 258 additions and 14 deletions.
1 change: 1 addition & 0 deletions src/heretic/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions src/heretic/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand Down
3 changes: 3 additions & 0 deletions src/heretic/doomdef.h
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
194 changes: 194 additions & 0 deletions src/heretic/p_blockmap.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
//

Check notice on line 1 in src/heretic/p_blockmap.c

View workflow job for this annotation

GitHub Actions / cpp-linter (clang)

Run clang-format on src/heretic/p_blockmap.c

File src/heretic/p_blockmap.c does not conform to Custom style guidelines. (lines 29, 30, 31, 33, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 53, 55, 57, 58, 59, 60, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 79, 80, 81, 82, 83, 85, 86, 87, 89, 90, 91, 93, 94, 95, 97, 98, 99, 100, 101, 102, 104, 105, 107, 108, 109, 111, 112, 114, 115, 116, 118, 119, 120, 121, 122, 123, 124, 125, 127, 128, 130, 131, 132, 134, 135, 136, 137, 138, 139, 140, 142, 143, 144, 145, 146, 147, 149, 150, 152, 153, 154, 156, 157, 158, 160, 161, 162, 163, 165, 166, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 181, 182, 183, 185, 186, 187, 188, 189, 190, 191)
// 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 <stdlib.h>
#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)

Check warning on line 28 in src/heretic/p_blockmap.c

View workflow job for this annotation

GitHub Actions / cpp-linter (clang)

src/heretic/p_blockmap.c:28:6 [readability-function-cognitive-complexity]

function 'P_CreateBlockMap' has cognitive complexity of 51 (threshold 25)
{
register int i;

Check warning on line 30 in src/heretic/p_blockmap.c

View workflow job for this annotation

GitHub Actions / cpp-linter (clang)

src/heretic/p_blockmap.c:30:16 [cppcoreguidelines-init-variables]

variable 'i' is not initialized

Check warning on line 30 in src/heretic/p_blockmap.c

View workflow job for this annotation

GitHub Actions / cpp-linter (clang)

src/heretic/p_blockmap.c:30:16 [readability-identifier-length]

variable name 'i' is too short, expected at least 3 characters
fixed_t minx = INT_MAX, miny = INT_MAX, maxx = INT_MIN, maxy = INT_MIN;

Check warning on line 31 in src/heretic/p_blockmap.c

View workflow job for this annotation

GitHub Actions / cpp-linter (clang)

src/heretic/p_blockmap.c:31:3 [readability-isolate-declaration]

multiple declarations in a single statement reduces readability

// First find limits of map

for (i=0; i<numvertexes; i++)
{
if (vertexes[i].x >> FRACBITS < minx)

Check warning on line 37 in src/heretic/p_blockmap.c

View workflow job for this annotation

GitHub Actions / cpp-linter (clang)

src/heretic/p_blockmap.c:37:44 [readability-braces-around-statements]

statement should be inside braces
minx = vertexes[i].x >> FRACBITS;
else
if (vertexes[i].x >> FRACBITS > maxx)

Check warning on line 40 in src/heretic/p_blockmap.c

View workflow job for this annotation

GitHub Actions / cpp-linter (clang)

src/heretic/p_blockmap.c:40:39 [readability-braces-around-statements]

statement should be inside braces
maxx = vertexes[i].x >> FRACBITS;
if (vertexes[i].y >> FRACBITS < miny)

Check warning on line 42 in src/heretic/p_blockmap.c

View workflow job for this annotation

GitHub Actions / cpp-linter (clang)

src/heretic/p_blockmap.c:42:44 [readability-braces-around-statements]

statement should be inside braces
miny = vertexes[i].y >> FRACBITS;
else
if (vertexes[i].y >> FRACBITS > maxy)

Check warning on line 45 in src/heretic/p_blockmap.c

View workflow job for this annotation

GitHub Actions / cpp-linter (clang)

src/heretic/p_blockmap.c:45:39 [readability-braces-around-statements]

statement should be inside braces
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;

Check warning on line 57 in src/heretic/p_blockmap.c

View workflow job for this annotation

GitHub Actions / cpp-linter (clang)

src/heretic/p_blockmap.c:57:19 [clang-analyzer-core.UndefinedBinaryOperatorResult]

The result of the left shift is undefined because the left operand is negative

Check warning on line 57 in src/heretic/p_blockmap.c

View workflow job for this annotation

GitHub Actions / cpp-linter (clang)

src/heretic/p_blockmap.c:57:19 [clang-analyzer-core.UndefinedBinaryOperatorResult]

The result of the left shift is undefined due to shifting '2147483647' by '16', which is unrepresentable in the unsigned version of the return type 'fixed_t'
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");
}
73 changes: 59 additions & 14 deletions src/heretic/p_setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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;
}


Expand All @@ -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
=================
*/

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit 48a5819

Please sign in to comment.