From cfe51f0c308e1924308e60e470d4d69a6a7c23dc Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 10 Nov 2018 08:04:03 +0100 Subject: [PATCH 01/25] - hole filling subsectors must also be explicitly triangulated for the automap because they may be non-convex. --- src/am_map.cpp | 51 +++++++++++++++++------- src/hwrenderer/data/hw_vertexbuilder.cpp | 10 +++-- src/v_2ddrawer.cpp | 18 +++++++-- src/v_2ddrawer.h | 2 +- src/v_draw.cpp | 4 +- src/v_video.h | 2 +- 6 files changed, 62 insertions(+), 25 deletions(-) diff --git a/src/am_map.cpp b/src/am_map.cpp index 58ac470855..305748317b 100644 --- a/src/am_map.cpp +++ b/src/am_map.cpp @@ -62,6 +62,7 @@ #include "a_keys.h" #include "g_levellocals.h" #include "actorinlines.h" +#include "earcut.hpp" //============================================================================= @@ -2054,6 +2055,7 @@ sector_t * AM_FakeFlat(AActor *viewer, sector_t * sec, sector_t * dest) void AM_drawSubsectors() { static TArray points; + std::vector indices; double scale = scale_mtof; DAngle rotation; sector_t tempsec; @@ -2067,27 +2069,28 @@ void AM_drawSubsectors() auto &subsectors = level.subsectors; for (unsigned i = 0; i < subsectors.Size(); ++i) { - if (subsectors[i].flags & SSECF_POLYORG) + auto sub = &subsectors[i]; + if (sub->flags & SSECF_POLYORG) { continue; } - if ((!(subsectors[i].flags & SSECMF_DRAWN) || (subsectors[i].flags & SSECF_HOLE) || (subsectors[i].render_sector->MoreFlags & SECMF_HIDDEN)) && am_cheat == 0) + if ((!(sub->flags & SSECMF_DRAWN) || (sub->flags & SSECF_HOLE) || (sub->render_sector->MoreFlags & SECMF_HIDDEN)) && am_cheat == 0) { continue; } - if (am_portaloverlay && subsectors[i].render_sector->PortalGroup != MapPortalGroup && subsectors[i].render_sector->PortalGroup != 0) + if (am_portaloverlay && sub->render_sector->PortalGroup != MapPortalGroup && sub->render_sector->PortalGroup != 0) { continue; } // Fill the points array from the subsector. - points.Resize(subsectors[i].numlines); - for (uint32_t j = 0; j < subsectors[i].numlines; ++j) + points.Resize(sub->numlines); + for (uint32_t j = 0; j < sub->numlines; ++j) { - mpoint_t pt = { subsectors[i].firstline[j].v1->fX(), - subsectors[i].firstline[j].v1->fY() }; + mpoint_t pt = { sub->firstline[j].v1->fX(), + sub->firstline[j].v1->fY() }; if (am_rotate == 1 || (am_rotate == 2 && viewactive)) { AM_rotatePoint(&pt.x, &pt.y); @@ -2096,7 +2099,7 @@ void AM_drawSubsectors() points[j].Y = float(f_y + (f_h - (pt.y - m_y) * scale)); } // For lighting and texture determination - sector_t *sec = AM_FakeFlat(players[consoleplayer].camera, subsectors[i].render_sector, &tempsec); + sector_t *sec = AM_FakeFlat(players[consoleplayer].camera, sub->render_sector, &tempsec); floorlight = sec->GetFloorLight(); // Find texture origin. originpt.x = -sec->GetXOffset(sector_t::floor); @@ -2123,7 +2126,7 @@ void AM_drawSubsectors() double secx; double secy; double seczb, seczt; - auto &vp = r_viewpoint; + auto &vp = r_viewpoint; double cmpz = vp.Pos.Z; if (players[consoleplayer].camera && sec == players[consoleplayer].camera->Sector) @@ -2144,7 +2147,7 @@ void AM_drawSubsectors() { F3DFloor *rover = sec->e->XFloor.ffloors[i]; if (!(rover->flags & FF_EXISTS)) continue; - if (rover->flags & (FF_FOG|FF_THISINSIDE)) continue; + if (rover->flags & (FF_FOG | FF_THISINSIDE)) continue; if (!(rover->flags & FF_RENDERPLANES)) continue; if (rover->alpha == 0) continue; double roverz = rover->top.plane->ZatPoint(secx, secy); @@ -2194,7 +2197,7 @@ void AM_drawSubsectors() // If this subsector has not actually been seen yet (because you are cheating // to see it on the map), tint and desaturate it. - if (!(subsectors[i].flags & SSECMF_DRAWN)) + if (!(sub->flags & SSECMF_DRAWN)) { colormap.LightColor = PalEntry( (colormap.LightColor.r + 255) / 2, @@ -2210,8 +2213,28 @@ void AM_drawSubsectors() // Draw the polygon. FTexture *pic = TexMan(maptex); - if (pic != NULL && pic->UseType != ETextureType::Null) + if (pic != nullptr && pic->UseType != ETextureType::Null) { + // Hole filling "subsectors" are not necessarily convex so they require real triangulation. + // These things are extremely rare so performance is secondary here. + if (sub->flags & SSECF_HOLE && sub->numlines > 3) + { + using Point = std::pair; + std::vector> polygon; + std::vector *curPoly; + + polygon.resize(1); + curPoly = &polygon.back(); + curPoly->resize(points.Size()); + + for (unsigned i = 0; i < points.Size(); i++) + { + (*curPoly)[i] = { points[i].X, points[i].Y }; + } + indices = mapbox::earcut(polygon); + } + else indices.clear(); + screen->FillSimplePoly(TexMan(maptex), &points[0], points.Size(), originx, originy, @@ -2221,8 +2244,8 @@ void AM_drawSubsectors() colormap, flatcolor, floorlight, - f_y + f_h - ); + f_y + f_h, + indices.data(), indices.size()); } } } diff --git a/src/hwrenderer/data/hw_vertexbuilder.cpp b/src/hwrenderer/data/hw_vertexbuilder.cpp index f989d99d08..6a0542cdf9 100644 --- a/src/hwrenderer/data/hw_vertexbuilder.cpp +++ b/src/hwrenderer/data/hw_vertexbuilder.cpp @@ -53,12 +53,14 @@ static void CreateVerticesForSubsector(subsector_t *sub, VertexContainer &gen, i using Point = std::pair; std::vector> polygon; std::vector *curPoly; - + + polygon.resize(1); + curPoly = &polygon.back(); + curPoly->resize(sub->numlines); + for (unsigned i = 0; i < sub->numlines; i++) { - polygon.resize(1); - curPoly = &polygon.back(); - curPoly->push_back({ sub->firstline[i].v1->fX(), sub->firstline[i].v1->fY() }); + (*curPoly)[i] = { sub->firstline[i].v1->fX(), sub->firstline[i].v1->fY() }; } auto indices = mapbox::earcut(polygon); for (auto vti : indices) diff --git a/src/v_2ddrawer.cpp b/src/v_2ddrawer.cpp index 40cea9904b..8fc487ef9a 100644 --- a/src/v_2ddrawer.cpp +++ b/src/v_2ddrawer.cpp @@ -419,7 +419,8 @@ void F2DDrawer::AddShape( FTexture *img, DShape2D *shape, DrawParms &parms ) void F2DDrawer::AddPoly(FTexture *texture, FVector2 *points, int npoints, double originx, double originy, double scalex, double scaley, - DAngle rotation, const FColormap &colormap, PalEntry flatcolor, int lightlevel) + DAngle rotation, const FColormap &colormap, PalEntry flatcolor, int lightlevel, + uint32_t *indices, size_t indexcount) { // Use an equation similar to player sprites to determine shade @@ -487,9 +488,20 @@ void F2DDrawer::AddPoly(FTexture *texture, FVector2 *points, int npoints, poly.mIndexIndex = mIndices.Size(); poly.mIndexCount += (npoints - 2) * 3; - for (int i = 2; i < npoints; ++i) + if (indices == nullptr || indexcount == 0) { - AddIndices(poly.mVertIndex, 3, 0, i - 1, i); + for (int i = 2; i < npoints; ++i) + { + AddIndices(poly.mVertIndex, 3, 0, i - 1, i); + } + } + else + { + int addr = mIndices.Reserve(indexcount); + for (size_t i = 0; i < indexcount; i++) + { + mIndices[addr + i] = addr + indices[i]; + } } AddCommand(&poly); diff --git a/src/v_2ddrawer.h b/src/v_2ddrawer.h index 9f7f16676f..33ca20dc99 100644 --- a/src/v_2ddrawer.h +++ b/src/v_2ddrawer.h @@ -130,7 +130,7 @@ public: void AddShape(FTexture *img, DShape2D *shape, DrawParms &parms); void AddPoly(FTexture *texture, FVector2 *points, int npoints, double originx, double originy, double scalex, double scaley, - DAngle rotation, const FColormap &colormap, PalEntry flatcolor, int lightlevel); + DAngle rotation, const FColormap &colormap, PalEntry flatcolor, int lightlevel, uint32_t *indices, size_t indexcount); void AddFlatFill(int left, int top, int right, int bottom, FTexture *src, bool local_origin); void AddColorOnlyQuad(int left, int top, int width, int height, PalEntry color, FRenderStyle *style); diff --git a/src/v_draw.cpp b/src/v_draw.cpp index f2b5a7800f..252d9bf4ea 100644 --- a/src/v_draw.cpp +++ b/src/v_draw.cpp @@ -1253,9 +1253,9 @@ DEFINE_ACTION_FUNCTION(_Screen, Dim) void DFrameBuffer::FillSimplePoly(FTexture *tex, FVector2 *points, int npoints, double originx, double originy, double scalex, double scaley, DAngle rotation, - const FColormap &colormap, PalEntry flatcolor, int lightlevel, int bottomclip) + const FColormap &colormap, PalEntry flatcolor, int lightlevel, int bottomclip, uint32_t *indices, size_t indexcount) { - m2DDrawer.AddPoly(tex, points, npoints, originx, originy, scalex, scaley, rotation, colormap, flatcolor, lightlevel); + m2DDrawer.AddPoly(tex, points, npoints, originx, originy, scalex, scaley, rotation, colormap, flatcolor, lightlevel, indices, indexcount); } //========================================================================== diff --git a/src/v_video.h b/src/v_video.h index b2fe73657b..61185e1b32 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -529,7 +529,7 @@ public: // Fill a simple polygon with a texture void FillSimplePoly(FTexture *tex, FVector2 *points, int npoints, double originx, double originy, double scalex, double scaley, DAngle rotation, - const FColormap &colormap, PalEntry flatcolor, int lightlevel, int bottomclip); + const FColormap &colormap, PalEntry flatcolor, int lightlevel, int bottomclip, uint32_t *indices, size_t indexcount); // Set an area to a specified color void Clear(int left, int top, int right, int bottom, int palcolor, uint32_t color); From 602ea8f723f788999fab50b4d1072f110c8d6216 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 10 Nov 2018 10:43:35 +0100 Subject: [PATCH 02/25] - made some minor changes to TArray after finding out that "new int()" is not the same as "new int". With parentheses this initializes to 0 which created needless initialization code in a few places. --- src/tarray.h | 44 ++++++++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/src/tarray.h b/src/tarray.h index 7e8c53f069..8543637cdb 100644 --- a/src/tarray.h +++ b/src/tarray.h @@ -164,7 +164,7 @@ public: Array = (T *)M_Malloc (sizeof(T)*max); if (reserve) { - for (unsigned i = 0; i < Count; i++) ::new(&Array[i]) T(); + ConstructEmpty(0, Count - 1); } } TArray (const TArray &other) @@ -362,17 +362,6 @@ public: } } - // Reserves a range of entries in the middle of the array, shifting elements as needed - void ReserveAt(unsigned int index, unsigned int amount) - { - Grow(amount); - memmove(&Array[index + amount], &Array[index], sizeof(T)*(Count - index - amount)); - for (unsigned i = 0; i < amount; i++) - { - ::new ((void *)&Array[index + i]) T(); - } - } - void ShrinkToFit () { if (Most > Count) @@ -411,10 +400,7 @@ public: { // Adding new entries Grow (amount - Count); - for (unsigned int i = Count; i < amount; ++i) - { - ::new((void *)&Array[i]) T; - } + ConstructEmpty(Count, amount - 1); } else if (Count != amount) { @@ -423,6 +409,18 @@ public: } Count = amount; } + // Ensures that the array has at most amount entries. + // Useful in cases where the initial allocation may be larger than the final result. + // Resize would create a lot of unneeded code in those cases. + void Clamp(unsigned int amount) + { + if (Count > amount) + { + // Deleting old entries + DoDelete(amount, Count - 1); + Count = amount; + } + } void Alloc(unsigned int amount) { // first destroys all content and then rebuilds the array. @@ -438,10 +436,7 @@ public: Grow (amount); unsigned int place = Count; Count += amount; - for (unsigned int i = place; i < Count; ++i) - { - ::new((void *)&Array[i]) T; - } + ConstructEmpty(place, Count - 1); return place; } unsigned int Size () const @@ -501,6 +496,15 @@ private: Array[i].~T(); } } + + void ConstructEmpty(unsigned int first, unsigned int last) + { + assert(last != ~0u); + for (unsigned int i = first; i <= last; ++i) + { + ::new(&Array[i]) T; + } + } }; // TDeletingArray ----------------------------------------------------------- From 3448749de67974c30bc62d86c2d986d27d526f0d Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 10 Nov 2018 11:56:18 +0100 Subject: [PATCH 03/25] - replaced a few temporary allocations with TArray and added a few convenience loader functions for this. Amazingly with today's optimizers this creates code which is just as good as doing it all manually with the added benefit of being safer. --- src/files.h | 8 ++++++++ src/p_setup.cpp | 26 +++++++------------------- src/p_setup.h | 7 +++++++ src/p_udmf.cpp | 6 +----- src/p_usdf.cpp | 5 +---- src/parsecontext.cpp | 8 ++------ src/sc_man.h | 4 ++++ src/tarray.h | 10 +++++----- src/w_wad.cpp | 24 ++++++++++++++++++++++++ src/w_wad.h | 1 + 10 files changed, 60 insertions(+), 39 deletions(-) diff --git a/src/files.h b/src/files.h index 4b281438f1..ea24cff20d 100644 --- a/src/files.h +++ b/src/files.h @@ -184,6 +184,14 @@ public: return mReader->Read(buffer, (long)len); } + TArray Read(size_t len) + { + TArray buffer((int)len, true); + Size length = mReader->Read(&buffer[0], (long)len); + buffer.Clamp((int)length); + return buffer; + } + TArray Read() { TArray buffer(mReader->Length, true); diff --git a/src/p_setup.cpp b/src/p_setup.cpp index 15cbb0b543..8f456c024c 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -1691,15 +1691,10 @@ uint16_t MakeSkill(int flags) void P_LoadThings (MapData * map) { - int lumplen = map->Size(ML_THINGS); - int numthings = lumplen / sizeof(mapthing_t); - - char *mtp; mapthing_t *mt; - - mtp = new char[lumplen]; - map->Read(ML_THINGS, mtp); - mt = (mapthing_t*)mtp; + auto mtp = map->Read(ML_THINGS); + int numthings = mtp.Size() / sizeof(mapthing_t); + mt = (mapthing_t*)mtp.Data(); MapThingsConverted.Resize(numthings); FMapThing *mti = &MapThingsConverted[0]; @@ -1767,7 +1762,6 @@ void P_LoadThings (MapData * map) if (flags & BTF_NOTSINGLE) mti[i].flags &= ~MTF_SINGLE; } } - delete [] mtp; } //=========================================================================== @@ -2109,29 +2103,24 @@ void P_LoadLineDefs (MapData * map) { int i, skipped; line_t *ld; - int lumplen = map->Size(ML_LINEDEFS); - char * mldf; maplinedef_t *mld; - int numlines = lumplen / sizeof(maplinedef_t); + auto mldf = map->Read(ML_LINEDEFS); + int numlines = mldf.Size() / sizeof(maplinedef_t); linemap.Resize(numlines); - mldf = new char[lumplen]; - map->Read(ML_LINEDEFS, mldf); - // [RH] Count the number of sidedef references. This is the number of // sidedefs we need. The actual number in the SIDEDEFS lump might be less. // Lines with 0 length are also removed. for (skipped = sidecount = i = 0; i < numlines; ) { - mld = ((maplinedef_t*)mldf) + i; + mld = ((maplinedef_t*)mldf.Data()) + i; unsigned v1 = LittleShort(mld->v1); unsigned v2 = LittleShort(mld->v2); if (v1 >= level.vertexes.Size() || v2 >= level.vertexes.Size()) { - delete [] mldf; I_Error ("Line %d has invalid vertices: %d and/or %d.\nThe map only contains %u vertices.", i+skipped, v1, v2, level.vertexes.Size()); } else if (v1 == v2 || @@ -2164,7 +2153,7 @@ void P_LoadLineDefs (MapData * map) P_AllocateSideDefs (map, sidecount); - mld = (maplinedef_t *)mldf; + mld = (maplinedef_t *)mldf.Data(); ld = &level.lines[0]; for (i = 0; i < numlines; i++, mld++, ld++) { @@ -2203,7 +2192,6 @@ void P_LoadLineDefs (MapData * map) if (level.flags2 & LEVEL2_WRAPMIDTEX) ld->flags |= ML_WRAP_MIDTEX; if (level.flags2 & LEVEL2_CHECKSWITCHRANGE) ld->flags |= ML_CHECKSWITCHRANGE; } - delete[] mldf; } //=========================================================================== diff --git a/src/p_setup.h b/src/p_setup.h index 1f773e951f..dd3a1e1e3b 100644 --- a/src/p_setup.h +++ b/src/p_setup.h @@ -104,6 +104,13 @@ public: } } + TArray Read(unsigned lumpindex) + { + TArray buffer(Size(lumpindex), true); + Read(lumpindex, buffer.Data(), (int)buffer.Size()); + return buffer; + } + uint32_t Size(unsigned int lumpindex) { if (lumpindexSize(ML_TEXTMAP)]; - isTranslated = true; isExtended = false; floordrop = false; - map->Read(ML_TEXTMAP, buffer); - sc.OpenMem(Wads.GetLumpFullName(map->lumpnum), buffer, map->Size(ML_TEXTMAP)); - delete [] buffer; + sc.OpenMem(Wads.GetLumpFullName(map->lumpnum), map->Read(ML_TEXTMAP)); sc.SetCMode(true); if (sc.CheckString("namespace")) { diff --git a/src/p_usdf.cpp b/src/p_usdf.cpp index 4838d4b8d7..f24cd5d7b8 100644 --- a/src/p_usdf.cpp +++ b/src/p_usdf.cpp @@ -473,10 +473,7 @@ class USDFParser : public UDMFParserBase public: bool Parse(int lumpnum, FileReader &lump, int lumplen) { - char *buffer = new char[lumplen]; - lump.Read(buffer, lumplen); - sc.OpenMem(Wads.GetLumpFullName(lumpnum), buffer, lumplen); - delete [] buffer; + sc.OpenMem(Wads.GetLumpFullName(lumpnum), lump.Read(lumplen)); sc.SetCMode(true); // Namespace must be the first field because everything else depends on it. if (sc.CheckString("namespace")) diff --git a/src/parsecontext.cpp b/src/parsecontext.cpp index cdc28c15a8..9631c4b494 100644 --- a/src/parsecontext.cpp +++ b/src/parsecontext.cpp @@ -323,15 +323,12 @@ void FParseContext::ParseLump(const char *lumpname) } // Read the lump into a buffer and add a 0-terminator - int lumplen = Wads.LumpLength(lumpno); - char *lumpdata = new char[lumplen+1]; - Wads.ReadLump(lumpno, lumpdata); - lumpdata[lumplen] = 0; + auto lumpdata = Wads.ReadLumpIntoArray(lumpno, 1); SourceLine = 0; SourceFile = lumpname; - char *sourcep = lumpdata; + char *sourcep = (char*)lumpdata.Data(); while ( (tokentype = GetToken(sourcep, &token)) ) { // It is much easier to handle include statements outside the main parser. @@ -349,7 +346,6 @@ void FParseContext::ParseLump(const char *lumpname) Parse(pParser, tokentype, token, this); } } - delete [] lumpdata; SourceLine = SavedSourceLine; SourceFile = SavedSourceFile; } diff --git a/src/sc_man.h b/src/sc_man.h index 9c4f34a22c..57ab6ec52e 100644 --- a/src/sc_man.h +++ b/src/sc_man.h @@ -21,6 +21,10 @@ public: void Open(const char *lumpname); bool OpenFile(const char *filename); void OpenMem(const char *name, const char *buffer, int size); + void OpenMem(const char *name, TArray &buffer) + { + OpenMem(name, (const char*)buffer.Data(), buffer.Size()); + } void OpenString(const char *name, FString buffer); void OpenLumpNum(int lump); void Close(); diff --git a/src/tarray.h b/src/tarray.h index 8543637cdb..77fc2fa5ca 100644 --- a/src/tarray.h +++ b/src/tarray.h @@ -157,12 +157,12 @@ public: Count = 0; Array = NULL; } - TArray (int max, bool reserve = false) + TArray (size_t max, bool reserve = false) { - Most = max; - Count = reserve? max : 0; + Most = (unsigned)max; + Count = (unsigned)(reserve? max : 0); Array = (T *)M_Malloc (sizeof(T)*max); - if (reserve) + if (reserve && Count > 0) { ConstructEmpty(0, Count - 1); } @@ -436,7 +436,7 @@ public: Grow (amount); unsigned int place = Count; Count += amount; - ConstructEmpty(place, Count - 1); + if (Count > 0) ConstructEmpty(place, Count - 1); return place; } unsigned int Size () const diff --git a/src/w_wad.cpp b/src/w_wad.cpp index 9c474ceb82..177a8b8028 100644 --- a/src/w_wad.cpp +++ b/src/w_wad.cpp @@ -1281,6 +1281,30 @@ void FWadCollection::ReadLump (int lump, void *dest) } } +//========================================================================== +// +// W_ReadLump +// +// Loads the lump into a TArray and returns it. +// +//========================================================================== + +TArray FWadCollection::ReadLumpIntoArray(int lump, int pad) +{ + auto lumpr = OpenLumpReader(lump); + auto size = lumpr.GetLength(); + TArray data(size + pad); + auto numread = lumpr.Read(data.Data(), size); + + if (numread != size) + { + I_Error("W_ReadLump: only read %ld of %ld on lump %i\n", + numread, size, lump); + } + if (pad > 0) memset(&data[size], 0, pad); + return data; +} + //========================================================================== // // ReadLump - variant 2 diff --git a/src/w_wad.h b/src/w_wad.h index dca4bd8feb..a7009d65ef 100644 --- a/src/w_wad.h +++ b/src/w_wad.h @@ -148,6 +148,7 @@ public: void ReadLump (int lump, void *dest); + TArray ReadLumpIntoArray(int lump, int pad = 0); // reads lump into a writable buffer and optionally adds some padding at the end. (FMemLump isn't writable!) FMemLump ReadLump (int lump); FMemLump ReadLump (const char *name) { return ReadLump (GetNumForName (name)); } From 6894912f44a64d5fc60ccd9c1450f5861f0279d4 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 10 Nov 2018 14:15:39 +0100 Subject: [PATCH 04/25] - use TArray for most buffers in p_glnodes.cpp. --- src/p_glnodes.cpp | 321 ++++++++++++++++++---------------------------- 1 file changed, 122 insertions(+), 199 deletions(-) diff --git a/src/p_glnodes.cpp b/src/p_glnodes.cpp index 0113208a10..75a53a9b18 100644 --- a/src/p_glnodes.cpp +++ b/src/p_glnodes.cpp @@ -210,16 +210,14 @@ static bool format5; static bool LoadGLVertexes(FileReader &lump) { - uint8_t *gldata; int i; firstglvertex = level.vertexes.Size(); - auto gllen=lump.GetLength(); - - gldata = new uint8_t[gllen]; lump.Seek(0, FileReader::SeekSet); - lump.Read(gldata, gllen); + auto glbuf = lump.Read(); + auto gllen=lump.GetLength(); + auto gldata = glbuf.Data(); if (*(int *)gldata == gNd5) { @@ -233,7 +231,6 @@ static bool LoadGLVertexes(FileReader &lump) Printf("GL nodes v%d found. This format is not supported by " GAMENAME "\n", (*(int *)gldata == gNd4)? 4:1); - delete [] gldata; return false; } else format5=false; @@ -256,7 +253,6 @@ static bool LoadGLVertexes(FileReader &lump) level.vertexes[i].set(LittleLong(mgl->x)/65536., LittleLong(mgl->y)/65536.); mgl++; } - delete[] gldata; return true; } @@ -288,139 +284,119 @@ static inline int checkGLVertex3(int num) static bool LoadGLSegs(FileReader &lump) { - char *data; int i; line_t *ldef=NULL; - - int numsegs = (int)lump.GetLength(); - data= new char[numsegs]; + lump.Seek(0, FileReader::SeekSet); - lump.Read(data, numsegs); + auto data = lump.Read(); + int numsegs = (int)lump.GetLength(); auto &segs = level.segs; -#ifdef _MSC_VER - __try -#endif + if (!format5 && memcmp(data.Data(), "gNd3", 4)) { - if (!format5 && memcmp(data, "gNd3", 4)) - { - numsegs/=sizeof(glseg_t); - level.segs.Alloc(numsegs); - memset(&segs[0],0,sizeof(seg_t)*numsegs); + numsegs/=sizeof(glseg_t); + level.segs.Alloc(numsegs); + memset(&segs[0],0,sizeof(seg_t)*numsegs); - glseg_t * ml = (glseg_t*)data; - for(i = 0; i < numsegs; i++) - { - // check for gl-vertices - segs[i].v1 = &level.vertexes[checkGLVertex(LittleShort(ml->v1))]; - segs[i].v2 = &level.vertexes[checkGLVertex(LittleShort(ml->v2))]; - segs[i].PartnerSeg = ml->partner == 0xFFFF ? nullptr : &segs[LittleShort(ml->partner)]; - if(ml->linedef != 0xffff) - { - ldef = &level.lines[LittleShort(ml->linedef)]; - segs[i].linedef = ldef; + glseg_t * ml = (glseg_t*)data.Data(); + for(i = 0; i < numsegs; i++) + { + // check for gl-vertices + segs[i].v1 = &level.vertexes[checkGLVertex(LittleShort(ml->v1))]; + segs[i].v2 = &level.vertexes[checkGLVertex(LittleShort(ml->v2))]; + segs[i].PartnerSeg = ml->partner == 0xFFFF ? nullptr : &segs[LittleShort(ml->partner)]; + if(ml->linedef != 0xffff) + { + ldef = &level.lines[LittleShort(ml->linedef)]; + segs[i].linedef = ldef; - ml->side=LittleShort(ml->side); - segs[i].sidedef = ldef->sidedef[ml->side]; - if (ldef->sidedef[ml->side] != NULL) - { - segs[i].frontsector = ldef->sidedef[ml->side]->sector; - } - else - { - segs[i].frontsector = NULL; - } - if (ldef->flags & ML_TWOSIDED && ldef->sidedef[ml->side^1] != NULL) - { - segs[i].backsector = ldef->sidedef[ml->side^1]->sector; - } - else - { - ldef->flags &= ~ML_TWOSIDED; - segs[i].backsector = NULL; - } - + ml->side=LittleShort(ml->side); + segs[i].sidedef = ldef->sidedef[ml->side]; + if (ldef->sidedef[ml->side] != NULL) + { + segs[i].frontsector = ldef->sidedef[ml->side]->sector; } else { - segs[i].linedef = NULL; - segs[i].sidedef = NULL; - segs[i].frontsector = NULL; - segs[i].backsector = NULL; } - ml++; + if (ldef->flags & ML_TWOSIDED && ldef->sidedef[ml->side^1] != NULL) + { + segs[i].backsector = ldef->sidedef[ml->side^1]->sector; + } + else + { + ldef->flags &= ~ML_TWOSIDED; + segs[i].backsector = NULL; + } + } + else + { + segs[i].linedef = NULL; + segs[i].sidedef = NULL; + + segs[i].frontsector = NULL; + segs[i].backsector = NULL; + } + ml++; } - else - { - if (!format5) numsegs-=4; - numsegs/=sizeof(glseg3_t); - level.segs.Alloc(numsegs); - memset(&segs[0],0,sizeof(seg_t)*numsegs); + } + else + { + if (!format5) numsegs-=4; + numsegs/=sizeof(glseg3_t); + level.segs.Alloc(numsegs); + memset(&segs[0],0,sizeof(seg_t)*numsegs); - glseg3_t * ml = (glseg3_t*)(data+ (format5? 0:4)); - for(i = 0; i < numsegs; i++) - { // check for gl-vertices - segs[i].v1 = &level.vertexes[checkGLVertex3(LittleLong(ml->v1))]; - segs[i].v2 = &level.vertexes[checkGLVertex3(LittleLong(ml->v2))]; + glseg3_t * ml = (glseg3_t*)(data.Data() + (format5? 0:4)); + for(i = 0; i < numsegs; i++) + { // check for gl-vertices + segs[i].v1 = &level.vertexes[checkGLVertex3(LittleLong(ml->v1))]; + segs[i].v2 = &level.vertexes[checkGLVertex3(LittleLong(ml->v2))]; - const uint32_t partner = LittleLong(ml->partner); - segs[i].PartnerSeg = DWORD_MAX == partner ? nullptr : &segs[partner]; + const uint32_t partner = LittleLong(ml->partner); + segs[i].PartnerSeg = DWORD_MAX == partner ? nullptr : &segs[partner]; - if(ml->linedef != 0xffff) // skip minisegs - { - ldef = &level.lines[LittleLong(ml->linedef)]; - segs[i].linedef = ldef; + if(ml->linedef != 0xffff) // skip minisegs + { + ldef = &level.lines[LittleLong(ml->linedef)]; + segs[i].linedef = ldef; - ml->side=LittleShort(ml->side); - segs[i].sidedef = ldef->sidedef[ml->side]; - if (ldef->sidedef[ml->side] != NULL) - { - segs[i].frontsector = ldef->sidedef[ml->side]->sector; - } - else - { - segs[i].frontsector = NULL; - } - if (ldef->flags & ML_TWOSIDED && ldef->sidedef[ml->side^1] != NULL) - { - segs[i].backsector = ldef->sidedef[ml->side^1]->sector; - } - else - { - ldef->flags &= ~ML_TWOSIDED; - segs[i].backsector = NULL; - } - + ml->side=LittleShort(ml->side); + segs[i].sidedef = ldef->sidedef[ml->side]; + if (ldef->sidedef[ml->side] != NULL) + { + segs[i].frontsector = ldef->sidedef[ml->side]->sector; } else { - segs[i].linedef = NULL; - segs[i].sidedef = NULL; segs[i].frontsector = NULL; - segs[i].backsector = NULL; } - ml++; + if (ldef->flags & ML_TWOSIDED && ldef->sidedef[ml->side^1] != NULL) + { + segs[i].backsector = ldef->sidedef[ml->side^1]->sector; + } + else + { + ldef->flags &= ~ML_TWOSIDED; + segs[i].backsector = NULL; + } + } + else + { + segs[i].linedef = NULL; + segs[i].sidedef = NULL; + segs[i].frontsector = NULL; + segs[i].backsector = NULL; + } + ml++; } - delete [] data; - return true; } -#ifdef _MSC_VER - __except(1) - { - // Invalid data has the bad habit of requiring extensive checks here - // so let's just catch anything invalid and output a message. - // (at least under MSVC. GCC can't do SEH even for Windows... :( ) - Printf("Invalid GL segs. The BSP will have to be rebuilt.\n"); - delete [] data; - level.segs.Clear(); - return false; - } -#endif + return true; } @@ -432,23 +408,20 @@ static bool LoadGLSegs(FileReader &lump) static bool LoadGLSubsectors(FileReader &lump) { - char * datab; int i; - + int numsubsectors = (int)lump.GetLength(); - datab = new char[numsubsectors]; lump.Seek(0, FileReader::SeekSet); - lump.Read(datab, numsubsectors); + auto datab = lump.Read(); if (numsubsectors == 0) { - delete [] datab; return false; } - if (!format5 && memcmp(datab, "gNd3", 4)) + if (!format5 && memcmp(datab.Data(), "gNd3", 4)) { - mapsubsector_t * data = (mapsubsector_t*) datab; + mapsubsector_t * data = (mapsubsector_t*) datab.Data(); numsubsectors /= sizeof(mapsubsector_t); level.subsectors.Alloc(numsubsectors); auto &subsectors = level.subsectors; @@ -461,14 +434,13 @@ static bool LoadGLSubsectors(FileReader &lump) if (subsectors[i].numlines == 0) { - delete [] datab; return false; } } } else { - gl3_mapsubsector_t * data = (gl3_mapsubsector_t*) (datab+(format5? 0:4)); + gl3_mapsubsector_t * data = (gl3_mapsubsector_t*) (datab.Data()+(format5? 0:4)); numsubsectors /= sizeof(gl3_mapsubsector_t); level.subsectors.Alloc(numsubsectors); auto &subsectors = level.subsectors; @@ -481,7 +453,6 @@ static bool LoadGLSubsectors(FileReader &lump) if (subsectors[i].numlines == 0) { - delete [] datab; return false; } } @@ -499,12 +470,10 @@ static bool LoadGLSubsectors(FileReader &lump) // The subsector must be closed. If it isn't we can't use these nodes and have to do a rebuild. if (lastseg->v2 != firstseg->v1) { - delete [] datab; return false; } } - delete [] datab; return true; } @@ -522,7 +491,7 @@ static bool LoadNodes (FileReader &lump) int j; int k; node_t* no; - uint16_t* used; + TArray used; if (!format5) { @@ -534,11 +503,11 @@ static bool LoadNodes (FileReader &lump) level.nodes.Alloc(numnodes); lump.Seek(0, FileReader::SeekSet); - basemn = mn = new mapnode_t[numnodes]; - lump.Read(mn, lump.GetLength()); + auto buf = lump.Read(); + basemn = mn = (mapnode_t*)buf.Data(); - used = (uint16_t *)alloca (sizeof(uint16_t)*numnodes); - memset (used, 0, sizeof(uint16_t)*numnodes); + used.Resize(numnodes); + memset (used.Data(), 0, sizeof(uint16_t)*numnodes); no = &level.nodes[0]; @@ -556,19 +525,16 @@ static bool LoadNodes (FileReader &lump) child &= ~NF_SUBSECTOR; if (child >= level.subsectors.Size()) { - delete [] basemn; return false; } no->children[j] = (uint8_t *)&level.subsectors[child] + 1; } else if (child >= numnodes) { - delete [] basemn; return false; } else if (used[child]) { - delete [] basemn; return false; } else @@ -582,7 +548,6 @@ static bool LoadNodes (FileReader &lump) } } } - delete [] basemn; } else { @@ -594,11 +559,11 @@ static bool LoadNodes (FileReader &lump) level.nodes.Alloc(numnodes); lump.Seek(0, FileReader::SeekSet); - basemn = mn = new gl5_mapnode_t[numnodes]; - lump.Read(mn, lump.GetLength()); + auto buf = lump.Read(); + basemn = mn = (gl5_mapnode_t*)buf.Data(); - used = (uint16_t *)alloca (sizeof(uint16_t)*numnodes); - memset (used, 0, sizeof(uint16_t)*numnodes); + used.Resize(numnodes); + memset(used.Data(), 0, sizeof(uint16_t)*numnodes); no = &level.nodes[0]; @@ -616,19 +581,16 @@ static bool LoadNodes (FileReader &lump) child &= ~GL5_NF_SUBSECTOR; if ((unsigned)child >= level.subsectors.Size()) { - delete [] basemn; return false; } no->children[j] = (uint8_t *)&level.subsectors[child] + 1; } else if ((unsigned)child >= numnodes) { - delete [] basemn; return false; } else if (used[child]) { - delete [] basemn; return false; } else @@ -642,7 +604,6 @@ static bool LoadNodes (FileReader &lump) } } } - delete [] basemn; } return true; } @@ -1097,31 +1058,30 @@ static void CreateCachedNodes(MapData *map) } uLongf outlen = ZNodes.Size(); - uint8_t *compressed; + TArray compressed; int offset = level.lines.Size() * 8 + 12 + 16; int r; do { - compressed = new Bytef[outlen + offset]; - r = compress (compressed + offset, &outlen, &ZNodes[0], ZNodes.Size()); + compressed.Resize(outlen + offset); + r = compress (compressed.Data() + offset, &outlen, &ZNodes[0], ZNodes.Size()); if (r == Z_BUF_ERROR) { - delete[] compressed; outlen += 1024; } } while (r == Z_BUF_ERROR); - memcpy(compressed, "CACH", 4); + memcpy(compressed.Data(), "CACH", 4); uint32_t len = LittleLong(level.lines.Size()); - memcpy(compressed+4, &len, 4); - map->GetChecksum(compressed+8); + memcpy(&compressed[4], &len, 4); + map->GetChecksum(&compressed[8]); for (unsigned i = 0; i < level.lines.Size(); i++) { uint32_t ndx[2] = { LittleLong(uint32_t(level.lines[i].v1->Index())), LittleLong(uint32_t(level.lines[i].v2->Index())) }; - memcpy(compressed + 8 + 16 + 8 * i, ndx, 8); + memcpy(&compressed[8 + 16 + 8 * i], ndx, 8); } - memcpy(compressed + offset - 4, "ZGL3", 4); + memcpy(&compressed[offset - 4], "ZGL3", 4); FString path = CreateCacheName(map, true); FileWriter *fw = FileWriter::Open(path); @@ -1129,7 +1089,7 @@ static void CreateCachedNodes(MapData *map) if (fw != nullptr) { const size_t length = outlen + offset; - if (fw->Write(compressed, length) != length) + if (fw->Write(compressed.Data(), length) != length) { Printf("Error saving nodes to file %s\n", path.GetChars()); } @@ -1139,8 +1099,6 @@ static void CreateCachedNodes(MapData *map) { Printf("Cannot open nodes file %s for writing\n", path.GetChars()); } - - delete [] compressed; } @@ -1150,29 +1108,29 @@ static bool CheckCachedNodes(MapData *map) uint8_t md5[16]; uint8_t md5map[16]; uint32_t numlin; - uint32_t *verts = NULL; + TArray verts; FString path = CreateCacheName(map, false); FileReader fr; if (!fr.OpenFile(path)) return false; - if (fr.Read(magic, 4) != 4) goto errorout; - if (memcmp(magic, "CACH", 4)) goto errorout; + if (fr.Read(magic, 4) != 4) return false; + if (memcmp(magic, "CACH", 4)) return false; - if (fr.Read(&numlin, 4) != 4) goto errorout; + if (fr.Read(&numlin, 4) != 4) return false; numlin = LittleLong(numlin); - if (numlin != level.lines.Size()) goto errorout; + if (numlin != level.lines.Size()) return false; - if (fr.Read(md5, 16) != 16) goto errorout; + if (fr.Read(md5, 16) != 16) return false; map->GetChecksum(md5map); - if (memcmp(md5, md5map, 16)) goto errorout; + if (memcmp(md5, md5map, 16)) return false; - verts = new uint32_t[numlin * 8]; - if (fr.Read(verts, 8 * numlin) != 8 * numlin) goto errorout; + verts.Resize(numlin * 2); + if (fr.Read(verts.Data(), 8 * numlin) != 8 * numlin) return false; - if (fr.Read(magic, 4) != 4) goto errorout; - if (memcmp(magic, "ZGL2", 4) && memcmp(magic, "ZGL3", 4)) goto errorout; + if (fr.Read(magic, 4) != 4) return false; + if (memcmp(magic, "ZGL2", 4) && memcmp(magic, "ZGL3", 4)) return false; try @@ -1186,7 +1144,7 @@ static bool CheckCachedNodes(MapData *map) level.subsectors.Clear(); level.segs.Clear(); level.nodes.Clear(); - goto errorout; + return false; } for(auto &line : level.lines) @@ -1195,16 +1153,7 @@ static bool CheckCachedNodes(MapData *map) line.v1 = &level.vertexes[LittleLong(verts[i*2])]; line.v2 = &level.vertexes[LittleLong(verts[i*2+1])]; } - delete [] verts; - return true; - -errorout: - if (verts != NULL) - { - delete[] verts; - } - return false; } UNSAFE_CCMD(clearnodecache) @@ -1308,32 +1257,6 @@ void P_SetRenderSector() TArray undetermined; subsector_t * ss; -#if 0 // doesn't work as expected :( - - // hide all sectors on textured automap that only have hidden lines. - bool *hidesec = new bool[numsectors]; - for(i = 0; i < numsectors; i++) - { - hidesec[i] = true; - } - for(i = 0; i < numlines; i++) - { - if (!(lines[i].flags & ML_DONTDRAW)) - { - hidesec[lines[i].frontsector - sectors] = false; - if (lines[i].backsector != NULL) - { - hidesec[lines[i].backsector - sectors] = false; - } - } - } - for(i = 0; i < numsectors; i++) - { - if (hidesec[i]) sectors[i].MoreFlags |= SECMF_HIDDEN; - } - delete [] hidesec; -#endif - // Check for incorrect partner seg info so that the following code does not crash. for (auto &seg : level.segs) From 4d06c17a4404347b44b80260e0b7e5bd5eb7c9e1 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 10 Nov 2018 14:18:34 +0100 Subject: [PATCH 05/25] - a few more buffers converted. --- src/c_consolebuffer.cpp | 7 +++---- src/f_wipe.cpp | 13 ++++--------- 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/src/c_consolebuffer.cpp b/src/c_consolebuffer.cpp index 9d32efffbb..9868bc6c3f 100644 --- a/src/c_consolebuffer.cpp +++ b/src/c_consolebuffer.cpp @@ -150,9 +150,9 @@ void FConsoleBuffer::AddText(int printlevel, const char *text, FILE *logfile) void FConsoleBuffer::WriteLineToLog(FILE *LogFile, const char *outline) { // Strip out any color escape sequences before writing to the log file - char * copy = new char[strlen(outline)+1]; + TArray copy(strlen(outline)+1); const char * srcp = outline; - char * dstp = copy; + char * dstp = copy.Data(); while (*srcp != 0) { @@ -193,8 +193,7 @@ void FConsoleBuffer::WriteLineToLog(FILE *LogFile, const char *outline) } *dstp=0; - fputs (copy, LogFile); - delete [] copy; + fputs (copy.Data(), LogFile); fflush (LogFile); } diff --git a/src/f_wipe.cpp b/src/f_wipe.cpp index 6d34936fd3..25c2830381 100644 --- a/src/f_wipe.cpp +++ b/src/f_wipe.cpp @@ -32,29 +32,24 @@ class FBurnTexture : public FTexture { - uint32_t *WorkBuffer; + TArray WorkBuffer; public: FBurnTexture(int w, int h) + : WorkBuffer(w*h, true) { Width = w; Height = h; - WorkBuffer = new uint32_t[w * h]; - } - - ~FBurnTexture() - { - delete [] WorkBuffer; } int CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rotate, FCopyInfo *inf) override { - bmp->CopyPixelDataRGB(x, y, (uint8_t*)WorkBuffer, Width, Height, 4, Width*4, rotate, CF_RGBA, inf); + bmp->CopyPixelDataRGB(x, y, (uint8_t*)WorkBuffer.Data(), Width, Height, 4, Width*4, rotate, CF_RGBA, inf); return 0; } uint32_t *GetBuffer() { - return WorkBuffer; + return WorkBuffer.Data(); } }; From 191f2d9d76813256f8ad1a4be93caab94a03e0f5 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 10 Nov 2018 14:19:55 +0100 Subject: [PATCH 06/25] - use TArray and FString in resource file management. --- src/d_iwad.cpp | 4 +-- src/d_main.cpp | 2 +- src/resourcefiles/file_7z.cpp | 4 +-- src/resourcefiles/file_directory.cpp | 8 ++--- src/resourcefiles/file_grp.cpp | 3 +- src/resourcefiles/file_lump.cpp | 20 ++++++------ src/resourcefiles/file_pak.cpp | 3 +- src/resourcefiles/file_wad.cpp | 6 ++-- src/resourcefiles/file_zip.cpp | 12 ++++---- src/resourcefiles/resourcefile.cpp | 46 ++++++++++------------------ src/resourcefiles/resourcefile.h | 8 ++--- src/tarray.h | 6 ++-- src/w_wad.cpp | 6 ++-- 13 files changed, 55 insertions(+), 73 deletions(-) diff --git a/src/d_iwad.cpp b/src/d_iwad.cpp index bb2c091a3c..2716d1eb14 100644 --- a/src/d_iwad.cpp +++ b/src/d_iwad.cpp @@ -257,7 +257,7 @@ FIWadManager::FIWadManager(const char *fn) if (lmp->Namespace == ns_global && !stricmp(lmp->Name, "IWADINFO")) { // Found one! - ParseIWadInfo(resfile->Filename, (const char*)lmp->CacheLump(), lmp->LumpSize); + ParseIWadInfo(resfile->FileName, (const char*)lmp->CacheLump(), lmp->LumpSize); break; } } @@ -349,7 +349,7 @@ int FIWadManager::CheckIWADInfo(const char *fn) try { FIWADInfo result; - ParseIWadInfo(resfile->Filename, (const char*)lmp->CacheLump(), lmp->LumpSize, &result); + ParseIWadInfo(resfile->FileName, (const char*)lmp->CacheLump(), lmp->LumpSize, &result); delete resfile; for (unsigned i = 0, count = mIWadInfos.Size(); i < count; ++i) diff --git a/src/d_main.cpp b/src/d_main.cpp index 01c97b2ae5..0a02f6d99d 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -1905,7 +1905,7 @@ static FString CheckGameInfo(TArray & pwads) if (lmp->Namespace == ns_global && !stricmp(lmp->Name, "GAMEINFO")) { // Found one! - FString iwad = ParseGameInfo(pwads, resfile->Filename, (const char*)lmp->CacheLump(), lmp->LumpSize); + FString iwad = ParseGameInfo(pwads, resfile->FileName, (const char*)lmp->CacheLump(), lmp->LumpSize); delete resfile; return iwad; } diff --git a/src/resourcefiles/file_7z.cpp b/src/resourcefiles/file_7z.cpp index 79ecea5838..01bd043efc 100644 --- a/src/resourcefiles/file_7z.cpp +++ b/src/resourcefiles/file_7z.cpp @@ -230,7 +230,7 @@ bool F7ZFile::Open(bool quiet) Archive = NULL; if (!quiet) { - Printf("\n" TEXTCOLOR_RED "%s: ", Filename); + Printf("\n" TEXTCOLOR_RED "%s: ", FileName.GetChars()); if (res == SZ_ERROR_UNSUPPORTED) { Printf("Decoder does not support this archive\n"); @@ -309,7 +309,7 @@ bool F7ZFile::Open(bool quiet) if (SZ_OK != Archive->Extract(Lumps[0].Position, &temp[0])) { - if (!quiet) Printf("\n%s: unsupported 7z/LZMA file!\n", Filename); + if (!quiet) Printf("\n%s: unsupported 7z/LZMA file!\n", FileName.GetChars()); return false; } } diff --git a/src/resourcefiles/file_directory.cpp b/src/resourcefiles/file_directory.cpp index 03b33e4001..1f2d63d183 100644 --- a/src/resourcefiles/file_directory.cpp +++ b/src/resourcefiles/file_directory.cpp @@ -102,9 +102,9 @@ FDirectory::FDirectory(const char * directory) #ifdef _WIN32 free((void *)directory); #endif - dirname.ReplaceChars('\\', '/'); + FixPathSeperator(dirname); if (dirname[dirname.Len()-1] != '/') dirname += '/'; - Filename = copystring(dirname); + FileName = dirname; } @@ -248,7 +248,7 @@ int FDirectory::AddDirectory(const char *dirpath) bool FDirectory::Open(bool quiet) { - NumLumps = AddDirectory(Filename); + NumLumps = AddDirectory(FileName); if (!quiet) Printf(", %d lumps\n", NumLumps); PostProcessArchive(&Lumps[0], sizeof(FDirectoryLump)); return true; @@ -268,7 +268,7 @@ void FDirectory::AddEntry(const char *fullpath, int size) lump_p->mFullPath = fullpath; // [mxd] Convert name to lowercase - FString name = fullpath + strlen(Filename); + FString name = fullpath + strlen(FileName); name.ToLower(); // The lump's name is only the part relative to the main directory diff --git a/src/resourcefiles/file_grp.cpp b/src/resourcefiles/file_grp.cpp index c0458276a9..ba0493dd6e 100644 --- a/src/resourcefiles/file_grp.cpp +++ b/src/resourcefiles/file_grp.cpp @@ -85,7 +85,6 @@ public: FGrpFile::FGrpFile(const char *filename, FileReader &file) : FUncompressedFile(filename, file) { - Lumps = NULL; } //========================================================================== @@ -104,7 +103,7 @@ bool FGrpFile::Open(bool quiet) GrpLump *fileinfo = new GrpLump[NumLumps]; Reader.Read (fileinfo, NumLumps * sizeof(GrpLump)); - Lumps = new FUncompressedLump[NumLumps]; + Lumps.Resize(NumLumps); int Position = sizeof(GrpInfo) + NumLumps * sizeof(GrpLump); diff --git a/src/resourcefiles/file_lump.cpp b/src/resourcefiles/file_lump.cpp index d7eb68e884..da458303a7 100644 --- a/src/resourcefiles/file_lump.cpp +++ b/src/resourcefiles/file_lump.cpp @@ -69,17 +69,17 @@ FLumpFile::FLumpFile(const char *filename, FileReader &file) bool FLumpFile::Open(bool quiet) { - FString name(ExtractFileBase (Filename)); + FString name(ExtractFileBase (FileName)); - Lumps = new FUncompressedLump[1]; // must use array allocator - uppercopy(Lumps->Name, name); - Lumps->Name[8] = 0; - Lumps->Owner = this; - Lumps->Position = 0; - Lumps->LumpSize = (int)Reader.GetLength(); - Lumps->Namespace = ns_global; - Lumps->Flags = 0; - Lumps->FullName = NULL; + Lumps.Resize(1); + uppercopy(Lumps[0].Name, name); + Lumps[0].Name[8] = 0; + Lumps[0].Owner = this; + Lumps[0].Position = 0; + Lumps[0].LumpSize = (int)Reader.GetLength(); + Lumps[0].Namespace = ns_global; + Lumps[0].Flags = 0; + Lumps[0].FullName = NULL; NumLumps = 1; if (!quiet) { diff --git a/src/resourcefiles/file_pak.cpp b/src/resourcefiles/file_pak.cpp index c2705a97fb..d7f091c025 100644 --- a/src/resourcefiles/file_pak.cpp +++ b/src/resourcefiles/file_pak.cpp @@ -80,7 +80,6 @@ public: FPakFile::FPakFile(const char *filename, FileReader &file) : FUncompressedFile(filename, file) { - Lumps = NULL; } //========================================================================== @@ -101,7 +100,7 @@ bool FPakFile::Open(bool quiet) Reader.Seek (header.dirofs, FileReader::SeekSet); Reader.Read (fileinfo, NumLumps * sizeof(dpackfile_t)); - Lumps = new FUncompressedLump[NumLumps]; + Lumps.Resize(NumLumps); if (!quiet && !batchrun) Printf(", %d lumps\n", NumLumps); diff --git a/src/resourcefiles/file_wad.cpp b/src/resourcefiles/file_wad.cpp index a0ae033db1..c1f5b3fdba 100644 --- a/src/resourcefiles/file_wad.cpp +++ b/src/resourcefiles/file_wad.cpp @@ -165,7 +165,7 @@ bool FWadFile::Open(bool quiet) // Check again to detect broken wads if (InfoTableOfs + NumLumps*sizeof(wadlump_t) > (unsigned)wadSize) { - I_Error("Cannot load broken WAD file %s\n", Filename); + I_Error("Cannot load broken WAD file %s\n", FileName.GetChars()); } } @@ -194,7 +194,7 @@ bool FWadFile::Open(bool quiet) { if (Lumps[i].LumpSize != 0) { - Printf(PRINT_HIGH, "%s: Lump %s contains invalid positioning info and will be ignored\n", Filename, Lumps[i].Name); + Printf(PRINT_HIGH, "%s: Lump %s contains invalid positioning info and will be ignored\n", FileName.GetChars(), Lumps[i].Name); Lumps[i].Name[0] = 0; } Lumps[i].LumpSize = Lumps[i].Position = 0; @@ -439,7 +439,7 @@ void FWadFile::SkinHack () "The maps in %s will not be loaded because it has a skin.\n" TEXTCOLOR_BLUE "You should remove the skin from the wad to play these maps.\n", - Filename); + FileName.GetChars()); } } diff --git a/src/resourcefiles/file_zip.cpp b/src/resourcefiles/file_zip.cpp index b3bfa7a2dc..04430384e3 100644 --- a/src/resourcefiles/file_zip.cpp +++ b/src/resourcefiles/file_zip.cpp @@ -181,7 +181,7 @@ bool FZipFile::Open(bool quiet) if (centraldir == 0) { - if (!quiet) Printf(TEXTCOLOR_RED "\n%s: ZIP file corrupt!\n", Filename); + if (!quiet) Printf(TEXTCOLOR_RED "\n%s: ZIP file corrupt!\n", FileName.GetChars()); return false; } @@ -193,7 +193,7 @@ bool FZipFile::Open(bool quiet) if (info.NumEntries != info.NumEntriesOnAllDisks || info.FirstDisk != 0 || info.DiskNumber != 0) { - if (!quiet) Printf(TEXTCOLOR_RED "\n%s: Multipart Zip files are not supported.\n", Filename); + if (!quiet) Printf(TEXTCOLOR_RED "\n%s: Multipart Zip files are not supported.\n", FileName.GetChars()); return false; } @@ -229,7 +229,7 @@ bool FZipFile::Open(bool quiet) if (dirptr > ((char*)directory) + dirsize) // This directory entry goes beyond the end of the file. { free(directory); - if (!quiet) Printf(TEXTCOLOR_RED "\n%s: Central directory corrupted.", Filename); + if (!quiet) Printf(TEXTCOLOR_RED "\n%s: Central directory corrupted.", FileName.GetChars()); return false; } @@ -300,7 +300,7 @@ bool FZipFile::Open(bool quiet) if (dirptr > ((char*)directory) + dirsize) // This directory entry goes beyond the end of the file. { free(directory); - if (!quiet) Printf(TEXTCOLOR_RED "\n%s: Central directory corrupted.", Filename); + if (!quiet) Printf(TEXTCOLOR_RED "\n%s: Central directory corrupted.", FileName.GetChars()); return false; } @@ -320,7 +320,7 @@ bool FZipFile::Open(bool quiet) zip_fh->Method != METHOD_IMPLODE && zip_fh->Method != METHOD_SHRINK) { - if (!quiet) Printf(TEXTCOLOR_YELLOW "\n%s: '%s' uses an unsupported compression algorithm (#%d).\n", Filename, name.GetChars(), zip_fh->Method); + if (!quiet) Printf(TEXTCOLOR_YELLOW "\n%s: '%s' uses an unsupported compression algorithm (#%d).\n", FileName.GetChars(), name.GetChars(), zip_fh->Method); skipped++; continue; } @@ -328,7 +328,7 @@ bool FZipFile::Open(bool quiet) zip_fh->Flags = LittleShort(zip_fh->Flags); if (zip_fh->Flags & ZF_ENCRYPTED) { - if (!quiet) Printf(TEXTCOLOR_YELLOW "\n%s: '%s' is encrypted. Encryption is not supported.\n", Filename, name.GetChars()); + if (!quiet) Printf(TEXTCOLOR_YELLOW "\n%s: '%s' is encrypted. Encryption is not supported.\n", FileName.GetChars(), name.GetChars()); skipped++; continue; } diff --git a/src/resourcefiles/resourcefile.cpp b/src/resourcefiles/resourcefile.cpp index 419bd47074..1cb1f4e9ff 100644 --- a/src/resourcefiles/resourcefile.cpp +++ b/src/resourcefiles/resourcefile.cpp @@ -156,7 +156,7 @@ static bool IsWadInFolder(const FResourceFile* const archive, const char* const return false; } - const FString dirName = ExtractFileBase(archive->Filename); + const FString dirName = ExtractFileBase(archive->FileName); const FString fileName = ExtractFileBase(resPath, true); const FString filePath = dirName + '/' + fileName; @@ -323,9 +323,8 @@ FResourceFile *FResourceFile::OpenDirectory(const char *filename, bool quiet) //========================================================================== FResourceFile::FResourceFile(const char *filename) + : FileName(filename) { - if (filename != NULL) Filename = copystring(filename); - else Filename = NULL; } FResourceFile::FResourceFile(const char *filename, FileReader &r) @@ -336,7 +335,6 @@ FResourceFile::FResourceFile(const char *filename, FileReader &r) FResourceFile::~FResourceFile() { - if (Filename != NULL) delete [] Filename; } int lumpcmp(const void * a, const void * b) @@ -653,12 +651,6 @@ FUncompressedFile::FUncompressedFile(const char *filename, FileReader &r) : FResourceFile(filename, r) {} -FUncompressedFile::~FUncompressedFile() -{ - if (Lumps != NULL) delete [] Lumps; -} - - //========================================================================== // @@ -667,9 +659,8 @@ FUncompressedFile::~FUncompressedFile() //========================================================================== FExternalLump::FExternalLump(const char *_filename, int filesize) + : Filename(_filename) { - filename = _filename? copystring(_filename) : NULL; - if (filesize == -1) { FileReader f; @@ -690,11 +681,6 @@ FExternalLump::FExternalLump(const char *_filename, int filesize) } -FExternalLump::~FExternalLump() -{ - if (filename != NULL) delete [] filename; -} - //========================================================================== // // Caches a lump's content and increases the reference counter @@ -707,7 +693,7 @@ int FExternalLump::FillCache() Cache = new char[LumpSize]; FileReader f; - if (f.OpenFile(filename)) + if (f.OpenFile(Filename)) { f.Read(Cache, LumpSize); } @@ -722,19 +708,19 @@ int FExternalLump::FillCache() bool FMemoryFile::Open(bool quiet) { - FString name(ExtractFileBase(Filename)); - FString fname(ExtractFileBase(Filename, true)); + FString name(ExtractFileBase(FileName)); + FString fname(ExtractFileBase(FileName, true)); - Lumps = new FUncompressedLump[1]; // must use array allocator - uppercopy(Lumps->Name, name); - Lumps->Name[8] = 0; - Lumps->FullName = fname; - Lumps->Owner = this; - Lumps->Position = 0; - Lumps->LumpSize = (int)Reader.GetLength(); - Lumps->Namespace = ns_global; - Lumps->Flags = 0; - Lumps->FullName = NULL; + Lumps.Resize(1); + uppercopy(Lumps[0].Name, name); + Lumps[0].Name[8] = 0; + Lumps[0].FullName = fname; + Lumps[0].Owner = this; + Lumps[0].Position = 0; + Lumps[0].LumpSize = (int)Reader.GetLength(); + Lumps[0].Namespace = ns_global; + Lumps[0].Flags = 0; + Lumps[0].FullName = nullptr; NumLumps = 1; return true; } diff --git a/src/resourcefiles/resourcefile.h b/src/resourcefiles/resourcefile.h index 9b39b09082..9ad2e43cf5 100644 --- a/src/resourcefiles/resourcefile.h +++ b/src/resourcefiles/resourcefile.h @@ -82,7 +82,7 @@ class FResourceFile { public: FileReader Reader; - const char *Filename; + FString FileName; protected: uint32_t NumLumps; @@ -133,21 +133,19 @@ struct FUncompressedLump : public FResourceLump class FUncompressedFile : public FResourceFile { protected: - FUncompressedLump * Lumps = nullptr; + TArray Lumps; FUncompressedFile(const char *filename); FUncompressedFile(const char *filename, FileReader &r); - virtual ~FUncompressedFile(); virtual FResourceLump *GetLump(int no) { return ((unsigned)no < NumLumps)? &Lumps[no] : NULL; } }; struct FExternalLump : public FResourceLump { - const char *filename; // the actual file name. This is not necessarily the same as the lump name! + FString Filename; FExternalLump(const char *_filename, int filesize = -1); - ~FExternalLump(); virtual int FillCache(); }; diff --git a/src/tarray.h b/src/tarray.h index 77fc2fa5ca..e5f58b5481 100644 --- a/src/tarray.h +++ b/src/tarray.h @@ -431,11 +431,11 @@ public: } // Reserves amount entries at the end of the array, but does nothing // with them. - unsigned int Reserve (unsigned int amount) + unsigned int Reserve (size_t amount) { - Grow (amount); + Grow ((unsigned)amount); unsigned int place = Count; - Count += amount; + Count += (unsigned)amount; if (Count > 0) ConstructEmpty(place, Count - 1); return place; } diff --git a/src/w_wad.cpp b/src/w_wad.cpp index 177a8b8028..9c0dd37606 100644 --- a/src/w_wad.cpp +++ b/src/w_wad.cpp @@ -1413,7 +1413,7 @@ const char *FWadCollection::GetWadName (int wadnum) const return NULL; } - name = Files[wadnum]->Filename; + name = Files[wadnum]->FileName; slash = strrchr (name, '/'); return slash != NULL ? slash+1 : name; } @@ -1476,10 +1476,10 @@ const char *FWadCollection::GetWadFullName (int wadnum) const { if ((unsigned int)wadnum >= Files.Size()) { - return NULL; + return nullptr; } - return Files[wadnum]->Filename; + return Files[wadnum]->FileName; } From 9a7f570b19961968d8d675596a06d4fa3fd988a4 Mon Sep 17 00:00:00 2001 From: Major Cooke Date: Sat, 10 Nov 2018 09:00:49 -0600 Subject: [PATCH 07/25] Added DMG_NO_ENHANCE for DamageMobj. - Disables PowerDamage's effect, similar to DMG_NO_PROTECT disabling PowerProtect. --- src/p_interaction.cpp | 2 +- src/p_local.h | 1 + wadsrc/static/zscript/constants.txt | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index 2d7d6026c5..d5404a19a5 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -1086,7 +1086,7 @@ static int DamageMobj (AActor *target, AActor *inflictor, AActor *source, int da damage = int(damage * source->DamageMultiply); // Handle active damage modifiers (e.g. PowerDamage) - if (damage > 0) + if (damage > 0 && !(flags & DMG_NO_ENHANCE)) { damage = source->GetModifiedDamage(mod, damage, false); } diff --git a/src/p_local.h b/src/p_local.h index 06748c76a6..9231058fd9 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -454,6 +454,7 @@ enum EDmgFlags DMG_USEANGLE = 512, DMG_NO_PAIN = 1024, DMG_EXPLOSION = 2048, + DMG_NO_ENHANCE = 4096, }; diff --git a/wadsrc/static/zscript/constants.txt b/wadsrc/static/zscript/constants.txt index 92f5483558..ccb3f48488 100644 --- a/wadsrc/static/zscript/constants.txt +++ b/wadsrc/static/zscript/constants.txt @@ -940,6 +940,7 @@ enum EDmgFlags DMG_USEANGLE = 512, DMG_NO_PAIN = 1024, DMG_EXPLOSION = 2048, + DMG_NO_ENHANCE = 4096, } enum EReplace From a90655b295b13cca7e92679d2dea4b61138dcf63 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 10 Nov 2018 20:06:10 +0100 Subject: [PATCH 08/25] - cache the results of hw_FakeFlat for the remainder of the current scene instead of storing this in local variables. An exception is made for the sprite drawer which needs to call this in the worker thread on some occasions for as-yet unprocessed sectors. This case may not alter the cache to avoid having to add thread synchronization to it. The main reason for this change is that pointers to such manipulated sectors can now be considered static in the renderer. Due to them being short lived local buffers it was not possible to carry them along with the render data for information retrieval. --- src/gl/renderer/gl_renderer.cpp | 7 +++- src/gl/renderer/gl_renderer.h | 2 - src/hwrenderer/scene/hw_bsp.cpp | 22 +++++------ src/hwrenderer/scene/hw_drawinfo.h | 2 - src/hwrenderer/scene/hw_drawlist.cpp | 1 + src/hwrenderer/scene/hw_fakeflat.cpp | 50 +++++++++++++++++++++---- src/hwrenderer/scene/hw_fakeflat.h | 3 +- src/hwrenderer/scene/hw_renderhacks.cpp | 44 ++++++++++------------ src/hwrenderer/scene/hw_sprites.cpp | 7 +++- src/hwrenderer/scene/hw_weapon.cpp | 3 +- 10 files changed, 87 insertions(+), 54 deletions(-) diff --git a/src/gl/renderer/gl_renderer.cpp b/src/gl/renderer/gl_renderer.cpp index ef1e6221d9..af6a3acac3 100644 --- a/src/gl/renderer/gl_renderer.cpp +++ b/src/gl/renderer/gl_renderer.cpp @@ -53,6 +53,7 @@ #include "hwrenderer/postprocessing/hw_shadowmapshader.h" #include "hwrenderer/data/flatvertices.h" #include "hwrenderer/scene/hw_skydome.h" +#include "hwrenderer/scene/hw_fakeflat.h" #include "gl/shaders/gl_postprocessshaderinstance.h" #include "gl/textures/gl_samplers.h" #include "hwrenderer/dynlights/hw_lightbuffer.h" @@ -231,6 +232,8 @@ sector_t *FGLRenderer::RenderView(player_t* player) } else { + hw_ClearFakeFlat(); + iter_dlightf = iter_dlight = draw_dlight = draw_dlightf = 0; checkBenchActive(); @@ -302,6 +305,7 @@ void FGLRenderer::BindToFrameBuffer(FMaterial *mat) void FGLRenderer::RenderTextureView(FCanvasTexture *tex, AActor *Viewpoint, double FOV) { + // This doesn't need to clear the fake flat cache. It can be shared between camera textures and the main view of a scene. FMaterial * gltex = FMaterial::ValidateTexture(tex, false); int width = gltex->TextureWidth(); @@ -343,7 +347,8 @@ void FGLRenderer::WriteSavePic (player_t *player, FileWriter *file, int width, i // Switch to render buffers dimensioned for the savepic mBuffers = mSaveBuffers; - P_FindParticleSubsectors(); // make sure that all recently spawned particles have a valid subsector. + hw_ClearFakeFlat(); + P_FindParticleSubsectors(); // make sure that all recently spawned particles have a valid subsector. gl_RenderState.SetVertexBuffer(screen->mVertexData); screen->mVertexData->Reset(); screen->mLights->Clear(); diff --git a/src/gl/renderer/gl_renderer.h b/src/gl/renderer/gl_renderer.h index 67d4fba283..f3765d3825 100644 --- a/src/gl/renderer/gl_renderer.h +++ b/src/gl/renderer/gl_renderer.h @@ -122,8 +122,6 @@ private: }; -#include "hwrenderer/scene/hw_fakeflat.h" - struct TexFilter_s { int minfilter; diff --git a/src/hwrenderer/scene/hw_bsp.cpp b/src/hwrenderer/scene/hw_bsp.cpp index 31a3694ee9..39d4145f37 100644 --- a/src/hwrenderer/scene/hw_bsp.cpp +++ b/src/hwrenderer/scene/hw_bsp.cpp @@ -96,7 +96,7 @@ static RenderJobQueue jobQueue; // One static queue is sufficient here. This cod void HWDrawInfo::WorkerThread() { - sector_t fakefront, fakeback, *front, *back; + sector_t *front, *back; WTTotal.Clock(); isWorkerThread = true; // for adding asserts in GL API code. The worker thread may never call any GL API. @@ -118,6 +118,8 @@ void HWDrawInfo::WorkerThread() _mm_pause(); _mm_pause(); } + // Note that the main thread MUST have prepared the fake sectors that get used below! + // This worker thread cannot prepare them itself without costly synchronization. else switch (job->type) { case RenderJob::TerminateJob: @@ -130,7 +132,7 @@ void HWDrawInfo::WorkerThread() SetupWall.Clock(); wall.sub = job->sub; - front = hw_FakeFlat(job->sub->sector, &fakefront, in_area, false); + front = hw_FakeFlat(job->sub->sector, in_area, false); auto seg = job->seg; if (seg->backsector) { @@ -140,7 +142,7 @@ void HWDrawInfo::WorkerThread() } else { - back = hw_FakeFlat(seg->backsector, &fakeback, in_area, true); + back = hw_FakeFlat(seg->backsector, in_area, true); } } else back = nullptr; @@ -156,7 +158,7 @@ void HWDrawInfo::WorkerThread() GLFlat flat; SetupFlat.Clock(); flat.section = job->sub->section; - front = hw_FakeFlat(job->sub->render_sector, &fakefront, in_area, false); + front = hw_FakeFlat(job->sub->render_sector, in_area, false); flat.ProcessSector(this, front); SetupFlat.Unclock(); break; @@ -164,14 +166,14 @@ void HWDrawInfo::WorkerThread() case RenderJob::SpriteJob: SetupSprite.Clock(); - front = hw_FakeFlat(job->sub->sector, &fakefront, in_area, false); + front = hw_FakeFlat(job->sub->sector, in_area, false); RenderThings(job->sub, front); SetupSprite.Unclock(); break; case RenderJob::ParticleJob: SetupSprite.Clock(); - front = hw_FakeFlat(job->sub->sector, &fakefront, in_area, false); + front = hw_FakeFlat(job->sub->sector, in_area, false); RenderParticles(job->sub, front); SetupSprite.Unclock(); break; @@ -228,7 +230,6 @@ void HWDrawInfo::AddLine (seg_t *seg, bool portalclip) #endif sector_t * backsector = nullptr; - sector_t bs; if (portalclip) { @@ -291,7 +292,7 @@ void HWDrawInfo::AddLine (seg_t *seg, bool portalclip) // clipping checks are only needed when the backsector is not the same as the front sector if (in_area == area_default) in_area = hw_CheckViewArea(seg->v1, seg->v2, seg->frontsector, seg->backsector); - backsector = hw_FakeFlat(seg->backsector, &bs, in_area, true); + backsector = hw_FakeFlat(seg->backsector, in_area, true); if (hw_CheckClip(seg->sidedef, currentsector, backsector)) { @@ -575,7 +576,6 @@ void HWDrawInfo::DoSubsector(subsector_t * sub) { sector_t * sector; sector_t * fakesector; - sector_t fake; #ifdef _DEBUG if (sub->sector->sectornum==931) @@ -600,7 +600,7 @@ void HWDrawInfo::DoSubsector(subsector_t * sub) } if (mClipper->IsBlocked()) return; // if we are inside a stacked sector portal which hasn't unclipped anything yet. - fakesector=hw_FakeFlat(sector, &fake, in_area, false); + fakesector=hw_FakeFlat(sector, in_area, false); if (mClipPortal) { @@ -677,7 +677,7 @@ void HWDrawInfo::DoSubsector(subsector_t * sub) sector = sub->render_sector; // the planes of this subsector are faked to belong to another sector // This means we need the heightsec parts and light info of the render sector, not the actual one. - fakesector = hw_FakeFlat(sector, &fake, in_area, false); + fakesector = hw_FakeFlat(sector, in_area, false); } uint8_t &srf = section_renderflags[level.sections.SectionIndex(sub->section)]; diff --git a/src/hwrenderer/scene/hw_drawinfo.h b/src/hwrenderer/scene/hw_drawinfo.h index 6fc0e212f9..24d6c22180 100644 --- a/src/hwrenderer/scene/hw_drawinfo.h +++ b/src/hwrenderer/scene/hw_drawinfo.h @@ -193,8 +193,6 @@ private: subsector_t *currentsubsector; // used by the line processing code. sector_t *currentsector; - sector_t fakesec; // this is a struct member because it gets used in recursively called functions so it cannot be put on the stack. - void WorkerThread(); void UnclipSubsector(subsector_t *sub); diff --git a/src/hwrenderer/scene/hw_drawlist.cpp b/src/hwrenderer/scene/hw_drawlist.cpp index 1ccbc31f30..067c5dee5f 100644 --- a/src/hwrenderer/scene/hw_drawlist.cpp +++ b/src/hwrenderer/scene/hw_drawlist.cpp @@ -36,6 +36,7 @@ #include "hwrenderer/utility/hw_clock.h" #include "hw_renderstate.h" #include "hw_drawinfo.h" +#include "hw_fakeflat.h" FMemArena RenderDataAllocator(1024*1024); // Use large blocks to reduce allocation time. diff --git a/src/hwrenderer/scene/hw_fakeflat.cpp b/src/hwrenderer/scene/hw_fakeflat.cpp index 555504bc42..38cfaeefc8 100644 --- a/src/hwrenderer/scene/hw_fakeflat.cpp +++ b/src/hwrenderer/scene/hw_fakeflat.cpp @@ -36,6 +36,9 @@ #include "hwrenderer/utility/hw_cvars.h" #include "r_utility.h" +static sector_t **fakesectorbuffer; + +extern thread_local bool isWorkerThread; //========================================================================== // @@ -182,6 +185,24 @@ area_t hw_CheckViewArea(vertex_t *v1, vertex_t *v2, sector_t *frontsector, secto return area_default; } +//========================================================================== +// +// +// +//========================================================================== +static FMemArena FakeSectorAllocator(20 * sizeof(sector_t)); + +static sector_t *allocateSector(sector_t *sec) +{ + if (fakesectorbuffer == nullptr) + { + fakesectorbuffer = (sector_t**)FakeSectorAllocator.Alloc(level.sectors.Size() * sizeof(sector_t*)); + memset(fakesectorbuffer, 0, level.sectors.Size() * sizeof(sector_t*)); + } + auto sectornum = sec->sectornum; + fakesectorbuffer[sectornum] = (sector_t*)FakeSectorAllocator.Alloc(sizeof(sector_t)); + return fakesectorbuffer[sectornum]; +} //========================================================================== // @@ -189,7 +210,8 @@ area_t hw_CheckViewArea(vertex_t *v1, vertex_t *v2, sector_t *frontsector, secto // by hardware rendering // //========================================================================== -sector_t * hw_FakeFlat(sector_t * sec, sector_t * dest, area_t in_area, bool back) + +sector_t * hw_FakeFlat(sector_t * sec, area_t in_area, bool back, sector_t *localcopy) { if (!sec->GetHeightSec() || sec->heightsec==sec) { @@ -197,6 +219,8 @@ sector_t * hw_FakeFlat(sector_t * sec, sector_t * dest, area_t in_area, bool bac // visual glitches because upper amd lower textures overlap. if (back && (sec->MoreFlags & SECMF_OVERLAPPING)) { + if (fakesectorbuffer && fakesectorbuffer[sec->sectornum]) return fakesectorbuffer[sec->sectornum]; + auto dest = localcopy? localcopy : allocateSector(sec); *dest = *sec; dest->ceilingplane = sec->floorplane; dest->ceilingplane.FlipVert(); @@ -215,6 +239,12 @@ sector_t * hw_FakeFlat(sector_t * sec, sector_t * dest, area_t in_area, bool bac } #endif + if (fakesectorbuffer && fakesectorbuffer[sec->sectornum]) + { + return fakesectorbuffer[sec->sectornum]; + } + assert(!(isWorkerThread && localcopy == nullptr)); + if (in_area==area_above) { if (sec->heightsec->MoreFlags&SECMF_FAKEFLOORONLY /*|| sec->GetTexture(sector_t::ceiling)==skyflatnum*/) in_area=area_normal; @@ -223,11 +253,8 @@ sector_t * hw_FakeFlat(sector_t * sec, sector_t * dest, area_t in_area, bool bac int diffTex = (sec->heightsec->MoreFlags & SECMF_CLIPFAKEPLANES); sector_t * s = sec->heightsec; -#if 0 - *dest=*sec; // This will invoke the copy operator which isn't really needed here. Memcpy is faster. -#else - memcpy(dest, sec, sizeof(sector_t)); -#endif + auto dest = localcopy ? localcopy : allocateSector(sec); + *dest = *sec; // Replace floor and ceiling height with control sector's heights. if (diffTex) @@ -309,7 +336,7 @@ sector_t * hw_FakeFlat(sector_t * sec, sector_t * dest, area_t in_area, bool bac dest->lightlevel = s->lightlevel; } - if (!back) + //if (!back) { dest->SetTexture(sector_t::floor, diffTex ? sec->GetTexture(sector_t::floor) : s->GetTexture(sector_t::floor), false); dest->planes[sector_t::floor].xform = s->planes[sector_t::floor].xform; @@ -362,7 +389,7 @@ sector_t * hw_FakeFlat(sector_t * sec, sector_t * dest, area_t in_area, bool bac dest->lightlevel = s->lightlevel; } - if (!back) + //if (!back) { dest->SetTexture(sector_t::ceiling, diffTex ? sec->GetTexture(sector_t::ceiling) : s->GetTexture(sector_t::ceiling), false); dest->SetTexture(sector_t::floor, s->GetTexture(sector_t::ceiling), false); @@ -386,3 +413,10 @@ sector_t * hw_FakeFlat(sector_t * sec, sector_t * dest, area_t in_area, bool bac } return dest; } + + +void hw_ClearFakeFlat() +{ + FakeSectorAllocator.FreeAll(); + fakesectorbuffer = nullptr; +} diff --git a/src/hwrenderer/scene/hw_fakeflat.h b/src/hwrenderer/scene/hw_fakeflat.h index c56f3798d3..2f670d222a 100644 --- a/src/hwrenderer/scene/hw_fakeflat.h +++ b/src/hwrenderer/scene/hw_fakeflat.h @@ -11,6 +11,7 @@ enum area_t : int // Global functions. bool hw_CheckClip(side_t * sidedef, sector_t * frontsector, sector_t * backsector); -sector_t * hw_FakeFlat(sector_t * sec, sector_t * dest, area_t in_area, bool back); +void hw_ClearFakeFlat(); +sector_t * hw_FakeFlat(sector_t * sec, area_t in_area, bool back, sector_t *localcopy = nullptr); area_t hw_CheckViewArea(vertex_t *v1, vertex_t *v2, sector_t *frontsector, sector_t *backsector); diff --git a/src/hwrenderer/scene/hw_renderhacks.cpp b/src/hwrenderer/scene/hw_renderhacks.cpp index 5592a03ab3..afa1eae78d 100644 --- a/src/hwrenderer/scene/hw_renderhacks.cpp +++ b/src/hwrenderer/scene/hw_renderhacks.cpp @@ -38,8 +38,7 @@ #include "hwrenderer/data/flatvertices.h" #include "hwrenderer/dynlights/hw_lightbuffer.h" #include "hwrenderer/scene/hw_portal.h" - -sector_t * hw_FakeFlat(sector_t * sec, sector_t * dest, area_t in_area, bool back); +#include "hw_fakeflat.h" //========================================================================== // @@ -53,32 +52,31 @@ void HWDrawInfo::DispatchRenderHacks() TMap::Pair *fpair; TMap::Iterator ofi(otherFloorPlanes); GLFlat glflat; - sector_t fakesec; glflat.section = nullptr; while (ofi.NextPair(pair)) { - auto sec = hw_FakeFlat(&level.sectors[pair->Key], &fakesec, in_area, false); + auto sec = hw_FakeFlat(&level.sectors[pair->Key], in_area, false); glflat.ProcessSector(this, sec, SSRF_RENDERFLOOR | SSRF_PLANEHACK); } TMap::Iterator oci(otherCeilingPlanes); while (ofi.NextPair(pair)) { - auto sec = hw_FakeFlat(&level.sectors[pair->Key], &fakesec, in_area, false); + auto sec = hw_FakeFlat(&level.sectors[pair->Key], in_area, false); glflat.ProcessSector(this, sec, SSRF_RENDERCEILING | SSRF_PLANEHACK); } TMap::Iterator ffi(floodFloorSegs); while (ffi.NextPair(fpair)) { - auto sec = hw_FakeFlat(&level.sectors[fpair->Key], &fakesec, in_area, false); + auto sec = hw_FakeFlat(&level.sectors[fpair->Key], in_area, false); glflat.ProcessSector(this, sec, SSRF_RENDERFLOOR | SSRF_FLOODHACK); } TMap::Iterator fci(floodCeilingSegs); while (fci.NextPair(fpair)) { - auto sec = hw_FakeFlat(&level.sectors[fpair->Key], &fakesec, in_area, false); + auto sec = hw_FakeFlat(&level.sectors[fpair->Key], in_area, false); glflat.ProcessSector(this, sec, SSRF_RENDERCEILING | SSRF_FLOODHACK); } } @@ -336,7 +334,7 @@ bool HWDrawInfo::DoOneSectorUpper(subsector_t * subsec, float Planez, area_t in_ // Note: if this is a real line between sectors // we can be sure that render_sector is the real sector! - sector_t * sec = hw_FakeFlat(seg->backsector, &fakesec, in_area, true); + sector_t * sec = hw_FakeFlat(seg->backsector, in_area, true); // Don't bother with slopes if (sec->ceilingplane.isSlope()) return false; @@ -394,7 +392,7 @@ bool HWDrawInfo::DoOneSectorLower(subsector_t * subsec, float Planez, area_t in_ // Note: if this is a real line between sectors // we can be sure that render_sector is the real sector! - sector_t * sec = hw_FakeFlat(seg->backsector, &fakesec, in_area, true); + sector_t * sec = hw_FakeFlat(seg->backsector, in_area, true); // Don't bother with slopes if (sec->floorplane.isSlope()) return false; @@ -453,7 +451,7 @@ bool HWDrawInfo::DoFakeBridge(subsector_t * subsec, float Planez, area_t in_area // Note: if this is a real line between sectors // we can be sure that render_sector is the real sector! - sector_t * sec = hw_FakeFlat(seg->backsector, &fakesec, in_area, true); + sector_t * sec = hw_FakeFlat(seg->backsector, in_area, true); // Don't bother with slopes if (sec->floorplane.isSlope()) return false; @@ -506,7 +504,7 @@ bool HWDrawInfo::DoFakeCeilingBridge(subsector_t * subsec, float Planez, area_t // Note: if this is a real line between sectors // we can be sure that render_sector is the real sector! - sector_t * sec = hw_FakeFlat(seg->backsector, &fakesec, in_area, true); + sector_t * sec = hw_FakeFlat(seg->backsector, in_area, true); // Don't bother with slopes if (sec->ceilingplane.isSlope()) return false; @@ -538,8 +536,6 @@ bool HWDrawInfo::DoFakeCeilingBridge(subsector_t * subsec, float Planez, area_t //========================================================================== void HWDrawInfo::HandleMissingTextures(area_t in_area) { - sector_t fake; - for (unsigned int i = 0; i < MissingUpperTextures.Size(); i++) { if (!MissingUpperTextures[i].seg) continue; @@ -589,7 +585,7 @@ void HWDrawInfo::HandleMissingTextures(area_t in_area) { // It isn't a hole. Now check whether it might be a fake bridge - sector_t * fakesector = hw_FakeFlat(MissingUpperTextures[i].seg->frontsector, &fake, in_area, false); + sector_t * fakesector = hw_FakeFlat(MissingUpperTextures[i].seg->frontsector, in_area, false); float planez = (float)fakesector->GetPlaneTexZ(sector_t::ceiling); backsub->validcount = validcount; @@ -655,7 +651,7 @@ void HWDrawInfo::HandleMissingTextures(area_t in_area) { // It isn't a hole. Now check whether it might be a fake bridge - sector_t * fakesector = hw_FakeFlat(MissingLowerTextures[i].seg->frontsector, &fake, in_area, false); + sector_t * fakesector = hw_FakeFlat(MissingLowerTextures[i].seg->frontsector, in_area, false); float planez = (float)fakesector->GetPlaneTexZ(sector_t::floor); backsub->validcount = validcount; @@ -729,9 +725,8 @@ void HWDrawInfo::CreateFloodPoly(wallseg * ws, FFlatVertex *vertices, float plan void HWDrawInfo::PrepareUpperGap(seg_t * seg) { wallseg ws; - sector_t ffake, bfake; - sector_t * fakefsector = hw_FakeFlat(seg->frontsector, &ffake, in_area, true); - sector_t * fakebsector = hw_FakeFlat(seg->backsector, &bfake, in_area, false); + sector_t * fakefsector = hw_FakeFlat(seg->frontsector, in_area, false); + sector_t * fakebsector = hw_FakeFlat(seg->backsector, in_area, true); vertex_t * v1, *v2; @@ -786,9 +781,8 @@ void HWDrawInfo::PrepareUpperGap(seg_t * seg) void HWDrawInfo::PrepareLowerGap(seg_t * seg) { wallseg ws; - sector_t ffake, bfake; - sector_t * fakefsector = hw_FakeFlat(seg->frontsector, &ffake, in_area, true); - sector_t * fakebsector = hw_FakeFlat(seg->backsector, &bfake, in_area, false); + sector_t * fakefsector = hw_FakeFlat(seg->frontsector, in_area, false); + sector_t * fakebsector = hw_FakeFlat(seg->backsector, in_area, true); vertex_t * v1, *v2; @@ -1220,7 +1214,7 @@ void HWDrawInfo::CollectSectorStacksCeiling(subsector_t * sub, sector_t * anchor if (sub->numlines>2 && !(ss_renderflags[sub->Index()]&SSRF_PROCESSED)) return; // Must be the exact same visplane - sector_t * me = hw_FakeFlat(sub->render_sector, &fakesec, in_area, false); + sector_t * me = hw_FakeFlat(sub->render_sector, in_area, false); if (me->GetTexture(sector_t::ceiling) != anchor->GetTexture(sector_t::ceiling) || me->ceilingplane != anchor->ceilingplane || me->GetCeilingLight() != anchor->GetCeilingLight() || @@ -1264,7 +1258,7 @@ void HWDrawInfo::CollectSectorStacksFloor(subsector_t * sub, sector_t * anchor, if (sub->numlines>2 && !(ss_renderflags[sub->Index()]&SSRF_PROCESSED)) return; // Must be the exact same visplane - sector_t * me = hw_FakeFlat(sub->render_sector, &fakesec, in_area, false); + sector_t * me = hw_FakeFlat(sub->render_sector, in_area, false); if (me->GetTexture(sector_t::floor) != anchor->GetTexture(sector_t::floor) || me->floorplane != anchor->floorplane || me->GetFloorLight() != anchor->GetFloorLight() || @@ -1303,7 +1297,7 @@ void HWDrawInfo::ProcessSectorStacks(area_t in_area) validcount++; for (i=0;iGetPortalGroup(sector_t::ceiling); if (portal != NULL) for(int k=0;ksubsectorcount;k++) { @@ -1347,7 +1341,7 @@ void HWDrawInfo::ProcessSectorStacks(area_t in_area) validcount++; for (i=0;iGetPortalGroup(sector_t::floor); if (portal != NULL) for(int k=0;ksubsectorcount;k++) { diff --git a/src/hwrenderer/scene/hw_sprites.cpp b/src/hwrenderer/scene/hw_sprites.cpp index 4bda3ab718..f3935dab69 100644 --- a/src/hwrenderer/scene/hw_sprites.cpp +++ b/src/hwrenderer/scene/hw_sprites.cpp @@ -755,7 +755,9 @@ void GLSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t if (sector->sectornum != thing->Sector->sectornum && !thruportal) { - rendersector = hw_FakeFlat(thing->Sector, &rs, in_area, false); + // This cannot create a copy in the fake sector cache because it'd interfere with the main thread, so provide a local buffer for the copy. + // Adding synchronization for this one case would cost more than it might save if the result here could be cached. + rendersector = hw_FakeFlat(thing->Sector, in_area, false, &rs); } else { @@ -1287,7 +1289,8 @@ void HWDrawInfo::ProcessActorsInPortal(FLinePortalSpan *glport, area_t in_area) th->Prev += newpos - savedpos; GLSprite spr; - spr.Process(this, th, hw_FakeFlat(th->Sector, &fakesector, in_area, false), in_area, 2); + // This is called from the worker thread and must not alter the fake sector cache. + spr.Process(this, th, hw_FakeFlat(th->Sector, in_area, false, &fakesector), in_area, 2); th->Angles.Yaw = savedangle; th->SetXYZ(savedpos); th->Prev -= newpos - savedpos; diff --git a/src/hwrenderer/scene/hw_weapon.cpp b/src/hwrenderer/scene/hw_weapon.cpp index bdcf1f08e8..d0bb20e4d3 100644 --- a/src/hwrenderer/scene/hw_weapon.cpp +++ b/src/hwrenderer/scene/hw_weapon.cpp @@ -222,8 +222,7 @@ static WeaponLighting GetWeaponLighting(sector_t *viewsector, const DVector3 &po } else { - sector_t fs; - auto fakesec = hw_FakeFlat(viewsector, &fs, in_area, false); + auto fakesec = hw_FakeFlat(viewsector, in_area, false); // calculate light level for weapon sprites l.lightlevel = hw_ClampLight(fakesec->lightlevel); From 67e012e445cef788f32cc087719a48a715aaa5de Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Sat, 10 Nov 2018 22:32:09 +0200 Subject: [PATCH 09/25] - fixed compilation on POSIX-like platforms src/p_udmf.cpp:2052:6: error: no matching member function for call to 'OpenMem' src/sc_man.h:24:7: note: candidate function not viable: expects an l-value for 2nd argument src/sc_man.h:23:7: note: candidate function not viable: requires 3 arguments, but 2 were provided src/resourcefiles/file_directory.cpp:198:32: error: use of undeclared identifier 'Filename'; did you mean 'FileName'? --- src/resourcefiles/file_directory.cpp | 2 +- src/sc_man.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/resourcefiles/file_directory.cpp b/src/resourcefiles/file_directory.cpp index 1f2d63d183..54cb1e7a6a 100644 --- a/src/resourcefiles/file_directory.cpp +++ b/src/resourcefiles/file_directory.cpp @@ -195,7 +195,7 @@ int FDirectory::AddDirectory(const char *dirpath) return 0; } - const size_t namepos = strlen(Filename); + const size_t namepos = strlen(FileName); FString pathfix; while ((ent = fts_read(fts)) != NULL) diff --git a/src/sc_man.h b/src/sc_man.h index 57ab6ec52e..c76fb724f7 100644 --- a/src/sc_man.h +++ b/src/sc_man.h @@ -21,7 +21,7 @@ public: void Open(const char *lumpname); bool OpenFile(const char *filename); void OpenMem(const char *name, const char *buffer, int size); - void OpenMem(const char *name, TArray &buffer) + void OpenMem(const char *name, const TArray &buffer) { OpenMem(name, (const char*)buffer.Data(), buffer.Size()); } From c946edd9bf54ca99d9438edbeb2182ba9d4466b5 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 10 Nov 2018 23:18:34 +0100 Subject: [PATCH 10/25] - instead of copying the sector planes to GLWall, just store pointers to the front and back sector for later use. Until now this wasn't doable because these could have come from hw_FakeFlat which only were local copies on the stack. With the recent change these faked sectors live long enough so that they can be passed around here. --- src/hwrenderer/scene/hw_decal.cpp | 4 ++-- src/hwrenderer/scene/hw_drawstructs.h | 4 ++-- src/hwrenderer/scene/hw_walls.cpp | 12 ++++++------ 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/hwrenderer/scene/hw_decal.cpp b/src/hwrenderer/scene/hw_decal.cpp index 5a3e509bfd..815032314f 100644 --- a/src/hwrenderer/scene/hw_decal.cpp +++ b/src/hwrenderer/scene/hw_decal.cpp @@ -95,7 +95,7 @@ void GLDecal::DrawDecal(HWDrawInfo *di, FRenderState &state) for (unsigned k = 0; k < lightlist.Size(); k++) { - secplane_t &lowplane = k == lightlist.Size() - 1 ? bottomplane : lightlist[k + 1].plane; + secplane_t &lowplane = k == lightlist.Size() - 1 ? frontsector->floorplane : lightlist[k + 1].plane; float low1 = lowplane.ZatPoint(dv[1].x, dv[1].y); float low2 = lowplane.ZatPoint(dv[2].x, dv[2].y); @@ -404,7 +404,7 @@ void GLWall::ProcessDecal(HWDrawInfo *di, DBaseDecal *decal, const FVector3 &nor gldecal->alpha = decal->Alpha; gldecal->zcenter = zpos - decalheight * 0.5f; - gldecal->bottomplane = bottomplane; + gldecal->frontsector = frontsector; gldecal->Normal = normal; gldecal->lightlist = lightlist; memcpy(gldecal->dv, dv, sizeof(dv)); diff --git a/src/hwrenderer/scene/hw_drawstructs.h b/src/hwrenderer/scene/hw_drawstructs.h index 35a6d340e3..d500e67957 100644 --- a/src/hwrenderer/scene/hw_drawstructs.h +++ b/src/hwrenderer/scene/hw_drawstructs.h @@ -186,7 +186,6 @@ public: }; - secplane_t topplane, bottomplane; // we need to save these to pass them to the shader for calculating glows. // these are not the same as ytop and ybottom!!! float zceil[2]; @@ -198,6 +197,7 @@ public: public: seg_t * seg; // this gives the easiest access to all other structs involved subsector_t * sub; // For polyobjects + sector_t *frontsector, *backsector; //private: void PutWall(HWDrawInfo *di, bool translucent); @@ -411,7 +411,7 @@ struct GLDecal int rellight; float alpha; FColormap Colormap; - secplane_t bottomplane; + sector_t *frontsector; FVector3 Normal; void DrawDecal(HWDrawInfo *di, FRenderState &state); diff --git a/src/hwrenderer/scene/hw_walls.cpp b/src/hwrenderer/scene/hw_walls.cpp index b91c38ae1a..f8455c2459 100644 --- a/src/hwrenderer/scene/hw_walls.cpp +++ b/src/hwrenderer/scene/hw_walls.cpp @@ -140,7 +140,7 @@ void GLWall::RenderTexturedWall(HWDrawInfo *di, FRenderState &state, int rflags) state.EnableGlow(true); state.SetGlowParams(topglowcolor, bottomglowcolor); } - state.SetGlowPlanes(topplane, bottomplane); + state.SetGlowPlanes(frontsector->ceilingplane, frontsector->floorplane); state.SetMaterial(gltexture, flags & 3, 0, -1); if (type == RENDERWALL_M2SNF) @@ -167,7 +167,7 @@ void GLWall::RenderTexturedWall(HWDrawInfo *di, FRenderState &state, int rflags) for (unsigned i = 0; i < lightlist->Size(); i++) { - secplane_t &lowplane = i == (*lightlist).Size() - 1 ? bottomplane : (*lightlist)[i + 1].plane; + secplane_t &lowplane = i == (*lightlist).Size() - 1 ? frontsector->floorplane : (*lightlist)[i + 1].plane; // this must use the exact same calculation method as GLWall::Process etc. float low1 = lowplane.ZatPoint(vertexes[0]); float low2 = lowplane.ZatPoint(vertexes[1]); @@ -1799,6 +1799,8 @@ void GLWall::Process(HWDrawInfo *di, seg_t *seg, sector_t * frontsector, sector_ // note: we always have a valid sidedef and linedef reference when getting here. this->seg = seg; + this->frontsector = frontsector; + this->backsector = backsector; vertindex = 0; vertcount = 0; @@ -1893,8 +1895,6 @@ void GLWall::Process(HWDrawInfo *di, seg_t *seg, sector_t * frontsector, sector_ if (frontsector->GetWallGlow(topglowcolor, bottomglowcolor)) flags |= GLWF_GLOW; - topplane = frontsector->ceilingplane; - bottomplane = frontsector->floorplane; zfloor[0] = ffh1 = segfront->floorplane.ZatPoint(v1); zfloor[1] = ffh2 = segfront->floorplane.ZatPoint(v2); @@ -2104,6 +2104,8 @@ void GLWall::ProcessLowerMiniseg(HWDrawInfo *di, seg_t *seg, sector_t * frontsec if (bfh > ffh) { this->seg = seg; + this->frontsector = frontsector; + this->backsector = backsector; this->sub = NULL; vertex_t * v1 = seg->v1; @@ -2129,8 +2131,6 @@ void GLWall::ProcessLowerMiniseg(HWDrawInfo *di, seg_t *seg, sector_t * frontsec Colormap = frontsector->Colormap; if (frontsector->GetWallGlow(topglowcolor, bottomglowcolor)) flags |= GLWF_GLOW; - topplane = frontsector->ceilingplane; - bottomplane = frontsector->floorplane; dynlightindex = -1; zfloor[0] = zfloor[1] = ffh; From 094afdfd5f0f8bcfcabc9e09b16276791cbbff4b Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 11 Nov 2018 09:33:40 +0100 Subject: [PATCH 11/25] - fixed: It may happen that a degenerate subsector ends up without any section or sector. Try to assign the best fit in such a case so that the relevant pointers are not null. --- src/r_data/r_sections.cpp | 84 +++++++++++++++++++++++++++++++++++++-- src/tarray.h | 7 +++- 2 files changed, 87 insertions(+), 4 deletions(-) diff --git a/src/r_data/r_sections.cpp b/src/r_data/r_sections.cpp index 9186a13a13..5be657c255 100644 --- a/src/r_data/r_sections.cpp +++ b/src/r_data/r_sections.cpp @@ -184,6 +184,33 @@ public: { CompileSections(pair->Value, rawsections); } + + // Make sure that all subsectors have a sector. In some degenerate cases a subsector may come up empty. + // An example is in Doom.wad E3M4 near linedef 1087. With the grouping data here this is relatively easy to fix. + sector_t *lastsector = &level.sectors[0]; + for (auto &rawsection : rawsections) + { + sector_t *mysector = nullptr; + bool missing = false; + for (auto num : rawsection) + { + auto &sub = level.subsectors[num]; + if (sub.sector == nullptr) missing = true; + else mysector = sub.sector; + } + // Should the worst case happen and no sector be found, use the last used one. Subsectors must not be sector-less! + if (mysector == nullptr) mysector = lastsector; + else lastsector = mysector; + for (auto num : rawsection) + { + auto &sub = level.subsectors[num]; + if (sub.sector == nullptr) + { + sub.sector = mysector; + } + } + } + subsectormap.Clear(); return rawsections; } @@ -253,8 +280,7 @@ public: { MakeOutline(list, lineForSeg); } - rawsections.Clear(); - rawsections.ShrinkToFit(); + rawsections.Reset(); // Assign partners after everything has been collected for (auto §ion : sections) @@ -720,8 +746,59 @@ public: curgroup++; } } -}; + //============================================================================= + // + // Check if some subsectors have come up empty on sections. + // In this case assign the best fit from the containing sector. + // This is only to ensure that the section pointer is not null. + // These are always degenerate and do not produce any actual render output. + // + //============================================================================= + + void FixMissingReferences() + { + for (auto &sub : level.subsectors) + { + if (sub.section == nullptr) + { + int sector = sub.sector->Index(); + int mapsection = sub.mapsection; + auto sections = level.sections.SectionsForSector(sector); + FSection *bestfit = nullptr; + for (auto §ion : sections) + { + if (bestfit == nullptr) + { + bestfit = §ion; + } + else if (bestfit->mapsection != section.mapsection && section.mapsection == mapsection) + { + bestfit = §ion; + } + else if (section.mapsection == mapsection) + { + BoundingRect rc; + for (unsigned i = 0; i < sub.numlines; i++) + { + rc.addVertex(sub.firstline[i].v1->fX(), sub.firstline[i].v1->fY()); + rc.addVertex(sub.firstline[i].v2->fX(), sub.firstline[i].v2->fY()); + } + // Pick the one closer to this subsector. + if (rc.distanceTo(section.bounds) < rc.distanceTo(bestfit->bounds)) + { + bestfit = §ion; + } + } + } + // This should really never happen, but better be safe than sorry and assign at least something. + if (bestfit == nullptr) bestfit = &level.sections.allSections[0]; + sub.section = bestfit; + } + } + } + +}; //============================================================================= @@ -787,6 +864,7 @@ void CreateSections(FSectionContainer &container) creat.FindOuterLoops(); creat.GroupSections(); creat.ConstructOutput(container); + creat.FixMissingReferences(); } CCMD(printsections) diff --git a/src/tarray.h b/src/tarray.h index e5f58b5481..167f85fa99 100644 --- a/src/tarray.h +++ b/src/tarray.h @@ -458,7 +458,12 @@ public: void Reset() { Clear(); - ShrinkToFit(); + Most = 0; + if (Array != nullptr) + { + M_Free(Array); + Array = nullptr; + } } private: T *Array; From d3aa9c6af17a077dcd0f26f154089232f6808bed Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 11 Nov 2018 10:08:13 +0100 Subject: [PATCH 12/25] - do not abort on unclosed sections. Apparently they can indeed happen with broken map setups like isolated linedefs somewhere in the wild (see Strife MAP08.) Although they are a problem for triangulation, this isn't what sections get used for currently so it's of no real concern. In case this is needed later their work data gets marked as 'bad' for the time being. --- src/r_data/r_sections.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/r_data/r_sections.cpp b/src/r_data/r_sections.cpp index 5be657c255..74b89f9a59 100644 --- a/src/r_data/r_sections.cpp +++ b/src/r_data/r_sections.cpp @@ -64,6 +64,7 @@ struct WorkSection int sectorindex; int mapsection; bool hasminisegs; + bool bad; // Did not produce a proper area and cannot be triangulated by tesselation. TArraysegments; TArray originalSides; // The segs will lose some of these while working on them. TArray subsectors; @@ -307,6 +308,7 @@ public: TArray outersegs; TArray loopedsegs; bool hasminisegs = false; + bool bad = false; // Collect all the segs that make up the outline of this section. for (auto j : rawsection) @@ -397,7 +399,8 @@ public: { // Did not find another one but have an unclosed loop. This should never happen and would indicate broken nodes. // Error out and let the calling code deal with it. - I_Error("Unclosed loop in sector %d at position (%d, %d)\n", loopedsegs[0]->Subsector->render_sector->Index(), (int)loopedsegs[0]->v1->fX(), (int)loopedsegs[0]->v1->fY()); + DPrintf(DMSG_NOTIFY, "Unclosed loop in sector %d at position (%d, %d)\n", loopedsegs[0]->Subsector->render_sector->Index(), (int)loopedsegs[0]->v1->fX(), (int)loopedsegs[0]->v1->fY()); + bad = true; } seg = nullptr; loopedsegs.Push(nullptr); // A separator is not really needed but useful for debugging. @@ -428,6 +431,7 @@ public: section.sectorindex = sector; section.mapsection = mapsec; section.hasminisegs = hasminisegs; + section.bad = bad; section.originalSides = std::move(foundsides); section.segments = std::move(sectionlines); section.subsectors = std::move(rawsection); From d37192c1e884f39d61519159df10ef8a1e79a774 Mon Sep 17 00:00:00 2001 From: Player701 Date: Sun, 11 Nov 2018 16:53:37 +0300 Subject: [PATCH 13/25] - Fixed: Decal generator should be taken from the current weapon instance instead of the default instance. --- src/p_map.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_map.cpp b/src/p_map.cpp index 148e1fd180..cea1a33d63 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -7063,7 +7063,7 @@ void SpawnShootDecal(AActor *t1, const FTraceResults &trace) if (t1->player != NULL && t1->player->ReadyWeapon != NULL) { - decalbase = t1->player->ReadyWeapon->GetDefault()->DecalGenerator; + decalbase = t1->player->ReadyWeapon->DecalGenerator; } else { From f2dcff43868b2cf34f7b69e677a32b76724b02b3 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 11 Nov 2018 16:04:05 +0100 Subject: [PATCH 14/25] - more options for Doom 64 style gradients on walls: * Colors can npw be defined per sidedef, not only per sector. * Gradients can be selectively disabled or vertically flipped per wall tier. * Gradients can be clamped to their respective tier, i.e top and bottom of the tier, not the front sector defines where it starts. The per-wall colors are implemented for hardware and softpoly renderer only, but not for the classic software renderer, because its code is far too scattered to do this efficiently. --- specs/udmf_zdoom.txt | 71 +++++++---- src/gl/renderer/gl_renderstate.cpp | 17 ++- src/gl/shaders/gl_shader.cpp | 5 + src/gl/shaders/gl_shader.h | 3 + src/hwrenderer/scene/hw_renderstate.h | 35 ++++-- src/hwrenderer/scene/hw_walls.cpp | 56 ++++++++- src/namedef.h | 20 +++ src/p_saveg.cpp | 3 + src/p_sectors.cpp | 11 -- src/p_setup.cpp | 170 ++++++++++++++------------ src/p_udmf.cpp | 74 +++++++++++ src/polyrenderer/scene/poly_wall.cpp | 7 +- src/r_defs.h | 54 +++++++- wadsrc/static/shaders/glsl/main.fp | 3 +- wadsrc/static/shaders/glsl/main.vp | 27 ++-- 15 files changed, 410 insertions(+), 146 deletions(-) diff --git a/specs/udmf_zdoom.txt b/specs/udmf_zdoom.txt index e26044dc6c..43722d0fe5 100644 --- a/specs/udmf_zdoom.txt +++ b/specs/udmf_zdoom.txt @@ -154,31 +154,52 @@ Note: All fields default to false unless mentioned otherwise. sidedef { - scalex_top = ; // X scale for upper texture, Default = 1.0. - scaley_top = ; // y scale for upper texture, Default = 1.0. - scalex_mid = ; // X scale for mid texture, Default = 1.0. - scaley_mid = ; // y scale for mid texture, Default = 1.0. - scalex_bottom = ; // X scale for lower texture, Default = 1.0. - scaley_bottom = ; // y scale for lower texture, Default = 1.0. - offsetx_top = ; // X offset for upper texture, Default = 0.0. - offsety_top = ; // y offset for upper texture, Default = 0.0. - offsetx_mid = ; // X offset for mid texture, Default = 0.0. - offsety_mid = ; // y offset for mid texture, Default = 0.0. - offsetx_bottom = ; // X offset for lower texture, Default = 0.0. - offsety_bottom = ; // y offset for lower texture, Default = 0.0. - // When global texture offsets are used they will - // be added on top of these values. - light = ; // This side's light level. Default is 0. - lightabsolute = ; // true = 'light' is an absolute value. Default is - // relative to the owning sector's light level. - lightfog = ; // true = This side's relative lighting is used even in - // foggy sectors. Default is to disable relative - // lighting in foggy sectors. - nofakecontrast = ; // Disables use of fake contrast on this sidedef. - smoothlighting = ; // Use smooth fake contrast. - clipmidtex = ; // Side's mid textures are clipped to floor and ceiling. - wrapmidtex = ; // Side's mid textures are wrapped. - nodecals = ; // Disables decals on the sidedef. + scalex_top = ; // X scale for upper texture, Default = 1.0. + scaley_top = ; // y scale for upper texture, Default = 1.0. + scalex_mid = ; // X scale for mid texture, Default = 1.0. + scaley_mid = ; // y scale for mid texture, Default = 1.0. + scalex_bottom = ; // X scale for lower texture, Default = 1.0. + scaley_bottom = ; // y scale for lower texture, Default = 1.0. + offsetx_top = ; // X offset for upper texture, Default = 0.0. + offsety_top = ; // y offset for upper texture, Default = 0.0. + offsetx_mid = ; // X offset for mid texture, Default = 0.0. + offsety_mid = ; // y offset for mid texture, Default = 0.0. + offsetx_bottom = ; // X offset for lower texture, Default = 0.0. + offsety_bottom = ; // y offset for lower texture, Default = 0.0. + // When global texture offsets are used they will + // be added on top of these values. + light = ; // This side's light level. Default is 0. + lightabsolute = ; // true = 'light' is an absolute value. Default is + // relative to the owning sector's light level. + lightfog = ; // true = This side's relative lighting is used even in + // foggy sectors. Default is to disable relative + // lighting in foggy sectors. + nofakecontrast = ; // Disables use of fake contrast on this sidedef. + smoothlighting = ; // Use smooth fake contrast. + clipmidtex = ; // Side's mid textures are clipped to floor and ceiling. + wrapmidtex = ; // Side's mid textures are wrapped. + nodecals = ; // Disables decals on the sidedef. + + nogradient_top = ; // disables color gradient on upper tier. (Hardware rendering only.) + flipgradient_top = ; // flips gradient colors on upper tier. (Hardware rendering only.) + clampgradient_top = ; // clamps gradient on upper tier to actual bounds (default is the entire front sector height, hardware rendering only.) + useowncolors_top = ; // Set to 1 to use the colors set in the sidedef. Default is using the colors from the owning sector. + uppercolor_top = ; // Material color of the top of the upper tier. + lowercolor_top = ; // Material color of the bottom of the upper tier. (Hardware rendering only.) + + nogradient_mid = ; // disables color gradient on middle tier. (Hardware rendering only.) + flipgradient_mid = ; // flips gradient colors on middle tier. (Hardware rendering only.) + clampgradient_mid = ; // clamps gradient on middle tier to actual bounds (default is the entire front sector height, hardware rendering only.) + useowncolors_mid = ; // Set to 1 to use the colors set in the sidedef. Default is using the colors from the owning sector. + uppercolor_mid = ; // Material color of the top of the middle tier. + lowercolor_mid = ; // Material color of the bottom of the middle tier. (Hardware rendering only.) + + nogradient_bottom = ; // disables color gradient on lower tier. (Hardware rendering only.) + flipgradient_bottom = ; // flips gradient colors on lower tier. (Hardware rendering only.) + clampgradient_bottom = ;// clamps gradient on lower tier to actual bounds (default is the entire front sector height, hardware rendering only.) + useowncolors_bottom = ; // Set to 1 to use the colors set in the sidedef. Default is using the colors from the owning sector. + uppercolor_bottom = ; // Material color of the top of the lower tier. + lowercolor_bottom = ; // Material color of the bottom of the lower tier. (Hardware rendering only.) } sector diff --git a/src/gl/renderer/gl_renderstate.cpp b/src/gl/renderer/gl_renderstate.cpp index 1bfed5fc64..76e8ba892e 100644 --- a/src/gl/renderer/gl_renderstate.cpp +++ b/src/gl/renderer/gl_renderstate.cpp @@ -138,7 +138,6 @@ bool FGLRenderState::ApplyShader() activeShader->muLightParms.Set(mLightParms); activeShader->muFogColor.Set(mFogColor); activeShader->muObjectColor.Set(mObjectColor); - activeShader->muObjectColor2.Set(mObjectColor2); activeShader->muDynLightColor.Set(mDynColor.vec); activeShader->muInterpolationFactor.Set(mInterpolationFactor); activeShader->muTimer.Set((double)(screen->FrameTime - firstFrame) * (double)mShaderTimer / 1000.); @@ -151,6 +150,8 @@ bool FGLRenderState::ApplyShader() { activeShader->muGlowTopColor.Set(mGlowTop.vec); activeShader->muGlowBottomColor.Set(mGlowBottom.vec); + activeShader->muGlowTopPlane.Set(mGlowTopPlane.vec); + activeShader->muGlowBottomPlane.Set(mGlowBottomPlane.vec); activeShader->currentglowstate = 1; } else if (activeShader->currentglowstate) @@ -160,10 +161,18 @@ bool FGLRenderState::ApplyShader() activeShader->muGlowBottomColor.Set(nulvec); activeShader->currentglowstate = 0; } - if (mGlowEnabled || mObjectColor2.a != 0) + + if (mGradientEnabled) { - activeShader->muGlowTopPlane.Set(mGlowTopPlane.vec); - activeShader->muGlowBottomPlane.Set(mGlowBottomPlane.vec); + activeShader->muObjectColor2.Set(mObjectColor2); + activeShader->muGradientTopPlane.Set(mGradientTopPlane.vec); + activeShader->muGradientBottomPlane.Set(mGradientBottomPlane.vec); + activeShader->currentgradientstate = 1; + } + else if (activeShader->currentgradientstate) + { + activeShader->muObjectColor2.Set(0); + activeShader->currentgradientstate = 0; } if (mSplitEnabled) diff --git a/src/gl/shaders/gl_shader.cpp b/src/gl/shaders/gl_shader.cpp index d4352dcb71..b31e9532fe 100644 --- a/src/gl/shaders/gl_shader.cpp +++ b/src/gl/shaders/gl_shader.cpp @@ -93,6 +93,9 @@ bool FShader::Load(const char * name, const char * vert_prog_lump, const char * i_data += "uniform vec4 uGlowBottomPlane;\n"; i_data += "uniform vec4 uGlowBottomColor;\n"; + i_data += "uniform vec4 uGradientTopPlane;\n"; + i_data += "uniform vec4 uGradientBottomPlane;\n"; + i_data += "uniform vec4 uSplitTopPlane;\n"; i_data += "uniform vec4 uSplitBottomPlane;\n"; @@ -335,6 +338,8 @@ bool FShader::Load(const char * name, const char * vert_prog_lump, const char * muGlowTopColor.Init(hShader, "uGlowTopColor"); muGlowBottomPlane.Init(hShader, "uGlowBottomPlane"); muGlowTopPlane.Init(hShader, "uGlowTopPlane"); + muGradientBottomPlane.Init(hShader, "uGradientBottomPlane"); + muGradientTopPlane.Init(hShader, "uGradientTopPlane"); muSplitBottomPlane.Init(hShader, "uSplitBottomPlane"); muSplitTopPlane.Init(hShader, "uSplitTopPlane"); muInterpolationFactor.Init(hShader, "uInterpolationFactor"); diff --git a/src/gl/shaders/gl_shader.h b/src/gl/shaders/gl_shader.h index 732b5eaafa..cc1dece32a 100644 --- a/src/gl/shaders/gl_shader.h +++ b/src/gl/shaders/gl_shader.h @@ -249,6 +249,8 @@ class FShader FUniform4f muGlowTopColor; FUniform4f muGlowBottomPlane; FUniform4f muGlowTopPlane; + FUniform4f muGradientBottomPlane; + FUniform4f muGradientTopPlane; FUniform4f muSplitBottomPlane; FUniform4f muSplitTopPlane; FBufferedUniform1f muInterpolationFactor; @@ -266,6 +268,7 @@ public: int fakevb_index; private: int currentglowstate = 0; + int currentgradientstate = 0; int currentsplitstate = 0; int currentcliplinestate = 0; int currentfixedcolormap = 0; diff --git a/src/hwrenderer/scene/hw_renderstate.h b/src/hwrenderer/scene/hw_renderstate.h index 22cabc4c61..66f7ccff3f 100644 --- a/src/hwrenderer/scene/hw_renderstate.h +++ b/src/hwrenderer/scene/hw_renderstate.h @@ -127,6 +127,7 @@ protected: uint8_t mFogEnabled; uint8_t mTextureEnabled:1; uint8_t mGlowEnabled : 1; + uint8_t mGradientEnabled : 1; uint8_t mBrightmapEnabled : 1; uint8_t mModelMatrixEnabled : 1; uint8_t mTextureMatrixEnabled : 1; @@ -147,6 +148,7 @@ protected: FStateVec4 mColor; FStateVec4 mGlowTop, mGlowBottom; FStateVec4 mGlowTopPlane, mGlowBottomPlane; + FStateVec4 mGradientTopPlane, mGradientBottomPlane; FStateVec4 mSplitTopPlane, mSplitBottomPlane; PalEntry mFogColor; PalEntry mObjectColor; @@ -172,7 +174,7 @@ public: void Reset() { mTextureEnabled = true; - mBrightmapEnabled = mFogEnabled = mGlowEnabled = false; + mGradientEnabled = mBrightmapEnabled = mFogEnabled = mGlowEnabled = false; mFogColor.d = -1; mTextureMode = -1; mDesaturation = 0; @@ -201,6 +203,8 @@ public: mGlowBottom.Set(0.0f, 0.0f, 0.0f, 0.0f); mGlowTopPlane.Set(0.0f, 0.0f, 0.0f, 0.0f); mGlowBottomPlane.Set(0.0f, 0.0f, 0.0f, 0.0f); + mGradientTopPlane.Set(0.0f, 0.0f, 0.0f, 0.0f); + mGradientBottomPlane.Set(0.0f, 0.0f, 0.0f, 0.0f); mSplitTopPlane.Set(0.0f, 0.0f, 0.0f, 0.0f); mSplitBottomPlane.Set(0.0f, 0.0f, 0.0f, 0.0f); mDynColor.Set(0.0f, 0.0f, 0.0f, 0.0f); @@ -290,6 +294,11 @@ public: mGlowEnabled = on; } + void EnableGradient(bool on) + { + mGradientEnabled = on; + } + void EnableBrightmap(bool on) { mBrightmapEnabled = on; @@ -324,18 +333,26 @@ public: void SetGlowPlanes(const secplane_t &top, const secplane_t &bottom) { - DVector3 tn = top.Normal(); - DVector3 bn = bottom.Normal(); - mGlowTopPlane.Set((float)tn.X, (float)tn.Y, (float)(1. / tn.Z), (float)top.fD()); - mGlowBottomPlane.Set((float)bn.X, (float)bn.Y, (float)(1. / bn.Z), (float)bottom.fD()); + auto &tn = top.Normal(); + auto &bn = bottom.Normal(); + mGlowTopPlane.Set((float)tn.X, (float)tn.Y, (float)top.negiC, (float)top.fD()); + mGlowBottomPlane.Set((float)bn.X, (float)bn.Y, (float)bottom.negiC, (float)bottom.fD()); + } + + void SetGradientPlanes(const secplane_t &top, const secplane_t &bottom) + { + auto &tn = top.Normal(); + auto &bn = bottom.Normal(); + mGradientTopPlane.Set((float)tn.X, (float)tn.Y, (float)top.negiC, (float)top.fD()); + mGradientBottomPlane.Set((float)bn.X, (float)bn.Y, (float)bottom.negiC, (float)bottom.fD()); } void SetSplitPlanes(const secplane_t &top, const secplane_t &bottom) { - DVector3 tn = top.Normal(); - DVector3 bn = bottom.Normal(); - mSplitTopPlane.Set((float)tn.X, (float)tn.Y, (float)(1. / tn.Z), (float)top.fD()); - mSplitBottomPlane.Set((float)bn.X, (float)bn.Y, (float)(1. / bn.Z), (float)bottom.fD()); + auto &tn = top.Normal(); + auto &bn = bottom.Normal(); + mSplitTopPlane.Set((float)tn.X, (float)tn.Y, (float)top.negiC, (float)top.fD()); + mSplitBottomPlane.Set((float)bn.X, (float)bn.Y, (float)bottom.negiC, (float)bottom.fD()); } void SetDynLight(float r, float g, float b) diff --git a/src/hwrenderer/scene/hw_walls.cpp b/src/hwrenderer/scene/hw_walls.cpp index f8455c2459..0622553f75 100644 --- a/src/hwrenderer/scene/hw_walls.cpp +++ b/src/hwrenderer/scene/hw_walls.cpp @@ -130,6 +130,20 @@ void GLWall::RenderMirrorSurface(HWDrawInfo *di, FRenderState &state) // //========================================================================== +static const uint8_t renderwalltotier[] = +{ + side_t::none, + side_t::top, + side_t::mid, + side_t::mid, + side_t::bottom, + side_t::none, + side_t::none, + side_t::mid, + side_t::none, + side_t::mid, +}; + void GLWall::RenderTexturedWall(HWDrawInfo *di, FRenderState &state, int rflags) { int tmode = state.GetTextureMode(); @@ -139,8 +153,8 @@ void GLWall::RenderTexturedWall(HWDrawInfo *di, FRenderState &state, int rflags) { state.EnableGlow(true); state.SetGlowParams(topglowcolor, bottomglowcolor); + state.SetGlowPlanes(frontsector->ceilingplane, frontsector->floorplane); } - state.SetGlowPlanes(frontsector->ceilingplane, frontsector->floorplane); state.SetMaterial(gltexture, flags & 3, 0, -1); if (type == RENDERWALL_M2SNF) @@ -151,8 +165,41 @@ void GLWall::RenderTexturedWall(HWDrawInfo *di, FRenderState &state, int rflags) } state.SetFog(255, 0, di->isFullbrightScene(), nullptr, false); } - state.SetObjectColor(seg->frontsector->SpecialColors[sector_t::walltop] | 0xff000000); - state.SetObjectColor2(seg->frontsector->SpecialColors[sector_t::wallbottom] | 0xff000000); + if (type != RENDERWALL_COLOR) + { + auto side = seg->sidedef; + auto tierndx = renderwalltotier[type]; + auto &tier = side->textures[tierndx]; + PalEntry color1 = side->GetSpecialColor(tierndx, side_t::walltop, frontsector); + PalEntry color2 = side->GetSpecialColor(tierndx, side_t::wallbottom, frontsector); + state.SetObjectColor(color1); + state.SetObjectColor2(color2); + if (color1 != color2) + { + // Do gradient setup only if there actually is a gradient. + + state.EnableGradient(true); + if ((tier.flags & side_t::part::ClampGradient) && backsector) + { + if (tierndx == side_t::top) + { + state.SetGradientPlanes(frontsector->ceilingplane, backsector->ceilingplane); + } + else if (tierndx == side_t::mid) + { + state.SetGradientPlanes(backsector->ceilingplane, backsector->floorplane); + } + else // side_t::bottom: + { + state.SetGradientPlanes(backsector->floorplane, frontsector->floorplane); + } + } + else + { + state.SetGradientPlanes(frontsector->ceilingplane, frontsector->floorplane); + } + } + } float absalpha = fabsf(alpha); if (lightlist == nullptr) @@ -174,7 +221,7 @@ void GLWall::RenderTexturedWall(HWDrawInfo *di, FRenderState &state, int rflags) if (low1 < ztop[0] || low2 < ztop[1]) { - int thisll = (*lightlist)[i].caster != NULL ? hw_ClampLight(*(*lightlist)[i].p_lightlevel) : lightlevel; + int thisll = (*lightlist)[i].caster != nullptr ? hw_ClampLight(*(*lightlist)[i].p_lightlevel) : lightlevel; FColormap thiscm; thiscm.FadeColor = Colormap.FadeColor; thiscm.FogDensity = Colormap.FogDensity; @@ -193,6 +240,7 @@ void GLWall::RenderTexturedWall(HWDrawInfo *di, FRenderState &state, int rflags) state.SetObjectColor2(0); state.SetTextureMode(tmode); state.EnableGlow(false); + state.EnableGradient(false); } //========================================================================== diff --git a/src/namedef.h b/src/namedef.h index ecac82b56a..5744ef4869 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -630,6 +630,26 @@ xx(hidden) xx(blocksight) xx(blockhitscan) +xx(nogradient_top) +xx(flipgradient_top) +xx(clampgradient_top) +xx(useowncolors_top) +xx(uppercolor_top) +xx(lowercolor_top) +xx(nogradient_mid) +xx(flipgradient_mid) +xx(clampgradient_mid) +xx(useowncolors_mid) +xx(uppercolor_mid) +xx(lowercolor_mid) +xx(nogradient_bottom) +xx(flipgradient_bottom) +xx(clampgradient_bottom) +xx(useowncolors_bottom) +xx(uppercolor_bottom) +xx(lowercolor_bottom) + + xx(Renderstyle) xx(ceilingplane_a) diff --git a/src/p_saveg.cpp b/src/p_saveg.cpp index 53f4959a25..a8dff68680 100644 --- a/src/p_saveg.cpp +++ b/src/p_saveg.cpp @@ -105,6 +105,9 @@ FSerializer &Serialize(FSerializer &arc, const char *key, side_t::part &part, si ("yscale", part.yScale, def->yScale) ("texture", part.texture, def->texture) ("interpolation", part.interpolation) + ("flags", part.flags, def->flags) + ("color1", part.SpecialColors[0], def->SpecialColors[0]) + ("color2", part.SpecialColors[1], def->SpecialColors[1]) .EndObject(); } return arc; diff --git a/src/p_sectors.cpp b/src/p_sectors.cpp index be86c87ef3..dd0eb882cc 100644 --- a/src/p_sectors.cpp +++ b/src/p_sectors.cpp @@ -878,17 +878,6 @@ DEFINE_ACTION_FUNCTION(_Sector, SetFade) // //===================================================================================== -void sector_t::SetSpecialColor(int slot, int r, int g, int b) -{ - SpecialColors[slot] = PalEntry(255, r, g, b); -} - -void sector_t::SetSpecialColor(int slot, PalEntry rgb) -{ - rgb.a = 255; - SpecialColors[slot] = rgb; -} - DEFINE_ACTION_FUNCTION(_Sector, SetSpecialColor) { PARAM_SELF_STRUCT_PROLOGUE(sector_t); diff --git a/src/p_setup.cpp b/src/p_setup.cpp index 8f456c024c..b0004b795f 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -3632,7 +3632,7 @@ void P_FreeExtraLevelData() // //=========================================================================== -void P_SetupLevel (const char *lumpname, int position, bool newGame) +void P_SetupLevel(const char *lumpname, int position, bool newGame) { cycle_t times[20]; #if 0 @@ -3662,7 +3662,7 @@ void P_SetupLevel (const char *lumpname, int position, bool newGame) level.SetMusicVolume(level.MusicVolume); for (i = 0; i < MAXPLAYERS; ++i) { - players[i].killcount = players[i].secretcount + players[i].killcount = players[i].secretcount = players[i].itemcount = 0; } } @@ -3683,16 +3683,16 @@ void P_SetupLevel (const char *lumpname, int position, bool newGame) translationtables[TRANSLATION_LevelScripted].Clear(); // Initial height of PointOfView will be set by player think. - players[consoleplayer].viewz = NO_VALUE; + players[consoleplayer].viewz = NO_VALUE; // Make sure all sounds are stopped before Z_FreeTags. - S_Start (); + S_Start(); // [RH] clear out the mid-screen message - C_MidPrint (NULL, NULL); + C_MidPrint(NULL, NULL); // Free all level data from the previous map - P_FreeLevelData (); + P_FreeLevelData(); MapData *map = P_OpenMapData(lumpname, true); if (map == NULL) @@ -3724,7 +3724,7 @@ void P_SetupLevel (const char *lumpname, int position, bool newGame) uint8_t *mapdata = new uint8_t[map->Size(0)]; map->Read(0, mapdata); times[0].Clock(); - buildmap = P_LoadBuildMap (mapdata, map->Size(0), &buildthings, &numbuildthings); + buildmap = P_LoadBuildMap(mapdata, map->Size(0), &buildthings, &numbuildthings); times[0].Unclock(); delete[] mapdata; } @@ -3736,10 +3736,10 @@ void P_SetupLevel (const char *lumpname, int position, bool newGame) ForceNodeBuild = gennodes; // [RH] Load in the BEHAVIOR lump - FBehavior::StaticUnloadModules (); + FBehavior::StaticUnloadModules(); if (map->HasBehavior) { - P_LoadBehavior (map); + P_LoadBehavior(map); level.maptype = MAPTYPE_HEXEN; } else @@ -3756,7 +3756,7 @@ void P_SetupLevel (const char *lumpname, int position, bool newGame) { // Has the user overridden the game's default translator with a commandline parameter? translator = Args->CheckValue("-xlat"); - if (translator == NULL) + if (translator == NULL) { // Use the game's default. translator = gameinfo.translator.GetChars(); @@ -3796,25 +3796,25 @@ void P_SetupLevel (const char *lumpname, int position, bool newGame) level.flags2 |= LEVEL2_DUMMYSWITCHES; } - FBehavior::StaticLoadDefaultModules (); + FBehavior::StaticLoadDefaultModules(); #ifndef NO_EDATA LoadMapinfoACSLump(); #endif - P_LoadStrifeConversations (map, lumpname); + P_LoadStrifeConversations(map, lumpname); FMissingTextureTracker missingtex; if (!map->isText) { times[0].Clock(); - P_LoadVertexes (map); + P_LoadVertexes(map); times[0].Unclock(); - + // Check for maps without any BSP data at all (e.g. SLIGE) times[1].Clock(); - P_LoadSectors (map, missingtex); + P_LoadSectors(map, missingtex); times[1].Unclock(); times[2].Clock(); @@ -3822,23 +3822,23 @@ void P_SetupLevel (const char *lumpname, int position, bool newGame) times[3].Clock(); if (!map->HasBehavior) - P_LoadLineDefs (map); + P_LoadLineDefs(map); else - P_LoadLineDefs2 (map); // [RH] Load Hexen-style linedefs + P_LoadLineDefs2(map); // [RH] Load Hexen-style linedefs times[3].Unclock(); times[4].Clock(); - P_LoadSideDefs2 (map, missingtex); + P_LoadSideDefs2(map, missingtex); times[4].Unclock(); times[5].Clock(); - P_FinishLoadingLineDefs (); + P_FinishLoadingLineDefs(); times[5].Unclock(); if (!map->HasBehavior) - P_LoadThings (map); + P_LoadThings(map); else - P_LoadThings2 (map); // [RH] Load Hexen-style things + P_LoadThings2(map); // [RH] Load Hexen-style things } else { @@ -3850,7 +3850,7 @@ void P_SetupLevel (const char *lumpname, int position, bool newGame) SetCompatibilityParams(checksum); times[6].Clock(); - P_LoopSidedefs (true); + P_LoopSidedefs(true); times[6].Unclock(); linemap.Clear(); @@ -3869,36 +3869,36 @@ void P_SetupLevel (const char *lumpname, int position, bool newGame) { // Check for compressed nodes first, then uncompressed nodes FileReader *fr = nullptr; - uint32_t id = MAKE_ID('X','x','X','x'), idcheck = 0, idcheck2 = 0, idcheck3 = 0, idcheck4 = 0, idcheck5 = 0, idcheck6 = 0; + uint32_t id = MAKE_ID('X', 'x', 'X', 'x'), idcheck = 0, idcheck2 = 0, idcheck3 = 0, idcheck4 = 0, idcheck5 = 0, idcheck6 = 0; if (map->Size(ML_ZNODES) != 0) { // Test normal nodes first fr = &map->Reader(ML_ZNODES); - idcheck = MAKE_ID('Z','N','O','D'); - idcheck2 = MAKE_ID('X','N','O','D'); + idcheck = MAKE_ID('Z', 'N', 'O', 'D'); + idcheck2 = MAKE_ID('X', 'N', 'O', 'D'); } else if (map->Size(ML_GLZNODES) != 0) { fr = &map->Reader(ML_GLZNODES); - idcheck = MAKE_ID('Z','G','L','N'); - idcheck2 = MAKE_ID('Z','G','L','2'); - idcheck3 = MAKE_ID('Z','G','L','3'); - idcheck4 = MAKE_ID('X','G','L','N'); - idcheck5 = MAKE_ID('X','G','L','2'); - idcheck6 = MAKE_ID('X','G','L','3'); + idcheck = MAKE_ID('Z', 'G', 'L', 'N'); + idcheck2 = MAKE_ID('Z', 'G', 'L', '2'); + idcheck3 = MAKE_ID('Z', 'G', 'L', '3'); + idcheck4 = MAKE_ID('X', 'G', 'L', 'N'); + idcheck5 = MAKE_ID('X', 'G', 'L', '2'); + idcheck6 = MAKE_ID('X', 'G', 'L', '3'); } - if (fr != nullptr && fr->isOpen()) fr->Read (&id, 4); + if (fr != nullptr && fr->isOpen()) fr->Read(&id, 4); if (id != 0 && (id == idcheck || id == idcheck2 || id == idcheck3 || id == idcheck4 || id == idcheck5 || id == idcheck6)) { try { - P_LoadZNodes (*fr, id); + P_LoadZNodes(*fr, id); } catch (CRecoverableError &error) { - Printf ("Error loading nodes: %s\n", error.GetMessage()); + Printf("Error loading nodes: %s\n", error.GetMessage()); ForceNodeBuild = true; level.subsectors.Clear(); @@ -3915,29 +3915,29 @@ void P_SetupLevel (const char *lumpname, int position, bool newGame) if (!P_CheckV4Nodes(map)) { times[7].Clock(); - P_LoadSubsectors (map); + P_LoadSubsectors(map); times[7].Unclock(); times[8].Clock(); - if (!ForceNodeBuild) P_LoadNodes (map); + if (!ForceNodeBuild) P_LoadNodes(map); times[8].Unclock(); times[9].Clock(); - if (!ForceNodeBuild) P_LoadSegs (map); + if (!ForceNodeBuild) P_LoadSegs(map); times[9].Unclock(); } else { times[7].Clock(); - P_LoadSubsectors (map); + P_LoadSubsectors(map); times[7].Unclock(); times[8].Clock(); - if (!ForceNodeBuild) P_LoadNodes (map); + if (!ForceNodeBuild) P_LoadNodes(map); times[8].Unclock(); times[9].Clock(); - if (!ForceNodeBuild) P_LoadSegs (map); + if (!ForceNodeBuild) P_LoadSegs(map); times[9].Unclock(); } } @@ -3948,7 +3948,7 @@ void P_SetupLevel (const char *lumpname, int position, bool newGame) // If loading the regular nodes failed try GL nodes before considering a rebuild if (ForceNodeBuild) { - if (P_LoadGLNodes(map)) + if (P_LoadGLNodes(map)) { ForceNodeBuild = false; reloop = true; @@ -3957,16 +3957,16 @@ void P_SetupLevel (const char *lumpname, int position, bool newGame) } else reloop = true; - uint64_t startTime=0, endTime=0; + uint64_t startTime = 0, endTime = 0; bool BuildGLNodes; if (ForceNodeBuild) { BuildGLNodes = RequireGLNodes || multiplayer || demoplayback || demorecording || genglnodes; - startTime = I_msTime (); + startTime = I_msTime(); TArray polyspots, anchors; - P_GetPolySpots (map, polyspots, anchors); + P_GetPolySpots(map, polyspots, anchors); FNodeBuilder::FLevel leveldata = { &level.vertexes[0], (int)level.vertexes.Size(), @@ -3974,14 +3974,14 @@ void P_SetupLevel (const char *lumpname, int position, bool newGame) &level.lines[0], (int)level.lines.Size(), 0, 0, 0, 0 }; - leveldata.FindMapBounds (); + leveldata.FindMapBounds(); // We need GL nodes if am_textured is on. // In case a sync critical game mode is started, also build GL nodes to avoid problems // if the different machines' am_textured setting differs. - FNodeBuilder builder (leveldata, polyspots, anchors, BuildGLNodes); - builder.Extract (level); - endTime = I_msTime (); - DPrintf (DMSG_NOTIFY, "BSP generation took %.3f sec (%d segs)\n", (endTime - startTime) * 0.001, level.segs.Size()); + FNodeBuilder builder(leveldata, polyspots, anchors, BuildGLNodes); + builder.Extract(level); + endTime = I_msTime(); + DPrintf(DMSG_NOTIFY, "BSP generation took %.3f sec (%d segs)\n", (endTime - startTime) * 0.001, level.segs.Size()); oldvertextable = builder.GetOldVertexTable(); reloop = true; } @@ -3989,14 +3989,14 @@ void P_SetupLevel (const char *lumpname, int position, bool newGame) { BuildGLNodes = false; // Older ZDBSPs had problems with compressed sidedefs and assigned wrong sides to the segs if both sides were the same sidedef. - for(auto &seg : level.segs) + for (auto &seg : level.segs) { if (seg.backsector == seg.frontsector && seg.linedef) { double d1 = (seg.v1->fPos() - seg.linedef->v1->fPos()).LengthSquared(); double d2 = (seg.v2->fPos() - seg.linedef->v1->fPos()).LengthSquared(); - if (d2sidedef[1]; } @@ -4023,22 +4023,22 @@ void P_SetupLevel (const char *lumpname, int position, bool newGame) } // set the head node for gameplay purposes. If the separate gamenodes array is not empty, use that, otherwise use the render nodes. - level.headgamenode = level.gamenodes.Size() > 0 ? &level.gamenodes[level.gamenodes.Size() - 1] : level.nodes.Size()? &level.nodes[level.nodes.Size() - 1] : nullptr; + level.headgamenode = level.gamenodes.Size() > 0 ? &level.gamenodes[level.gamenodes.Size() - 1] : level.nodes.Size() ? &level.nodes[level.nodes.Size() - 1] : nullptr; times[10].Clock(); - P_LoadBlockMap (map); + P_LoadBlockMap(map); times[10].Unclock(); times[11].Clock(); - P_LoadReject (map, buildmap); + P_LoadReject(map, buildmap); times[11].Unclock(); times[12].Clock(); - P_GroupLines (buildmap); + P_GroupLines(buildmap); times[12].Unclock(); times[13].Clock(); - P_FloodZones (); + P_FloodZones(); times[13].Unclock(); if (hasglnodes) @@ -4049,8 +4049,8 @@ void P_SetupLevel (const char *lumpname, int position, bool newGame) } bodyqueslot = 0; -// phares 8/10/98: Clear body queue so the corpses from previous games are -// not assumed to be from this one. + // phares 8/10/98: Clear body queue so the corpses from previous games are + // not assumed to be from this one. for (i = 0; i < BODYQUESIZE; i++) bodyque[i] = NULL; @@ -4060,7 +4060,7 @@ void P_SetupLevel (const char *lumpname, int position, bool newGame) if (!buildmap) { // [RH] Spawn slope creating things first. - P_SpawnSlopeMakers (&MapThingsConverted[0], &MapThingsConverted[MapThingsConverted.Size()], oldvertextable); + P_SpawnSlopeMakers(&MapThingsConverted[0], &MapThingsConverted[MapThingsConverted.Size()], oldvertextable); P_CopySlopes(); // Spawn 3d floors - must be done before spawning things so it can't be done in P_SpawnSpecials @@ -4078,7 +4078,7 @@ void P_SetupLevel (const char *lumpname, int position, bool newGame) times[15].Clock(); if (!map->HasBehavior && !map->isText) - P_TranslateTeleportThings (); // [RH] Assign teleport destination TIDs + P_TranslateTeleportThings(); // [RH] Assign teleport destination TIDs times[15].Unclock(); } #if 0 // There is no such thing as a build map. @@ -4086,7 +4086,7 @@ void P_SetupLevel (const char *lumpname, int position, bool newGame) { for (i = 0; i < numbuildthings; ++i) { - SpawnMapThing (i, &buildthings[i], 0); + SpawnMapThing(i, &buildthings[i], 0); } delete[] buildthings; } @@ -4098,7 +4098,7 @@ void P_SetupLevel (const char *lumpname, int position, bool newGame) } // set up world state - P_SpawnSpecials (); + P_SpawnSpecials(); // disable reflective planes on sloped sectors. for (auto &sec : level.sectors) @@ -4121,8 +4121,8 @@ void P_SetupLevel (const char *lumpname, int position, bool newGame) P_InitHealthGroups(); times[16].Clock(); - if (reloop) P_LoopSidedefs (false); - PO_Init (); // Initialize the polyobjs + if (reloop) P_LoopSidedefs(false); + PO_Init(); // Initialize the polyobjs if (!level.IsReentering()) P_FinalizePortals(); // finalize line portals after polyobjects have been initialized. This info is needed for properly flagging them. times[16].Unclock(); @@ -4134,12 +4134,12 @@ void P_SetupLevel (const char *lumpname, int position, bool newGame) // if deathmatch, randomly spawn the active players if (deathmatch) { - for (i=0 ; i 0) + if (level.deathmatchstarts.Size() > 0) { for (i = 0; i < MAXPLAYERS; ++i) { @@ -4168,7 +4168,7 @@ void P_SetupLevel (const char *lumpname, int position, bool newGame) if (!(players[i].mo->flags & MF_FRIENDLY)) { AActor * oldSpawn = players[i].mo; - G_DeathMatchSpawnPlayer (i); + G_DeathMatchSpawnPlayer(i); oldSpawn->Destroy(); } } @@ -4182,11 +4182,11 @@ void P_SetupLevel (const char *lumpname, int position, bool newGame) TThinkerIterator it; AActor * mo; - while ((mo=it.Next())) + while ((mo = it.Next())) { if (mo->flags & MF_COUNTKILL) { - if (mo->Sector->damageamount > 0 && (mo->Sector->Flags & (SECF_ENDGODMODE|SECF_ENDLEVEL)) == (SECF_ENDGODMODE|SECF_ENDLEVEL)) + if (mo->Sector->damageamount > 0 && (mo->Sector->Flags & (SECF_ENDGODMODE | SECF_ENDLEVEL)) == (SECF_ENDGODMODE | SECF_ENDLEVEL)) { mo->ClearCounters(); } @@ -4202,20 +4202,20 @@ void P_SetupLevel (const char *lumpname, int position, bool newGame) R_OldBlend = 0xffffffff; // [RH] Remove all particles - P_ClearParticles (); + P_ClearParticles(); times[17].Clock(); // preload graphics and sounds if (precache) { - P_PrecacheLevel (); - S_PrecacheLevel (); + P_PrecacheLevel(); + S_PrecacheLevel(); } times[17].Unclock(); if (deathmatch) { - AnnounceGameStart (); + AnnounceGameStart(); } // This check was previously done at run time each time the heightsec was checked. @@ -4235,12 +4235,12 @@ void P_SetupLevel (const char *lumpname, int position, bool newGame) } } - P_ResetSightCounters (true); + P_ResetSightCounters(true); //Printf ("free memory: 0x%x\n", Z_FreeMemory()); if (showloadtimes) { - Printf ("---Total load times---\n"); + Printf("---Total load times---\n"); for (i = 0; i < 18; ++i) { static const char *timenames[] = @@ -4264,7 +4264,7 @@ void P_SetupLevel (const char *lumpname, int position, bool newGame) "init polys", "precache" }; - Printf ("Time%3d:%9.4f ms (%s)\n", i, times[i].TimeMS(), timenames[i]); + Printf("Time%3d:%9.4f ms (%s)\n", i, times[i].TimeMS(), timenames[i]); } } MapThingsConverted.Clear(); @@ -4280,10 +4280,22 @@ void P_SetupLevel (const char *lumpname, int position, bool newGame) memcpy(&level.loadlines[0], &level.lines[0], level.lines.Size() * sizeof(level.lines[0])); level.loadsides.Resize(level.sides.Size()); memcpy(&level.loadsides[0], &level.sides[0], level.sides.Size() * sizeof(level.sides[0])); + + + for (auto i : { 29, 30 }) + { + level.lines[i].sidedef[0]->SetSpecialColor(side_t::top, side_t::walltop, PalEntry(255, 255, 0)); + level.lines[i].sidedef[0]->SetSpecialColor(side_t::top, side_t::wallbottom, PalEntry(0, 255, 255)); + level.lines[i].sidedef[0]->SetSpecialColor(side_t::bottom, side_t::walltop, PalEntry(255, 0, 0)); + level.lines[i].sidedef[0]->SetSpecialColor(side_t::bottom, side_t::wallbottom, PalEntry(0, 0, 255)); + } + level.lines[29].sidedef[0]->textures[side_t::top].flags = side_t::part::UseOwnColors; + level.lines[30].sidedef[0]->textures[side_t::top].flags = side_t::part::UseOwnColors | side_t::part::ClampGradient; + level.lines[29].sidedef[0]->textures[side_t::bottom].flags = side_t::part::UseOwnColors; + level.lines[30].sidedef[0]->textures[side_t::bottom].flags = side_t::part::UseOwnColors | side_t::part::ClampGradient; + } - - // // P_Init // diff --git a/src/p_udmf.cpp b/src/p_udmf.cpp index e0bccff7d1..6bacd4229e 100644 --- a/src/p_udmf.cpp +++ b/src/p_udmf.cpp @@ -1223,6 +1223,7 @@ public: { FName key = ParseKey(); switch(key) + { case NAME_Offsetx: texOfs[0] = CheckInt(key); @@ -1334,6 +1335,79 @@ public: Flag(sd->Flags, WALLF_NOAUTODECALS, key); continue; + case NAME_nogradient_top: + Flag(sd->textures[side_t::top].flags, side_t::part::NoGradient, key); + break; + + case NAME_flipgradient_top: + Flag(sd->textures[side_t::top].flags, side_t::part::FlipGradient, key); + break; + + case NAME_clampgradient_top: + Flag(sd->textures[side_t::top].flags, side_t::part::ClampGradient, key); + break; + + case NAME_useowncolors_top: + Flag(sd->textures[side_t::top].flags, side_t::part::UseOwnColors, key); + break; + + case NAME_uppercolor_top: + sd->SetSpecialColor(side_t::top, 0, CheckInt(key)); + break; + + case NAME_lowercolor_top: + sd->SetSpecialColor(side_t::top, 1, CheckInt(key)); + break; + + case NAME_nogradient_mid: + Flag(sd->textures[side_t::mid].flags, side_t::part::NoGradient, key); + break; + + case NAME_flipgradient_mid: + Flag(sd->textures[side_t::mid].flags, side_t::part::FlipGradient, key); + break; + + case NAME_clampgradient_mid: + Flag(sd->textures[side_t::mid].flags, side_t::part::ClampGradient, key); + break; + + case NAME_useowncolors_mid: + Flag(sd->textures[side_t::mid].flags, side_t::part::UseOwnColors, key); + break; + + case NAME_uppercolor_mid: + sd->SetSpecialColor(side_t::mid, 0, CheckInt(key)); + break; + + case NAME_lowercolor_mid: + sd->SetSpecialColor(side_t::mid, 1, CheckInt(key)); + break; + + case NAME_nogradient_bottom: + Flag(sd->textures[side_t::bottom].flags, side_t::part::NoGradient, key); + break; + + case NAME_flipgradient_bottom: + Flag(sd->textures[side_t::bottom].flags, side_t::part::FlipGradient, key); + break; + + case NAME_clampgradient_bottom: + Flag(sd->textures[side_t::bottom].flags, side_t::part::ClampGradient, key); + break; + + case NAME_useowncolors_bottom: + Flag(sd->textures[side_t::bottom].flags, side_t::part::UseOwnColors, key); + break; + + case NAME_uppercolor_bottom: + sd->SetSpecialColor(side_t::bottom, 0, CheckInt(key)); + break; + + case NAME_lowercolor_bottom: + sd->SetSpecialColor(side_t::bottom, 1, CheckInt(key)); + break; + + default: break; diff --git a/src/polyrenderer/scene/poly_wall.cpp b/src/polyrenderer/scene/poly_wall.cpp index b7872724bd..3ba2e9f56e 100644 --- a/src/polyrenderer/scene/poly_wall.cpp +++ b/src/polyrenderer/scene/poly_wall.cpp @@ -88,7 +88,6 @@ bool RenderPolyWall::RenderLine(PolyRenderThread *thread, seg_t *line, sector_t wall.Line = line->linedef; wall.Side = line->sidedef; wall.LineSegLine = line->linedef; - wall.Colormap = GetColorTable(frontsector->Colormap, frontsector->SpecialColors[sector_t::walltop]); wall.Masked = false; wall.SubsectorDepth = subsectorDepth; wall.StencilValue = stencilValue; @@ -102,6 +101,7 @@ bool RenderPolyWall::RenderLine(PolyRenderThread *thread, seg_t *line, sector_t wall.TopTexZ = topTexZ; wall.BottomTexZ = bottomTexZ; wall.Wallpart = side_t::mid; + wall.Colormap = GetColorTable(frontsector->Colormap, wall.Side->GetSpecialColor(wall.Wallpart, side_t::walltop, frontsector)); wall.Texture = GetTexture(wall.Line, wall.Side, side_t::mid); wall.Polyportal = polyportal; wall.Render(thread); @@ -140,6 +140,7 @@ bool RenderPolyWall::RenderLine(PolyRenderThread *thread, seg_t *line, sector_t wall.TopTexZ = topTexZ; wall.BottomTexZ = MIN(MIN(backceilz1, frontceilz1), MIN(backceilz2, frontceilz2)); wall.Wallpart = side_t::top; + wall.Colormap = GetColorTable(frontsector->Colormap, wall.Side->GetSpecialColor(wall.Wallpart, side_t::walltop, frontsector)); wall.Texture = GetTexture(wall.Line, wall.Side, side_t::top); wall.Render(thread); } @@ -152,6 +153,7 @@ bool RenderPolyWall::RenderLine(PolyRenderThread *thread, seg_t *line, sector_t wall.UnpeggedCeil1 = topceilz1; wall.UnpeggedCeil2 = topceilz2; wall.Wallpart = side_t::bottom; + wall.Colormap = GetColorTable(frontsector->Colormap, wall.Side->GetSpecialColor(wall.Wallpart, side_t::walltop, frontsector)); wall.Texture = GetTexture(wall.Line, wall.Side, side_t::bottom); wall.Render(thread); } @@ -162,6 +164,7 @@ bool RenderPolyWall::RenderLine(PolyRenderThread *thread, seg_t *line, sector_t wall.TopTexZ = MAX(middleceilz1, middleceilz2); wall.BottomTexZ = MIN(middlefloorz1, middlefloorz2); wall.Wallpart = side_t::mid; + wall.Colormap = GetColorTable(frontsector->Colormap, wall.Side->GetSpecialColor(wall.Wallpart, side_t::walltop, frontsector)); wall.Texture = GetTexture(wall.Line, wall.Side, side_t::mid); wall.Masked = true; wall.Additive = !!(wall.Line->flags & ML_ADDTRANS); @@ -212,7 +215,6 @@ void RenderPolyWall::Render3DFloorLine(PolyRenderThread *thread, seg_t *line, se wall.LineSegLine = line->linedef; wall.Line = fakeFloor->master; wall.Side = fakeFloor->master->sidedef[0]; - wall.Colormap = GetColorTable(frontsector->Colormap, frontsector->SpecialColors[sector_t::walltop]); wall.SectorLightLevel = frontsector->lightlevel; wall.Additive = !!(fakeFloor->flags & FF_ADDITIVETRANS); if (!wall.Additive && fakeFloor->alpha == 255) @@ -231,6 +233,7 @@ void RenderPolyWall::Render3DFloorLine(PolyRenderThread *thread, seg_t *line, se wall.TopTexZ = topTexZ; wall.BottomTexZ = bottomTexZ; wall.Wallpart = side_t::mid; + wall.Colormap = GetColorTable(frontsector->Colormap, wall.Side->GetSpecialColor(wall.Wallpart, side_t::walltop, frontsector)); if (fakeFloor->flags & FF_UPPERTEXTURE) wall.Texture = GetTexture(line->linedef, line->sidedef, side_t::top); else if (fakeFloor->flags & FF_LOWERTEXTURE) diff --git a/src/r_defs.h b/src/r_defs.h index cb394cd410..ad128c4dc8 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -325,7 +325,7 @@ public: return !normal.XY().isZero(); } - DVector3 Normal() const + const DVector3 &Normal() const { return normal; } @@ -645,8 +645,6 @@ public: void SetColor(int r, int g, int b, int desat); void SetFade(int r, int g, int b); void SetFogDensity(int dens); - void SetSpecialColor(int num, int r, int g, int b); - void SetSpecialColor(int num, PalEntry rgb); void ClosestPoint(const DVector2 &pos, DVector2 &out) const; int GetFloorLight () const; int GetCeilingLight () const; @@ -917,6 +915,17 @@ public: Flags &= ~SECF_SPECIALFLAGS; } + void SetSpecialColor(int slot, int r, int g, int b) + { + SpecialColors[slot] = PalEntry(255, r, g, b); + } + + void SetSpecialColor(int slot, PalEntry rgb) + { + rgb.a = 255; + SpecialColors[slot] = rgb; + } + inline bool PortalBlocksView(int plane); inline bool PortalBlocksSight(int plane); inline bool PortalBlocksMovement(int plane); @@ -1138,16 +1147,31 @@ struct side_t { top=0, mid=1, - bottom=2 + bottom=2, + none = 1, // this is just for clarification in a mapping table + }; + enum EColorSlot + { + walltop = 0, + wallbottom = 1, }; struct part { + enum EPartFlags + { + NoGradient = 1, + FlipGradient = 2, + ClampGradient = 4, + UseOwnColors = 8, + }; double xOffset; double yOffset; double xScale; double yScale; TObjPtr interpolation; FTextureID texture; + int flags; + PalEntry SpecialColors[2]; void InitFrom(const part &other) { @@ -1270,6 +1294,28 @@ struct side_t textures[which].yScale *= delta; } + void SetSpecialColor(int which, int slot, int r, int g, int b) + { + textures[which].SpecialColors[slot] = PalEntry(255, r, g, b); + } + + void SetSpecialColor(int which, int slot, PalEntry rgb) + { + rgb.a = 255; + textures[which].SpecialColors[slot] = rgb; + } + + // Note that the sector being passed in here may not be the actual sector this sidedef belongs to + // (either for polyobjects or FakeFlat'ed temporaries.) + PalEntry GetSpecialColor(int which, int slot, sector_t *frontsector) const + { + auto &part = textures[which]; + if (part.flags & part::NoGradient) slot = 0; + if (part.flags & part::FlipGradient) slot ^= 1; + return (part.flags & part::UseOwnColors) ? part.SpecialColors[slot] : frontsector->SpecialColors[sector_t::walltop + slot]; + } + + DInterpolation *SetInterpolation(int position); void StopInterpolation(int position); diff --git a/wadsrc/static/shaders/glsl/main.fp b/wadsrc/static/shaders/glsl/main.fp index dd082e6146..77855a85a6 100644 --- a/wadsrc/static/shaders/glsl/main.fp +++ b/wadsrc/static/shaders/glsl/main.fp @@ -1,5 +1,6 @@ in vec4 pixelpos; in vec3 glowdist; +in vec3 gradientdist; in vec4 vWorldNormal; in vec4 vEyeNormal; @@ -111,7 +112,7 @@ vec4 getTexel(vec2 st) } if (uObjectColor2.a == 0.0) texel *= uObjectColor; - else texel *= mix(uObjectColor, uObjectColor2, glowdist.z); + else texel *= mix(uObjectColor, uObjectColor2, gradientdist.z); return desaturate(texel); } diff --git a/wadsrc/static/shaders/glsl/main.vp b/wadsrc/static/shaders/glsl/main.vp index 0be91afb8a..dccbb77c00 100644 --- a/wadsrc/static/shaders/glsl/main.vp +++ b/wadsrc/static/shaders/glsl/main.vp @@ -7,6 +7,7 @@ layout(location = 3) in vec4 aVertex2; layout(location = 4) in vec4 aNormal; out vec4 pixelpos; out vec3 glowdist; +out vec3 gradientdist; out vec4 vWorldNormal; out vec4 vEyeNormal; @@ -37,16 +38,28 @@ void main() pixelpos.xyz = worldcoord.xyz; pixelpos.w = -eyeCoordPos.z/eyeCoordPos.w; - float topatpoint = -((uGlowTopPlane.w + uGlowTopPlane.x * worldcoord.x + uGlowTopPlane.y * worldcoord.z) * uGlowTopPlane.z); - float bottomatpoint = -((uGlowBottomPlane.w + uGlowBottomPlane.x * worldcoord.x + uGlowBottomPlane.y * worldcoord.z) * uGlowBottomPlane.z); - glowdist.x = topatpoint - worldcoord.y; - glowdist.y = worldcoord.y - bottomatpoint; - glowdist.z = clamp(glowdist.x / (topatpoint - bottomatpoint), 0.0, 1.0); + if (uGlowTopColor.a > 0 || uGlowBottomColor.a > 0) + { + float topatpoint = (uGlowTopPlane.w + uGlowTopPlane.x * worldcoord.x + uGlowTopPlane.y * worldcoord.z) * uGlowTopPlane.z; + float bottomatpoint = (uGlowBottomPlane.w + uGlowBottomPlane.x * worldcoord.x + uGlowBottomPlane.y * worldcoord.z) * uGlowBottomPlane.z; + glowdist.x = topatpoint - worldcoord.y; + glowdist.y = worldcoord.y - bottomatpoint; + glowdist.z = clamp(glowdist.x / (topatpoint - bottomatpoint), 0.0, 1.0); + } + + if (uObjectColor2.a != 0) + { + float topatpoint = (uGradientTopPlane.w + uGradientTopPlane.x * worldcoord.x + uGradientTopPlane.y * worldcoord.z) * uGradientTopPlane.z; + float bottomatpoint = (uGradientBottomPlane.w + uGradientBottomPlane.x * worldcoord.x + uGradientBottomPlane.y * worldcoord.z) * uGradientBottomPlane.z; + gradientdist.x = topatpoint - worldcoord.y; + gradientdist.y = worldcoord.y - bottomatpoint; + gradientdist.z = clamp(gradientdist.x / (topatpoint - bottomatpoint), 0.0, 1.0); + } if (uSplitBottomPlane.z != 0.0) { - gl_ClipDistance[3] = -((uSplitTopPlane.w + uSplitTopPlane.x * worldcoord.x + uSplitTopPlane.y * worldcoord.z) * uSplitTopPlane.z) - worldcoord.y; - gl_ClipDistance[4] = worldcoord.y + ((uSplitBottomPlane.w + uSplitBottomPlane.x * worldcoord.x + uSplitBottomPlane.y * worldcoord.z) * uSplitBottomPlane.z); + gl_ClipDistance[3] = ((uSplitTopPlane.w + uSplitTopPlane.x * worldcoord.x + uSplitTopPlane.y * worldcoord.z) * uSplitTopPlane.z) - worldcoord.y; + gl_ClipDistance[4] = worldcoord.y - ((uSplitBottomPlane.w + uSplitBottomPlane.x * worldcoord.x + uSplitBottomPlane.y * worldcoord.z) * uSplitBottomPlane.z); } vWorldNormal = NormalModelMatrix * vec4(normalize(aNormal.xyz), 1.0); From a0a2230b928618fdc52224dd54909a97e40428d9 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 11 Nov 2018 21:50:33 +0100 Subject: [PATCH 15/25] - removed test code that was accidentally left in. --- src/p_setup.cpp | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/src/p_setup.cpp b/src/p_setup.cpp index b0004b795f..8d502b42bd 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -4280,20 +4280,6 @@ void P_SetupLevel(const char *lumpname, int position, bool newGame) memcpy(&level.loadlines[0], &level.lines[0], level.lines.Size() * sizeof(level.lines[0])); level.loadsides.Resize(level.sides.Size()); memcpy(&level.loadsides[0], &level.sides[0], level.sides.Size() * sizeof(level.sides[0])); - - - for (auto i : { 29, 30 }) - { - level.lines[i].sidedef[0]->SetSpecialColor(side_t::top, side_t::walltop, PalEntry(255, 255, 0)); - level.lines[i].sidedef[0]->SetSpecialColor(side_t::top, side_t::wallbottom, PalEntry(0, 255, 255)); - level.lines[i].sidedef[0]->SetSpecialColor(side_t::bottom, side_t::walltop, PalEntry(255, 0, 0)); - level.lines[i].sidedef[0]->SetSpecialColor(side_t::bottom, side_t::wallbottom, PalEntry(0, 0, 255)); - } - level.lines[29].sidedef[0]->textures[side_t::top].flags = side_t::part::UseOwnColors; - level.lines[30].sidedef[0]->textures[side_t::top].flags = side_t::part::UseOwnColors | side_t::part::ClampGradient; - level.lines[29].sidedef[0]->textures[side_t::bottom].flags = side_t::part::UseOwnColors; - level.lines[30].sidedef[0]->textures[side_t::bottom].flags = side_t::part::UseOwnColors | side_t::part::ClampGradient; - } // From 59790302ece1c79b898d8bb505d0adcd9ffb9990 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 11 Nov 2018 22:17:44 +0100 Subject: [PATCH 16/25] - fixed rendering of lower untextured linedef parts. --- src/hwrenderer/scene/hw_renderhacks.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hwrenderer/scene/hw_renderhacks.cpp b/src/hwrenderer/scene/hw_renderhacks.cpp index afa1eae78d..380a432245 100644 --- a/src/hwrenderer/scene/hw_renderhacks.cpp +++ b/src/hwrenderer/scene/hw_renderhacks.cpp @@ -820,13 +820,13 @@ void HWDrawInfo::PrepareLowerGap(seg_t * seg) CreateFloodPoly(&ws, vertices.first+4, ws.z1, fakebsector, false); gl_floodrendernode *node = NewFloodRenderNode(); - auto pNode = floodCeilingSegs.CheckKey(fakebsector->sectornum); + auto pNode = floodFloorSegs.CheckKey(fakebsector->sectornum); node->next = pNode? *pNode : nullptr; node->seg = seg; node->vertexindex = vertices.second; - floodCeilingSegs[fakebsector->sectornum] = node; + floodFloorSegs[fakebsector->sectornum] = node; } //========================================================================== From 65a6866a1b287169025b4dcdae7fc7f2fb48d7e0 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 11 Nov 2018 22:22:29 +0100 Subject: [PATCH 17/25] - fixed typo in ceiling render hack code. --- src/hwrenderer/scene/hw_renderhacks.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hwrenderer/scene/hw_renderhacks.cpp b/src/hwrenderer/scene/hw_renderhacks.cpp index 380a432245..c9e34b0628 100644 --- a/src/hwrenderer/scene/hw_renderhacks.cpp +++ b/src/hwrenderer/scene/hw_renderhacks.cpp @@ -60,7 +60,7 @@ void HWDrawInfo::DispatchRenderHacks() } TMap::Iterator oci(otherCeilingPlanes); - while (ofi.NextPair(pair)) + while (oci.NextPair(pair)) { auto sec = hw_FakeFlat(&level.sectors[pair->Key], in_area, false); glflat.ProcessSector(this, sec, SSRF_RENDERCEILING | SSRF_PLANEHACK); From ca2defa6a2b68632df65d909b161a5d11d520b88 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 12 Nov 2018 00:13:14 +0100 Subject: [PATCH 18/25] - added ZScript export for side_t::SetSpecialColor. --- src/p_sectors.cpp | 20 ++++++++++++++++++++ wadsrc/static/zscript/mapdata.txt | 8 ++++++++ 2 files changed, 28 insertions(+) diff --git a/src/p_sectors.cpp b/src/p_sectors.cpp index dd0eb882cc..1abb971b61 100644 --- a/src/p_sectors.cpp +++ b/src/p_sectors.cpp @@ -2230,6 +2230,26 @@ DEFINE_ACTION_FUNCTION(_Sector, NextLowestFloorAt) ACTION_RETURN_INT(self->Index()); } + //===================================================================================== +// +// +//===================================================================================== + + DEFINE_ACTION_FUNCTION(_Side, SetSpecialColor) + { + PARAM_SELF_STRUCT_PROLOGUE(side_t); + PARAM_INT(tier); + PARAM_INT(position); + PARAM_COLOR(color); + if (tier >= 0 && tier < 3 && position >= 0 && position < 2) + { + color.a = 255; + self->SetSpecialColor(tier, position, color); + } + return 0; + } + + DEFINE_ACTION_FUNCTION(_Vertex, Index) { PARAM_SELF_STRUCT_PROLOGUE(vertex_t); diff --git a/wadsrc/static/zscript/mapdata.txt b/wadsrc/static/zscript/mapdata.txt index 549513b4ac..11827e3adb 100644 --- a/wadsrc/static/zscript/mapdata.txt +++ b/wadsrc/static/zscript/mapdata.txt @@ -45,6 +45,12 @@ struct Side native play bottom=2 }; + enum EColorPos + { + walltop = 0, + wallbottom = 1 + } + enum EWallFlags { WALLF_ABSLIGHTING = 1, // Light is absolute instead of relative @@ -57,6 +63,7 @@ struct Side native play WALLF_LIGHT_FOG = 128, // This wall's Light is used even in fog. }; + native readonly Sector sector; // Sector the SideDef is facing. //DBaseDecal* AttachedDecals; // [RH] Decals bound to the wall native readonly Line linedef; @@ -77,6 +84,7 @@ struct Side native play native void SetTextureYScale(int which, double scale); native double GetTextureYScale(int which); native void MultiplyTextureYScale(int which, double delta); + native void SetSpecialColor(int tier, int position, Color scolor); //native DInterpolation *SetInterpolation(int position); //native void StopInterpolation(int position); From 33f2f9f34ecbc5e57abd2c679b8d6bdbba32476b Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 12 Nov 2018 00:22:50 +0100 Subject: [PATCH 19/25] - fixed: ZScript's finalization code used the last parsed lump for of one translation unit as reference, not the base lump. This resulted in incorrect messages but also could produce some more subtle errors. --- src/scripting/zscript/zcc_parser.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/scripting/zscript/zcc_parser.cpp b/src/scripting/zscript/zcc_parser.cpp index 5ddc9207da..9093b7b516 100644 --- a/src/scripting/zscript/zcc_parser.cpp +++ b/src/scripting/zscript/zcc_parser.cpp @@ -443,7 +443,7 @@ static void DoParse(int lumpnum) // If the parser fails, there is no point starting the compiler, because it'd only flood the output with endless errors. if (FScriptPosition::ErrorCounter > 0) { - I_Error("%d errors while parsing %s", FScriptPosition::ErrorCounter, Wads.GetLumpFullPath(lumpnum).GetChars()); + I_Error("%d errors while parsing %s", FScriptPosition::ErrorCounter, Wads.GetLumpFullPath(baselump).GetChars()); } #ifndef NDEBUG @@ -457,7 +457,7 @@ static void DoParse(int lumpnum) if (Args->CheckParm("-dumpast")) { FString ast = ZCC_PrintAST(state.TopNode); - FString filename = Wads.GetLumpFullPath(lumpnum); + FString filename = Wads.GetLumpFullPath(baselump); filename.ReplaceChars(":\\/?|", '.'); filename << ".ast"; FileWriter *ff = FileWriter::Open(filename); @@ -469,19 +469,19 @@ static void DoParse(int lumpnum) } PSymbolTable symtable; - auto newns = Wads.GetLumpFile(lumpnum) == 0 ? Namespaces.GlobalNamespace : Namespaces.NewNamespace(Wads.GetLumpFile(lumpnum)); - ZCCCompiler cc(state, NULL, symtable, newns, lumpnum, state.ParseVersion); + auto newns = Wads.GetLumpFile(baselump) == 0 ? Namespaces.GlobalNamespace : Namespaces.NewNamespace(Wads.GetLumpFile(baselump)); + ZCCCompiler cc(state, NULL, symtable, newns, baselump, state.ParseVersion); cc.Compile(); if (FScriptPosition::ErrorCounter > 0) { // Abort if the compiler produced any errors. Also do not compile further lumps, because they very likely miss some stuff. - I_Error("%d errors, %d warnings while compiling %s", FScriptPosition::ErrorCounter, FScriptPosition::WarnCounter, Wads.GetLumpFullPath(lumpnum).GetChars()); + I_Error("%d errors, %d warnings while compiling %s", FScriptPosition::ErrorCounter, FScriptPosition::WarnCounter, Wads.GetLumpFullPath(baselump).GetChars()); } else if (FScriptPosition::WarnCounter > 0) { // If we got warnings, but no errors, print the information but continue. - Printf(TEXTCOLOR_ORANGE "%d warnings while compiling %s\n", FScriptPosition::WarnCounter, Wads.GetLumpFullPath(lumpnum).GetChars()); + Printf(TEXTCOLOR_ORANGE "%d warnings while compiling %s\n", FScriptPosition::WarnCounter, Wads.GetLumpFullPath(baselump).GetChars()); } } From 9520a3c640ce4b0bcb8f16004a404e98c2a37912 Mon Sep 17 00:00:00 2001 From: Kevin Caccamo Date: Mon, 12 Nov 2018 14:55:41 -0500 Subject: [PATCH 20/25] Fix swapped horizontal/vertical scale The UDMF specs for things had the descriptions for horizontal and vertical scale swapped. --- specs/udmf_zdoom.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/specs/udmf_zdoom.txt b/specs/udmf_zdoom.txt index 43722d0fe5..9e06948780 100644 --- a/specs/udmf_zdoom.txt +++ b/specs/udmf_zdoom.txt @@ -321,8 +321,8 @@ Note: All fields default to false unless mentioned otherwise. score = ; // Score value of this actor, overriding the class default if not null. Default = 0. pitch = ; // Pitch of thing in degrees. Default = 0 (horizontal). roll = ; // Pitch of thing in degrees. Default = 0 (horizontal). - scalex = ; // Vertical scaling on thing. Default = 0 (ignored). - scaley = ; // Horizontal scaling on thing. Default = 0 (ignored). + scalex = ; // Horizontal scaling on thing. Default = 0 (ignored). + scaley = ; // Vertical scaling on thing. Default = 0 (ignored). scale = ; // Vertical and horizontal scaling on thing. Default = 0 (ignored). floatbobphase = ; // Sets the thing's floatbobphase. Valid phase values are 0-63. Default = -1 (use actor class default). From b553be153df7c27e85cf5961a16d1044d00cefd8 Mon Sep 17 00:00:00 2001 From: Major Cooke Date: Mon, 5 Nov 2018 20:22:37 -0600 Subject: [PATCH 21/25] Added CanResurrect(Actor other, bool passive) - Works similarly to CanCollideWith. - Passive means the caller is trying to be resurrected by 'other'. - Non-passive means the caller is trying to resurrect 'other'. --- src/p_enemy.cpp | 56 +++++++++++++++++++++++++++++++-- src/p_local.h | 1 + src/p_things.cpp | 2 ++ wadsrc/static/zscript/actor.txt | 7 +++++ 4 files changed, 64 insertions(+), 2 deletions(-) diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index a1730c7cef..f49da99836 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -2757,11 +2757,63 @@ void A_DoChase (AActor *actor, bool fastchase, FState *meleestate, FState *missi actor->flags &= ~MF_INCHASE; } +//========================================================================== +// +// CanResurrect +// +// Checks if an actor can resurrect with another one, calling virtual script +// functions to check. +// +//========================================================================== +// [MC] Code is almost a duplicate of CanCollideWith but with changes to +// accommodate checking of just one actor. +bool P_CanResurrect(AActor *tmthing, AActor *thing) +{ + if (tmthing == nullptr) + return false; + + static unsigned VIndex = ~0u; + if (VIndex == ~0u) + { + VIndex = GetVirtualIndex(RUNTIME_CLASS(AActor), "CanResurrect"); + assert(VIndex != ~0u); + } + + VMValue params[3] = { tmthing, thing, false }; + VMReturn ret; + int retval; + ret.IntAt(&retval); + + auto clss = tmthing->GetClass(); + VMFunction *func = clss->Virtuals.Size() > VIndex ? clss->Virtuals[VIndex] : nullptr; + if (func != nullptr) + { + VMCall(func, params, 3, &ret, 1); + if (!retval) return false; + } + + // Pointless to be running it again if it's just self. + if (thing == nullptr || thing == tmthing) + return true; + + std::swap(params[0].a, params[1].a); + params[2].i = true; + + // re-get for the other actor. + clss = thing->GetClass(); + func = clss->Virtuals.Size() > VIndex ? clss->Virtuals[VIndex] : nullptr; + if (func != nullptr) + { + VMCall(func, params, 3, &ret, 1); + if (!retval) return false; + } + return true; +} //========================================================================== // // P_CheckForResurrection (formerly part of A_VileChase) -// Check for ressurecting a body +// Check for resurrecting a body // //========================================================================== @@ -2834,7 +2886,7 @@ static bool P_CheckForResurrection(AActor *self, bool usevilestates) corpsehit->flags = oldflags; corpsehit->radius = oldradius; corpsehit->Height = oldheight; - if (!check) continue; + if (!check || !P_CanResurrect(self, corpsehit)) continue; // got one! temp = self->target; diff --git a/src/p_local.h b/src/p_local.h index 9231058fd9..e9c2d0f2e7 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -162,6 +162,7 @@ void P_Thing_SetVelocity(AActor *actor, const DVector3 &vec, bool add, bool setb void P_RemoveThing(AActor * actor); bool P_Thing_Raise(AActor *thing, AActor *raiser, int nocheck = false); bool P_Thing_CanRaise(AActor *thing); +bool P_CanResurrect(AActor *ththing, AActor *thing); PClassActor *P_GetSpawnableType(int spawnnum); void InitSpawnablesFromMapinfo(); int P_Thing_CheckInputNum(player_t *p, int inputnum); diff --git a/src/p_things.cpp b/src/p_things.cpp index 9fac1cd674..44ef08b949 100644 --- a/src/p_things.cpp +++ b/src/p_things.cpp @@ -460,6 +460,8 @@ bool P_Thing_Raise(AActor *thing, AActor *raiser, int nocheck) return false; } + if (!P_CanResurrect(thing, raiser)) + return false; S_Sound (thing, CHAN_BODY, "vile/raise", 1, ATTN_IDLE); diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 3d4e74fc89..3ce5cf447e 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -445,6 +445,13 @@ class Actor : Thinker native return true; } + // Called by revival/resurrection to check if one can resurrect the other. + // "other" can be null when not passive. + virtual bool CanResurrect(Actor other, bool passive) + { + return true; + } + // Called when an actor is to be reflected by a disc of repulsion. // Returns true to continue normal blast processing. virtual bool SpecialBlastHandling (Actor source, double strength) From 71d2b39d920a180b80d17935c8c0a98e0b3e2b42 Mon Sep 17 00:00:00 2001 From: Major Cooke Date: Tue, 6 Nov 2018 11:20:51 -0600 Subject: [PATCH 22/25] Added A_RaiseActor(Actor other, int flags = 0) --- src/p_actionfunctions.cpp | 14 ++++++++++++++ src/p_things.cpp | 3 +++ wadsrc/static/zscript/actor.txt | 1 + 3 files changed, 18 insertions(+) diff --git a/src/p_actionfunctions.cpp b/src/p_actionfunctions.cpp index 3c0d351534..8ac2b5665b 100644 --- a/src/p_actionfunctions.cpp +++ b/src/p_actionfunctions.cpp @@ -4564,6 +4564,20 @@ DEFINE_ACTION_FUNCTION(AActor, A_RaiseSelf) ACTION_RETURN_BOOL(P_Thing_Raise(self, NULL, (flags & RF_NOCHECKPOSITION))); } +//=========================================================================== +// +// A_RaiseActor +// +// Generalized version that allows passing pointers for ZScript's sake. +//=========================================================================== +DEFINE_ACTION_FUNCTION(AActor, A_RaiseActor) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_OBJECT(other, AActor); + PARAM_INT_DEF(flags); + ACTION_RETURN_BOOL(P_Thing_Raise(other, self, (flags & RF_NOCHECKPOSITION))); +} + //=========================================================================== // // CanRaise diff --git a/src/p_things.cpp b/src/p_things.cpp index 44ef08b949..010eb2e9d9 100644 --- a/src/p_things.cpp +++ b/src/p_things.cpp @@ -434,6 +434,9 @@ void P_RemoveThing(AActor * actor) bool P_Thing_Raise(AActor *thing, AActor *raiser, int nocheck) { + if (!thing) + return false; + FState * RaiseState = thing->GetRaiseState(); if (RaiseState == NULL) { diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 3ce5cf447e..34ed24ad11 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -1092,6 +1092,7 @@ class Actor : Thinker native native void A_RaiseChildren(int flags = 0); native void A_RaiseSiblings(int flags = 0); native bool A_RaiseSelf(int flags = 0); + native bool A_RaiseActor(Actor other, int flags = 0); native bool CanRaise(); native void Revive(); action native bool, Actor A_ThrowGrenade(class itemtype, double zheight = 0, double xyvel = 0, double zvel = 0, bool useammo = true); From f47210df4e8f96b463df755d1fea7a1b7aa55fe9 Mon Sep 17 00:00:00 2001 From: Major Cooke Date: Tue, 6 Nov 2018 11:23:52 -0600 Subject: [PATCH 23/25] Fixed inconsistency. - P_Thing_Raise returned true while P_Thing_CanRaise returned false for the condition of having no raise state. P_Thing_Raise now returns false. --- src/p_things.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_things.cpp b/src/p_things.cpp index 010eb2e9d9..e7de17aab4 100644 --- a/src/p_things.cpp +++ b/src/p_things.cpp @@ -440,7 +440,7 @@ bool P_Thing_Raise(AActor *thing, AActor *raiser, int nocheck) FState * RaiseState = thing->GetRaiseState(); if (RaiseState == NULL) { - return true; // monster doesn't have a raise state + return false; // monster doesn't have a raise state } AActor *info = thing->GetDefault (); From 55f17fa90c38edf77f25633d8de506a966b15e30 Mon Sep 17 00:00:00 2001 From: Major Cooke Date: Tue, 6 Nov 2018 18:31:43 -0600 Subject: [PATCH 24/25] Changed A_RaiseActor to just RaiseActor. --- src/p_actionfunctions.cpp | 4 ++-- wadsrc/static/zscript/actor.txt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/p_actionfunctions.cpp b/src/p_actionfunctions.cpp index 8ac2b5665b..60771a469c 100644 --- a/src/p_actionfunctions.cpp +++ b/src/p_actionfunctions.cpp @@ -4566,11 +4566,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_RaiseSelf) //=========================================================================== // -// A_RaiseActor +// RaiseActor // // Generalized version that allows passing pointers for ZScript's sake. //=========================================================================== -DEFINE_ACTION_FUNCTION(AActor, A_RaiseActor) +DEFINE_ACTION_FUNCTION(AActor, RaiseActor) { PARAM_SELF_PROLOGUE(AActor); PARAM_OBJECT(other, AActor); diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 34ed24ad11..7f9cd5afde 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -1092,7 +1092,7 @@ class Actor : Thinker native native void A_RaiseChildren(int flags = 0); native void A_RaiseSiblings(int flags = 0); native bool A_RaiseSelf(int flags = 0); - native bool A_RaiseActor(Actor other, int flags = 0); + native bool RaiseActor(Actor other, int flags = 0); native bool CanRaise(); native void Revive(); action native bool, Actor A_ThrowGrenade(class itemtype, double zheight = 0, double xyvel = 0, double zvel = 0, bool useammo = true); From a6b44b02b716e91ddf077cfec2f00a8b1acb7b21 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 13 Nov 2018 20:36:23 +0100 Subject: [PATCH 25/25] - fixed incompletely initialized secplanes in sprite splitting code. The recent optimization of the shader setup needs the negiC value properly set. --- src/hwrenderer/scene/hw_sprites.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hwrenderer/scene/hw_sprites.cpp b/src/hwrenderer/scene/hw_sprites.cpp index f3935dab69..94e86beb4b 100644 --- a/src/hwrenderer/scene/hw_sprites.cpp +++ b/src/hwrenderer/scene/hw_sprites.cpp @@ -207,8 +207,8 @@ void GLSprite::DrawSprite(HWDrawInfo *di, FRenderState &state, bool translucent) state.EnableSplit(true); } - secplane_t bottomp = { { 0, 0, -1. }, bottomclip }; - secplane_t topp = { { 0, 0, -1. }, topclip }; + secplane_t bottomp = { { 0, 0, -1. }, bottomclip, 1. }; + secplane_t topp = { { 0, 0, -1. }, topclip, 1. }; for (unsigned i = 0; i < iter; i++) { if (lightlist)