support maps with NODES in compressed or uncompressed ZDBSP format or DeePBSP format (#67)

* support maps with NODES in compressed or uncompressed ZDBSP format or DeePBSP format (Fixes #63)

* move some stuff around

* fix loading DeepBSP nodes

* support maps with NODES in compressed or uncompressed ZDBSP format or DeePBSP format

* move some stuff around

* fix loading DeepBSP nodes
This commit is contained in:
Fabian Greffrath 2020-02-28 08:20:47 +01:00 committed by GitHub
parent 4ad5a3b012
commit 0a690dc10e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 547 additions and 15 deletions

View File

@ -31,6 +31,7 @@ option("${PROJECT_NAME}_RANGECHECK" "Enable bounds-checking of performance-sensi
# Compiler environment requirements.
check_library_exists(m pow "" m_FOUND)
check_library_exists(dl dlopen "" dl_FOUND)
check_library_exists(z inflate "" z_FOUND)
# Library requirements.
find_package(SDL2)

View File

@ -45,6 +45,7 @@ set(WOOF_SOURCES
p_ceilng.c
p_doors.c
p_enemy.c p_enemy.h
p_extnodes.c p_extnodes.h
p_floor.c
p_genlin.c
p_inter.c p_inter.h
@ -91,6 +92,9 @@ endif()
if(dl_FOUND)
list(APPEND WOOF_LIBRARIES dl)
endif()
if(z_FOUND)
list(APPEND WOOF_LIBRARIES z)
endif()
if(WIN32)
# Stamp out and compile resource file on Windows.

471
Source/p_extnodes.c Normal file
View File

@ -0,0 +1,471 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id: r_defs.h,v 1.18 1998/04/27 02:12:59 killough Exp $
//
// Copyright (C) 1999 by
// id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
// Copyright(C) 2015-2020 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.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
// 02111-1307, USA.
//
// DESCRIPTION:
// support maps with NODES in compressed or uncompressed ZDBSP format or DeePBSP format
//
//-----------------------------------------------------------------------------
#include "r_main.h"
#include "w_wad.h"
// [FG] support maps with NODES in compressed ZDBSP format
#include "config.h"
#ifdef z_FOUND
#include <zlib.h>
#endif
#include "p_extnodes.h"
// [crispy] support maps with NODES in DeePBSP format
typedef PACKED_STRUCT (
{
int v1;
int v2;
unsigned short angle;
unsigned short linedef;
short side;
unsigned short offset;
}) mapseg_deepbsp_t;
typedef PACKED_STRUCT (
{
short x;
short y;
short dx;
short dy;
short bbox[2][4];
int children[2];
}) mapnode_deepbsp_t;
typedef PACKED_STRUCT (
{
unsigned short numsegs;
int firstseg;
}) mapsubsector_deepbsp_t;
// [crispy] support maps with NODES in ZDBSP format
typedef PACKED_STRUCT (
{
unsigned int v1, v2;
unsigned short linedef;
unsigned char side;
}) mapseg_zdbsp_t;
typedef PACKED_STRUCT (
{
short x;
short y;
short dx;
short dy;
short bbox[2][4];
int children[2];
}) mapnode_zdbsp_t;
typedef PACKED_STRUCT (
{
unsigned int numsegs;
}) mapsubsector_zdbsp_t;
// [FG] support maps with NODES in compressed or uncompressed ZDBSP format or DeePBSP format
mapformat_t P_CheckMapFormat (int lumpnum)
{
mapformat_t format = MFMT_DOOMBSP;
byte *nodes = NULL;
int b;
if ((b = lumpnum+ML_BLOCKMAP+1) < numlumps &&
!strcasecmp(lumpinfo[b].name, "BEHAVIOR"))
I_Error("P_SetupLevel: Hexen map format not supported in %s.\n",
lumpinfo[lumpnum-ML_NODES].name);
if ((b = lumpnum+ML_NODES) < numlumps &&
(nodes = W_CacheLumpNum(b, PU_STATIC)) &&
W_LumpLength(b) > 8)
{
if (!memcmp(nodes, "xNd4\0\0\0\0", 8))
format = MFMT_DEEPBSP;
else if (!memcmp(nodes, "XNOD", 4))
format = MFMT_ZDBSPX;
else if (!memcmp(nodes, "ZNOD", 4))
format = MFMT_ZDBSPZ;
}
if (nodes)
Z_Free(nodes);
return format;
}
// [FG] recalculate seg offsets
static fixed_t GetOffset(vertex_t *v1, vertex_t *v2)
{
fixed_t dx, dy;
fixed_t r;
dx = (v1->x - v2->x)>>FRACBITS;
dy = (v1->y - v2->y)>>FRACBITS;
r = (fixed_t)(sqrt(dx*dx + dy*dy))<<FRACBITS;
return r;
}
// [FG] support maps with DeePBSP nodes
void P_LoadSegs_DeePBSP (int lump)
{
int i;
byte *data;
numsegs = W_LumpLength(lump) / sizeof(mapseg_deepbsp_t);
segs = Z_Malloc(numsegs*sizeof(seg_t),PU_LEVEL,0);
memset(segs, 0, numsegs*sizeof(seg_t));
data = W_CacheLumpNum(lump,PU_STATIC);
for (i=0; i<numsegs; i++)
{
seg_t *li = segs+i;
mapseg_deepbsp_t *ml = (mapseg_deepbsp_t *) data + i;
int side, linedef;
line_t *ldef;
// [FG] extended nodes
li->v1 = &vertexes[ml->v1];
li->v2 = &vertexes[ml->v2];
li->angle = (SHORT(ml->angle))<<16;
li->offset = (SHORT(ml->offset))<<16;
linedef = (unsigned short)SHORT(ml->linedef); // [FG] extended nodes
ldef = &lines[linedef];
li->linedef = ldef;
side = SHORT(ml->side);
li->sidedef = &sides[ldef->sidenum[side]];
li->frontsector = sides[ldef->sidenum[side]].sector;
// killough 5/3/98: ignore 2s flag if second sidedef missing:
if (ldef->flags & ML_TWOSIDED && ldef->sidenum[side^1]!=NO_INDEX)
li->backsector = sides[ldef->sidenum[side^1]].sector;
else
li->backsector = 0;
}
Z_Free (data);
}
void P_LoadSubsectors_DeePBSP (int lump)
{
mapsubsector_deepbsp_t *data;
int i;
numsubsectors = W_LumpLength (lump) / sizeof(mapsubsector_deepbsp_t);
subsectors = Z_Malloc(numsubsectors*sizeof(subsector_t),PU_LEVEL,0);
data = (mapsubsector_deepbsp_t *)W_CacheLumpNum(lump, PU_STATIC);
memset(subsectors, 0, numsubsectors*sizeof(subsector_t));
for (i=0; i<numsubsectors; i++)
{
subsectors[i].numlines = (int)data[i].numsegs;
subsectors[i].firstline = (int)data[i].firstseg;
}
Z_Free (data);
}
void P_LoadNodes_DeePBSP (int lump)
{
byte *data;
int i;
numnodes = W_LumpLength (lump) / sizeof(mapnode_deepbsp_t);
nodes = Z_Malloc (numnodes*sizeof(node_t),PU_LEVEL,0);
data = W_CacheLumpNum (lump, PU_STATIC);
// [FG] skip header
data += 8;
for (i=0; i<numnodes; i++)
{
node_t *no = nodes + i;
mapnode_deepbsp_t *mn = (mapnode_deepbsp_t *) data + i;
int j;
no->x = SHORT(mn->x)<<FRACBITS;
no->y = SHORT(mn->y)<<FRACBITS;
no->dx = SHORT(mn->dx)<<FRACBITS;
no->dy = SHORT(mn->dy)<<FRACBITS;
for (j=0 ; j<2 ; j++)
{
int k;
no->children[j] = (unsigned int)(mn->children[j]);
for (k=0 ; k<4 ; k++)
no->bbox[j][k] = SHORT(mn->bbox[j][k])<<FRACBITS;
}
}
W_CacheLumpNum(lump, PU_CACHE);
}
// [FG] support maps with compressed or uncompressed ZDBSP nodes
// adapted from prboom-plus/src/p_setup.c:1040-1331
// heavily modified, condensed and simplyfied
// - removed most paranoid checks, brought in line with Vanilla P_LoadNodes()
// - removed const type punning pointers
// - inlined P_LoadZSegs()
// - added support for compressed ZDBSP nodes
// - added support for flipped levels
void P_LoadNodes_ZDBSP (int lump, boolean compressed)
{
byte *data;
unsigned int i;
#ifdef z_FOUND
byte *output;
#endif
unsigned int orgVerts, newVerts;
unsigned int numSubs, currSeg;
unsigned int numSegs;
unsigned int numNodes;
vertex_t *newvertarray = NULL;
data = W_CacheLumpNum(lump, PU_LEVEL);
// 0. Uncompress nodes lump (or simply skip header)
if (compressed)
{
#ifdef z_FOUND
const int len = W_LumpLength(lump);
int outlen, err;
z_stream *zstream;
// first estimate for compression rate:
// output buffer size == 2.5 * input size
outlen = 2.5 * len;
output = Z_Malloc(outlen, PU_STATIC, 0);
// initialize stream state for decompression
zstream = malloc(sizeof(*zstream));
memset(zstream, 0, sizeof(*zstream));
zstream->next_in = data + 4;
zstream->avail_in = len - 4;
zstream->next_out = output;
zstream->avail_out = outlen;
if (inflateInit(zstream) != Z_OK)
I_Error("P_LoadNodes: Error during ZDBSP nodes decompression initialization!");
// resize if output buffer runs full
while ((err = inflate(zstream, Z_SYNC_FLUSH)) == Z_OK)
{
int outlen_old = outlen;
outlen = 2 * outlen_old;
output = Z_Realloc(output, outlen, PU_STATIC, 0);
zstream->next_out = output + outlen_old;
zstream->avail_out = outlen - outlen_old;
}
if (err != Z_STREAM_END)
I_Error("P_LoadNodes: Error during ZDBSP nodes decompression!");
fprintf(stderr, "P_LoadNodes: ZDBSP nodes compression ratio %.3f\n",
(float)zstream->total_out/zstream->total_in);
data = output;
if (inflateEnd(zstream) != Z_OK)
I_Error("P_LoadNodes: Error during ZDBSP nodes decompression shut-down!");
// release the original data lump
W_CacheLumpNum(lump, PU_CACHE);
free(zstream);
#else
I_Error("P_LoadNodes: Compressed ZDBSP nodes are not supported!");
#endif
}
else
{
// skip header
data += 4;
}
// 1. Load new vertices added during node building
orgVerts = *((unsigned int*)data);
data += sizeof(orgVerts);
newVerts = *((unsigned int*)data);
data += sizeof(newVerts);
if (orgVerts + newVerts == (unsigned int)numvertexes)
{
newvertarray = vertexes;
}
else
{
newvertarray = Z_Malloc((orgVerts + newVerts) * sizeof(vertex_t), PU_LEVEL, 0);
memcpy(newvertarray, vertexes, orgVerts * sizeof(vertex_t));
memset(newvertarray + orgVerts, 0, newVerts * sizeof(vertex_t));
}
for (i = 0; i < newVerts; i++)
{
newvertarray[i + orgVerts].x = *((unsigned int*)data);
data += sizeof(newvertarray[0].x);
newvertarray[i + orgVerts].y = *((unsigned int*)data);
data += sizeof(newvertarray[0].y);
}
if (vertexes != newvertarray)
{
for (i = 0; i < (unsigned int)numlines; i++)
{
lines[i].v1 = lines[i].v1 - vertexes + newvertarray;
lines[i].v2 = lines[i].v2 - vertexes + newvertarray;
}
Z_Free(vertexes);
vertexes = newvertarray;
numvertexes = orgVerts + newVerts;
}
// 2. Load subsectors
numSubs = *((unsigned int*)data);
data += sizeof(numSubs);
if (numSubs < 1)
I_Error("P_LoadNodes: No subsectors in map!");
numsubsectors = numSubs;
subsectors = Z_Malloc(numsubsectors * sizeof(subsector_t), PU_LEVEL, 0);
for (i = currSeg = 0; i < numsubsectors; i++)
{
mapsubsector_zdbsp_t *mseg = (mapsubsector_zdbsp_t*) data + i;
subsectors[i].firstline = currSeg;
subsectors[i].numlines = mseg->numsegs;
currSeg += mseg->numsegs;
}
data += numsubsectors * sizeof(mapsubsector_zdbsp_t);
// 3. Load segs
numSegs = *((unsigned int*)data);
data += sizeof(numSegs);
// The number of stored segs should match the number of segs used by subsectors
if (numSegs != currSeg)
{
I_Error("P_LoadNodes: Incorrect number of segs in ZDBSP nodes!");
}
numsegs = numSegs;
segs = Z_Malloc(numsegs * sizeof(seg_t), PU_LEVEL, 0);
for (i = 0; i < numsegs; i++)
{
line_t *ldef;
unsigned int linedef;
unsigned char side;
seg_t *li = segs + i;
mapseg_zdbsp_t *ml = (mapseg_zdbsp_t *) data + i;
li->v1 = &vertexes[ml->v1];
li->v2 = &vertexes[ml->v2];
linedef = (unsigned short)SHORT(ml->linedef);
ldef = &lines[linedef];
li->linedef = ldef;
side = ml->side;
// e6y: check for wrong indexes
if ((unsigned)ldef->sidenum[side] >= (unsigned)numsides)
{
I_Error("P_LoadSegs: linedef %d for seg %d references a non-existent sidedef %d",
linedef, i, (unsigned)ldef->sidenum[side]);
}
li->sidedef = &sides[ldef->sidenum[side]];
li->frontsector = sides[ldef->sidenum[side]].sector;
// seg angle and offset are not included
li->angle = R_PointToAngle2(segs[i].v1->x, segs[i].v1->y, segs[i].v2->x, segs[i].v2->y);
li->offset = GetOffset(li->v1, (ml->side ? ldef->v2 : ldef->v1));
// killough 5/3/98: ignore 2s flag if second sidedef missing:
if (ldef->flags & ML_TWOSIDED && ldef->sidenum[side^1]!=NO_INDEX)
li->backsector = sides[ldef->sidenum[side^1]].sector;
else
li->backsector = 0;
}
data += numsegs * sizeof(mapseg_zdbsp_t);
// 4. Load nodes
numNodes = *((unsigned int*)data);
data += sizeof(numNodes);
numnodes = numNodes;
nodes = Z_Malloc(numnodes * sizeof(node_t), PU_LEVEL, 0);
for (i = 0; i < numnodes; i++)
{
int j, k;
node_t *no = nodes + i;
mapnode_zdbsp_t *mn = (mapnode_zdbsp_t *) data + i;
no->x = SHORT(mn->x)<<FRACBITS;
no->y = SHORT(mn->y)<<FRACBITS;
no->dx = SHORT(mn->dx)<<FRACBITS;
no->dy = SHORT(mn->dy)<<FRACBITS;
for (j = 0; j < 2; j++)
{
no->children[j] = (unsigned int)(mn->children[j]);
for (k = 0; k < 4; k++)
no->bbox[j][k] = SHORT(mn->bbox[j][k])<<FRACBITS;
}
}
#ifdef z_FOUND
if (compressed)
Z_Free(output);
else
#endif
W_CacheLumpNum(lump, PU_CACHE);
}

49
Source/p_extnodes.h Normal file
View File

@ -0,0 +1,49 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id: r_defs.h,v 1.18 1998/04/27 02:12:59 killough Exp $
//
// Copyright (C) 1999 by
// id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
// Copyright(C) 2015-2020 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.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
// 02111-1307, USA.
//
// DESCRIPTION:
// support maps with NODES in compressed or uncompressed ZDBSP format or DeePBSP format
//
//-----------------------------------------------------------------------------
#ifndef __P_EXTNODES__
#define __P_EXTNODES__
typedef enum
{
MFMT_DOOMBSP = 0x000,
MFMT_DEEPBSP = 0x001,
MFMT_ZDBSPX = 0x002,
MFMT_ZDBSPZ = 0x004,
} mapformat_t;
extern mapformat_t P_CheckMapFormat (int lumpnum);
extern void P_LoadSegs_DeePBSP (int lump);
extern void P_LoadSubsectors_DeePBSP (int lump);
extern void P_LoadNodes_DeePBSP (int lump);
extern void P_LoadNodes_ZDBSP (int lump, boolean compressed);
#endif

View File

@ -42,6 +42,9 @@
#include "p_enemy.h"
#include "s_sound.h"
// [FG] support maps with NODES in compressed or uncompressed ZDBSP format or DeePBSP format
#include "p_extnodes.h"
//
// MAP related Lookup tables.
// Store VERTEXES, LINEDEFS, SIDEDEFS, etc.
@ -284,21 +287,6 @@ void P_LoadNodes (int lump)
nodes = Z_Malloc (numnodes*sizeof(node_t),PU_LEVEL,0);
data = W_CacheLumpNum (lump, PU_STATIC);
// [FG] warn about unsupported node formats and exit gracefully
if (W_LumpLength(lump) >= 8)
{
if (!memcmp(data, "xNd4\0\0\0\0", 8) ||
!memcmp(data, "XNOD", 4) ||
!memcmp(data, "ZNOD", 4))
{
char fmt[5];
memcpy(fmt, data, 4);
fmt[4] = '\0';
I_Error("Unsupported nodes format for %s: %s.\n",
lumpinfo[lump-ML_NODES].name, fmt);
}
}
for (i=0; i<numnodes; i++)
{
node_t *no = nodes + i;
@ -990,6 +978,7 @@ void P_SetupLevel(int episode, int map, int playermask, skill_t skill)
int i;
char lumpname[9];
int lumpnum;
mapformat_t mapformat;
totalkills = totalitems = totalsecret = wminfo.maxfrags = 0;
wminfo.partime = 180;
@ -1025,6 +1014,9 @@ void P_SetupLevel(int episode, int map, int playermask, skill_t skill)
// killough 4/4/98: split load of sidedefs into two parts,
// to allow texture names to be used in special linedefs
// [FG] check nodes format
mapformat = P_CheckMapFormat(lumpnum);
P_LoadVertexes (lumpnum+ML_VERTEXES);
P_LoadSectors (lumpnum+ML_SECTORS);
P_LoadSideDefs (lumpnum+ML_SIDEDEFS); // killough 4/4/98
@ -1032,9 +1024,23 @@ void P_SetupLevel(int episode, int map, int playermask, skill_t skill)
P_LoadSideDefs2 (lumpnum+ML_SIDEDEFS); // |
P_LoadLineDefs2 (lumpnum+ML_LINEDEFS); // killough 4/4/98
P_LoadBlockMap (lumpnum+ML_BLOCKMAP); // killough 3/1/98
// [FG] support maps with NODES in compressed or uncompressed ZDBSP format or DeePBSP format
if (mapformat == MFMT_ZDBSPX || mapformat == MFMT_ZDBSPZ)
{
P_LoadNodes_ZDBSP (lumpnum+ML_NODES, mapformat == MFMT_ZDBSPZ);
}
else if (mapformat == MFMT_DEEPBSP)
{
P_LoadSubsectors_DeePBSP (lumpnum+ML_SSECTORS);
P_LoadNodes_DeePBSP (lumpnum+ML_NODES);
P_LoadSegs_DeePBSP (lumpnum+ML_SEGS);
}
else
{
P_LoadSubsectors(lumpnum+ML_SSECTORS);
P_LoadNodes (lumpnum+ML_NODES);
P_LoadSegs (lumpnum+ML_SEGS);
}
// [FG] pad the REJECT table when the lump is too small
P_LoadReject (lumpnum+ML_REJECT);

View File

@ -3,3 +3,4 @@
#cmakedefine PROJECT_TARNAME "@PROJECT_TARNAME@"
#cmakedefine m_FOUND
#cmakedefine dl_FOUND
#cmakedefine z_FOUND