mirror of
https://github.com/ZDoom/zdbsp.git
synced 2024-11-24 12:51:24 +00:00
c51e49f02f
- Fixed the OrgSectorMap generation in FLevel::RemoveExtraSectors(). - Added a version of ClassifyLine compiled with SSE (but not SSE2) optimization for people with Pentium 3/Athlon XPs to use. - Added ClassifyLine backpatching for the GCC Windows build. The first time a function calls ClassifyLine, it has to check which version to use and jump to the appropriate one. After that, it calls the desired one straight away. SVN r227 (trunk)
1449 lines
34 KiB
C++
1449 lines
34 KiB
C++
/*
|
|
Reads wad files, builds nodes, and saves new wad files.
|
|
Copyright (C) 2002-2006 Randy Heit
|
|
|
|
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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
*/
|
|
|
|
#include "processor.h"
|
|
//#include "rejectbuilder.h"
|
|
|
|
extern void ShowView (FLevel *level);
|
|
|
|
enum
|
|
{
|
|
// Thing numbers used in Hexen maps
|
|
PO_HEX_ANCHOR_TYPE = 3000,
|
|
PO_HEX_SPAWN_TYPE,
|
|
PO_HEX_SPAWNCRUSH_TYPE,
|
|
|
|
// Thing numbers used in Doom and Heretic maps
|
|
PO_ANCHOR_TYPE = 9300,
|
|
PO_SPAWN_TYPE,
|
|
PO_SPAWNCRUSH_TYPE
|
|
};
|
|
|
|
FLevel::FLevel ()
|
|
{
|
|
memset (this, 0, sizeof(*this));
|
|
}
|
|
|
|
FLevel::~FLevel ()
|
|
{
|
|
if (Things) delete[] Things;
|
|
if (Lines) delete[] Lines;
|
|
if (Vertices) delete[] Vertices;
|
|
if (Sides) delete[] Sides;
|
|
if (Sectors) delete[] Sectors;
|
|
if (Subsectors) delete[] Subsectors;
|
|
if (Segs) delete[] Segs;
|
|
if (Nodes) delete[] Nodes;
|
|
if (Blockmap) delete[] Blockmap;
|
|
if (Reject) delete[] Reject;
|
|
if (GLSubsectors) delete[] GLSubsectors;
|
|
if (GLSegs) delete[] GLSegs;
|
|
if (GLNodes) delete[] GLNodes;
|
|
if (GLPVS) delete[] GLPVS;
|
|
if (OrgSectorMap) delete[] OrgSectorMap;
|
|
}
|
|
|
|
FProcessor::FProcessor (FWadReader &inwad, int lump)
|
|
:
|
|
Wad (inwad), Lump (lump)
|
|
{
|
|
printf ("----%s----\n", Wad.LumpName (Lump));
|
|
|
|
Extended = Wad.MapHasBehavior (lump);
|
|
LoadThings ();
|
|
LoadVertices ();
|
|
LoadLines ();
|
|
LoadSides ();
|
|
LoadSectors ();
|
|
|
|
if (Level.NumLines == 0 || Level.NumVertices == 0 || Level.NumSides == 0 || Level.NumSectors == 0)
|
|
{
|
|
printf (" Map is incomplete\n");
|
|
}
|
|
else
|
|
{
|
|
// Removing extra vertices is done by the node builder.
|
|
Level.RemoveExtraLines ();
|
|
if (!NoPrune)
|
|
{
|
|
Level.RemoveExtraSides ();
|
|
Level.RemoveExtraSectors ();
|
|
}
|
|
|
|
if (BuildNodes)
|
|
{
|
|
GetPolySpots ();
|
|
}
|
|
|
|
Level.FindMapBounds ();
|
|
}
|
|
}
|
|
|
|
void FProcessor::LoadThings ()
|
|
{
|
|
if (Extended)
|
|
{
|
|
ReadMapLump<MapThing2> (Wad, "THINGS", Lump, Level.Things, Level.NumThings);
|
|
|
|
for (int i = 0; i < Level.NumThings; ++i)
|
|
{
|
|
Level.Things[i].x = LittleShort(Level.Things[i].x);
|
|
Level.Things[i].y = LittleShort(Level.Things[i].y);
|
|
Level.Things[i].angle = LittleShort(Level.Things[i].angle);
|
|
Level.Things[i].type = LittleShort(Level.Things[i].type);
|
|
Level.Things[i].flags = LittleShort(Level.Things[i].flags);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
MapThing *mt;
|
|
ReadMapLump<MapThing> (Wad, "THINGS", Lump, mt, Level.NumThings);
|
|
|
|
Level.Things = new MapThing2[Level.NumThings];
|
|
memset (Level.Things, 0, sizeof(*Level.Things)*Level.NumThings);
|
|
for (int i = 0; i < Level.NumThings; ++i)
|
|
{
|
|
Level.Things[i].x = LittleShort(mt[i].x);
|
|
Level.Things[i].y = LittleShort(mt[i].y);
|
|
Level.Things[i].angle = LittleShort(mt[i].angle);
|
|
Level.Things[i].type = LittleShort(mt[i].type);
|
|
Level.Things[i].flags = LittleShort(mt[i].flags);
|
|
}
|
|
delete[] mt;
|
|
}
|
|
}
|
|
|
|
void FProcessor::LoadLines ()
|
|
{
|
|
if (Extended)
|
|
{
|
|
ReadMapLump<MapLineDef2> (Wad, "LINEDEFS", Lump, Level.Lines, Level.NumLines);
|
|
|
|
for (int i = 0; i < Level.NumLines; ++i)
|
|
{
|
|
Level.Lines[i].v1 = LittleShort(Level.Lines[i].v1);
|
|
Level.Lines[i].v2 = LittleShort(Level.Lines[i].v2);
|
|
Level.Lines[i].flags = LittleShort(Level.Lines[i].flags);
|
|
Level.Lines[i].sidenum[0] = LittleShort(Level.Lines[i].sidenum[0]);
|
|
Level.Lines[i].sidenum[1] = LittleShort(Level.Lines[i].sidenum[1]);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
MapLineDef *ml;
|
|
ReadMapLump<MapLineDef> (Wad, "LINEDEFS", Lump, ml, Level.NumLines);
|
|
|
|
Level.Lines = new MapLineDef2[Level.NumLines];
|
|
memset (Level.Lines, 0, sizeof(*Level.Lines)*Level.NumLines);
|
|
for (int i = 0; i < Level.NumLines; ++i)
|
|
{
|
|
Level.Lines[i].v1 = LittleShort(ml[i].v1);
|
|
Level.Lines[i].v2 = LittleShort(ml[i].v2);
|
|
Level.Lines[i].flags = LittleShort(ml[i].flags);
|
|
Level.Lines[i].sidenum[0] = LittleShort(ml[i].sidenum[0]);
|
|
Level.Lines[i].sidenum[1] = LittleShort(ml[i].sidenum[1]);
|
|
|
|
// Store the special and tag in the args array so we don't lose them
|
|
short t = LittleShort(ml[i].special);
|
|
Level.Lines[i].args[2] = t & 255;
|
|
Level.Lines[i].args[3] = t >> 8;
|
|
t = LittleShort(ml[i].tag);
|
|
Level.Lines[i].args[0] = t & 255;
|
|
Level.Lines[i].args[1] = t >> 8;
|
|
}
|
|
delete[] ml;
|
|
}
|
|
}
|
|
|
|
void FProcessor::LoadVertices ()
|
|
{
|
|
MapVertex *verts;
|
|
ReadMapLump<MapVertex> (Wad, "VERTEXES", Lump, verts, Level.NumVertices);
|
|
|
|
Level.Vertices = new WideVertex[Level.NumVertices];
|
|
|
|
for (int i = 0; i < Level.NumVertices; ++i)
|
|
{
|
|
Level.Vertices[i].x = LittleShort(verts[i].x) << FRACBITS;
|
|
Level.Vertices[i].y = LittleShort(verts[i].y) << FRACBITS;
|
|
}
|
|
}
|
|
|
|
void FProcessor::LoadSides ()
|
|
{
|
|
ReadMapLump<MapSideDef> (Wad, "SIDEDEFS", Lump, Level.Sides, Level.NumSides);
|
|
|
|
for (int i = 0; i < Level.NumSides; ++i)
|
|
{
|
|
Level.Sides[i].sector = LittleShort(Level.Sides[i].sector);
|
|
}
|
|
}
|
|
|
|
void FProcessor::LoadSectors ()
|
|
{
|
|
ReadMapLump<MapSector> (Wad, "SECTORS", Lump, Level.Sectors, Level.NumSectors);
|
|
}
|
|
|
|
void FLevel::FindMapBounds ()
|
|
{
|
|
fixed_t minx, maxx, miny, maxy;
|
|
|
|
minx = maxx = Vertices[0].x;
|
|
miny = maxy = Vertices[0].y;
|
|
|
|
for (int i = 1; i < NumVertices; ++i)
|
|
{
|
|
if (Vertices[i].x < minx) minx = Vertices[i].x;
|
|
else if (Vertices[i].x > maxx) maxx = Vertices[i].x;
|
|
if (Vertices[i].y < miny) miny = Vertices[i].y;
|
|
else if (Vertices[i].y > maxy) maxy = Vertices[i].y;
|
|
}
|
|
|
|
MinX = minx;
|
|
MinY = miny;
|
|
MaxX = maxx;
|
|
MaxY = maxy;
|
|
}
|
|
|
|
void FLevel::RemoveExtraLines ()
|
|
{
|
|
int i, newNumLines;
|
|
|
|
// Extra lines are those with 0 length. Collision detection against
|
|
// one of those could cause a divide by 0, so it's best to remove them.
|
|
|
|
for (i = newNumLines = 0; i < NumLines; ++i)
|
|
{
|
|
if (Vertices[Lines[i].v1].x != Vertices[Lines[i].v2].x ||
|
|
Vertices[Lines[i].v1].y != Vertices[Lines[i].v2].y)
|
|
{
|
|
if (i != newNumLines)
|
|
{
|
|
Lines[newNumLines] = Lines[i];
|
|
}
|
|
++newNumLines;
|
|
}
|
|
}
|
|
if (newNumLines < NumLines)
|
|
{
|
|
int diff = NumLines - newNumLines;
|
|
|
|
printf (" Removed %d line%s with 0 length.\n", diff, diff > 1 ? "s" : "");
|
|
}
|
|
NumLines = newNumLines;
|
|
}
|
|
|
|
void FLevel::RemoveExtraSides ()
|
|
{
|
|
BYTE *used;
|
|
WORD *remap;
|
|
int i, newNumSides;
|
|
|
|
// Extra sides are those that aren't referenced by any lines.
|
|
// They just waste space, so get rid of them.
|
|
|
|
used = new BYTE[NumSides];
|
|
memset (used, 0, NumSides*sizeof(*used));
|
|
remap = new WORD[NumSides];
|
|
|
|
// Mark all used sides
|
|
for (i = 0; i < NumLines; ++i)
|
|
{
|
|
if (Lines[i].sidenum[0] != NO_INDEX)
|
|
{
|
|
used[Lines[i].sidenum[0]] = 1;
|
|
}
|
|
else
|
|
{
|
|
printf (" Line %d needs a front sidedef before it will run with ZDoom.\n", i);
|
|
}
|
|
if (Lines[i].sidenum[1] != NO_INDEX)
|
|
{
|
|
used[Lines[i].sidenum[1]] = 1;
|
|
}
|
|
}
|
|
|
|
// Shift out any unused sides
|
|
for (i = newNumSides = 0; i < NumSides; ++i)
|
|
{
|
|
if (used[i])
|
|
{
|
|
if (i != newNumSides)
|
|
{
|
|
Sides[newNumSides] = Sides[i];
|
|
}
|
|
remap[i] = newNumSides++;
|
|
}
|
|
else
|
|
{
|
|
remap[i] = NO_INDEX;
|
|
}
|
|
}
|
|
|
|
if (newNumSides < NumSides)
|
|
{
|
|
int diff = NumSides - newNumSides;
|
|
|
|
printf (" Removed %d unused sidedef%s.\n", diff, diff > 1 ? "s" : "");
|
|
NumSides = newNumSides;
|
|
|
|
// Renumber side references in lines
|
|
for (i = 0; i < NumLines; ++i)
|
|
{
|
|
if (Lines[i].sidenum[0] != NO_INDEX)
|
|
{
|
|
Lines[i].sidenum[0] = remap[Lines[i].sidenum[0]];
|
|
}
|
|
if (Lines[i].sidenum[1] != NO_INDEX)
|
|
{
|
|
Lines[i].sidenum[1] = remap[Lines[i].sidenum[1]];
|
|
}
|
|
}
|
|
}
|
|
|
|
delete[] used;
|
|
delete[] remap;
|
|
}
|
|
|
|
void FLevel::RemoveExtraSectors ()
|
|
{
|
|
BYTE *used;
|
|
WORD *remap;
|
|
int i, newNumSectors;
|
|
|
|
// Extra sectors are those that aren't referenced by any sides.
|
|
// They just waste space, so get rid of them.
|
|
|
|
NumOrgSectors = NumSectors;
|
|
used = new BYTE[NumSectors];
|
|
memset (used, 0, NumSectors*sizeof(*used));
|
|
remap = new WORD[NumSectors];
|
|
|
|
// Mark all used sectors
|
|
for (i = 0; i < NumSides; ++i)
|
|
{
|
|
if (Sides[i].sector != NO_INDEX)
|
|
{
|
|
used[Sides[i].sector] = 1;
|
|
}
|
|
else
|
|
{
|
|
printf (" Sidedef %d needs a front sector before it will run with ZDoom.\n", i);
|
|
}
|
|
}
|
|
|
|
// Shift out any unused sides
|
|
for (i = newNumSectors = 0; i < NumSectors; ++i)
|
|
{
|
|
if (used[i])
|
|
{
|
|
if (i != newNumSectors)
|
|
{
|
|
Sectors[newNumSectors] = Sectors[i];
|
|
}
|
|
remap[i] = newNumSectors++;
|
|
}
|
|
else
|
|
{
|
|
remap[i] = NO_INDEX;
|
|
}
|
|
}
|
|
|
|
if (newNumSectors < NumSectors)
|
|
{
|
|
int diff = NumSectors - newNumSectors;
|
|
printf (" Removed %d unused sector%s.\n", diff, diff > 1 ? "s" : "");
|
|
|
|
// Renumber sector references in sides
|
|
for (i = 0; i < NumSides; ++i)
|
|
{
|
|
if (Sides[i].sector != NO_INDEX)
|
|
{
|
|
Sides[i].sector = remap[Sides[i].sector];
|
|
}
|
|
}
|
|
// Make a reverse map for fixing reject lumps
|
|
OrgSectorMap = new WORD[newNumSectors];
|
|
for (i = 0; i < NumSectors; ++i)
|
|
{
|
|
if (remap[i] != NO_INDEX)
|
|
{
|
|
OrgSectorMap[remap[i]] = i;
|
|
}
|
|
}
|
|
|
|
NumSectors = newNumSectors;
|
|
}
|
|
|
|
delete[] used;
|
|
delete[] remap;
|
|
}
|
|
|
|
void FProcessor::GetPolySpots ()
|
|
{
|
|
if (Extended && CheckPolyobjs)
|
|
{
|
|
int spot1, spot2, anchor, i;
|
|
|
|
// Determine if this is a Hexen map by looking for things of type 3000
|
|
// Only Hexen maps use them, and they are the polyobject anchors
|
|
for (i = 0; i < Level.NumThings; ++i)
|
|
{
|
|
if (Level.Things[i].type == PO_HEX_ANCHOR_TYPE)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (i < Level.NumThings)
|
|
{
|
|
spot1 = PO_HEX_SPAWN_TYPE;
|
|
spot2 = PO_HEX_SPAWNCRUSH_TYPE;
|
|
anchor = PO_HEX_ANCHOR_TYPE;
|
|
}
|
|
else
|
|
{
|
|
spot1 = PO_SPAWN_TYPE;
|
|
spot2 = PO_SPAWNCRUSH_TYPE;
|
|
anchor = PO_ANCHOR_TYPE;
|
|
}
|
|
|
|
for (i = 0; i < Level.NumThings; ++i)
|
|
{
|
|
if (Level.Things[i].type == spot1 ||
|
|
Level.Things[i].type == spot2 ||
|
|
Level.Things[i].type == anchor)
|
|
{
|
|
FNodeBuilder::FPolyStart newvert;
|
|
newvert.x = Level.Things[i].x << FRACBITS;
|
|
newvert.y = Level.Things[i].y << FRACBITS;
|
|
newvert.polynum = Level.Things[i].angle;
|
|
if (Level.Things[i].type == anchor)
|
|
{
|
|
PolyAnchors.Push (newvert);
|
|
}
|
|
else
|
|
{
|
|
PolyStarts.Push (newvert);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void FProcessor::Write (FWadWriter &out)
|
|
{
|
|
if (Level.NumLines == 0 || Level.NumSides == 0 || Level.NumSectors == 0 || Level.NumVertices == 0)
|
|
{
|
|
// Map is empty, so just copy it as-is
|
|
out.CopyLump (Wad, Lump);
|
|
out.CopyLump (Wad, Wad.FindMapLump ("THINGS", Lump));
|
|
out.CopyLump (Wad, Wad.FindMapLump ("LINEDEFS", Lump));
|
|
out.CopyLump (Wad, Wad.FindMapLump ("SIDEDEFS", Lump));
|
|
out.CopyLump (Wad, Wad.FindMapLump ("VERTEXES", Lump));
|
|
out.CreateLabel ("SEGS");
|
|
out.CreateLabel ("SSECTORS");
|
|
out.CreateLabel ("NODES");
|
|
out.CopyLump (Wad, Wad.FindMapLump ("SECTORS", Lump));
|
|
out.CreateLabel ("REJECT");
|
|
out.CreateLabel ("BLOCKMAP");
|
|
if (Extended)
|
|
{
|
|
out.CopyLump (Wad, Wad.FindMapLump ("BEHAVIOR", Lump));
|
|
out.CopyLump (Wad, Wad.FindMapLump ("SCRIPTS", Lump));
|
|
}
|
|
return;
|
|
}
|
|
|
|
bool compress, compressGL, gl5;
|
|
|
|
#ifdef BLOCK_TEST
|
|
int size;
|
|
BYTE *blockmap;
|
|
ReadLump<BYTE> (Wad, Wad.FindMapLump ("BLOCKMAP", Lump), blockmap, size);
|
|
if (blockmap)
|
|
{
|
|
FILE *f = fopen ("blockmap.lmp", "wb");
|
|
if (f)
|
|
{
|
|
fwrite (blockmap, 1, size, f);
|
|
fclose (f);
|
|
}
|
|
delete[] blockmap;
|
|
}
|
|
#endif
|
|
|
|
if (BuildNodes)
|
|
{
|
|
FNodeBuilder *builder = NULL;
|
|
|
|
try
|
|
{
|
|
int ssetype;
|
|
|
|
if (HaveSSE2)
|
|
{
|
|
ssetype = 2;
|
|
}
|
|
else if (HaveSSE1)
|
|
{
|
|
ssetype = 1;
|
|
}
|
|
else
|
|
{
|
|
ssetype = 0;
|
|
}
|
|
builder = new FNodeBuilder (Level, PolyStarts, PolyAnchors, Wad.LumpName (Lump), BuildGLNodes, ssetype);
|
|
if (builder == NULL)
|
|
{
|
|
throw std::runtime_error(" Not enough memory to build nodes!");
|
|
}
|
|
|
|
delete[] Level.Vertices;
|
|
builder->GetVertices (Level.Vertices, Level.NumVertices);
|
|
|
|
if (ConformNodes)
|
|
{
|
|
// When the nodes are "conformed", the normal and GL nodes use the same
|
|
// basic information. This creates normal nodes that are less "good" than
|
|
// possible, but it makes it easier to compare the two sets of nodes to
|
|
// determine the correctness of the GL nodes.
|
|
builder->GetNodes (Level.Nodes, Level.NumNodes,
|
|
Level.Segs, Level.NumSegs,
|
|
Level.Subsectors, Level.NumSubsectors);
|
|
builder->GetVertices (Level.GLVertices, Level.NumGLVertices);
|
|
builder->GetGLNodes (Level.GLNodes, Level.NumGLNodes,
|
|
Level.GLSegs, Level.NumGLSegs,
|
|
Level.GLSubsectors, Level.NumGLSubsectors);
|
|
}
|
|
else
|
|
{
|
|
if (BuildGLNodes)
|
|
{
|
|
builder->GetVertices (Level.GLVertices, Level.NumGLVertices);
|
|
builder->GetGLNodes (Level.GLNodes, Level.NumGLNodes,
|
|
Level.GLSegs, Level.NumGLSegs,
|
|
Level.GLSubsectors, Level.NumGLSubsectors);
|
|
|
|
if (!GLOnly)
|
|
{
|
|
// Now repeat the process to obtain regular nodes
|
|
delete builder;
|
|
builder = new FNodeBuilder (Level, PolyStarts, PolyAnchors, Wad.LumpName (Lump), false, ssetype);
|
|
if (builder == NULL)
|
|
{
|
|
throw std::runtime_error(" Not enough memory to build regular nodes!");
|
|
}
|
|
delete[] Level.Vertices;
|
|
builder->GetVertices (Level.Vertices, Level.NumVertices);
|
|
}
|
|
}
|
|
if (!GLOnly)
|
|
{
|
|
builder->GetNodes (Level.Nodes, Level.NumNodes,
|
|
Level.Segs, Level.NumSegs,
|
|
Level.Subsectors, Level.NumSubsectors);
|
|
}
|
|
}
|
|
delete builder;
|
|
builder = NULL;
|
|
}
|
|
catch (...)
|
|
{
|
|
if (builder != NULL)
|
|
{
|
|
delete builder;
|
|
}
|
|
throw;
|
|
}
|
|
}
|
|
|
|
FBlockmapBuilder bbuilder (Level);
|
|
WORD *blocks = bbuilder.GetBlockmap (Level.BlockmapSize);
|
|
Level.Blockmap = new WORD[Level.BlockmapSize];
|
|
memcpy (Level.Blockmap, blocks, Level.BlockmapSize*sizeof(WORD));
|
|
|
|
Level.RejectSize = (Level.NumSectors*Level.NumSectors + 7) / 8;
|
|
Level.Reject = NULL;
|
|
|
|
switch (RejectMode)
|
|
{
|
|
case ERM_Rebuild:
|
|
//FRejectBuilder reject (Level);
|
|
//Level.Reject = reject.GetReject ();
|
|
printf (" Rebuilding the reject is unsupported.\n");
|
|
// Intentional fall-through
|
|
|
|
case ERM_DontTouch:
|
|
{
|
|
int lump = Wad.FindMapLump ("REJECT", Lump);
|
|
|
|
if (lump >= 0)
|
|
{
|
|
ReadLump<BYTE> (Wad, lump, Level.Reject, Level.RejectSize);
|
|
if (Level.RejectSize != (Level.NumOrgSectors*Level.NumOrgSectors + 7) / 8)
|
|
{
|
|
// If the reject is the wrong size, don't use it.
|
|
delete[] Level.Reject;
|
|
Level.Reject = NULL;
|
|
if (Level.RejectSize != 0)
|
|
{ // Do not warn about 0-length rejects
|
|
printf (" REJECT is the wrong size, so it will be removed.\n");
|
|
}
|
|
Level.RejectSize = 0;
|
|
}
|
|
else if (Level.NumOrgSectors != Level.NumSectors)
|
|
{
|
|
// Some sectors have been removed, so fix the reject.
|
|
BYTE *newreject = FixReject (Level.Reject);
|
|
delete[] Level.Reject;
|
|
Level.Reject = newreject;
|
|
Level.RejectSize = (Level.NumSectors * Level.NumSectors + 7) / 8;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case ERM_Create0:
|
|
break;
|
|
|
|
case ERM_CreateZeroes:
|
|
Level.Reject = new BYTE[Level.RejectSize];
|
|
memset (Level.Reject, 0, Level.RejectSize);
|
|
break;
|
|
}
|
|
|
|
if (ShowMap)
|
|
{
|
|
#ifndef NO_MAP_VIEWER
|
|
if(BuildNodes||BuildGLNodes)
|
|
{
|
|
ShowView (&Level);
|
|
}
|
|
else
|
|
{
|
|
puts(" ERROR: You can't view the nodes (-v) if you don't build them! (-N).");
|
|
}
|
|
#else
|
|
puts (" This version of ZDBSP was not compiled with the map viewer enabled.");
|
|
#endif
|
|
}
|
|
|
|
if (Level.GLNodes != NULL )
|
|
{
|
|
gl5 = V5GLNodes ||
|
|
(Level.NumGLVertices > 32767) ||
|
|
(Level.NumGLSegs > 65534) ||
|
|
(Level.NumGLNodes > 32767) ||
|
|
(Level.NumGLSubsectors > 32767);
|
|
compressGL = CompressGLNodes || (Level.NumVertices > 32767);
|
|
}
|
|
else
|
|
{
|
|
compressGL = false;
|
|
}
|
|
|
|
// If the GL nodes are compressed, then the regular nodes must also be compressed.
|
|
compress = CompressNodes || compressGL ||
|
|
(Level.NumVertices > 65535) ||
|
|
(Level.NumSegs > 65535) ||
|
|
(Level.NumSubsectors > 32767) ||
|
|
(Level.NumNodes > 32767);
|
|
|
|
out.CopyLump (Wad, Lump);
|
|
out.CopyLump (Wad, Wad.FindMapLump ("THINGS", Lump));
|
|
WriteLines (out);
|
|
WriteSides (out);
|
|
WriteVertices (out, compress || GLOnly ? Level.NumOrgVerts : Level.NumVertices);
|
|
if (BuildNodes)
|
|
{
|
|
if (!compress)
|
|
{
|
|
if (!GLOnly)
|
|
{
|
|
WriteSegs (out);
|
|
WriteSSectors (out);
|
|
WriteNodes (out);
|
|
}
|
|
else
|
|
{
|
|
out.CreateLabel ("SEGS");
|
|
out.CreateLabel ("SSECTORS");
|
|
out.CreateLabel ("NODES");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
out.CreateLabel ("SEGS");
|
|
if (compressGL)
|
|
{
|
|
WriteGLBSPZ (out, "SSECTORS");
|
|
}
|
|
else
|
|
{
|
|
out.CreateLabel ("SSECTORS");
|
|
}
|
|
if (!GLOnly)
|
|
{
|
|
WriteBSPZ (out, "NODES");
|
|
}
|
|
else
|
|
{
|
|
out.CreateLabel ("NODES");
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
out.CopyLump (Wad, Wad.FindMapLump ("SEGS", Lump));
|
|
out.CopyLump (Wad, Wad.FindMapLump ("SSECTORS", Lump));
|
|
out.CopyLump (Wad, Wad.FindMapLump ("NODES", Lump));
|
|
}
|
|
WriteSectors (out);
|
|
WriteReject (out);
|
|
WriteBlockmap (out);
|
|
if (Extended)
|
|
{
|
|
out.CopyLump (Wad, Wad.FindMapLump ("BEHAVIOR", Lump));
|
|
out.CopyLump (Wad, Wad.FindMapLump ("SCRIPTS", Lump));
|
|
}
|
|
if (Level.GLNodes != NULL && !compressGL)
|
|
{
|
|
char glname[9];
|
|
glname[0] = 'G';
|
|
glname[1] = 'L';
|
|
glname[2] = '_';
|
|
glname[8] = 0;
|
|
strncpy (glname+3, Wad.LumpName (Lump), 5);
|
|
out.CreateLabel (glname);
|
|
WriteGLVertices (out, gl5);
|
|
WriteGLSegs (out, gl5);
|
|
WriteGLSSect (out, gl5);
|
|
WriteGLNodes (out, gl5);
|
|
}
|
|
}
|
|
|
|
//
|
|
BYTE *FProcessor::FixReject (const BYTE *oldreject)
|
|
{
|
|
int x, y, ox, oy, pnum, opnum;
|
|
int rejectSize = (Level.NumSectors*Level.NumSectors + 7) / 8;
|
|
BYTE *newreject = new BYTE[rejectSize];
|
|
|
|
memset (newreject, 0, rejectSize);
|
|
|
|
for (y = 0; y < Level.NumSectors; ++y)
|
|
{
|
|
oy = Level.OrgSectorMap[y];
|
|
for (x = 0; x < Level.NumSectors; ++x)
|
|
{
|
|
ox = Level.OrgSectorMap[x];
|
|
pnum = y*Level.NumSectors + x;
|
|
opnum = oy*Level.NumSectors + ox;
|
|
|
|
if (oldreject[opnum >> 3] & (1 << (opnum & 7)))
|
|
{
|
|
newreject[pnum >> 3] |= 1 << (pnum & 7);
|
|
}
|
|
}
|
|
}
|
|
return newreject;
|
|
}
|
|
|
|
MapNodeEx *FProcessor::NodesToEx (const MapNode *nodes, int count)
|
|
{
|
|
if (count == 0)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
MapNodeEx *Nodes = new MapNodeEx[Level.NumNodes];
|
|
int x;
|
|
|
|
for (x = 0; x < count; ++x)
|
|
{
|
|
WORD child;
|
|
int i;
|
|
|
|
for (i = 0; i < 4+2*4; ++i)
|
|
{
|
|
*((WORD *)&Nodes[x] + i) = LittleShort(*((WORD *)&nodes[x] + i));
|
|
}
|
|
for (i = 0; i < 2; ++i)
|
|
{
|
|
child = LittleShort(nodes[x].children[i]);
|
|
if (child & NF_SUBSECTOR)
|
|
{
|
|
Nodes[x].children[i] = child + (NFX_SUBSECTOR - NF_SUBSECTOR);
|
|
}
|
|
else
|
|
{
|
|
Nodes[x].children[i] = child;
|
|
}
|
|
}
|
|
}
|
|
return Nodes;
|
|
}
|
|
|
|
MapSubsectorEx *FProcessor::SubsectorsToEx (const MapSubsector *ssec, int count)
|
|
{
|
|
if (count == 0)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
MapSubsectorEx *out = new MapSubsectorEx[Level.NumSubsectors];
|
|
int x;
|
|
|
|
for (x = 0; x < count; ++x)
|
|
{
|
|
out[x].numlines = LittleShort(ssec[x].numlines);
|
|
out[x].firstline = LittleShort(ssec[x].firstline);
|
|
}
|
|
|
|
return out;
|
|
}
|
|
|
|
MapSegGLEx *FProcessor::SegGLsToEx (const MapSegGL *segs, int count)
|
|
{
|
|
if (count == 0)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
MapSegGLEx *out = new MapSegGLEx[count];
|
|
int x;
|
|
|
|
for (x = 0; x < count; ++x)
|
|
{
|
|
out[x].v1 = LittleShort(segs[x].v1);
|
|
out[x].v2 = LittleShort(segs[x].v2);
|
|
out[x].linedef = LittleShort(segs[x].linedef);
|
|
out[x].side = LittleShort(segs[x].side);
|
|
out[x].partner = LittleShort(segs[x].partner);
|
|
}
|
|
|
|
return out;
|
|
}
|
|
|
|
void FProcessor::WriteVertices (FWadWriter &out, int count)
|
|
{
|
|
int i;
|
|
fixed_t *vertdata = (fixed_t *)Level.Vertices;
|
|
|
|
count *= 2;
|
|
short *verts = new short[count];
|
|
|
|
for (i = 0; i < count; ++i)
|
|
{
|
|
verts[i] = LittleShort(vertdata[i] >> FRACBITS);
|
|
}
|
|
out.WriteLump ("VERTEXES", verts, sizeof(*verts)*count);
|
|
delete[] verts;
|
|
|
|
if (count >= 65536)
|
|
{
|
|
printf (" VERTEXES is past the normal limit. (%d vertices)\n", count/2);
|
|
}
|
|
}
|
|
|
|
void FProcessor::WriteLines (FWadWriter &out)
|
|
{
|
|
int i;
|
|
|
|
if (Extended)
|
|
{
|
|
for (i = 0; i < Level.NumLines; ++i)
|
|
{
|
|
Level.Lines[i].v1 = LittleShort(Level.Lines[i].v1);
|
|
Level.Lines[i].v2 = LittleShort(Level.Lines[i].v2);
|
|
Level.Lines[i].flags = LittleShort(Level.Lines[i].flags);
|
|
Level.Lines[i].sidenum[0] = LittleShort(Level.Lines[i].sidenum[0]);
|
|
Level.Lines[i].sidenum[1] = LittleShort(Level.Lines[i].sidenum[1]);
|
|
}
|
|
out.WriteLump ("LINEDEFS", Level.Lines, Level.NumLines*sizeof(*Level.Lines));
|
|
}
|
|
else
|
|
{
|
|
MapLineDef *ld = new MapLineDef[Level.NumLines];
|
|
|
|
for (i = 0; i < Level.NumLines; ++i)
|
|
{
|
|
short t;
|
|
|
|
ld[i].v1 = LittleShort(Level.Lines[i].v1);
|
|
ld[i].v2 = LittleShort(Level.Lines[i].v2);
|
|
ld[i].flags = LittleShort(Level.Lines[i].flags);
|
|
ld[i].sidenum[0] = LittleShort(Level.Lines[i].sidenum[0]);
|
|
ld[i].sidenum[1] = LittleShort(Level.Lines[i].sidenum[1]);
|
|
|
|
t = Level.Lines[i].args[2] + (Level.Lines[i].args[3]<<8);
|
|
ld[i].special = LittleShort(t);
|
|
|
|
t = Level.Lines[i].args[0] + (Level.Lines[i].args[1]<<8);
|
|
ld[i].tag = LittleShort(t);
|
|
}
|
|
out.WriteLump ("LINEDEFS", ld, Level.NumLines*sizeof(*ld));
|
|
delete[] ld;
|
|
}
|
|
}
|
|
|
|
void FProcessor::WriteSides (FWadWriter &out)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < Level.NumSides; ++i)
|
|
{
|
|
Level.Sides[i].sector = LittleShort(Level.Sides[i].sector);
|
|
}
|
|
out.WriteLump ("SIDEDEFS", Level.Sides, Level.NumSides*sizeof(*Level.Sides));
|
|
}
|
|
|
|
void FProcessor::WriteSectors (FWadWriter &out)
|
|
{
|
|
out.WriteLump ("SECTORS", Level.Sectors, Level.NumSectors*sizeof(*Level.Sectors));
|
|
}
|
|
|
|
void FProcessor::WriteSegs (FWadWriter &out)
|
|
{
|
|
int i, count;
|
|
short *segdata;
|
|
|
|
segdata = (short *)Level.Segs;
|
|
count = Level.NumSegs*sizeof(MapSeg)/sizeof(*segdata);
|
|
|
|
for (i = 0; i < count; ++i)
|
|
{
|
|
segdata[i] = LittleShort(segdata[i]);
|
|
}
|
|
out.WriteLump ("SEGS", segdata, sizeof(*segdata)*count);
|
|
|
|
count /= sizeof(MapSeg)/sizeof(*segdata);
|
|
if (count >= 65536)
|
|
{
|
|
printf (" SEGS is too big for any port. (%d segs)\n", count);
|
|
}
|
|
else if (count >= 32768)
|
|
{
|
|
printf (" SEGS is too big for vanilla Doom and most ports. (%d segs)\n", count);
|
|
}
|
|
}
|
|
|
|
void FProcessor::WriteSSectors (FWadWriter &out) const
|
|
{
|
|
WriteSSectors2 (out, "SSECTORS", Level.Subsectors, Level.NumSubsectors);
|
|
}
|
|
|
|
void FProcessor::WriteSSectors2 (FWadWriter &out, const char *name, const MapSubsectorEx *subs, int count) const
|
|
{
|
|
int i;
|
|
MapSubsector *ssec;
|
|
|
|
ssec = new MapSubsector[count];
|
|
|
|
for (i = 0; i < count; ++i)
|
|
{
|
|
ssec[i].firstline = LittleShort((WORD)subs[i].firstline);
|
|
ssec[i].numlines = LittleShort((WORD)subs[i].numlines);
|
|
}
|
|
out.WriteLump (name, ssec, sizeof(*ssec)*count);
|
|
delete[] ssec;
|
|
|
|
if (count >= 65536)
|
|
{
|
|
printf (" %s is too big. (%d subsectors)\n", name, count);
|
|
}
|
|
}
|
|
|
|
void FProcessor::WriteSSectors5 (FWadWriter &out, const char *name, const MapSubsectorEx *subs, int count) const
|
|
{
|
|
int i;
|
|
MapSubsectorEx *ssec;
|
|
|
|
ssec = new MapSubsectorEx[count];
|
|
|
|
for (i = 0; i < count; ++i)
|
|
{
|
|
ssec[i].firstline = LittleLong(subs[i].firstline);
|
|
ssec[i].numlines = LittleLong(subs[i].numlines);
|
|
}
|
|
out.WriteLump (name, ssec, sizeof(*ssec)*count);
|
|
delete[] ssec;
|
|
}
|
|
|
|
void FProcessor::WriteNodes (FWadWriter &out) const
|
|
{
|
|
WriteNodes2 (out, "NODES", Level.Nodes, Level.NumNodes);
|
|
}
|
|
|
|
void FProcessor::WriteNodes2 (FWadWriter &out, const char *name, const MapNodeEx *zaNodes, int count) const
|
|
{
|
|
int i, j;
|
|
short *onodes, *nodes;
|
|
|
|
nodes = onodes = new short[count * sizeof(MapNode)/2];
|
|
|
|
for (i = 0; i < count; ++i)
|
|
{
|
|
short *inodes = (short *)&zaNodes[i];
|
|
for (j = 0; j < 4+2*4; ++j)
|
|
{
|
|
nodes[j] = LittleShort(inodes[j]);
|
|
}
|
|
nodes += j;
|
|
for (j = 0; j < 2; ++j)
|
|
{
|
|
DWORD child = zaNodes[i].children[j];
|
|
if (child & NFX_SUBSECTOR)
|
|
{
|
|
*nodes++ = LittleShort(WORD(child - (NFX_SUBSECTOR + NF_SUBSECTOR)));
|
|
}
|
|
else
|
|
{
|
|
*nodes++ = LittleShort((WORD)child);
|
|
}
|
|
}
|
|
}
|
|
out.WriteLump (name, onodes, count * sizeof(MapNode));
|
|
delete[] onodes;
|
|
|
|
if (count >= 32768)
|
|
{
|
|
printf (" %s is too big. (%d nodes)\n", name, count);
|
|
}
|
|
}
|
|
|
|
void FProcessor::WriteNodes5 (FWadWriter &out, const char *name, const MapNodeEx *zaNodes, int count) const
|
|
{
|
|
int i, j;
|
|
MapNodeEx *const nodes = new MapNodeEx[count * sizeof(MapNodeEx)];
|
|
|
|
for (i = 0; i < count; ++i)
|
|
{
|
|
const short *inodes = &zaNodes[i].x;
|
|
short *coord = &nodes[i].x;
|
|
for (j = 0; j < 4+2*4; ++j)
|
|
{
|
|
coord[j] = LittleShort(inodes[j]);
|
|
}
|
|
for (j = 0; j < 2; ++j)
|
|
{
|
|
nodes[i].children[j] = LittleLong(zaNodes[i].children[j]);
|
|
}
|
|
}
|
|
out.WriteLump (name, nodes, count * sizeof(MapNodeEx));
|
|
delete[] nodes;
|
|
}
|
|
|
|
void FProcessor::WriteBlockmap (FWadWriter &out)
|
|
{
|
|
if (BlockmapMode == EBM_Create0)
|
|
{
|
|
out.CreateLabel ("BLOCKMAP");
|
|
return;
|
|
}
|
|
|
|
size_t i, count;
|
|
WORD *blocks;
|
|
|
|
count = Level.BlockmapSize;
|
|
blocks = Level.Blockmap;
|
|
|
|
for (i = 0; i < count; ++i)
|
|
{
|
|
blocks[i] = LittleShort(blocks[i]);
|
|
}
|
|
out.WriteLump ("BLOCKMAP", blocks, int(sizeof(*blocks)*count));
|
|
|
|
#ifdef BLOCK_TEST
|
|
FILE *f = fopen ("blockmap.lm2", "wb");
|
|
if (f)
|
|
{
|
|
fwrite (blocks, count, sizeof(*blocks), f);
|
|
fclose (f);
|
|
}
|
|
#endif
|
|
|
|
for (i = 0; i < count; ++i)
|
|
{
|
|
blocks[i] = LittleShort(blocks[i]);
|
|
}
|
|
|
|
if (count >= 65536)
|
|
{
|
|
printf (" BLOCKMAP is so big that ports will have to recreate it.\n"
|
|
" Vanilla Doom cannot handle it at all. If this map is for ZDoom 2+,\n"
|
|
" you should use the -b switch to save space in the wad.\n");
|
|
}
|
|
else if (count >= 32768)
|
|
{
|
|
printf (" BLOCKMAP is too big for vanilla Doom.\n");
|
|
}
|
|
}
|
|
|
|
void FProcessor::WriteReject (FWadWriter &out)
|
|
{
|
|
if (RejectMode == ERM_Create0 || Level.Reject == NULL)
|
|
{
|
|
out.CreateLabel ("REJECT");
|
|
}
|
|
else
|
|
{
|
|
out.WriteLump ("REJECT", Level.Reject, Level.RejectSize);
|
|
}
|
|
}
|
|
|
|
void FProcessor::WriteGLVertices (FWadWriter &out, bool v5)
|
|
{
|
|
int i, count = (Level.NumGLVertices - Level.NumOrgVerts) * 2;
|
|
fixed_t *vertdata = (fixed_t *)Level.GLVertices + Level.NumOrgVerts * 2;
|
|
|
|
fixed_t *verts = new fixed_t[count+1];
|
|
char *magic = (char *)verts;
|
|
magic[0] = 'g';
|
|
magic[1] = 'N';
|
|
magic[2] = 'd';
|
|
magic[3] = v5 ? '5' : '2';
|
|
|
|
for (i = 0; i < count; ++i)
|
|
{
|
|
verts[i+1] = LittleLong(vertdata[i]);
|
|
}
|
|
out.WriteLump ("GL_VERT", verts, sizeof(*verts)*(count+1));
|
|
delete[] verts;
|
|
|
|
if (count > 65536)
|
|
{
|
|
printf (" GL_VERT is too big. (%d GL vertices)\n", count/2);
|
|
}
|
|
}
|
|
|
|
void FProcessor::WriteGLSegs (FWadWriter &out, bool v5)
|
|
{
|
|
if (v5)
|
|
{
|
|
WriteGLSegs5 (out);
|
|
return;
|
|
}
|
|
int i, count;
|
|
MapSegGL *segdata;
|
|
|
|
count = Level.NumGLSegs;
|
|
segdata = new MapSegGL[count];
|
|
|
|
for (i = 0; i < count; ++i)
|
|
{
|
|
if (Level.GLSegs[i].v1 < (DWORD)Level.NumOrgVerts)
|
|
{
|
|
segdata[i].v1 = LittleShort((WORD)Level.GLSegs[i].v1);
|
|
}
|
|
else
|
|
{
|
|
segdata[i].v1 = LittleShort(0x8000 | (WORD)(Level.GLSegs[i].v1 - Level.NumOrgVerts));
|
|
}
|
|
if (Level.GLSegs[i].v2 < (DWORD)Level.NumOrgVerts)
|
|
{
|
|
segdata[i].v2 = (WORD)LittleShort(Level.GLSegs[i].v2);
|
|
}
|
|
else
|
|
{
|
|
segdata[i].v2 = LittleShort(0x8000 | (WORD)(Level.GLSegs[i].v2 - Level.NumOrgVerts));
|
|
}
|
|
segdata[i].linedef = LittleShort(Level.GLSegs[i].linedef);
|
|
segdata[i].side = LittleShort(Level.GLSegs[i].side);
|
|
segdata[i].partner = LittleShort((WORD)Level.GLSegs[i].partner);
|
|
}
|
|
out.WriteLump ("GL_SEGS", segdata, sizeof(MapSegGL)*count);
|
|
delete[] segdata;
|
|
|
|
if (count >= 65536)
|
|
{
|
|
printf (" GL_SEGS is too big for any port. (%d GL segs)\n", count);
|
|
}
|
|
else if (count >= 32768)
|
|
{
|
|
printf (" GL_SEGS is too big for some ports. (%d GL segs)\n", count);
|
|
}
|
|
}
|
|
|
|
void FProcessor::WriteGLSegs5 (FWadWriter &out)
|
|
{
|
|
int i, count;
|
|
MapSegGLEx *segdata;
|
|
|
|
count = Level.NumGLSegs;
|
|
segdata = new MapSegGLEx[count];
|
|
|
|
for (i = 0; i < count; ++i)
|
|
{
|
|
if (Level.GLSegs[i].v1 < (DWORD)Level.NumOrgVerts)
|
|
{
|
|
segdata[i].v1 = LittleLong(Level.GLSegs[i].v1);
|
|
}
|
|
else
|
|
{
|
|
segdata[i].v1 = LittleLong(0x80000000u | ((int)Level.GLSegs[i].v1 - Level.NumOrgVerts));
|
|
}
|
|
if (Level.GLSegs[i].v2 < (DWORD)Level.NumOrgVerts)
|
|
{
|
|
segdata[i].v2 = LittleLong(Level.GLSegs[i].v2);
|
|
}
|
|
else
|
|
{
|
|
segdata[i].v2 = LittleLong(0x80000000u | ((int)Level.GLSegs[i].v2 - Level.NumOrgVerts));
|
|
}
|
|
segdata[i].linedef = LittleShort(Level.GLSegs[i].linedef);
|
|
segdata[i].side = LittleShort(Level.GLSegs[i].side);
|
|
segdata[i].partner = LittleLong(Level.GLSegs[i].partner);
|
|
}
|
|
out.WriteLump ("GL_SEGS", segdata, sizeof(MapSegGLEx)*count);
|
|
delete[] segdata;
|
|
}
|
|
|
|
void FProcessor::WriteGLSSect (FWadWriter &out, bool v5)
|
|
{
|
|
if (!v5)
|
|
{
|
|
WriteSSectors2 (out, "GL_SSECT", Level.GLSubsectors, Level.NumGLSubsectors);
|
|
}
|
|
else
|
|
{
|
|
WriteSSectors5 (out, "GL_SSECT", Level.GLSubsectors, Level.NumGLSubsectors);
|
|
}
|
|
}
|
|
|
|
void FProcessor::WriteGLNodes (FWadWriter &out, bool v5)
|
|
{
|
|
if (!v5)
|
|
{
|
|
WriteNodes2 (out, "GL_NODES", Level.GLNodes, Level.NumGLNodes);
|
|
}
|
|
else
|
|
{
|
|
WriteNodes5 (out, "GL_NODES", Level.GLNodes, Level.NumGLNodes);
|
|
}
|
|
}
|
|
|
|
void FProcessor::WriteBSPZ (FWadWriter &out, const char *label)
|
|
{
|
|
ZLibOut zout (out);
|
|
|
|
if (!CompressNodes)
|
|
{
|
|
printf (" Nodes are so big that compression has been forced.\n");
|
|
}
|
|
|
|
out.StartWritingLump (label);
|
|
out.AddToLump ("ZNOD", 4);
|
|
WriteVerticesZ (zout, &Level.Vertices[Level.NumOrgVerts], Level.NumOrgVerts, Level.NumVertices - Level.NumOrgVerts);
|
|
WriteSubsectorsZ (zout, Level.Subsectors, Level.NumSubsectors);
|
|
WriteSegsZ (zout, Level.Segs, Level.NumSegs);
|
|
WriteNodesZ (zout, Level.Nodes, Level.NumNodes);
|
|
}
|
|
|
|
void FProcessor::WriteGLBSPZ (FWadWriter &out, const char *label)
|
|
{
|
|
ZLibOut zout (out);
|
|
|
|
if (!CompressGLNodes)
|
|
{
|
|
printf (" GL Nodes are so big that compression has been forced.\n");
|
|
}
|
|
|
|
out.StartWritingLump (label);
|
|
out.AddToLump ("ZGLN", 4);
|
|
WriteVerticesZ (zout, &Level.GLVertices[Level.NumOrgVerts], Level.NumOrgVerts, Level.NumGLVertices - Level.NumOrgVerts);
|
|
WriteSubsectorsZ (zout, Level.GLSubsectors, Level.NumGLSubsectors);
|
|
WriteGLSegsZ (zout, Level.GLSegs, Level.NumGLSegs);
|
|
WriteNodesZ (zout, Level.GLNodes, Level.NumGLNodes);
|
|
}
|
|
|
|
void FProcessor::WriteVerticesZ (ZLibOut &out, const WideVertex *verts, int orgverts, int newverts)
|
|
{
|
|
out << (DWORD)orgverts << (DWORD)newverts;
|
|
|
|
for (int i = 0; i < newverts; ++i)
|
|
{
|
|
out << verts[i].x << verts[i].y;
|
|
}
|
|
}
|
|
|
|
void FProcessor::WriteSubsectorsZ (ZLibOut &out, const MapSubsectorEx *subs, int numsubs)
|
|
{
|
|
out << (DWORD)numsubs;
|
|
|
|
for (int i = 0; i < numsubs; ++i)
|
|
{
|
|
out << (DWORD)subs[i].numlines;
|
|
}
|
|
}
|
|
|
|
void FProcessor::WriteSegsZ (ZLibOut &out, const MapSeg *segs, int numsegs)
|
|
{
|
|
out << (DWORD)numsegs;
|
|
|
|
for (int i = 0; i < numsegs; ++i)
|
|
{
|
|
out << (DWORD)segs[i].v1
|
|
<< (DWORD)segs[i].v2
|
|
<< (WORD)segs[i].linedef
|
|
<< (BYTE)segs[i].side;
|
|
}
|
|
}
|
|
|
|
void FProcessor::WriteGLSegsZ (ZLibOut &out, const MapSegGLEx *segs, int numsegs)
|
|
{
|
|
out << (DWORD)numsegs;
|
|
|
|
for (int i = 0; i < numsegs; ++i)
|
|
{
|
|
out << (DWORD)segs[i].v1
|
|
<< (DWORD)segs[i].partner
|
|
<< (WORD)segs[i].linedef
|
|
<< (BYTE)segs[i].side;
|
|
}
|
|
}
|
|
|
|
void FProcessor::WriteNodesZ (ZLibOut &out, const MapNodeEx *nodes, int numnodes)
|
|
{
|
|
out << (DWORD)numnodes;
|
|
|
|
for (int i = 0; i < numnodes; ++i)
|
|
{
|
|
out << (SWORD)nodes[i].x
|
|
<< (SWORD)nodes[i].y
|
|
<< (SWORD)nodes[i].dx
|
|
<< (SWORD)nodes[i].dy;
|
|
for (int j = 0; j < 2; ++j)
|
|
{
|
|
for (int k = 0; k < 4; ++k)
|
|
{
|
|
out << (SWORD)nodes[i].bbox[j][k];
|
|
}
|
|
}
|
|
out << (DWORD)nodes[i].children[0]
|
|
<< (DWORD)nodes[i].children[1];
|
|
}
|
|
}
|
|
|
|
// zlib lump writer ---------------------------------------------------------
|
|
|
|
ZLibOut::ZLibOut (FWadWriter &out)
|
|
: Out (out)
|
|
{
|
|
int err;
|
|
|
|
Stream.next_in = Z_NULL;
|
|
Stream.avail_in = 0;
|
|
Stream.zalloc = Z_NULL;
|
|
Stream.zfree = Z_NULL;
|
|
err = deflateInit (&Stream, 9);
|
|
|
|
if (err != Z_OK)
|
|
{
|
|
throw std::runtime_error("Could not initialize deflate buffer.");
|
|
}
|
|
|
|
Stream.next_out = Buffer;
|
|
Stream.avail_out = BUFFER_SIZE;
|
|
}
|
|
|
|
ZLibOut::~ZLibOut ()
|
|
{
|
|
int err;
|
|
|
|
for (;;)
|
|
{
|
|
err = deflate (&Stream, Z_FINISH);
|
|
if (err != Z_OK)
|
|
{
|
|
break;
|
|
}
|
|
if (Stream.avail_out == 0)
|
|
{
|
|
Out.AddToLump (Buffer, BUFFER_SIZE);
|
|
Stream.next_out = Buffer;
|
|
Stream.avail_out = BUFFER_SIZE;
|
|
}
|
|
}
|
|
deflateEnd (&Stream);
|
|
if (err != Z_STREAM_END)
|
|
{
|
|
throw std::runtime_error("Error deflating data.");
|
|
}
|
|
Out.AddToLump (Buffer, BUFFER_SIZE - Stream.avail_out);
|
|
}
|
|
|
|
void ZLibOut::Write (BYTE *data, int len)
|
|
{
|
|
int err;
|
|
|
|
Stream.next_in = data;
|
|
Stream.avail_in = len;
|
|
err = deflate (&Stream, 0);
|
|
while (Stream.avail_out == 0 && err == Z_OK)
|
|
{
|
|
Out.AddToLump (Buffer, BUFFER_SIZE);
|
|
Stream.next_out = Buffer;
|
|
Stream.avail_out = BUFFER_SIZE;
|
|
if (Stream.avail_in != 0)
|
|
{
|
|
err = deflate (&Stream, 0);
|
|
}
|
|
}
|
|
if (err != Z_OK)
|
|
{
|
|
throw std::runtime_error("Error deflating data.");
|
|
}
|
|
}
|
|
|
|
ZLibOut &ZLibOut::operator << (BYTE val)
|
|
{
|
|
Write (&val, 1);
|
|
return *this;
|
|
}
|
|
|
|
ZLibOut &ZLibOut::operator << (WORD val)
|
|
{
|
|
val = LittleShort(val);
|
|
Write ((BYTE *)&val, 2);
|
|
return *this;
|
|
}
|
|
|
|
ZLibOut &ZLibOut::operator << (SWORD val)
|
|
{
|
|
val = LittleShort(val);
|
|
Write ((BYTE *)&val, 2);
|
|
return *this;
|
|
}
|
|
|
|
ZLibOut &ZLibOut::operator << (DWORD val)
|
|
{
|
|
val = LittleLong(val);
|
|
Write ((BYTE *)&val, 4);
|
|
return *this;
|
|
}
|
|
|
|
ZLibOut &ZLibOut::operator << (fixed_t val)
|
|
{
|
|
val = LittleLong(val);
|
|
Write ((BYTE *)&val, 4);
|
|
return *this;
|
|
}
|