diff --git a/specs/udmf_zdoom.txt b/specs/udmf_zdoom.txt index e26044dc6..9e0694878 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 @@ -300,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). diff --git a/src/am_map.cpp b/src/am_map.cpp index 58ac47085..305748317 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/c_consolebuffer.cpp b/src/c_consolebuffer.cpp index 9d32efffb..9868bc6c3 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/d_iwad.cpp b/src/d_iwad.cpp index bb2c091a3..2716d1eb1 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 01c97b2ae..0a02f6d99 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/f_wipe.cpp b/src/f_wipe.cpp index 6d34936fd..25c283038 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(); } }; diff --git a/src/files.h b/src/files.h index 4b281438f..ea24cff20 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/gl/renderer/gl_renderer.cpp b/src/gl/renderer/gl_renderer.cpp index ef1e6221d..af6a3acac 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 67d4fba28..f3765d382 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/gl/renderer/gl_renderstate.cpp b/src/gl/renderer/gl_renderstate.cpp index 1bfed5fc6..76e8ba892 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 d4352dcb7..b31e9532f 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 732b5eaaf..cc1dece32 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/data/hw_vertexbuilder.cpp b/src/hwrenderer/data/hw_vertexbuilder.cpp index f989d99d0..6a0542cdf 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/hwrenderer/scene/hw_bsp.cpp b/src/hwrenderer/scene/hw_bsp.cpp index 31a3694ee..39d4145f3 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_decal.cpp b/src/hwrenderer/scene/hw_decal.cpp index 5a3e509bf..815032314 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_drawinfo.h b/src/hwrenderer/scene/hw_drawinfo.h index 6fc0e212f..24d6c2218 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 1ccbc31f3..067c5dee5 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_drawstructs.h b/src/hwrenderer/scene/hw_drawstructs.h index 35a6d340e..d500e6795 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_fakeflat.cpp b/src/hwrenderer/scene/hw_fakeflat.cpp index 555504bc4..38cfaeefc 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 c56f3798d..2f670d222 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 5592a03ab..c9e34b062 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)) + while (oci.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; @@ -826,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; } //========================================================================== @@ -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_renderstate.h b/src/hwrenderer/scene/hw_renderstate.h index 22cabc4c6..66f7ccff3 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_sprites.cpp b/src/hwrenderer/scene/hw_sprites.cpp index 4bda3ab71..94e86beb4 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) @@ -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_walls.cpp b/src/hwrenderer/scene/hw_walls.cpp index b91c38ae1..0622553f7 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(topplane, bottomplane); 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) @@ -167,14 +214,14 @@ 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]); 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); } //========================================================================== @@ -1799,6 +1847,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 +1943,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 +2152,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 +2179,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; diff --git a/src/hwrenderer/scene/hw_weapon.cpp b/src/hwrenderer/scene/hw_weapon.cpp index bdcf1f08e..d0bb20e4d 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); diff --git a/src/namedef.h b/src/namedef.h index ecac82b56..5744ef486 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_actionfunctions.cpp b/src/p_actionfunctions.cpp index 3c0d35153..60771a469 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))); } +//=========================================================================== +// +// RaiseActor +// +// Generalized version that allows passing pointers for ZScript's sake. +//=========================================================================== +DEFINE_ACTION_FUNCTION(AActor, 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_enemy.cpp b/src/p_enemy.cpp index a1730c7ce..f49da9983 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_glnodes.cpp b/src/p_glnodes.cpp index 0113208a1..75a53a9b1 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) diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index 2d7d6026c..d5404a19a 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 06748c76a..e9c2d0f2e 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); @@ -454,6 +455,7 @@ enum EDmgFlags DMG_USEANGLE = 512, DMG_NO_PAIN = 1024, DMG_EXPLOSION = 2048, + DMG_NO_ENHANCE = 4096, }; diff --git a/src/p_map.cpp b/src/p_map.cpp index 148e1fd18..cea1a33d6 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 { diff --git a/src/p_saveg.cpp b/src/p_saveg.cpp index 53f4959a2..a8dff6868 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 be86c87ef..1abb971b6 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); @@ -2241,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/src/p_setup.cpp b/src/p_setup.cpp index 15cbb0b54..8d502b42b 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; } //=========================================================================== @@ -3644,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 @@ -3674,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; } } @@ -3695,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) @@ -3736,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; } @@ -3748,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 @@ -3768,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(); @@ -3808,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(); @@ -3834,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 { @@ -3862,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(); @@ -3881,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(); @@ -3927,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(); } } @@ -3960,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; @@ -3969,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(), @@ -3986,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; } @@ -4001,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]; } @@ -4035,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) @@ -4061,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; @@ -4072,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 @@ -4090,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. @@ -4098,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; } @@ -4110,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) @@ -4133,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(); @@ -4146,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) { @@ -4180,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(); } } @@ -4194,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(); } @@ -4214,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. @@ -4247,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[] = @@ -4276,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(); @@ -4294,8 +4282,6 @@ void P_SetupLevel (const char *lumpname, int position, bool newGame) memcpy(&level.loadsides[0], &level.sides[0], level.sides.Size() * sizeof(level.sides[0])); } - - // // P_Init // diff --git a/src/p_setup.h b/src/p_setup.h index 1f773e951..dd3a1e1e3 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 (lumpindexGetRaiseState(); 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 (); @@ -460,6 +463,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/src/p_udmf.cpp b/src/p_udmf.cpp index 11652abfc..6bacd4229 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; @@ -2045,15 +2119,11 @@ public: void ParseTextMap(MapData *map) { - char *buffer = new char[map->Size(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 4838d4b8d..f24cd5d7b 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 cdc28c15a..9631c4b49 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/polyrenderer/scene/poly_wall.cpp b/src/polyrenderer/scene/poly_wall.cpp index b7872724b..3ba2e9f56 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_data/r_sections.cpp b/src/r_data/r_sections.cpp index 9186a13a1..74b89f9a5 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; @@ -184,6 +185,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 +281,7 @@ public: { MakeOutline(list, lineForSeg); } - rawsections.Clear(); - rawsections.ShrinkToFit(); + rawsections.Reset(); // Assign partners after everything has been collected for (auto §ion : sections) @@ -281,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) @@ -371,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. @@ -402,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); @@ -720,8 +750,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 +868,7 @@ void CreateSections(FSectionContainer &container) creat.FindOuterLoops(); creat.GroupSections(); creat.ConstructOutput(container); + creat.FixMissingReferences(); } CCMD(printsections) diff --git a/src/r_defs.h b/src/r_defs.h index cb394cd41..ad128c4dc 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/src/resourcefiles/file_7z.cpp b/src/resourcefiles/file_7z.cpp index 79ecea583..01bd043ef 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 03b33e400..54cb1e7a6 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; } @@ -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) @@ -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 c0458276a..ba0493dd6 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 d7eb68e88..da458303a 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 c2705a97f..d7f091c02 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 a0ae033db..c1f5b3fdb 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 b3bfa7a2d..04430384e 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 419bd4707..1cb1f4e9f 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 9b39b0908..9ad2e43cf 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/sc_man.h b/src/sc_man.h index 9c4f34a22..c76fb724f 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, const 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/scripting/zscript/zcc_parser.cpp b/src/scripting/zscript/zcc_parser.cpp index 5ddc9207d..9093b7b51 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()); } } diff --git a/src/tarray.h b/src/tarray.h index 7e8c53f06..167f85fa9 100644 --- a/src/tarray.h +++ b/src/tarray.h @@ -157,14 +157,14 @@ 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) { - 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. @@ -433,15 +431,12 @@ 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; - for (unsigned int i = place; i < Count; ++i) - { - ::new((void *)&Array[i]) T; - } + Count += (unsigned)amount; + if (Count > 0) ConstructEmpty(place, Count - 1); return place; } unsigned int Size () const @@ -463,7 +458,12 @@ public: void Reset() { Clear(); - ShrinkToFit(); + Most = 0; + if (Array != nullptr) + { + M_Free(Array); + Array = nullptr; + } } private: T *Array; @@ -501,6 +501,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 ----------------------------------------------------------- diff --git a/src/v_2ddrawer.cpp b/src/v_2ddrawer.cpp index 40cea9904..8fc487ef9 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 9f7f16676..33ca20dc9 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 f2b5a7800..252d9bf4e 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 b2fe73657..61185e1b3 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); diff --git a/src/w_wad.cpp b/src/w_wad.cpp index 9c474ceb8..9c0dd3760 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 @@ -1389,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; } @@ -1452,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; } diff --git a/src/w_wad.h b/src/w_wad.h index dca4bd8fe..a7009d65e 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)); } diff --git a/wadsrc/static/shaders/glsl/main.fp b/wadsrc/static/shaders/glsl/main.fp index dd082e614..77855a85a 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 0be91afb8..dccbb77c0 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); diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 3d4e74fc8..7f9cd5afd 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) @@ -1085,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 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); diff --git a/wadsrc/static/zscript/constants.txt b/wadsrc/static/zscript/constants.txt index 92f548355..ccb3f4848 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 diff --git a/wadsrc/static/zscript/mapdata.txt b/wadsrc/static/zscript/mapdata.txt index 549513b4a..11827e3ad 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);