diff --git a/Makefile b/Makefile index 52dec25..7fcaad1 100644 --- a/Makefile +++ b/Makefile @@ -50,7 +50,7 @@ ifeq ($(sse),1) CFLAGS += -msse2 -mfpmath=sse endif -OBJS = main.o getopt.o getopt1.o blockmapbuilder.o processor.o view.o wad.o \ +OBJS = main.o getopt.o getopt1.o blockmapbuilder.o processor.o processor_udmf.o sc_man.o view.o wad.o \ nodebuild.o nodebuild_events.o nodebuild_extract.o nodebuild_gl.o \ nodebuild_utility.o nodebuild_classify_nosse2.o \ zlib/adler32.o zlib/compress.o zlib/crc32.o zlib/deflate.o zlib/trees.o \ diff --git a/blockmapbuilder.cpp b/blockmapbuilder.cpp index 0e58653..5758019 100644 --- a/blockmapbuilder.cpp +++ b/blockmapbuilder.cpp @@ -211,7 +211,7 @@ void FBlockmapBuilder::BuildBlockmap () BlockLists = new TArray[bmapwidth * bmapheight]; - for (line = 0; line < Level.NumLines; ++line) + for (line = 0; line < Level.NumLines(); ++line) { int x1 = Level.Vertices[Level.Lines[line].v1].x >> FRACBITS; int y1 = Level.Vertices[Level.Lines[line].v1].y >> FRACBITS; diff --git a/doomdata.h b/doomdata.h index 6483823..4bc61f4 100644 --- a/doomdata.h +++ b/doomdata.h @@ -5,11 +5,19 @@ #pragma once #endif +#include "tarray.h" + enum { BOXTOP, BOXBOTTOM, BOXLEFT, BOXRIGHT }; +struct UDMFKey +{ + int key; + int value; +}; + struct MapVertex { short x, y; @@ -30,6 +38,20 @@ struct MapSideDef WORD sector; }; +struct IntSideDef +{ + // the first 5 values are only used for binary format maps + short textureoffset; + short rowoffset; + char toptexture[8]; + char bottomtexture[8]; + char midtexture[8]; + + int sector; + + TArray props; +}; + struct MapLineDef { WORD v1; @@ -50,6 +72,18 @@ struct MapLineDef2 WORD sidenum[2]; }; +struct IntLineDef +{ + DWORD v1; + DWORD v2; + int flags; + int special; + int args[5]; + DWORD sidenum[2]; + + TArray props; +}; + struct MapSector { short floorheight; @@ -61,6 +95,17 @@ struct MapSector short tag; }; +struct IntSector +{ + // none of the sector properties are used by the node builder + // so there's no need to store them in their expanded form for + // UDMF. JUst storing the UDMF keys and leaving the binary fields + // empty is enough + MapSector data; + + TArray props; +}; + struct MapSubsector { WORD numlines; @@ -140,19 +185,35 @@ struct MapThing2 char args[5]; }; +struct IntThing +{ + unsigned short thingid; + fixed_t x; // full precision coordinates for UDMF support + fixed_t y; + // everything else is not needed or has no extended form in UDMF + short z; + short angle; + short type; + short flags; + char special; + char args[5]; + + TArray props; +}; + struct FLevel { FLevel (); ~FLevel (); WideVertex *Vertices; int NumVertices; - MapSideDef *Sides; int NumSides; - MapLineDef2 *Lines; int NumLines; - MapSector *Sectors; int NumSectors; + TArray Sides; + TArray Lines; + TArray Sectors; + TArray Things; MapSubsectorEx *Subsectors; int NumSubsectors; MapSeg *Segs; int NumSegs; MapNodeEx *Nodes; int NumNodes; - MapThing2 *Things; int NumThings; WORD *Blockmap; int BlockmapSize; BYTE *Reject; int RejectSize; @@ -164,7 +225,7 @@ struct FLevel int NumOrgVerts; - WORD *OrgSectorMap; int NumOrgSectors; + DWORD *OrgSectorMap; int NumOrgSectors; fixed_t MinX, MinY, MaxX, MaxY; @@ -172,6 +233,11 @@ struct FLevel void RemoveExtraLines (); void RemoveExtraSides (); void RemoveExtraSectors (); + + int NumSides() const { return Sides.Size(); } + int NumLines() const { return Lines.Size(); } + int NumSectors() const { return Sectors.Size(); } + int NumThings() const { return Things.Size(); } }; const int BLOCKSIZE = 128; diff --git a/nodebuild_extract.cpp b/nodebuild_extract.cpp index 7c4262f..b10c8ca 100644 --- a/nodebuild_extract.cpp +++ b/nodebuild_extract.cpp @@ -1,22 +1,22 @@ -/* - Routines for extracting usable data from the new BSP tree. - 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. - -*/ +/* + Routines for extracting usable data from the new BSP tree. + 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 #include #include @@ -320,7 +320,7 @@ DWORD FNodeBuilder::PushGLSeg (TArray &segs, const FPrivSeg *seg) if (newseg.linedef != NO_INDEX) { - MapLineDef2 * ld = &Level.Lines[newseg.linedef]; + IntLineDef * ld = &Level.Lines[newseg.linedef]; if (ld->sidenum[0]==ld->sidenum[1]) { @@ -478,7 +478,7 @@ int FNodeBuilder::StripMinisegs (TArray &segs, int subsector, short bbox // Just checking the sidedef to determine the side is insufficient. // When a level is sidedef compressed both sides may well have the same sidedef. - MapLineDef2 * ld = &Level.Lines[newseg.linedef]; + IntLineDef * ld = &Level.Lines[newseg.linedef]; if (ld->sidenum[0]==ld->sidenum[1]) { diff --git a/nodebuild_utility.cpp b/nodebuild_utility.cpp index 94899f2..ae7c285 100644 --- a/nodebuild_utility.cpp +++ b/nodebuild_utility.cpp @@ -47,13 +47,13 @@ const fixed_t VERTEX_EPSILON = 6; void FNodeBuilder::FindUsedVertices (WideVertex *oldverts, int max) { - int *map = (int *)alloca (max*sizeof(int)); + int *map = new int[max]; int i; FPrivVert newvert; memset (&map[0], -1, sizeof(int)*max); - for (i = 0; i < Level.NumLines; ++i) + for (i = 0; i < Level.NumLines(); ++i) { int v1 = Level.Lines[i].v1; int v2 = Level.Lines[i].v2; @@ -71,11 +71,12 @@ void FNodeBuilder::FindUsedVertices (WideVertex *oldverts, int max) map[v2] = VertexMap->SelectVertexExact (newvert); } - Level.Lines[i].v1 = (WORD)map[v1]; - Level.Lines[i].v2 = (WORD)map[v2]; + Level.Lines[i].v1 = map[v1]; + Level.Lines[i].v2 = map[v2]; } InitialVertices = Vertices.Size (); Level.NumOrgVerts = (int)InitialVertices; + delete[] map; } // For every sidedef in the map, create a corresponding seg. @@ -84,7 +85,7 @@ void FNodeBuilder::MakeSegsFromSides () { int i, j; - for (i = 0; i < Level.NumLines; ++i) + for (i = 0; i < Level.NumLines(); ++i) { if (Level.Lines[i].sidenum[0] != NO_INDEX) { @@ -110,7 +111,7 @@ void FNodeBuilder::MakeSegsFromSides () int FNodeBuilder::CreateSeg (int linenum, int sidenum) { FPrivSeg seg; - WORD backside; + DWORD backside; int segnum; seg.next = DWORD_MAX; diff --git a/processor.cpp b/processor.cpp index 44e3645..042ff33 100644 --- a/processor.cpp +++ b/processor.cpp @@ -43,11 +43,7 @@ FLevel::FLevel () 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; @@ -66,14 +62,24 @@ FProcessor::FProcessor (FWadReader &inwad, int lump) { printf ("----%s----\n", Wad.LumpName (Lump)); - Extended = Wad.MapHasBehavior (lump); - LoadThings (); - LoadVertices (); - LoadLines (); - LoadSides (); - LoadSectors (); + isUDMF = Wad.isUDMF(lump); - if (Level.NumLines == 0 || Level.NumVertices == 0 || Level.NumSides == 0 || Level.NumSectors == 0) + if (isUDMF) + { + Extended = false; + LoadUDMF(); + } + else + { + 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"); } @@ -98,33 +104,52 @@ FProcessor::FProcessor (FWadReader &inwad, int lump) void FProcessor::LoadThings () { + int NumThings; + if (Extended) { - ReadMapLump (Wad, "THINGS", Lump, Level.Things, Level.NumThings); + MapThing2 *Things; + ReadMapLump (Wad, "THINGS", Lump, Things, NumThings); - for (int i = 0; i < Level.NumThings; ++i) + Level.Things.Resize(NumThings); + for (int i = 0; i < 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); + Level.Things[i].thingid = Things[i].thingid; + Level.Things[i].x = LittleShort(Things[i].x) << FRACBITS; + Level.Things[i].y = LittleShort(Things[i].y) << FRACBITS; + Level.Things[i].z = LittleShort(Things[i].z); + Level.Things[i].angle = LittleShort(Things[i].angle); + Level.Things[i].type = LittleShort(Things[i].type); + Level.Things[i].flags = LittleShort(Things[i].flags); + Level.Things[i].special = Things[i].special; + Level.Things[i].args[0] = Things[i].args[0]; + Level.Things[i].args[1] = Things[i].args[1]; + Level.Things[i].args[2] = Things[i].args[2]; + Level.Things[i].args[3] = Things[i].args[3]; + Level.Things[i].args[4] = Things[i].args[4]; } + delete[] Things; } else { MapThing *mt; - ReadMapLump (Wad, "THINGS", Lump, mt, Level.NumThings); + ReadMapLump (Wad, "THINGS", Lump, mt, 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.Resize(NumThings); + for (int i = 0; i < NumThings; ++i) { - Level.Things[i].x = LittleShort(mt[i].x); - Level.Things[i].y = LittleShort(mt[i].y); + Level.Things[i].x = LittleShort(mt[i].x) << FRACBITS; + Level.Things[i].y = LittleShort(mt[i].y) << FRACBITS; Level.Things[i].angle = LittleShort(mt[i].angle); Level.Things[i].type = LittleShort(mt[i].type); Level.Things[i].flags = LittleShort(mt[i].flags); + Level.Things[i].z = 0; + Level.Things[i].special = 0; + Level.Things[i].args[0] = 0; + Level.Things[i].args[1] = 0; + Level.Things[i].args[2] = 0; + Level.Things[i].args[3] = 0; + Level.Things[i].args[4] = 0; } delete[] mt; } @@ -132,41 +157,53 @@ void FProcessor::LoadThings () void FProcessor::LoadLines () { + int NumLines; + if (Extended) { - ReadMapLump (Wad, "LINEDEFS", Lump, Level.Lines, Level.NumLines); + MapLineDef2 *Lines; - for (int i = 0; i < Level.NumLines; ++i) + ReadMapLump (Wad, "LINEDEFS", Lump, Lines, NumLines); + + Level.Lines.Resize(NumLines); + for (int i = 0; i < 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]); + Level.Lines[i].special = Lines[i].special; + Level.Lines[i].args[0] = Lines[i].args[0]; + Level.Lines[i].args[1] = Lines[i].args[1]; + Level.Lines[i].args[2] = Lines[i].args[2]; + Level.Lines[i].args[3] = Lines[i].args[3]; + Level.Lines[i].args[4] = Lines[i].args[4]; + Level.Lines[i].v1 = LittleShort(Lines[i].v1); + Level.Lines[i].v2 = LittleShort(Lines[i].v2); + Level.Lines[i].flags = LittleShort(Lines[i].flags); + Level.Lines[i].sidenum[0] = LittleShort(Lines[i].sidenum[0]); + Level.Lines[i].sidenum[1] = LittleShort(Lines[i].sidenum[1]); + if (Level.Lines[i].sidenum[0] == 0xffff) Level.Lines[i].sidenum[0] = NO_INDEX; + if (Level.Lines[i].sidenum[1] == 0xffff) Level.Lines[i].sidenum[1] = NO_INDEX; } + delete[] Lines; } else { MapLineDef *ml; - ReadMapLump (Wad, "LINEDEFS", Lump, ml, Level.NumLines); + ReadMapLump (Wad, "LINEDEFS", Lump, ml, 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.Resize(NumLines); + for (int i = 0; i < 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]); + if (Level.Lines[i].sidenum[0] == 0xffff) Level.Lines[i].sidenum[0] = NO_INDEX; + if (Level.Lines[i].sidenum[1] == 0xffff) Level.Lines[i].sidenum[1] = NO_INDEX; // 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; + Level.Lines[i].special = 0; + Level.Lines[i].args[0] = LittleShort(ml[i].special); + Level.Lines[i].args[1] = LittleShort(ml[i].tag); } delete[] ml; } @@ -188,17 +225,37 @@ void FProcessor::LoadVertices () void FProcessor::LoadSides () { - ReadMapLump (Wad, "SIDEDEFS", Lump, Level.Sides, Level.NumSides); + MapSideDef *Sides; + int NumSides; + ReadMapLump (Wad, "SIDEDEFS", Lump, Sides, NumSides); - for (int i = 0; i < Level.NumSides; ++i) + Level.Sides.Resize(NumSides); + for (int i = 0; i < NumSides; ++i) { - Level.Sides[i].sector = LittleShort(Level.Sides[i].sector); + Level.Sides[i].textureoffset = Sides[i].textureoffset; + Level.Sides[i].rowoffset = Sides[i].rowoffset; + memcpy(Level.Sides[i].toptexture, Sides[i].toptexture, 8); + memcpy(Level.Sides[i].bottomtexture, Sides[i].bottomtexture, 8); + memcpy(Level.Sides[i].midtexture, Sides[i].midtexture, 8); + + Level.Sides[i].sector = LittleShort(Sides[i].sector); + if (Level.Sides[i].sector == 0xffff) Level.Sides[i].sector = NO_INDEX; } + delete [] Sides; } void FProcessor::LoadSectors () { - ReadMapLump (Wad, "SECTORS", Lump, Level.Sectors, Level.NumSectors); + MapSector *Sectors; + int NumSectors; + + ReadMapLump (Wad, "SECTORS", Lump, Sectors, NumSectors); + Level.Sectors.Resize(NumSectors); + + for (int i = 0; i < NumSectors; ++i) + { + Level.Sectors[i].data = Sectors[i]; + } } void FLevel::FindMapBounds () @@ -229,7 +286,7 @@ void FLevel::RemoveExtraLines () // 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) + 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) @@ -241,30 +298,31 @@ void FLevel::RemoveExtraLines () ++newNumLines; } } - if (newNumLines < NumLines) + if (newNumLines < NumLines()) { - int diff = NumLines - newNumLines; + int diff = NumLines() - newNumLines; printf (" Removed %d line%s with 0 length.\n", diff, diff > 1 ? "s" : ""); } - NumLines = newNumLines; + Lines.Resize(newNumLines); } void FLevel::RemoveExtraSides () { BYTE *used; - WORD *remap; + int *remap; int i, newNumSides; // Extra sides are those that aren't referenced by any lines. // They just waste space, so get rid of them. + int NumSides = this->NumSides(); used = new BYTE[NumSides]; memset (used, 0, NumSides*sizeof(*used)); - remap = new WORD[NumSides]; + remap = new int[NumSides]; // Mark all used sides - for (i = 0; i < NumLines; ++i) + for (i = 0; i < NumLines(); ++i) { if (Lines[i].sidenum[0] != NO_INDEX) { @@ -302,10 +360,10 @@ void FLevel::RemoveExtraSides () int diff = NumSides - newNumSides; printf (" Removed %d unused sidedef%s.\n", diff, diff > 1 ? "s" : ""); - NumSides = newNumSides; + Sides.Resize(newNumSides); // Renumber side references in lines - for (i = 0; i < NumLines; ++i) + for (i = 0; i < NumLines(); ++i) { if (Lines[i].sidenum[0] != NO_INDEX) { @@ -317,7 +375,6 @@ void FLevel::RemoveExtraSides () } } } - delete[] used; delete[] remap; } @@ -325,19 +382,19 @@ void FLevel::RemoveExtraSides () void FLevel::RemoveExtraSectors () { BYTE *used; - WORD *remap; + DWORD *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]; + NumOrgSectors = NumSectors(); + used = new BYTE[NumSectors()]; + memset (used, 0, NumSectors()*sizeof(*used)); + remap = new DWORD[NumSectors()]; // Mark all used sectors - for (i = 0; i < NumSides; ++i) + for (i = 0; i < NumSides(); ++i) { if (Sides[i].sector != NO_INDEX) { @@ -350,7 +407,7 @@ void FLevel::RemoveExtraSectors () } // Shift out any unused sides - for (i = newNumSectors = 0; i < NumSectors; ++i) + for (i = newNumSectors = 0; i < NumSectors(); ++i) { if (used[i]) { @@ -366,13 +423,13 @@ void FLevel::RemoveExtraSectors () } } - if (newNumSectors < NumSectors) + if (newNumSectors < NumSectors()) { - int diff = NumSectors - newNumSectors; + 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) + for (i = 0; i < NumSides(); ++i) { if (Sides[i].sector != NO_INDEX) { @@ -380,8 +437,8 @@ void FLevel::RemoveExtraSectors () } } // Make a reverse map for fixing reject lumps - OrgSectorMap = new WORD[newNumSectors]; - for (i = 0; i < NumSectors; ++i) + OrgSectorMap = new DWORD[newNumSectors]; + for (i = 0; i < NumSectors(); ++i) { if (remap[i] != NO_INDEX) { @@ -389,7 +446,7 @@ void FLevel::RemoveExtraSectors () } } - NumSectors = newNumSectors; + Sectors.Resize(newNumSectors); } delete[] used; @@ -404,7 +461,7 @@ void FProcessor::GetPolySpots () // 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) + for (i = 0; i < Level.NumThings(); ++i) { if (Level.Things[i].type == PO_HEX_ANCHOR_TYPE) { @@ -412,7 +469,7 @@ void FProcessor::GetPolySpots () } } - if (i < Level.NumThings) + if (i < Level.NumThings()) { spot1 = PO_HEX_SPAWN_TYPE; spot2 = PO_HEX_SPAWNCRUSH_TYPE; @@ -425,15 +482,15 @@ void FProcessor::GetPolySpots () anchor = PO_ANCHOR_TYPE; } - for (i = 0; i < Level.NumThings; ++i) + 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.x = Level.Things[i].x; + newvert.y = Level.Things[i].y; newvert.polynum = Level.Things[i].angle; if (Level.Things[i].type == anchor) { @@ -450,24 +507,30 @@ void FProcessor::GetPolySpots () void FProcessor::Write (FWadWriter &out) { - if (Level.NumLines == 0 || Level.NumSides == 0 || Level.NumSectors == 0 || Level.NumVertices == 0) + 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) + if (!isUDMF) + { + // 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)); + } + } + else { - out.CopyLump (Wad, Wad.FindMapLump ("BEHAVIOR", Lump)); - out.CopyLump (Wad, Wad.FindMapLump ("SCRIPTS", Lump)); } return; } @@ -493,6 +556,9 @@ void FProcessor::Write (FWadWriter &out) if (BuildNodes) { FNodeBuilder *builder = NULL; + + // UDMF spec requires GL nodes. + if (isUDMF) BuildGLNodes = true; try { @@ -580,7 +646,7 @@ void FProcessor::Write (FWadWriter &out) Level.Blockmap = new WORD[Level.BlockmapSize]; memcpy (Level.Blockmap, blocks, Level.BlockmapSize*sizeof(WORD)); - Level.RejectSize = (Level.NumSectors*Level.NumSectors + 7) / 8; + Level.RejectSize = (Level.NumSectors()*Level.NumSectors() + 7) / 8; Level.Reject = NULL; switch (RejectMode) @@ -609,13 +675,13 @@ void FProcessor::Write (FWadWriter &out) } Level.RejectSize = 0; } - else if (Level.NumOrgSectors != Level.NumSectors) + 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; + Level.RejectSize = (Level.NumSectors() * Level.NumSectors() + 7) / 8; } } } @@ -744,19 +810,19 @@ void FProcessor::Write (FWadWriter &out) BYTE *FProcessor::FixReject (const BYTE *oldreject) { int x, y, ox, oy, pnum, opnum; - int rejectSize = (Level.NumSectors*Level.NumSectors + 7) / 8; + int rejectSize = (Level.NumSectors()*Level.NumSectors() + 7) / 8; BYTE *newreject = new BYTE[rejectSize]; memset (newreject, 0, rejectSize); - for (y = 0; y < Level.NumSectors; ++y) + for (y = 0; y < Level.NumSectors(); ++y) { oy = Level.OrgSectorMap[y]; - for (x = 0; x < Level.NumSectors; ++x) + for (x = 0; x < Level.NumSectors(); ++x) { ox = Level.OrgSectorMap[x]; - pnum = y*Level.NumSectors + x; - opnum = oy*Level.NumSectors + ox; + pnum = y*Level.NumSectors() + x; + opnum = oy*Level.NumSectors() + ox; if (oldreject[opnum >> 3] & (1 << (opnum & 7))) { @@ -870,37 +936,39 @@ void FProcessor::WriteLines (FWadWriter &out) if (Extended) { - for (i = 0; i < Level.NumLines; ++i) + MapLineDef2 *Lines = new MapLineDef2[Level.NumLines()]; + 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]); + Lines[i].special = Level.Lines[i].special; + Lines[i].args[0] = Level.Lines[i].args[0]; + Lines[i].args[1] = Level.Lines[i].args[1]; + Lines[i].args[2] = Level.Lines[i].args[2]; + Lines[i].args[3] = Level.Lines[i].args[3]; + Lines[i].args[4] = Level.Lines[i].args[4]; + Lines[i].v1 = LittleShort(WORD(Level.Lines[i].v1)); + Lines[i].v2 = LittleShort(WORD(Level.Lines[i].v2)); + Lines[i].flags = LittleShort(WORD(Level.Lines[i].flags)); + Lines[i].sidenum[0] = LittleShort(WORD(Level.Lines[i].sidenum[0])); + Lines[i].sidenum[1] = LittleShort(WORD(Level.Lines[i].sidenum[1])); } - out.WriteLump ("LINEDEFS", Level.Lines, Level.NumLines*sizeof(*Level.Lines)); + out.WriteLump ("LINEDEFS", Lines, Level.NumLines()*sizeof(*Lines)); + delete[] Lines; } else { - MapLineDef *ld = new MapLineDef[Level.NumLines]; + MapLineDef *ld = new MapLineDef[Level.NumLines()]; - for (i = 0; i < Level.NumLines; ++i) + 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); + ld[i].v1 = LittleShort(WORD(Level.Lines[i].v1)); + ld[i].v2 = LittleShort(WORD(Level.Lines[i].v2)); + ld[i].flags = LittleShort(WORD(Level.Lines[i].flags)); + ld[i].sidenum[0] = LittleShort(WORD(Level.Lines[i].sidenum[0])); + ld[i].sidenum[1] = LittleShort(WORD(Level.Lines[i].sidenum[1])); + ld[i].special = LittleShort(WORD(Level.Lines[i].args[0])); + ld[i].tag = LittleShort(WORD(Level.Lines[i].args[1])); } - out.WriteLump ("LINEDEFS", ld, Level.NumLines*sizeof(*ld)); + out.WriteLump ("LINEDEFS", ld, Level.NumLines()*sizeof(*ld)); delete[] ld; } } @@ -908,17 +976,32 @@ void FProcessor::WriteLines (FWadWriter &out) void FProcessor::WriteSides (FWadWriter &out) { int i; + MapSideDef *Sides = new MapSideDef[Level.NumSides()]; - for (i = 0; i < Level.NumSides; ++i) + for (i = 0; i < Level.NumSides(); ++i) { - Level.Sides[i].sector = LittleShort(Level.Sides[i].sector); + Sides[i].textureoffset = Level.Sides[i].textureoffset; + Sides[i].rowoffset = Level.Sides[i].rowoffset; + memcpy(Sides[i].toptexture, Level.Sides[i].toptexture, 8); + memcpy(Sides[i].bottomtexture, Level.Sides[i].bottomtexture, 8); + memcpy(Sides[i].midtexture, Level.Sides[i].midtexture, 8); + Sides[i].sector = LittleShort(Level.Sides[i].sector); } - out.WriteLump ("SIDEDEFS", Level.Sides, Level.NumSides*sizeof(*Level.Sides)); + out.WriteLump ("SIDEDEFS", Sides, Level.NumSides()*sizeof(*Sides)); + delete[] Sides; } void FProcessor::WriteSectors (FWadWriter &out) { - out.WriteLump ("SECTORS", Level.Sectors, Level.NumSectors*sizeof(*Level.Sectors)); + int i; + MapSector *Sectors = new MapSector[Level.NumSectors()]; + + for (i = 0; i < Level.NumSectors(); ++i) + { + Sectors[i] = Level.Sectors[i].data; + } + + out.WriteLump ("SECTORS", Sectors, Level.NumSectors()*sizeof(*Sectors)); } void FProcessor::WriteSegs (FWadWriter &out) diff --git a/processor.h b/processor.h index 07b7dd4..a2578f3 100644 --- a/processor.h +++ b/processor.h @@ -43,6 +43,7 @@ public: void Write (FWadWriter &out); private: + void LoadUDMF(); void LoadThings (); void LoadLines (); void LoadVertices (); @@ -92,6 +93,7 @@ private: TArray PolyAnchors; bool Extended; + bool isUDMF; FWadReader &Wad; int Lump; diff --git a/processor_udmf.cpp b/processor_udmf.cpp new file mode 100644 index 0000000..1ff26ea --- /dev/null +++ b/processor_udmf.cpp @@ -0,0 +1,7 @@ + +#include "processor.h" + + +void FProcessor::LoadUDMF() +{ +} diff --git a/sc_man.cpp b/sc_man.cpp new file mode 100644 index 0000000..b6ebc4c --- /dev/null +++ b/sc_man.cpp @@ -0,0 +1,733 @@ +/* + Reads wad files, builds nodes, and saves new wad files. + Copyright (C) 1996 Raven Software + 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. + +*/ + +// HEADER FILES ------------------------------------------------------------ + +#include +#include +#include +#include +#include +#include "sc_man.h" + +#ifdef _MSC_VER +#pragma warning(disable:4996) +#endif + +// MACROS ------------------------------------------------------------------ + +#define MAX_STRING_SIZE 4096 +#define ASCII_COMMENT (';') +#define CPP_COMMENT ('/') +#define C_COMMENT ('*') +#define ASCII_QUOTE (34) +#define LUMP_SCRIPT 1 +#define FILE_ZONE_SCRIPT 2 + +// TYPES ------------------------------------------------------------------- + +// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- + +// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- + +// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- + +static void SC_PrepareScript (void); +static void CheckOpen (void); + +// EXTERNAL DATA DECLARATIONS ---------------------------------------------- + +// PUBLIC DATA DEFINITIONS ------------------------------------------------- + +char *sc_String; +int sc_StringLen; +int sc_Number; +float sc_Float; +int sc_Line; +bool sc_End; +bool sc_Crossed; +bool sc_StringQuoted; +bool sc_FileScripts = false; +FILE *sc_Out; + +// PRIVATE DATA DEFINITIONS ------------------------------------------------ + +static char *ScriptBuffer; +static char *ScriptPtr; +static char *ScriptEndPtr; +static char StringBuffer[MAX_STRING_SIZE]; +static bool ScriptOpen = false; +static int ScriptSize; +static bool AlreadyGot = false; +static char *SavedScriptPtr; +static int SavedScriptLine; +static bool CMode; + +// CODE -------------------------------------------------------------------- + +//========================================================================== +// +// SC_OpenFile +// +// Loads a script (from a file). Uses the new/delete memory allocator for +// memory allocation and de-allocation. +// +//========================================================================== + +void SC_OpenFile (const char *name) +{ + SC_Close (); + FILE * f = fopen(name, "rb"); + if (f == NULL) + { + printf("%s: file not found\n", name); + exit(1); + } + fseek(f, 0, SEEK_END); + ScriptSize = ftell(f); + fseek(f, 0, SEEK_SET); + ScriptBuffer = (char*)malloc(ScriptSize); + if (ScriptSize != int(fread(ScriptBuffer, 1, ScriptSize, f))) + { + fclose(f); + printf("%s: unable to read file\n", name); + exit(1); + } + fclose(f); + SC_PrepareScript (); +} + +//========================================================================== +// +// SC_PrepareScript +// +// Prepares a script for parsing. +// +//========================================================================== + +static void SC_PrepareScript (void) +{ + ScriptPtr = ScriptBuffer; + ScriptEndPtr = ScriptPtr + ScriptSize; + sc_Line = 1; + sc_End = false; + ScriptOpen = true; + sc_String = StringBuffer; + AlreadyGot = false; + SavedScriptPtr = NULL; + CMode = false; +} + +//========================================================================== +// +// SC_Close +// +//========================================================================== + +void SC_Close (void) +{ + if (ScriptOpen) + { + if (ScriptBuffer) + { + free(ScriptBuffer); + } + ScriptBuffer = NULL; + ScriptOpen = false; + } +} + +//========================================================================== +// +// SC_SavePos +// +// Saves the current script location for restoration later +// +//========================================================================== + +void SC_SavePos (void) +{ + CheckOpen (); + if (sc_End) + { + SavedScriptPtr = NULL; + } + else + { + SavedScriptPtr = ScriptPtr; + SavedScriptLine = sc_Line; + } +} + +//========================================================================== +// +// SC_RestorePos +// +// Restores the previously saved script location +// +//========================================================================== + +void SC_RestorePos (void) +{ + if (SavedScriptPtr) + { + ScriptPtr = SavedScriptPtr; + sc_Line = SavedScriptLine; + sc_End = false; + AlreadyGot = false; + } +} + +//========================================================================== +// +// SC_SetCMode +// +// Enables/disables C mode. In C mode, more characters are considered to +// be whole words than in non-C mode. +// +//========================================================================== + +void SC_SetCMode (bool cmode) +{ + CMode = cmode; +} + +//========================================================================== +// +// SC_GetString +// +//========================================================================== + +bool SC_GetString (bool multiline) +{ + char *text; + bool foundToken; + + CheckOpen(); + if (AlreadyGot) + { + AlreadyGot = false; + return true; + } + foundToken = false; + sc_Crossed = false; + sc_StringQuoted = false; + if (ScriptPtr >= ScriptEndPtr) + { + sc_End = true; + return false; + } + while (foundToken == false) + { + while (ScriptPtr < ScriptEndPtr && *ScriptPtr <= ' ') + { + if (*ScriptPtr++ == '\n') + { + sc_Line++; + sc_Crossed = true; + } + } + if (ScriptPtr >= ScriptEndPtr) + { + sc_End = true; + return false; + } + if ((CMode || *ScriptPtr != ASCII_COMMENT) && + !(ScriptPtr[0] == CPP_COMMENT && ScriptPtr < ScriptEndPtr - 1 && + (ScriptPtr[1] == CPP_COMMENT || ScriptPtr[1] == C_COMMENT))) + { // Found a token + foundToken = true; + } + else + { // Skip comment + if (ScriptPtr[0] == CPP_COMMENT && ScriptPtr[1] == C_COMMENT) + { // C comment + while (ScriptPtr[0] != C_COMMENT || ScriptPtr[1] != CPP_COMMENT) + { + if (ScriptPtr[0] == '\n') + { + sc_Line++; + sc_Crossed = true; + } + fputc(ScriptPtr[0], sc_Out); + ScriptPtr++; + if (ScriptPtr >= ScriptEndPtr - 1) + { + sc_End = true; + return false; + } + fputs("*/", sc_Out); + } + ScriptPtr += 2; + } + else + { // C++ comment + while (*ScriptPtr++ != '\n') + { + fputc(ScriptPtr[-1], sc_Out); + if (ScriptPtr >= ScriptEndPtr) + { + sc_End = true; + return false; + } + } + sc_Line++; + sc_Crossed = true; + fputc('\n', sc_Out); + } + } + } + text = sc_String; + if (*ScriptPtr == ASCII_QUOTE) + { // Quoted string - return string including the quotes + *text++ = *ScriptPtr++; + sc_StringQuoted = true; + while (*ScriptPtr != ASCII_QUOTE) + { + if (multiline && *ScriptPtr == '\n') + { + *text++ = '"'; + *text++ = ','; + *text++ = '\n'; + *text++ = '\t'; + *text++ = '\t'; + *text++ = '"'; + ScriptPtr++; + continue; + } + else if (*ScriptPtr < ' ') + { + ScriptPtr++; + } + else + { + *text++ = *ScriptPtr++; + } + if (ScriptPtr == ScriptEndPtr + || text == &sc_String[MAX_STRING_SIZE-1]) + { + break; + } + } + *text++ = '"'; + ScriptPtr++; + } + else + { // Normal string + static const char *stopchars; + + if (CMode) + { + stopchars = "`~!@#$%^&*(){}[]/=\?+|;:<>,"; + + // '-' can be its own token, or it can be part of a negative number + if (*ScriptPtr == '-') + { + *text++ = '-'; + ScriptPtr++; + if (ScriptPtr < ScriptEndPtr || (*ScriptPtr >= '0' && *ScriptPtr <= '9')) + { + goto grabtoken; + } + goto gottoken; + } + } + else + { + stopchars = "{}|="; + } + if (strchr (stopchars, *ScriptPtr)) + { + *text++ = *ScriptPtr++; + } + else + { +grabtoken: + while ((*ScriptPtr > ' ') && (strchr (stopchars, *ScriptPtr) == NULL) + && (CMode || *ScriptPtr != ASCII_COMMENT) + && !(ScriptPtr[0] == CPP_COMMENT && (ScriptPtr < ScriptEndPtr - 1) && + (ScriptPtr[1] == CPP_COMMENT || ScriptPtr[1] == C_COMMENT))) + { + *text++ = *ScriptPtr++; + if (ScriptPtr == ScriptEndPtr + || text == &sc_String[MAX_STRING_SIZE-1]) + { + break; + } + } + } + } +gottoken: + *text = 0; + sc_StringLen = int(text - sc_String); + return true; +} + +//========================================================================== +// +// SC_MustGetString +// +//========================================================================== + +void SC_MustGetString (void) +{ + if (SC_GetString () == false) + { + SC_ScriptError ("Missing string (unexpected end of file)."); + } +} + +//========================================================================== +// +// SC_MustGetStringName +// +//========================================================================== + +void SC_MustGetStringName (const char *name) +{ + SC_MustGetString (); + if (SC_Compare (name) == false) + { + SC_ScriptError ("Expected '%s', got '%s'.", name, sc_String); + } +} + +//========================================================================== +// +// SC_CheckString +// +// Checks if the next token matches the specified string. Returns true if +// it does. If it doesn't, it ungets it and returns false. +//========================================================================== + +bool SC_CheckString (const char *name) +{ + if (SC_GetString ()) + { + if (SC_Compare (name)) + { + return true; + } + SC_UnGet (); + } + return false; +} + +//========================================================================== +// +// SC_GetNumber +// +//========================================================================== + +bool SC_GetNumber (void) +{ + char *stopper; + + CheckOpen (); + if (SC_GetString()) + { + if (strcmp (sc_String, "MAXINT") == 0) + { + sc_Number = INT_MAX; + } + else + { + sc_Number = strtol (sc_String, &stopper, 0); + if (*stopper != 0) + { + SC_ScriptError ("SC_GetNumber: Bad numeric constant \"%s\".", sc_String); + } + } + sc_Float = (float)sc_Number; + return true; + } + else + { + return false; + } +} + +//========================================================================== +// +// SC_MustGetNumber +// +//========================================================================== + +void SC_MustGetNumber (void) +{ + if (SC_GetNumber() == false) + { + SC_ScriptError ("Missing integer (unexpected end of file)."); + } +} + +//========================================================================== +// +// SC_CheckNumber +// similar to SC_GetNumber but ungets the token if it isn't a number +// and does not print an error +// +//========================================================================== + +bool SC_CheckNumber (void) +{ + char *stopper; + + //CheckOpen (); + if (SC_GetString()) + { + if (strcmp (sc_String, "MAXINT") == 0) + { + sc_Number = INT_MAX; + } + else + { + sc_Number = strtol (sc_String, &stopper, 0); + if (*stopper != 0) + { + SC_UnGet(); + return false; + } + } + sc_Float = (float)sc_Number; + return true; + } + else + { + return false; + } +} + +//========================================================================== +// +// SC_CheckFloat +// [GRB] Same as SC_CheckNumber, only for floats +// +//========================================================================== + +bool SC_CheckFloat (void) +{ + char *stopper; + + //CheckOpen (); + if (SC_GetString()) + { + sc_Float = (float)strtod (sc_String, &stopper); + if (*stopper != 0) + { + SC_UnGet(); + return false; + } + return true; + } + else + { + return false; + } +} + + +//========================================================================== +// +// SC_GetFloat +// +//========================================================================== + +bool SC_GetFloat (void) +{ + char *stopper; + + CheckOpen (); + if (SC_GetString()) + { + sc_Float = (float)strtod (sc_String, &stopper); + if (*stopper != 0) + { + SC_ScriptError("SC_GetFloat: Bad numeric constant \"%s\".\n",sc_String); + } + sc_Number = (int)sc_Float; + return true; + } + else + { + return false; + } +} + +//========================================================================== +// +// SC_MustGetFloat +// +//========================================================================== + +void SC_MustGetFloat (void) +{ + if (SC_GetFloat() == false) + { + SC_ScriptError ("Missing floating-point number (unexpected end of file)."); + } +} + +//========================================================================== +// +// SC_UnGet +// +// Assumes there is a valid string in sc_String. +// +//========================================================================== + +void SC_UnGet (void) +{ + AlreadyGot = true; +} + +//========================================================================== +// +// SC_Check +// +// Returns true if another token is on the current line. +// +//========================================================================== + +/* +bool SC_Check(void) +{ + char *text; + + CheckOpen(); + text = ScriptPtr; + if(text >= ScriptEndPtr) + { + return false; + } + while(*text <= 32) + { + if(*text == '\n') + { + return false; + } + text++; + if(text == ScriptEndPtr) + { + return false; + } + } + if(*text == ASCII_COMMENT) + { + return false; + } + return true; +} +*/ + +//========================================================================== +// +// SC_MatchString +// +// Returns the index of the first match to sc_String from the passed +// array of strings, or -1 if not found. +// +//========================================================================== + +int SC_MatchString (const char **strings) +{ + int i; + + for (i = 0; *strings != NULL; i++) + { + if (SC_Compare (*strings++)) + { + return i; + } + } + return -1; +} + +//========================================================================== +// +// SC_MustMatchString +// +//========================================================================== + +int SC_MustMatchString (const char **strings) +{ + int i; + + i = SC_MatchString (strings); + if (i == -1) + { + SC_ScriptError (NULL); + } + return i; +} + +//========================================================================== +// +// SC_Compare +// +//========================================================================== + +bool SC_Compare (const char *text) +{ +#ifdef _MSC_VER + return (_stricmp (text, sc_String) == 0); +#else + return (strcasecmp (text, sc_String) == 0); +#endif +} + +//========================================================================== +// +// SC_ScriptError +// +//========================================================================== + +void SC_ScriptError (const char *message, ...) +{ + char composed[2048]; + if (message == NULL) + { + message = "Bad syntax."; + } + + va_list arglist; + va_start (arglist, message); + vsprintf (composed, message, arglist); + va_end (arglist); + + printf ("Script error, line %d:\n%s\n", sc_Line, composed); + exit(1); +} + +//========================================================================== +// +// CheckOpen +// +//========================================================================== + +static void CheckOpen(void) +{ + if (ScriptOpen == false) + { + printf ("SC_ call before SC_Open().\n"); + exit(1); + } +} diff --git a/sc_man.h b/sc_man.h new file mode 100644 index 0000000..719b6b5 --- /dev/null +++ b/sc_man.h @@ -0,0 +1,44 @@ +#ifndef __SC_MAN_H__ +#define __SC_MAN_H__ + +void SC_Open (const char *name); +void SC_OpenFile (const char *name); +void SC_OpenMem (const char *name, char *buffer, int size); +void SC_OpenLumpNum (int lump, const char *name); +void SC_Close (void); +void SC_SetCMode (bool cmode); +void SC_SetEscape (bool esc); +void SC_SavePos (void); +void SC_RestorePos (void); +bool SC_GetString (bool multiline = false); +void SC_MustGetString (void); +void SC_MustGetStringName (const char *name); +bool SC_CheckString (const char *name); +bool SC_GetNumber (void); +void SC_MustGetNumber (void); +bool SC_CheckNumber (void); +bool SC_CheckFloat (void); +bool SC_GetFloat (void); +void SC_MustGetFloat (void); +void SC_UnGet (void); +//boolean SC_Check(void); +bool SC_Compare (const char *text); +int SC_MatchString (const char **strings); +int SC_MustMatchString (const char **strings); +void SC_ScriptError (const char *message, ...); +void SC_SaveScriptState(); +void SC_RestoreScriptState(); + +extern char *sc_String; +extern int sc_StringLen; +extern int sc_Number; +extern float sc_Float; +extern int sc_Line; +extern bool sc_End; +extern bool sc_Crossed; +extern bool sc_FileScripts; +extern bool sc_StringQuoted; +extern char *sc_ScriptsDir; +extern FILE *sc_Out; + +#endif //__SC_MAN_H__ diff --git a/tarray.h b/tarray.h index edd3414..1c57503 100644 --- a/tarray.h +++ b/tarray.h @@ -3,7 +3,7 @@ ** Templated, automatically resizing array ** **--------------------------------------------------------------------------- -** Copyright 1998-2006 Randy Heit +** Copyright 1998-2007 Randy Heit ** All rights reserved. ** ** Redistribution and use in source and binary forms, with or without @@ -37,10 +37,19 @@ #include #include -#include #include -template +#if !defined(_WIN32) +#include // for intptr_t +#elif !defined(_MSC_VER) +#include // for mingw +#endif + +// TArray ------------------------------------------------------------------- + +// T is the type stored in the array. +// TT is the type returned by operator(). +template class TArray { public: @@ -108,10 +117,16 @@ public: Most = 0; } } + // Return a reference to an element T &operator[] (unsigned int index) const { return Array[index]; } + // Returns the value of an element + TT operator() (unsigned int index) const + { + return Array[index]; + } unsigned int Push (const T &item) { Grow (1); @@ -133,10 +148,30 @@ public: if (index < Count) { Array[index].~T(); - memmove (&Array[index], &Array[index+1], sizeof(T)*(Count - index - 1)); - Count--; + if (index < --Count) + { + memmove (&Array[index], &Array[index+1], sizeof(T)*(Count - index)); + } } } + + void Delete (unsigned int index, int deletecount) + { + if (index + deletecount > Count) deletecount = Count - index; + if (deletecount > 0) + { + for(int i = 0; i < deletecount; i++) + { + Array[index + i].~T(); + } + Count -= deletecount; + if (index < Count) + { + memmove (&Array[index], &Array[index+deletecount], sizeof(T)*(Count - index)); + } + } + } + // Inserts an item into the array, shifting elements as needed void Insert (unsigned int index, const T &item) { @@ -217,6 +252,10 @@ public: Grow (amount); unsigned int place = Count; Count += amount; + for (unsigned int i = place; i < Count; ++i) + { + ::new((void *)&Array[i]) T; + } return place; } unsigned int Size () const @@ -252,7 +291,7 @@ private: } for (unsigned int i = 0; i < Count; ++i) { - Array[i] = other.Array[i]; + ::new(&Array[i]) T(other.Array[i]); } } else @@ -281,12 +320,29 @@ private: } }; -// An array with accessors that automatically grow the -// array as needed. But can still be used as a normal -// TArray if needed. Used by ACS world and global arrays. +// TDeletingArray ----------------------------------------------------------- +// An array that deletes its elements when it gets deleted. +template +class TDeletingArray : public TArray +{ +public: + ~TDeletingArray () + { + for (unsigned int i = 0; i < TArray::Size(); ++i) + { + if ((*this)[i] != NULL) + delete (*this)[i]; + } + } +}; -template -class TAutoGrowArray : public TArray +// TAutoGrowArray ----------------------------------------------------------- +// An array with accessors that automatically grow the array as needed. +// It can still be used as a normal TArray if needed. ACS uses this for +// world and global arrays. + +template +class TAutoGrowArray : public TArray { public: T GetVal (unsigned int index) @@ -299,6 +355,8 @@ public: } void SetVal (unsigned int index, T val) { + if ((int)index < 0) return; // These always result in an out of memory condition. + if (index >= this->Size()) { this->Resize (index + 1); @@ -307,4 +365,5 @@ public: } }; + #endif //__TARRAY_H__ diff --git a/view.cpp b/view.cpp index f6eb22d..268d048 100644 --- a/view.cpp +++ b/view.cpp @@ -576,7 +576,7 @@ static int DesiredSector; static void DrawLevelReject (HDC dc) { - int seeFromRow = DesiredSector * Level->NumSectors; + int seeFromRow = DesiredSector * Level->NumSectors(); HPEN oldPen; HPEN cantSee; HPEN canSee; @@ -589,7 +589,7 @@ static void DrawLevelReject (HDC dc) oldPen = (HPEN)SelectObject (dc, canSee); enum { UNDECIDED, CANT_SEE, CAN_SEE, SEE_FROM } choice, prevchoice = CAN_SEE; - for (int i = 0; i < Level->NumLines; ++i) + for (int i = 0; i < Level->NumLines(); ++i) { choice = UNDECIDED; diff --git a/wad.cpp b/wad.cpp index 8aae8b9..25cd725 100644 --- a/wad.cpp +++ b/wad.cpp @@ -161,11 +161,27 @@ int FWadReader::FindMapLump (const char *name, int map) const return -1; } +bool FWadReader::isUDMF (int index) const +{ + index++; + + if (strnicmp(Lumps[index].Name, "TEXTMAP", 8) == NULL) + { + // UDMF map + return true; + } + return false; +} + + bool FWadReader::IsMap (int index) const { int i, j; + if (isUDMF(index)) return true; + index++; + for (i = j = 0; i < 12; ++i) { if (strnicmp (Lumps[index+j].Name, MapLumpNames[i], 8) != 0) @@ -279,7 +295,18 @@ int FWadReader::LumpAfterMap (int i) const { int j, k; - ++i; + if (isUDMF(i)) + { + // UDMF map + i += 2; + while (strnicmp(Lumps[i].Name, "ENDMAP", 8) != NULL && i < Header.NumLumps) + { + i++; + } + return i; + } + + i++; for (j = k = 0; j < 12; ++j) { if (strnicmp (Lumps[i+k].Name, MapLumpNames[j], 8) != 0) diff --git a/wad.h b/wad.h index f6402da..b7a06ee 100644 --- a/wad.h +++ b/wad.h @@ -32,6 +32,7 @@ public: ~FWadReader (); bool IsIWAD () const; + bool isUDMF(int lump) const; int FindLump (const char *name, int index=0) const; int FindMapLump (const char *name, int map) const; int FindGLLump (const char *name, int glheader) const; diff --git a/zdbsp.h b/zdbsp.h index 5d53a47..a6ce383 100644 --- a/zdbsp.h +++ b/zdbsp.h @@ -66,6 +66,7 @@ typedef uint32_t angle_t; angle_t PointToAngle (fixed_t x, fixed_t y); +static const DWORD NO_MAP_INDEX = 0xffffffff; static const WORD NO_INDEX = 0xffff; static const angle_t ANGLE_MAX = 0xffffffff; static const DWORD DWORD_MAX = 0xffffffff; diff --git a/zdbsp_vs2005.vcproj b/zdbsp_vs2005.vcproj index e57d26c..2cb4f21 100644 --- a/zdbsp_vs2005.vcproj +++ b/zdbsp_vs2005.vcproj @@ -1,7 +1,7 @@ + + + + @@ -402,6 +410,10 @@ RelativePath=".\resource.h" > + +