Merge remote-tracking branch 'origin/master' into asmjit

This commit is contained in:
Magnus Norddahl 2018-11-14 01:23:17 +01:00
commit 99849bc0c5
66 changed files with 1042 additions and 601 deletions

View file

@ -154,31 +154,52 @@ Note: All <bool> fields default to false unless mentioned otherwise.
sidedef sidedef
{ {
scalex_top = <float>; // X scale for upper texture, Default = 1.0. scalex_top = <float>; // X scale for upper texture, Default = 1.0.
scaley_top = <float>; // y scale for upper texture, Default = 1.0. scaley_top = <float>; // y scale for upper texture, Default = 1.0.
scalex_mid = <float>; // X scale for mid texture, Default = 1.0. scalex_mid = <float>; // X scale for mid texture, Default = 1.0.
scaley_mid = <float>; // y scale for mid texture, Default = 1.0. scaley_mid = <float>; // y scale for mid texture, Default = 1.0.
scalex_bottom = <float>; // X scale for lower texture, Default = 1.0. scalex_bottom = <float>; // X scale for lower texture, Default = 1.0.
scaley_bottom = <float>; // y scale for lower texture, Default = 1.0. scaley_bottom = <float>; // y scale for lower texture, Default = 1.0.
offsetx_top = <float>; // X offset for upper texture, Default = 0.0. offsetx_top = <float>; // X offset for upper texture, Default = 0.0.
offsety_top = <float>; // y offset for upper texture, Default = 0.0. offsety_top = <float>; // y offset for upper texture, Default = 0.0.
offsetx_mid = <float>; // X offset for mid texture, Default = 0.0. offsetx_mid = <float>; // X offset for mid texture, Default = 0.0.
offsety_mid = <float>; // y offset for mid texture, Default = 0.0. offsety_mid = <float>; // y offset for mid texture, Default = 0.0.
offsetx_bottom = <float>; // X offset for lower texture, Default = 0.0. offsetx_bottom = <float>; // X offset for lower texture, Default = 0.0.
offsety_bottom = <float>; // y offset for lower texture, Default = 0.0. offsety_bottom = <float>; // y offset for lower texture, Default = 0.0.
// When global texture offsets are used they will // When global texture offsets are used they will
// be added on top of these values. // be added on top of these values.
light = <integer>; // This side's light level. Default is 0. light = <integer>; // This side's light level. Default is 0.
lightabsolute = <bool>; // true = 'light' is an absolute value. Default is lightabsolute = <bool>; // true = 'light' is an absolute value. Default is
// relative to the owning sector's light level. // relative to the owning sector's light level.
lightfog = <bool>; // true = This side's relative lighting is used even in lightfog = <bool>; // true = This side's relative lighting is used even in
// foggy sectors. Default is to disable relative // foggy sectors. Default is to disable relative
// lighting in foggy sectors. // lighting in foggy sectors.
nofakecontrast = <bool>; // Disables use of fake contrast on this sidedef. nofakecontrast = <bool>; // Disables use of fake contrast on this sidedef.
smoothlighting = <bool>; // Use smooth fake contrast. smoothlighting = <bool>; // Use smooth fake contrast.
clipmidtex = <bool>; // Side's mid textures are clipped to floor and ceiling. clipmidtex = <bool>; // Side's mid textures are clipped to floor and ceiling.
wrapmidtex = <bool>; // Side's mid textures are wrapped. wrapmidtex = <bool>; // Side's mid textures are wrapped.
nodecals = <bool>; // Disables decals on the sidedef. nodecals = <bool>; // Disables decals on the sidedef.
nogradient_top = <bool>; // disables color gradient on upper tier. (Hardware rendering only.)
flipgradient_top = <bool>; // flips gradient colors on upper tier. (Hardware rendering only.)
clampgradient_top = <bool>; // clamps gradient on upper tier to actual bounds (default is the entire front sector height, hardware rendering only.)
useowncolors_top = <bool>; // Set to 1 to use the colors set in the sidedef. Default is using the colors from the owning sector.
uppercolor_top = <int>; // Material color of the top of the upper tier.
lowercolor_top = <int>; // Material color of the bottom of the upper tier. (Hardware rendering only.)
nogradient_mid = <bool>; // disables color gradient on middle tier. (Hardware rendering only.)
flipgradient_mid = <bool>; // flips gradient colors on middle tier. (Hardware rendering only.)
clampgradient_mid = <bool>; // clamps gradient on middle tier to actual bounds (default is the entire front sector height, hardware rendering only.)
useowncolors_mid = <bool>; // Set to 1 to use the colors set in the sidedef. Default is using the colors from the owning sector.
uppercolor_mid = <int>; // Material color of the top of the middle tier.
lowercolor_mid = <int>; // Material color of the bottom of the middle tier. (Hardware rendering only.)
nogradient_bottom = <bool>; // disables color gradient on lower tier. (Hardware rendering only.)
flipgradient_bottom = <bool>; // flips gradient colors on lower tier. (Hardware rendering only.)
clampgradient_bottom = <bool>;// clamps gradient on lower tier to actual bounds (default is the entire front sector height, hardware rendering only.)
useowncolors_bottom = <bool>; // Set to 1 to use the colors set in the sidedef. Default is using the colors from the owning sector.
uppercolor_bottom = <int>; // Material color of the top of the lower tier.
lowercolor_bottom = <int>; // Material color of the bottom of the lower tier. (Hardware rendering only.)
} }
sector sector
@ -300,8 +321,8 @@ Note: All <bool> fields default to false unless mentioned otherwise.
score = <int>; // Score value of this actor, overriding the class default if not null. Default = 0. score = <int>; // Score value of this actor, overriding the class default if not null. Default = 0.
pitch = <integer>; // Pitch of thing in degrees. Default = 0 (horizontal). pitch = <integer>; // Pitch of thing in degrees. Default = 0 (horizontal).
roll = <integer>; // Pitch of thing in degrees. Default = 0 (horizontal). roll = <integer>; // Pitch of thing in degrees. Default = 0 (horizontal).
scalex = <float>; // Vertical scaling on thing. Default = 0 (ignored). scalex = <float>; // Horizontal scaling on thing. Default = 0 (ignored).
scaley = <float>; // Horizontal scaling on thing. Default = 0 (ignored). scaley = <float>; // Vertical scaling on thing. Default = 0 (ignored).
scale = <float>; // Vertical and horizontal scaling on thing. Default = 0 (ignored). scale = <float>; // Vertical and horizontal scaling on thing. Default = 0 (ignored).
floatbobphase = <int>; // Sets the thing's floatbobphase. Valid phase values are 0-63. Default = -1 (use actor class default). floatbobphase = <int>; // Sets the thing's floatbobphase. Valid phase values are 0-63. Default = -1 (use actor class default).

View file

@ -62,6 +62,7 @@
#include "a_keys.h" #include "a_keys.h"
#include "g_levellocals.h" #include "g_levellocals.h"
#include "actorinlines.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() void AM_drawSubsectors()
{ {
static TArray<FVector2> points; static TArray<FVector2> points;
std::vector<uint32_t> indices;
double scale = scale_mtof; double scale = scale_mtof;
DAngle rotation; DAngle rotation;
sector_t tempsec; sector_t tempsec;
@ -2067,27 +2069,28 @@ void AM_drawSubsectors()
auto &subsectors = level.subsectors; auto &subsectors = level.subsectors;
for (unsigned i = 0; i < subsectors.Size(); ++i) for (unsigned i = 0; i < subsectors.Size(); ++i)
{ {
if (subsectors[i].flags & SSECF_POLYORG) auto sub = &subsectors[i];
if (sub->flags & SSECF_POLYORG)
{ {
continue; 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; 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; continue;
} }
// Fill the points array from the subsector. // Fill the points array from the subsector.
points.Resize(subsectors[i].numlines); points.Resize(sub->numlines);
for (uint32_t j = 0; j < subsectors[i].numlines; ++j) for (uint32_t j = 0; j < sub->numlines; ++j)
{ {
mpoint_t pt = { subsectors[i].firstline[j].v1->fX(), mpoint_t pt = { sub->firstline[j].v1->fX(),
subsectors[i].firstline[j].v1->fY() }; sub->firstline[j].v1->fY() };
if (am_rotate == 1 || (am_rotate == 2 && viewactive)) if (am_rotate == 1 || (am_rotate == 2 && viewactive))
{ {
AM_rotatePoint(&pt.x, &pt.y); 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)); points[j].Y = float(f_y + (f_h - (pt.y - m_y) * scale));
} }
// For lighting and texture determination // 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(); floorlight = sec->GetFloorLight();
// Find texture origin. // Find texture origin.
originpt.x = -sec->GetXOffset(sector_t::floor); originpt.x = -sec->GetXOffset(sector_t::floor);
@ -2123,7 +2126,7 @@ void AM_drawSubsectors()
double secx; double secx;
double secy; double secy;
double seczb, seczt; double seczb, seczt;
auto &vp = r_viewpoint; auto &vp = r_viewpoint;
double cmpz = vp.Pos.Z; double cmpz = vp.Pos.Z;
if (players[consoleplayer].camera && sec == players[consoleplayer].camera->Sector) if (players[consoleplayer].camera && sec == players[consoleplayer].camera->Sector)
@ -2144,7 +2147,7 @@ void AM_drawSubsectors()
{ {
F3DFloor *rover = sec->e->XFloor.ffloors[i]; F3DFloor *rover = sec->e->XFloor.ffloors[i];
if (!(rover->flags & FF_EXISTS)) continue; 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->flags & FF_RENDERPLANES)) continue;
if (rover->alpha == 0) continue; if (rover->alpha == 0) continue;
double roverz = rover->top.plane->ZatPoint(secx, secy); 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 // If this subsector has not actually been seen yet (because you are cheating
// to see it on the map), tint and desaturate it. // 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 = PalEntry(
(colormap.LightColor.r + 255) / 2, (colormap.LightColor.r + 255) / 2,
@ -2210,8 +2213,28 @@ void AM_drawSubsectors()
// Draw the polygon. // Draw the polygon.
FTexture *pic = TexMan(maptex); 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<double, double>;
std::vector<std::vector<Point>> polygon;
std::vector<Point> *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), screen->FillSimplePoly(TexMan(maptex),
&points[0], points.Size(), &points[0], points.Size(),
originx, originy, originx, originy,
@ -2221,8 +2244,8 @@ void AM_drawSubsectors()
colormap, colormap,
flatcolor, flatcolor,
floorlight, floorlight,
f_y + f_h f_y + f_h,
); indices.data(), indices.size());
} }
} }
} }

View file

@ -150,9 +150,9 @@ void FConsoleBuffer::AddText(int printlevel, const char *text, FILE *logfile)
void FConsoleBuffer::WriteLineToLog(FILE *LogFile, const char *outline) void FConsoleBuffer::WriteLineToLog(FILE *LogFile, const char *outline)
{ {
// Strip out any color escape sequences before writing to the log file // Strip out any color escape sequences before writing to the log file
char * copy = new char[strlen(outline)+1]; TArray<char> copy(strlen(outline)+1);
const char * srcp = outline; const char * srcp = outline;
char * dstp = copy; char * dstp = copy.Data();
while (*srcp != 0) while (*srcp != 0)
{ {
@ -193,8 +193,7 @@ void FConsoleBuffer::WriteLineToLog(FILE *LogFile, const char *outline)
} }
*dstp=0; *dstp=0;
fputs (copy, LogFile); fputs (copy.Data(), LogFile);
delete [] copy;
fflush (LogFile); fflush (LogFile);
} }

View file

@ -257,7 +257,7 @@ FIWadManager::FIWadManager(const char *fn)
if (lmp->Namespace == ns_global && !stricmp(lmp->Name, "IWADINFO")) if (lmp->Namespace == ns_global && !stricmp(lmp->Name, "IWADINFO"))
{ {
// Found one! // Found one!
ParseIWadInfo(resfile->Filename, (const char*)lmp->CacheLump(), lmp->LumpSize); ParseIWadInfo(resfile->FileName, (const char*)lmp->CacheLump(), lmp->LumpSize);
break; break;
} }
} }
@ -349,7 +349,7 @@ int FIWadManager::CheckIWADInfo(const char *fn)
try try
{ {
FIWADInfo result; FIWADInfo result;
ParseIWadInfo(resfile->Filename, (const char*)lmp->CacheLump(), lmp->LumpSize, &result); ParseIWadInfo(resfile->FileName, (const char*)lmp->CacheLump(), lmp->LumpSize, &result);
delete resfile; delete resfile;
for (unsigned i = 0, count = mIWadInfos.Size(); i < count; ++i) for (unsigned i = 0, count = mIWadInfos.Size(); i < count; ++i)

View file

@ -1905,7 +1905,7 @@ static FString CheckGameInfo(TArray<FString> & pwads)
if (lmp->Namespace == ns_global && !stricmp(lmp->Name, "GAMEINFO")) if (lmp->Namespace == ns_global && !stricmp(lmp->Name, "GAMEINFO"))
{ {
// Found one! // 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; delete resfile;
return iwad; return iwad;
} }

View file

@ -32,29 +32,24 @@
class FBurnTexture : public FTexture class FBurnTexture : public FTexture
{ {
uint32_t *WorkBuffer; TArray<uint32_t> WorkBuffer;
public: public:
FBurnTexture(int w, int h) FBurnTexture(int w, int h)
: WorkBuffer(w*h, true)
{ {
Width = w; Width = w;
Height = h; Height = h;
WorkBuffer = new uint32_t[w * h];
}
~FBurnTexture()
{
delete [] WorkBuffer;
} }
int CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rotate, FCopyInfo *inf) override 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; return 0;
} }
uint32_t *GetBuffer() uint32_t *GetBuffer()
{ {
return WorkBuffer; return WorkBuffer.Data();
} }
}; };

View file

@ -184,6 +184,14 @@ public:
return mReader->Read(buffer, (long)len); return mReader->Read(buffer, (long)len);
} }
TArray<uint8_t> Read(size_t len)
{
TArray<uint8_t> buffer((int)len, true);
Size length = mReader->Read(&buffer[0], (long)len);
buffer.Clamp((int)length);
return buffer;
}
TArray<uint8_t> Read() TArray<uint8_t> Read()
{ {
TArray<uint8_t> buffer(mReader->Length, true); TArray<uint8_t> buffer(mReader->Length, true);

View file

@ -53,6 +53,7 @@
#include "hwrenderer/postprocessing/hw_shadowmapshader.h" #include "hwrenderer/postprocessing/hw_shadowmapshader.h"
#include "hwrenderer/data/flatvertices.h" #include "hwrenderer/data/flatvertices.h"
#include "hwrenderer/scene/hw_skydome.h" #include "hwrenderer/scene/hw_skydome.h"
#include "hwrenderer/scene/hw_fakeflat.h"
#include "gl/shaders/gl_postprocessshaderinstance.h" #include "gl/shaders/gl_postprocessshaderinstance.h"
#include "gl/textures/gl_samplers.h" #include "gl/textures/gl_samplers.h"
#include "hwrenderer/dynlights/hw_lightbuffer.h" #include "hwrenderer/dynlights/hw_lightbuffer.h"
@ -231,6 +232,8 @@ sector_t *FGLRenderer::RenderView(player_t* player)
} }
else else
{ {
hw_ClearFakeFlat();
iter_dlightf = iter_dlight = draw_dlight = draw_dlightf = 0; iter_dlightf = iter_dlight = draw_dlight = draw_dlightf = 0;
checkBenchActive(); checkBenchActive();
@ -302,6 +305,7 @@ void FGLRenderer::BindToFrameBuffer(FMaterial *mat)
void FGLRenderer::RenderTextureView(FCanvasTexture *tex, AActor *Viewpoint, double FOV) 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); FMaterial * gltex = FMaterial::ValidateTexture(tex, false);
int width = gltex->TextureWidth(); 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 // Switch to render buffers dimensioned for the savepic
mBuffers = mSaveBuffers; 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); gl_RenderState.SetVertexBuffer(screen->mVertexData);
screen->mVertexData->Reset(); screen->mVertexData->Reset();
screen->mLights->Clear(); screen->mLights->Clear();

View file

@ -122,8 +122,6 @@ private:
}; };
#include "hwrenderer/scene/hw_fakeflat.h"
struct TexFilter_s struct TexFilter_s
{ {
int minfilter; int minfilter;

View file

@ -138,7 +138,6 @@ bool FGLRenderState::ApplyShader()
activeShader->muLightParms.Set(mLightParms); activeShader->muLightParms.Set(mLightParms);
activeShader->muFogColor.Set(mFogColor); activeShader->muFogColor.Set(mFogColor);
activeShader->muObjectColor.Set(mObjectColor); activeShader->muObjectColor.Set(mObjectColor);
activeShader->muObjectColor2.Set(mObjectColor2);
activeShader->muDynLightColor.Set(mDynColor.vec); activeShader->muDynLightColor.Set(mDynColor.vec);
activeShader->muInterpolationFactor.Set(mInterpolationFactor); activeShader->muInterpolationFactor.Set(mInterpolationFactor);
activeShader->muTimer.Set((double)(screen->FrameTime - firstFrame) * (double)mShaderTimer / 1000.); activeShader->muTimer.Set((double)(screen->FrameTime - firstFrame) * (double)mShaderTimer / 1000.);
@ -151,6 +150,8 @@ bool FGLRenderState::ApplyShader()
{ {
activeShader->muGlowTopColor.Set(mGlowTop.vec); activeShader->muGlowTopColor.Set(mGlowTop.vec);
activeShader->muGlowBottomColor.Set(mGlowBottom.vec); activeShader->muGlowBottomColor.Set(mGlowBottom.vec);
activeShader->muGlowTopPlane.Set(mGlowTopPlane.vec);
activeShader->muGlowBottomPlane.Set(mGlowBottomPlane.vec);
activeShader->currentglowstate = 1; activeShader->currentglowstate = 1;
} }
else if (activeShader->currentglowstate) else if (activeShader->currentglowstate)
@ -160,10 +161,18 @@ bool FGLRenderState::ApplyShader()
activeShader->muGlowBottomColor.Set(nulvec); activeShader->muGlowBottomColor.Set(nulvec);
activeShader->currentglowstate = 0; activeShader->currentglowstate = 0;
} }
if (mGlowEnabled || mObjectColor2.a != 0)
if (mGradientEnabled)
{ {
activeShader->muGlowTopPlane.Set(mGlowTopPlane.vec); activeShader->muObjectColor2.Set(mObjectColor2);
activeShader->muGlowBottomPlane.Set(mGlowBottomPlane.vec); 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) if (mSplitEnabled)

View file

@ -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 uGlowBottomPlane;\n";
i_data += "uniform vec4 uGlowBottomColor;\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 uSplitTopPlane;\n";
i_data += "uniform vec4 uSplitBottomPlane;\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"); muGlowTopColor.Init(hShader, "uGlowTopColor");
muGlowBottomPlane.Init(hShader, "uGlowBottomPlane"); muGlowBottomPlane.Init(hShader, "uGlowBottomPlane");
muGlowTopPlane.Init(hShader, "uGlowTopPlane"); muGlowTopPlane.Init(hShader, "uGlowTopPlane");
muGradientBottomPlane.Init(hShader, "uGradientBottomPlane");
muGradientTopPlane.Init(hShader, "uGradientTopPlane");
muSplitBottomPlane.Init(hShader, "uSplitBottomPlane"); muSplitBottomPlane.Init(hShader, "uSplitBottomPlane");
muSplitTopPlane.Init(hShader, "uSplitTopPlane"); muSplitTopPlane.Init(hShader, "uSplitTopPlane");
muInterpolationFactor.Init(hShader, "uInterpolationFactor"); muInterpolationFactor.Init(hShader, "uInterpolationFactor");

View file

@ -249,6 +249,8 @@ class FShader
FUniform4f muGlowTopColor; FUniform4f muGlowTopColor;
FUniform4f muGlowBottomPlane; FUniform4f muGlowBottomPlane;
FUniform4f muGlowTopPlane; FUniform4f muGlowTopPlane;
FUniform4f muGradientBottomPlane;
FUniform4f muGradientTopPlane;
FUniform4f muSplitBottomPlane; FUniform4f muSplitBottomPlane;
FUniform4f muSplitTopPlane; FUniform4f muSplitTopPlane;
FBufferedUniform1f muInterpolationFactor; FBufferedUniform1f muInterpolationFactor;
@ -266,6 +268,7 @@ public:
int fakevb_index; int fakevb_index;
private: private:
int currentglowstate = 0; int currentglowstate = 0;
int currentgradientstate = 0;
int currentsplitstate = 0; int currentsplitstate = 0;
int currentcliplinestate = 0; int currentcliplinestate = 0;
int currentfixedcolormap = 0; int currentfixedcolormap = 0;

View file

@ -53,12 +53,14 @@ static void CreateVerticesForSubsector(subsector_t *sub, VertexContainer &gen, i
using Point = std::pair<double, double>; using Point = std::pair<double, double>;
std::vector<std::vector<Point>> polygon; std::vector<std::vector<Point>> polygon;
std::vector<Point> *curPoly; std::vector<Point> *curPoly;
polygon.resize(1);
curPoly = &polygon.back();
curPoly->resize(sub->numlines);
for (unsigned i = 0; i < sub->numlines; i++) for (unsigned i = 0; i < sub->numlines; i++)
{ {
polygon.resize(1); (*curPoly)[i] = { sub->firstline[i].v1->fX(), sub->firstline[i].v1->fY() };
curPoly = &polygon.back();
curPoly->push_back({ sub->firstline[i].v1->fX(), sub->firstline[i].v1->fY() });
} }
auto indices = mapbox::earcut(polygon); auto indices = mapbox::earcut(polygon);
for (auto vti : indices) for (auto vti : indices)

View file

@ -96,7 +96,7 @@ static RenderJobQueue jobQueue; // One static queue is sufficient here. This cod
void HWDrawInfo::WorkerThread() void HWDrawInfo::WorkerThread()
{ {
sector_t fakefront, fakeback, *front, *back; sector_t *front, *back;
WTTotal.Clock(); WTTotal.Clock();
isWorkerThread = true; // for adding asserts in GL API code. The worker thread may never call any GL API. 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();
_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) else switch (job->type)
{ {
case RenderJob::TerminateJob: case RenderJob::TerminateJob:
@ -130,7 +132,7 @@ void HWDrawInfo::WorkerThread()
SetupWall.Clock(); SetupWall.Clock();
wall.sub = job->sub; 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; auto seg = job->seg;
if (seg->backsector) if (seg->backsector)
{ {
@ -140,7 +142,7 @@ void HWDrawInfo::WorkerThread()
} }
else else
{ {
back = hw_FakeFlat(seg->backsector, &fakeback, in_area, true); back = hw_FakeFlat(seg->backsector, in_area, true);
} }
} }
else back = nullptr; else back = nullptr;
@ -156,7 +158,7 @@ void HWDrawInfo::WorkerThread()
GLFlat flat; GLFlat flat;
SetupFlat.Clock(); SetupFlat.Clock();
flat.section = job->sub->section; 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); flat.ProcessSector(this, front);
SetupFlat.Unclock(); SetupFlat.Unclock();
break; break;
@ -164,14 +166,14 @@ void HWDrawInfo::WorkerThread()
case RenderJob::SpriteJob: case RenderJob::SpriteJob:
SetupSprite.Clock(); 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); RenderThings(job->sub, front);
SetupSprite.Unclock(); SetupSprite.Unclock();
break; break;
case RenderJob::ParticleJob: case RenderJob::ParticleJob:
SetupSprite.Clock(); 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); RenderParticles(job->sub, front);
SetupSprite.Unclock(); SetupSprite.Unclock();
break; break;
@ -228,7 +230,6 @@ void HWDrawInfo::AddLine (seg_t *seg, bool portalclip)
#endif #endif
sector_t * backsector = nullptr; sector_t * backsector = nullptr;
sector_t bs;
if (portalclip) 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 // 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); 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)) if (hw_CheckClip(seg->sidedef, currentsector, backsector))
{ {
@ -575,7 +576,6 @@ void HWDrawInfo::DoSubsector(subsector_t * sub)
{ {
sector_t * sector; sector_t * sector;
sector_t * fakesector; sector_t * fakesector;
sector_t fake;
#ifdef _DEBUG #ifdef _DEBUG
if (sub->sector->sectornum==931) 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. 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) if (mClipPortal)
{ {
@ -677,7 +677,7 @@ void HWDrawInfo::DoSubsector(subsector_t * sub)
sector = sub->render_sector; sector = sub->render_sector;
// the planes of this subsector are faked to belong to another 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. // 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)]; uint8_t &srf = section_renderflags[level.sections.SectionIndex(sub->section)];

View file

@ -95,7 +95,7 @@ void GLDecal::DrawDecal(HWDrawInfo *di, FRenderState &state)
for (unsigned k = 0; k < lightlist.Size(); k++) 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 low1 = lowplane.ZatPoint(dv[1].x, dv[1].y);
float low2 = lowplane.ZatPoint(dv[2].x, dv[2].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->alpha = decal->Alpha;
gldecal->zcenter = zpos - decalheight * 0.5f; gldecal->zcenter = zpos - decalheight * 0.5f;
gldecal->bottomplane = bottomplane; gldecal->frontsector = frontsector;
gldecal->Normal = normal; gldecal->Normal = normal;
gldecal->lightlist = lightlist; gldecal->lightlist = lightlist;
memcpy(gldecal->dv, dv, sizeof(dv)); memcpy(gldecal->dv, dv, sizeof(dv));

View file

@ -193,8 +193,6 @@ private:
subsector_t *currentsubsector; // used by the line processing code. subsector_t *currentsubsector; // used by the line processing code.
sector_t *currentsector; 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 WorkerThread();
void UnclipSubsector(subsector_t *sub); void UnclipSubsector(subsector_t *sub);

View file

@ -36,6 +36,7 @@
#include "hwrenderer/utility/hw_clock.h" #include "hwrenderer/utility/hw_clock.h"
#include "hw_renderstate.h" #include "hw_renderstate.h"
#include "hw_drawinfo.h" #include "hw_drawinfo.h"
#include "hw_fakeflat.h"
FMemArena RenderDataAllocator(1024*1024); // Use large blocks to reduce allocation time. FMemArena RenderDataAllocator(1024*1024); // Use large blocks to reduce allocation time.

View file

@ -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!!! // these are not the same as ytop and ybottom!!!
float zceil[2]; float zceil[2];
@ -198,6 +197,7 @@ public:
public: public:
seg_t * seg; // this gives the easiest access to all other structs involved seg_t * seg; // this gives the easiest access to all other structs involved
subsector_t * sub; // For polyobjects subsector_t * sub; // For polyobjects
sector_t *frontsector, *backsector;
//private: //private:
void PutWall(HWDrawInfo *di, bool translucent); void PutWall(HWDrawInfo *di, bool translucent);
@ -411,7 +411,7 @@ struct GLDecal
int rellight; int rellight;
float alpha; float alpha;
FColormap Colormap; FColormap Colormap;
secplane_t bottomplane; sector_t *frontsector;
FVector3 Normal; FVector3 Normal;
void DrawDecal(HWDrawInfo *di, FRenderState &state); void DrawDecal(HWDrawInfo *di, FRenderState &state);

View file

@ -36,6 +36,9 @@
#include "hwrenderer/utility/hw_cvars.h" #include "hwrenderer/utility/hw_cvars.h"
#include "r_utility.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; 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 // 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) 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. // visual glitches because upper amd lower textures overlap.
if (back && (sec->MoreFlags & SECMF_OVERLAPPING)) if (back && (sec->MoreFlags & SECMF_OVERLAPPING))
{ {
if (fakesectorbuffer && fakesectorbuffer[sec->sectornum]) return fakesectorbuffer[sec->sectornum];
auto dest = localcopy? localcopy : allocateSector(sec);
*dest = *sec; *dest = *sec;
dest->ceilingplane = sec->floorplane; dest->ceilingplane = sec->floorplane;
dest->ceilingplane.FlipVert(); dest->ceilingplane.FlipVert();
@ -215,6 +239,12 @@ sector_t * hw_FakeFlat(sector_t * sec, sector_t * dest, area_t in_area, bool bac
} }
#endif #endif
if (fakesectorbuffer && fakesectorbuffer[sec->sectornum])
{
return fakesectorbuffer[sec->sectornum];
}
assert(!(isWorkerThread && localcopy == nullptr));
if (in_area==area_above) if (in_area==area_above)
{ {
if (sec->heightsec->MoreFlags&SECMF_FAKEFLOORONLY /*|| sec->GetTexture(sector_t::ceiling)==skyflatnum*/) in_area=area_normal; 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); int diffTex = (sec->heightsec->MoreFlags & SECMF_CLIPFAKEPLANES);
sector_t * s = sec->heightsec; sector_t * s = sec->heightsec;
#if 0 auto dest = localcopy ? localcopy : allocateSector(sec);
*dest=*sec; // This will invoke the copy operator which isn't really needed here. Memcpy is faster. *dest = *sec;
#else
memcpy(dest, sec, sizeof(sector_t));
#endif
// Replace floor and ceiling height with control sector's heights. // Replace floor and ceiling height with control sector's heights.
if (diffTex) 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; 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->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; 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; 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::ceiling, diffTex ? sec->GetTexture(sector_t::ceiling) : s->GetTexture(sector_t::ceiling), false);
dest->SetTexture(sector_t::floor, 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; return dest;
} }
void hw_ClearFakeFlat()
{
FakeSectorAllocator.FreeAll();
fakesectorbuffer = nullptr;
}

View file

@ -11,6 +11,7 @@ enum area_t : int
// Global functions. // Global functions.
bool hw_CheckClip(side_t * sidedef, sector_t * frontsector, sector_t * backsector); 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); area_t hw_CheckViewArea(vertex_t *v1, vertex_t *v2, sector_t *frontsector, sector_t *backsector);

View file

@ -38,8 +38,7 @@
#include "hwrenderer/data/flatvertices.h" #include "hwrenderer/data/flatvertices.h"
#include "hwrenderer/dynlights/hw_lightbuffer.h" #include "hwrenderer/dynlights/hw_lightbuffer.h"
#include "hwrenderer/scene/hw_portal.h" #include "hwrenderer/scene/hw_portal.h"
#include "hw_fakeflat.h"
sector_t * hw_FakeFlat(sector_t * sec, sector_t * dest, area_t in_area, bool back);
//========================================================================== //==========================================================================
// //
@ -53,32 +52,31 @@ void HWDrawInfo::DispatchRenderHacks()
TMap<int, gl_floodrendernode*>::Pair *fpair; TMap<int, gl_floodrendernode*>::Pair *fpair;
TMap<int, gl_subsectorrendernode*>::Iterator ofi(otherFloorPlanes); TMap<int, gl_subsectorrendernode*>::Iterator ofi(otherFloorPlanes);
GLFlat glflat; GLFlat glflat;
sector_t fakesec;
glflat.section = nullptr; glflat.section = nullptr;
while (ofi.NextPair(pair)) 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); glflat.ProcessSector(this, sec, SSRF_RENDERFLOOR | SSRF_PLANEHACK);
} }
TMap<int, gl_subsectorrendernode*>::Iterator oci(otherCeilingPlanes); TMap<int, gl_subsectorrendernode*>::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); glflat.ProcessSector(this, sec, SSRF_RENDERCEILING | SSRF_PLANEHACK);
} }
TMap<int, gl_floodrendernode*>::Iterator ffi(floodFloorSegs); TMap<int, gl_floodrendernode*>::Iterator ffi(floodFloorSegs);
while (ffi.NextPair(fpair)) 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); glflat.ProcessSector(this, sec, SSRF_RENDERFLOOR | SSRF_FLOODHACK);
} }
TMap<int, gl_floodrendernode*>::Iterator fci(floodCeilingSegs); TMap<int, gl_floodrendernode*>::Iterator fci(floodCeilingSegs);
while (fci.NextPair(fpair)) 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); 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 // Note: if this is a real line between sectors
// we can be sure that render_sector is the real sector! // 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 // Don't bother with slopes
if (sec->ceilingplane.isSlope()) return false; 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 // Note: if this is a real line between sectors
// we can be sure that render_sector is the real sector! // 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 // Don't bother with slopes
if (sec->floorplane.isSlope()) return false; 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 // Note: if this is a real line between sectors
// we can be sure that render_sector is the real sector! // 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 // Don't bother with slopes
if (sec->floorplane.isSlope()) return false; 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 // Note: if this is a real line between sectors
// we can be sure that render_sector is the real sector! // 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 // Don't bother with slopes
if (sec->ceilingplane.isSlope()) return false; 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) void HWDrawInfo::HandleMissingTextures(area_t in_area)
{ {
sector_t fake;
for (unsigned int i = 0; i < MissingUpperTextures.Size(); i++) for (unsigned int i = 0; i < MissingUpperTextures.Size(); i++)
{ {
if (!MissingUpperTextures[i].seg) continue; 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 // 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); float planez = (float)fakesector->GetPlaneTexZ(sector_t::ceiling);
backsub->validcount = validcount; 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 // 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); float planez = (float)fakesector->GetPlaneTexZ(sector_t::floor);
backsub->validcount = validcount; backsub->validcount = validcount;
@ -729,9 +725,8 @@ void HWDrawInfo::CreateFloodPoly(wallseg * ws, FFlatVertex *vertices, float plan
void HWDrawInfo::PrepareUpperGap(seg_t * seg) void HWDrawInfo::PrepareUpperGap(seg_t * seg)
{ {
wallseg ws; wallseg ws;
sector_t ffake, bfake; sector_t * fakefsector = hw_FakeFlat(seg->frontsector, in_area, false);
sector_t * fakefsector = hw_FakeFlat(seg->frontsector, &ffake, in_area, true); sector_t * fakebsector = hw_FakeFlat(seg->backsector, in_area, true);
sector_t * fakebsector = hw_FakeFlat(seg->backsector, &bfake, in_area, false);
vertex_t * v1, *v2; vertex_t * v1, *v2;
@ -786,9 +781,8 @@ void HWDrawInfo::PrepareUpperGap(seg_t * seg)
void HWDrawInfo::PrepareLowerGap(seg_t * seg) void HWDrawInfo::PrepareLowerGap(seg_t * seg)
{ {
wallseg ws; wallseg ws;
sector_t ffake, bfake; sector_t * fakefsector = hw_FakeFlat(seg->frontsector, in_area, false);
sector_t * fakefsector = hw_FakeFlat(seg->frontsector, &ffake, in_area, true); sector_t * fakebsector = hw_FakeFlat(seg->backsector, in_area, true);
sector_t * fakebsector = hw_FakeFlat(seg->backsector, &bfake, in_area, false);
vertex_t * v1, *v2; vertex_t * v1, *v2;
@ -826,13 +820,13 @@ void HWDrawInfo::PrepareLowerGap(seg_t * seg)
CreateFloodPoly(&ws, vertices.first+4, ws.z1, fakebsector, false); CreateFloodPoly(&ws, vertices.first+4, ws.z1, fakebsector, false);
gl_floodrendernode *node = NewFloodRenderNode(); gl_floodrendernode *node = NewFloodRenderNode();
auto pNode = floodCeilingSegs.CheckKey(fakebsector->sectornum); auto pNode = floodFloorSegs.CheckKey(fakebsector->sectornum);
node->next = pNode? *pNode : nullptr; node->next = pNode? *pNode : nullptr;
node->seg = seg; node->seg = seg;
node->vertexindex = vertices.second; 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; if (sub->numlines>2 && !(ss_renderflags[sub->Index()]&SSRF_PROCESSED)) return;
// Must be the exact same visplane // 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) || if (me->GetTexture(sector_t::ceiling) != anchor->GetTexture(sector_t::ceiling) ||
me->ceilingplane != anchor->ceilingplane || me->ceilingplane != anchor->ceilingplane ||
me->GetCeilingLight() != anchor->GetCeilingLight() || 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; if (sub->numlines>2 && !(ss_renderflags[sub->Index()]&SSRF_PROCESSED)) return;
// Must be the exact same visplane // 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) || if (me->GetTexture(sector_t::floor) != anchor->GetTexture(sector_t::floor) ||
me->floorplane != anchor->floorplane || me->floorplane != anchor->floorplane ||
me->GetFloorLight() != anchor->GetFloorLight() || me->GetFloorLight() != anchor->GetFloorLight() ||
@ -1303,7 +1297,7 @@ void HWDrawInfo::ProcessSectorStacks(area_t in_area)
validcount++; validcount++;
for (i=0;i<CeilingStacks.Size (); i++) for (i=0;i<CeilingStacks.Size (); i++)
{ {
sector_t *sec = hw_FakeFlat(CeilingStacks[i], &fakesec, in_area, false); sector_t *sec = hw_FakeFlat(CeilingStacks[i], in_area, false);
auto portal = sec->GetPortalGroup(sector_t::ceiling); auto portal = sec->GetPortalGroup(sector_t::ceiling);
if (portal != NULL) for(int k=0;k<sec->subsectorcount;k++) if (portal != NULL) for(int k=0;k<sec->subsectorcount;k++)
{ {
@ -1347,7 +1341,7 @@ void HWDrawInfo::ProcessSectorStacks(area_t in_area)
validcount++; validcount++;
for (i=0;i<FloorStacks.Size (); i++) for (i=0;i<FloorStacks.Size (); i++)
{ {
sector_t *sec = hw_FakeFlat(FloorStacks[i], &fakesec, in_area, false); sector_t *sec = hw_FakeFlat(FloorStacks[i], in_area, false);
auto portal = sec->GetPortalGroup(sector_t::floor); auto portal = sec->GetPortalGroup(sector_t::floor);
if (portal != NULL) for(int k=0;k<sec->subsectorcount;k++) if (portal != NULL) for(int k=0;k<sec->subsectorcount;k++)
{ {

View file

@ -127,6 +127,7 @@ protected:
uint8_t mFogEnabled; uint8_t mFogEnabled;
uint8_t mTextureEnabled:1; uint8_t mTextureEnabled:1;
uint8_t mGlowEnabled : 1; uint8_t mGlowEnabled : 1;
uint8_t mGradientEnabled : 1;
uint8_t mBrightmapEnabled : 1; uint8_t mBrightmapEnabled : 1;
uint8_t mModelMatrixEnabled : 1; uint8_t mModelMatrixEnabled : 1;
uint8_t mTextureMatrixEnabled : 1; uint8_t mTextureMatrixEnabled : 1;
@ -147,6 +148,7 @@ protected:
FStateVec4 mColor; FStateVec4 mColor;
FStateVec4 mGlowTop, mGlowBottom; FStateVec4 mGlowTop, mGlowBottom;
FStateVec4 mGlowTopPlane, mGlowBottomPlane; FStateVec4 mGlowTopPlane, mGlowBottomPlane;
FStateVec4 mGradientTopPlane, mGradientBottomPlane;
FStateVec4 mSplitTopPlane, mSplitBottomPlane; FStateVec4 mSplitTopPlane, mSplitBottomPlane;
PalEntry mFogColor; PalEntry mFogColor;
PalEntry mObjectColor; PalEntry mObjectColor;
@ -172,7 +174,7 @@ public:
void Reset() void Reset()
{ {
mTextureEnabled = true; mTextureEnabled = true;
mBrightmapEnabled = mFogEnabled = mGlowEnabled = false; mGradientEnabled = mBrightmapEnabled = mFogEnabled = mGlowEnabled = false;
mFogColor.d = -1; mFogColor.d = -1;
mTextureMode = -1; mTextureMode = -1;
mDesaturation = 0; mDesaturation = 0;
@ -201,6 +203,8 @@ public:
mGlowBottom.Set(0.0f, 0.0f, 0.0f, 0.0f); mGlowBottom.Set(0.0f, 0.0f, 0.0f, 0.0f);
mGlowTopPlane.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); 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); mSplitTopPlane.Set(0.0f, 0.0f, 0.0f, 0.0f);
mSplitBottomPlane.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); mDynColor.Set(0.0f, 0.0f, 0.0f, 0.0f);
@ -290,6 +294,11 @@ public:
mGlowEnabled = on; mGlowEnabled = on;
} }
void EnableGradient(bool on)
{
mGradientEnabled = on;
}
void EnableBrightmap(bool on) void EnableBrightmap(bool on)
{ {
mBrightmapEnabled = on; mBrightmapEnabled = on;
@ -324,18 +333,26 @@ public:
void SetGlowPlanes(const secplane_t &top, const secplane_t &bottom) void SetGlowPlanes(const secplane_t &top, const secplane_t &bottom)
{ {
DVector3 tn = top.Normal(); auto &tn = top.Normal();
DVector3 bn = bottom.Normal(); auto &bn = bottom.Normal();
mGlowTopPlane.Set((float)tn.X, (float)tn.Y, (float)(1. / tn.Z), (float)top.fD()); mGlowTopPlane.Set((float)tn.X, (float)tn.Y, (float)top.negiC, (float)top.fD());
mGlowBottomPlane.Set((float)bn.X, (float)bn.Y, (float)(1. / bn.Z), (float)bottom.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) void SetSplitPlanes(const secplane_t &top, const secplane_t &bottom)
{ {
DVector3 tn = top.Normal(); auto &tn = top.Normal();
DVector3 bn = bottom.Normal(); auto &bn = bottom.Normal();
mSplitTopPlane.Set((float)tn.X, (float)tn.Y, (float)(1. / tn.Z), (float)top.fD()); mSplitTopPlane.Set((float)tn.X, (float)tn.Y, (float)top.negiC, (float)top.fD());
mSplitBottomPlane.Set((float)bn.X, (float)bn.Y, (float)(1. / bn.Z), (float)bottom.fD()); mSplitBottomPlane.Set((float)bn.X, (float)bn.Y, (float)bottom.negiC, (float)bottom.fD());
} }
void SetDynLight(float r, float g, float b) void SetDynLight(float r, float g, float b)

View file

@ -207,8 +207,8 @@ void GLSprite::DrawSprite(HWDrawInfo *di, FRenderState &state, bool translucent)
state.EnableSplit(true); state.EnableSplit(true);
} }
secplane_t bottomp = { { 0, 0, -1. }, bottomclip }; secplane_t bottomp = { { 0, 0, -1. }, bottomclip, 1. };
secplane_t topp = { { 0, 0, -1. }, topclip }; secplane_t topp = { { 0, 0, -1. }, topclip, 1. };
for (unsigned i = 0; i < iter; i++) for (unsigned i = 0; i < iter; i++)
{ {
if (lightlist) 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) 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 else
{ {
@ -1287,7 +1289,8 @@ void HWDrawInfo::ProcessActorsInPortal(FLinePortalSpan *glport, area_t in_area)
th->Prev += newpos - savedpos; th->Prev += newpos - savedpos;
GLSprite spr; 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->Angles.Yaw = savedangle;
th->SetXYZ(savedpos); th->SetXYZ(savedpos);
th->Prev -= newpos - savedpos; th->Prev -= newpos - savedpos;

View file

@ -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) void GLWall::RenderTexturedWall(HWDrawInfo *di, FRenderState &state, int rflags)
{ {
int tmode = state.GetTextureMode(); int tmode = state.GetTextureMode();
@ -139,8 +153,8 @@ void GLWall::RenderTexturedWall(HWDrawInfo *di, FRenderState &state, int rflags)
{ {
state.EnableGlow(true); state.EnableGlow(true);
state.SetGlowParams(topglowcolor, bottomglowcolor); state.SetGlowParams(topglowcolor, bottomglowcolor);
state.SetGlowPlanes(frontsector->ceilingplane, frontsector->floorplane);
} }
state.SetGlowPlanes(topplane, bottomplane);
state.SetMaterial(gltexture, flags & 3, 0, -1); state.SetMaterial(gltexture, flags & 3, 0, -1);
if (type == RENDERWALL_M2SNF) 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.SetFog(255, 0, di->isFullbrightScene(), nullptr, false);
} }
state.SetObjectColor(seg->frontsector->SpecialColors[sector_t::walltop] | 0xff000000); if (type != RENDERWALL_COLOR)
state.SetObjectColor2(seg->frontsector->SpecialColors[sector_t::wallbottom] | 0xff000000); {
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); float absalpha = fabsf(alpha);
if (lightlist == nullptr) if (lightlist == nullptr)
@ -167,14 +214,14 @@ void GLWall::RenderTexturedWall(HWDrawInfo *di, FRenderState &state, int rflags)
for (unsigned i = 0; i < lightlist->Size(); i++) 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. // this must use the exact same calculation method as GLWall::Process etc.
float low1 = lowplane.ZatPoint(vertexes[0]); float low1 = lowplane.ZatPoint(vertexes[0]);
float low2 = lowplane.ZatPoint(vertexes[1]); float low2 = lowplane.ZatPoint(vertexes[1]);
if (low1 < ztop[0] || low2 < ztop[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; FColormap thiscm;
thiscm.FadeColor = Colormap.FadeColor; thiscm.FadeColor = Colormap.FadeColor;
thiscm.FogDensity = Colormap.FogDensity; thiscm.FogDensity = Colormap.FogDensity;
@ -193,6 +240,7 @@ void GLWall::RenderTexturedWall(HWDrawInfo *di, FRenderState &state, int rflags)
state.SetObjectColor2(0); state.SetObjectColor2(0);
state.SetTextureMode(tmode); state.SetTextureMode(tmode);
state.EnableGlow(false); 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. // note: we always have a valid sidedef and linedef reference when getting here.
this->seg = seg; this->seg = seg;
this->frontsector = frontsector;
this->backsector = backsector;
vertindex = 0; vertindex = 0;
vertcount = 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; if (frontsector->GetWallGlow(topglowcolor, bottomglowcolor)) flags |= GLWF_GLOW;
topplane = frontsector->ceilingplane;
bottomplane = frontsector->floorplane;
zfloor[0] = ffh1 = segfront->floorplane.ZatPoint(v1); zfloor[0] = ffh1 = segfront->floorplane.ZatPoint(v1);
zfloor[1] = ffh2 = segfront->floorplane.ZatPoint(v2); 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) if (bfh > ffh)
{ {
this->seg = seg; this->seg = seg;
this->frontsector = frontsector;
this->backsector = backsector;
this->sub = NULL; this->sub = NULL;
vertex_t * v1 = seg->v1; vertex_t * v1 = seg->v1;
@ -2129,8 +2179,6 @@ void GLWall::ProcessLowerMiniseg(HWDrawInfo *di, seg_t *seg, sector_t * frontsec
Colormap = frontsector->Colormap; Colormap = frontsector->Colormap;
if (frontsector->GetWallGlow(topglowcolor, bottomglowcolor)) flags |= GLWF_GLOW; if (frontsector->GetWallGlow(topglowcolor, bottomglowcolor)) flags |= GLWF_GLOW;
topplane = frontsector->ceilingplane;
bottomplane = frontsector->floorplane;
dynlightindex = -1; dynlightindex = -1;
zfloor[0] = zfloor[1] = ffh; zfloor[0] = zfloor[1] = ffh;

View file

@ -222,8 +222,7 @@ static WeaponLighting GetWeaponLighting(sector_t *viewsector, const DVector3 &po
} }
else else
{ {
sector_t fs; auto fakesec = hw_FakeFlat(viewsector, in_area, false);
auto fakesec = hw_FakeFlat(viewsector, &fs, in_area, false);
// calculate light level for weapon sprites // calculate light level for weapon sprites
l.lightlevel = hw_ClampLight(fakesec->lightlevel); l.lightlevel = hw_ClampLight(fakesec->lightlevel);

View file

@ -630,6 +630,26 @@ xx(hidden)
xx(blocksight) xx(blocksight)
xx(blockhitscan) 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(Renderstyle)
xx(ceilingplane_a) xx(ceilingplane_a)

View file

@ -4564,6 +4564,20 @@ DEFINE_ACTION_FUNCTION(AActor, A_RaiseSelf)
ACTION_RETURN_BOOL(P_Thing_Raise(self, NULL, (flags & RF_NOCHECKPOSITION))); 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 // CanRaise

View file

@ -2757,11 +2757,63 @@ void A_DoChase (AActor *actor, bool fastchase, FState *meleestate, FState *missi
actor->flags &= ~MF_INCHASE; 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) // 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->flags = oldflags;
corpsehit->radius = oldradius; corpsehit->radius = oldradius;
corpsehit->Height = oldheight; corpsehit->Height = oldheight;
if (!check) continue; if (!check || !P_CanResurrect(self, corpsehit)) continue;
// got one! // got one!
temp = self->target; temp = self->target;

View file

@ -210,16 +210,14 @@ static bool format5;
static bool LoadGLVertexes(FileReader &lump) static bool LoadGLVertexes(FileReader &lump)
{ {
uint8_t *gldata;
int i; int i;
firstglvertex = level.vertexes.Size(); firstglvertex = level.vertexes.Size();
auto gllen=lump.GetLength();
gldata = new uint8_t[gllen];
lump.Seek(0, FileReader::SeekSet); 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) 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", Printf("GL nodes v%d found. This format is not supported by " GAMENAME "\n",
(*(int *)gldata == gNd4)? 4:1); (*(int *)gldata == gNd4)? 4:1);
delete [] gldata;
return false; return false;
} }
else format5=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.); level.vertexes[i].set(LittleLong(mgl->x)/65536., LittleLong(mgl->y)/65536.);
mgl++; mgl++;
} }
delete[] gldata;
return true; return true;
} }
@ -288,139 +284,119 @@ static inline int checkGLVertex3(int num)
static bool LoadGLSegs(FileReader &lump) static bool LoadGLSegs(FileReader &lump)
{ {
char *data;
int i; int i;
line_t *ldef=NULL; line_t *ldef=NULL;
int numsegs = (int)lump.GetLength();
data= new char[numsegs];
lump.Seek(0, FileReader::SeekSet); lump.Seek(0, FileReader::SeekSet);
lump.Read(data, numsegs); auto data = lump.Read();
int numsegs = (int)lump.GetLength();
auto &segs = level.segs; auto &segs = level.segs;
#ifdef _MSC_VER if (!format5 && memcmp(data.Data(), "gNd3", 4))
__try
#endif
{ {
if (!format5 && memcmp(data, "gNd3", 4)) numsegs/=sizeof(glseg_t);
{ level.segs.Alloc(numsegs);
numsegs/=sizeof(glseg_t); memset(&segs[0],0,sizeof(seg_t)*numsegs);
level.segs.Alloc(numsegs);
memset(&segs[0],0,sizeof(seg_t)*numsegs);
glseg_t * ml = (glseg_t*)data; glseg_t * ml = (glseg_t*)data.Data();
for(i = 0; i < numsegs; i++) for(i = 0; i < numsegs; i++)
{ {
// check for gl-vertices // check for gl-vertices
segs[i].v1 = &level.vertexes[checkGLVertex(LittleShort(ml->v1))]; segs[i].v1 = &level.vertexes[checkGLVertex(LittleShort(ml->v1))];
segs[i].v2 = &level.vertexes[checkGLVertex(LittleShort(ml->v2))]; segs[i].v2 = &level.vertexes[checkGLVertex(LittleShort(ml->v2))];
segs[i].PartnerSeg = ml->partner == 0xFFFF ? nullptr : &segs[LittleShort(ml->partner)]; segs[i].PartnerSeg = ml->partner == 0xFFFF ? nullptr : &segs[LittleShort(ml->partner)];
if(ml->linedef != 0xffff) if(ml->linedef != 0xffff)
{ {
ldef = &level.lines[LittleShort(ml->linedef)]; ldef = &level.lines[LittleShort(ml->linedef)];
segs[i].linedef = ldef; segs[i].linedef = ldef;
ml->side=LittleShort(ml->side); ml->side=LittleShort(ml->side);
segs[i].sidedef = ldef->sidedef[ml->side]; segs[i].sidedef = ldef->sidedef[ml->side];
if (ldef->sidedef[ml->side] != NULL) if (ldef->sidedef[ml->side] != NULL)
{ {
segs[i].frontsector = ldef->sidedef[ml->side]->sector; 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;
}
} }
else else
{ {
segs[i].linedef = NULL;
segs[i].sidedef = NULL;
segs[i].frontsector = 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 }
{ else
if (!format5) numsegs-=4; {
numsegs/=sizeof(glseg3_t); if (!format5) numsegs-=4;
level.segs.Alloc(numsegs); numsegs/=sizeof(glseg3_t);
memset(&segs[0],0,sizeof(seg_t)*numsegs); level.segs.Alloc(numsegs);
memset(&segs[0],0,sizeof(seg_t)*numsegs);
glseg3_t * ml = (glseg3_t*)(data+ (format5? 0:4)); glseg3_t * ml = (glseg3_t*)(data.Data() + (format5? 0:4));
for(i = 0; i < numsegs; i++) for(i = 0; i < numsegs; i++)
{ // check for gl-vertices { // check for gl-vertices
segs[i].v1 = &level.vertexes[checkGLVertex3(LittleLong(ml->v1))]; segs[i].v1 = &level.vertexes[checkGLVertex3(LittleLong(ml->v1))];
segs[i].v2 = &level.vertexes[checkGLVertex3(LittleLong(ml->v2))]; segs[i].v2 = &level.vertexes[checkGLVertex3(LittleLong(ml->v2))];
const uint32_t partner = LittleLong(ml->partner); const uint32_t partner = LittleLong(ml->partner);
segs[i].PartnerSeg = DWORD_MAX == partner ? nullptr : &segs[partner]; segs[i].PartnerSeg = DWORD_MAX == partner ? nullptr : &segs[partner];
if(ml->linedef != 0xffff) // skip minisegs if(ml->linedef != 0xffff) // skip minisegs
{ {
ldef = &level.lines[LittleLong(ml->linedef)]; ldef = &level.lines[LittleLong(ml->linedef)];
segs[i].linedef = ldef; segs[i].linedef = ldef;
ml->side=LittleShort(ml->side); ml->side=LittleShort(ml->side);
segs[i].sidedef = ldef->sidedef[ml->side]; segs[i].sidedef = ldef->sidedef[ml->side];
if (ldef->sidedef[ml->side] != NULL) if (ldef->sidedef[ml->side] != NULL)
{ {
segs[i].frontsector = ldef->sidedef[ml->side]->sector; 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;
}
} }
else else
{ {
segs[i].linedef = NULL;
segs[i].sidedef = NULL;
segs[i].frontsector = 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 return true;
__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
} }
@ -432,23 +408,20 @@ static bool LoadGLSegs(FileReader &lump)
static bool LoadGLSubsectors(FileReader &lump) static bool LoadGLSubsectors(FileReader &lump)
{ {
char * datab;
int i; int i;
int numsubsectors = (int)lump.GetLength(); int numsubsectors = (int)lump.GetLength();
datab = new char[numsubsectors];
lump.Seek(0, FileReader::SeekSet); lump.Seek(0, FileReader::SeekSet);
lump.Read(datab, numsubsectors); auto datab = lump.Read();
if (numsubsectors == 0) if (numsubsectors == 0)
{ {
delete [] datab;
return false; 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); numsubsectors /= sizeof(mapsubsector_t);
level.subsectors.Alloc(numsubsectors); level.subsectors.Alloc(numsubsectors);
auto &subsectors = level.subsectors; auto &subsectors = level.subsectors;
@ -461,14 +434,13 @@ static bool LoadGLSubsectors(FileReader &lump)
if (subsectors[i].numlines == 0) if (subsectors[i].numlines == 0)
{ {
delete [] datab;
return false; return false;
} }
} }
} }
else 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); numsubsectors /= sizeof(gl3_mapsubsector_t);
level.subsectors.Alloc(numsubsectors); level.subsectors.Alloc(numsubsectors);
auto &subsectors = level.subsectors; auto &subsectors = level.subsectors;
@ -481,7 +453,6 @@ static bool LoadGLSubsectors(FileReader &lump)
if (subsectors[i].numlines == 0) if (subsectors[i].numlines == 0)
{ {
delete [] datab;
return false; 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. // 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) if (lastseg->v2 != firstseg->v1)
{ {
delete [] datab;
return false; return false;
} }
} }
delete [] datab;
return true; return true;
} }
@ -522,7 +491,7 @@ static bool LoadNodes (FileReader &lump)
int j; int j;
int k; int k;
node_t* no; node_t* no;
uint16_t* used; TArray<uint16_t> used;
if (!format5) if (!format5)
{ {
@ -534,11 +503,11 @@ static bool LoadNodes (FileReader &lump)
level.nodes.Alloc(numnodes); level.nodes.Alloc(numnodes);
lump.Seek(0, FileReader::SeekSet); lump.Seek(0, FileReader::SeekSet);
basemn = mn = new mapnode_t[numnodes]; auto buf = lump.Read();
lump.Read(mn, lump.GetLength()); basemn = mn = (mapnode_t*)buf.Data();
used = (uint16_t *)alloca (sizeof(uint16_t)*numnodes); used.Resize(numnodes);
memset (used, 0, sizeof(uint16_t)*numnodes); memset (used.Data(), 0, sizeof(uint16_t)*numnodes);
no = &level.nodes[0]; no = &level.nodes[0];
@ -556,19 +525,16 @@ static bool LoadNodes (FileReader &lump)
child &= ~NF_SUBSECTOR; child &= ~NF_SUBSECTOR;
if (child >= level.subsectors.Size()) if (child >= level.subsectors.Size())
{ {
delete [] basemn;
return false; return false;
} }
no->children[j] = (uint8_t *)&level.subsectors[child] + 1; no->children[j] = (uint8_t *)&level.subsectors[child] + 1;
} }
else if (child >= numnodes) else if (child >= numnodes)
{ {
delete [] basemn;
return false; return false;
} }
else if (used[child]) else if (used[child])
{ {
delete [] basemn;
return false; return false;
} }
else else
@ -582,7 +548,6 @@ static bool LoadNodes (FileReader &lump)
} }
} }
} }
delete [] basemn;
} }
else else
{ {
@ -594,11 +559,11 @@ static bool LoadNodes (FileReader &lump)
level.nodes.Alloc(numnodes); level.nodes.Alloc(numnodes);
lump.Seek(0, FileReader::SeekSet); lump.Seek(0, FileReader::SeekSet);
basemn = mn = new gl5_mapnode_t[numnodes]; auto buf = lump.Read();
lump.Read(mn, lump.GetLength()); basemn = mn = (gl5_mapnode_t*)buf.Data();
used = (uint16_t *)alloca (sizeof(uint16_t)*numnodes); used.Resize(numnodes);
memset (used, 0, sizeof(uint16_t)*numnodes); memset(used.Data(), 0, sizeof(uint16_t)*numnodes);
no = &level.nodes[0]; no = &level.nodes[0];
@ -616,19 +581,16 @@ static bool LoadNodes (FileReader &lump)
child &= ~GL5_NF_SUBSECTOR; child &= ~GL5_NF_SUBSECTOR;
if ((unsigned)child >= level.subsectors.Size()) if ((unsigned)child >= level.subsectors.Size())
{ {
delete [] basemn;
return false; return false;
} }
no->children[j] = (uint8_t *)&level.subsectors[child] + 1; no->children[j] = (uint8_t *)&level.subsectors[child] + 1;
} }
else if ((unsigned)child >= numnodes) else if ((unsigned)child >= numnodes)
{ {
delete [] basemn;
return false; return false;
} }
else if (used[child]) else if (used[child])
{ {
delete [] basemn;
return false; return false;
} }
else else
@ -642,7 +604,6 @@ static bool LoadNodes (FileReader &lump)
} }
} }
} }
delete [] basemn;
} }
return true; return true;
} }
@ -1097,31 +1058,30 @@ static void CreateCachedNodes(MapData *map)
} }
uLongf outlen = ZNodes.Size(); uLongf outlen = ZNodes.Size();
uint8_t *compressed; TArray<Bytef> compressed;
int offset = level.lines.Size() * 8 + 12 + 16; int offset = level.lines.Size() * 8 + 12 + 16;
int r; int r;
do do
{ {
compressed = new Bytef[outlen + offset]; compressed.Resize(outlen + offset);
r = compress (compressed + offset, &outlen, &ZNodes[0], ZNodes.Size()); r = compress (compressed.Data() + offset, &outlen, &ZNodes[0], ZNodes.Size());
if (r == Z_BUF_ERROR) if (r == Z_BUF_ERROR)
{ {
delete[] compressed;
outlen += 1024; outlen += 1024;
} }
} }
while (r == Z_BUF_ERROR); while (r == Z_BUF_ERROR);
memcpy(compressed, "CACH", 4); memcpy(compressed.Data(), "CACH", 4);
uint32_t len = LittleLong(level.lines.Size()); uint32_t len = LittleLong(level.lines.Size());
memcpy(compressed+4, &len, 4); memcpy(&compressed[4], &len, 4);
map->GetChecksum(compressed+8); map->GetChecksum(&compressed[8]);
for (unsigned i = 0; i < level.lines.Size(); i++) 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())) }; 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); FString path = CreateCacheName(map, true);
FileWriter *fw = FileWriter::Open(path); FileWriter *fw = FileWriter::Open(path);
@ -1129,7 +1089,7 @@ static void CreateCachedNodes(MapData *map)
if (fw != nullptr) if (fw != nullptr)
{ {
const size_t length = outlen + offset; 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()); 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()); 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 md5[16];
uint8_t md5map[16]; uint8_t md5map[16];
uint32_t numlin; uint32_t numlin;
uint32_t *verts = NULL; TArray<uint32_t> verts;
FString path = CreateCacheName(map, false); FString path = CreateCacheName(map, false);
FileReader fr; FileReader fr;
if (!fr.OpenFile(path)) return false; if (!fr.OpenFile(path)) return false;
if (fr.Read(magic, 4) != 4) goto errorout; if (fr.Read(magic, 4) != 4) return false;
if (memcmp(magic, "CACH", 4)) goto errorout; 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); 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); map->GetChecksum(md5map);
if (memcmp(md5, md5map, 16)) goto errorout; if (memcmp(md5, md5map, 16)) return false;
verts = new uint32_t[numlin * 8]; verts.Resize(numlin * 2);
if (fr.Read(verts, 8 * numlin) != 8 * numlin) goto errorout; if (fr.Read(verts.Data(), 8 * numlin) != 8 * numlin) return false;
if (fr.Read(magic, 4) != 4) goto errorout; if (fr.Read(magic, 4) != 4) return false;
if (memcmp(magic, "ZGL2", 4) && memcmp(magic, "ZGL3", 4)) goto errorout; if (memcmp(magic, "ZGL2", 4) && memcmp(magic, "ZGL3", 4)) return false;
try try
@ -1186,7 +1144,7 @@ static bool CheckCachedNodes(MapData *map)
level.subsectors.Clear(); level.subsectors.Clear();
level.segs.Clear(); level.segs.Clear();
level.nodes.Clear(); level.nodes.Clear();
goto errorout; return false;
} }
for(auto &line : level.lines) for(auto &line : level.lines)
@ -1195,16 +1153,7 @@ static bool CheckCachedNodes(MapData *map)
line.v1 = &level.vertexes[LittleLong(verts[i*2])]; line.v1 = &level.vertexes[LittleLong(verts[i*2])];
line.v2 = &level.vertexes[LittleLong(verts[i*2+1])]; line.v2 = &level.vertexes[LittleLong(verts[i*2+1])];
} }
delete [] verts;
return true; return true;
errorout:
if (verts != NULL)
{
delete[] verts;
}
return false;
} }
UNSAFE_CCMD(clearnodecache) UNSAFE_CCMD(clearnodecache)
@ -1308,32 +1257,6 @@ void P_SetRenderSector()
TArray<subsector_t *> undetermined; TArray<subsector_t *> undetermined;
subsector_t * ss; 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. // Check for incorrect partner seg info so that the following code does not crash.
for (auto &seg : level.segs) for (auto &seg : level.segs)

View file

@ -1086,7 +1086,7 @@ static int DamageMobj (AActor *target, AActor *inflictor, AActor *source, int da
damage = int(damage * source->DamageMultiply); damage = int(damage * source->DamageMultiply);
// Handle active damage modifiers (e.g. PowerDamage) // Handle active damage modifiers (e.g. PowerDamage)
if (damage > 0) if (damage > 0 && !(flags & DMG_NO_ENHANCE))
{ {
damage = source->GetModifiedDamage(mod, damage, false); damage = source->GetModifiedDamage(mod, damage, false);
} }

View file

@ -162,6 +162,7 @@ void P_Thing_SetVelocity(AActor *actor, const DVector3 &vec, bool add, bool setb
void P_RemoveThing(AActor * actor); void P_RemoveThing(AActor * actor);
bool P_Thing_Raise(AActor *thing, AActor *raiser, int nocheck = false); bool P_Thing_Raise(AActor *thing, AActor *raiser, int nocheck = false);
bool P_Thing_CanRaise(AActor *thing); bool P_Thing_CanRaise(AActor *thing);
bool P_CanResurrect(AActor *ththing, AActor *thing);
PClassActor *P_GetSpawnableType(int spawnnum); PClassActor *P_GetSpawnableType(int spawnnum);
void InitSpawnablesFromMapinfo(); void InitSpawnablesFromMapinfo();
int P_Thing_CheckInputNum(player_t *p, int inputnum); int P_Thing_CheckInputNum(player_t *p, int inputnum);
@ -454,6 +455,7 @@ enum EDmgFlags
DMG_USEANGLE = 512, DMG_USEANGLE = 512,
DMG_NO_PAIN = 1024, DMG_NO_PAIN = 1024,
DMG_EXPLOSION = 2048, DMG_EXPLOSION = 2048,
DMG_NO_ENHANCE = 4096,
}; };

View file

@ -7063,7 +7063,7 @@ void SpawnShootDecal(AActor *t1, const FTraceResults &trace)
if (t1->player != NULL && t1->player->ReadyWeapon != NULL) if (t1->player != NULL && t1->player->ReadyWeapon != NULL)
{ {
decalbase = t1->player->ReadyWeapon->GetDefault()->DecalGenerator; decalbase = t1->player->ReadyWeapon->DecalGenerator;
} }
else else
{ {

View file

@ -105,6 +105,9 @@ FSerializer &Serialize(FSerializer &arc, const char *key, side_t::part &part, si
("yscale", part.yScale, def->yScale) ("yscale", part.yScale, def->yScale)
("texture", part.texture, def->texture) ("texture", part.texture, def->texture)
("interpolation", part.interpolation) ("interpolation", part.interpolation)
("flags", part.flags, def->flags)
("color1", part.SpecialColors[0], def->SpecialColors[0])
("color2", part.SpecialColors[1], def->SpecialColors[1])
.EndObject(); .EndObject();
} }
return arc; return arc;

View file

@ -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) DEFINE_ACTION_FUNCTION(_Sector, SetSpecialColor)
{ {
PARAM_SELF_STRUCT_PROLOGUE(sector_t); PARAM_SELF_STRUCT_PROLOGUE(sector_t);
@ -2241,6 +2230,26 @@ DEFINE_ACTION_FUNCTION(_Sector, NextLowestFloorAt)
ACTION_RETURN_INT(self->Index()); 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) DEFINE_ACTION_FUNCTION(_Vertex, Index)
{ {
PARAM_SELF_STRUCT_PROLOGUE(vertex_t); PARAM_SELF_STRUCT_PROLOGUE(vertex_t);

View file

@ -1691,15 +1691,10 @@ uint16_t MakeSkill(int flags)
void P_LoadThings (MapData * map) void P_LoadThings (MapData * map)
{ {
int lumplen = map->Size(ML_THINGS);
int numthings = lumplen / sizeof(mapthing_t);
char *mtp;
mapthing_t *mt; mapthing_t *mt;
auto mtp = map->Read(ML_THINGS);
mtp = new char[lumplen]; int numthings = mtp.Size() / sizeof(mapthing_t);
map->Read(ML_THINGS, mtp); mt = (mapthing_t*)mtp.Data();
mt = (mapthing_t*)mtp;
MapThingsConverted.Resize(numthings); MapThingsConverted.Resize(numthings);
FMapThing *mti = &MapThingsConverted[0]; FMapThing *mti = &MapThingsConverted[0];
@ -1767,7 +1762,6 @@ void P_LoadThings (MapData * map)
if (flags & BTF_NOTSINGLE) mti[i].flags &= ~MTF_SINGLE; if (flags & BTF_NOTSINGLE) mti[i].flags &= ~MTF_SINGLE;
} }
} }
delete [] mtp;
} }
//=========================================================================== //===========================================================================
@ -2109,29 +2103,24 @@ void P_LoadLineDefs (MapData * map)
{ {
int i, skipped; int i, skipped;
line_t *ld; line_t *ld;
int lumplen = map->Size(ML_LINEDEFS);
char * mldf;
maplinedef_t *mld; 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); linemap.Resize(numlines);
mldf = new char[lumplen];
map->Read(ML_LINEDEFS, mldf);
// [RH] Count the number of sidedef references. This is the number of // [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. // sidedefs we need. The actual number in the SIDEDEFS lump might be less.
// Lines with 0 length are also removed. // Lines with 0 length are also removed.
for (skipped = sidecount = i = 0; i < numlines; ) for (skipped = sidecount = i = 0; i < numlines; )
{ {
mld = ((maplinedef_t*)mldf) + i; mld = ((maplinedef_t*)mldf.Data()) + i;
unsigned v1 = LittleShort(mld->v1); unsigned v1 = LittleShort(mld->v1);
unsigned v2 = LittleShort(mld->v2); unsigned v2 = LittleShort(mld->v2);
if (v1 >= level.vertexes.Size() || v2 >= level.vertexes.Size()) 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()); 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 || else if (v1 == v2 ||
@ -2164,7 +2153,7 @@ void P_LoadLineDefs (MapData * map)
P_AllocateSideDefs (map, sidecount); P_AllocateSideDefs (map, sidecount);
mld = (maplinedef_t *)mldf; mld = (maplinedef_t *)mldf.Data();
ld = &level.lines[0]; ld = &level.lines[0];
for (i = 0; i < numlines; i++, mld++, ld++) 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_WRAPMIDTEX) ld->flags |= ML_WRAP_MIDTEX;
if (level.flags2 & LEVEL2_CHECKSWITCHRANGE) ld->flags |= ML_CHECKSWITCHRANGE; 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]; cycle_t times[20];
#if 0 #if 0
@ -3674,7 +3662,7 @@ void P_SetupLevel (const char *lumpname, int position, bool newGame)
level.SetMusicVolume(level.MusicVolume); level.SetMusicVolume(level.MusicVolume);
for (i = 0; i < MAXPLAYERS; ++i) for (i = 0; i < MAXPLAYERS; ++i)
{ {
players[i].killcount = players[i].secretcount players[i].killcount = players[i].secretcount
= players[i].itemcount = 0; = players[i].itemcount = 0;
} }
} }
@ -3695,16 +3683,16 @@ void P_SetupLevel (const char *lumpname, int position, bool newGame)
translationtables[TRANSLATION_LevelScripted].Clear(); translationtables[TRANSLATION_LevelScripted].Clear();
// Initial height of PointOfView will be set by player think. // 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. // Make sure all sounds are stopped before Z_FreeTags.
S_Start (); S_Start();
// [RH] clear out the mid-screen message // [RH] clear out the mid-screen message
C_MidPrint (NULL, NULL); C_MidPrint(NULL, NULL);
// Free all level data from the previous map // Free all level data from the previous map
P_FreeLevelData (); P_FreeLevelData();
MapData *map = P_OpenMapData(lumpname, true); MapData *map = P_OpenMapData(lumpname, true);
if (map == NULL) 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)]; uint8_t *mapdata = new uint8_t[map->Size(0)];
map->Read(0, mapdata); map->Read(0, mapdata);
times[0].Clock(); times[0].Clock();
buildmap = P_LoadBuildMap (mapdata, map->Size(0), &buildthings, &numbuildthings); buildmap = P_LoadBuildMap(mapdata, map->Size(0), &buildthings, &numbuildthings);
times[0].Unclock(); times[0].Unclock();
delete[] mapdata; delete[] mapdata;
} }
@ -3748,10 +3736,10 @@ void P_SetupLevel (const char *lumpname, int position, bool newGame)
ForceNodeBuild = gennodes; ForceNodeBuild = gennodes;
// [RH] Load in the BEHAVIOR lump // [RH] Load in the BEHAVIOR lump
FBehavior::StaticUnloadModules (); FBehavior::StaticUnloadModules();
if (map->HasBehavior) if (map->HasBehavior)
{ {
P_LoadBehavior (map); P_LoadBehavior(map);
level.maptype = MAPTYPE_HEXEN; level.maptype = MAPTYPE_HEXEN;
} }
else 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? // Has the user overridden the game's default translator with a commandline parameter?
translator = Args->CheckValue("-xlat"); translator = Args->CheckValue("-xlat");
if (translator == NULL) if (translator == NULL)
{ {
// Use the game's default. // Use the game's default.
translator = gameinfo.translator.GetChars(); translator = gameinfo.translator.GetChars();
@ -3808,25 +3796,25 @@ void P_SetupLevel (const char *lumpname, int position, bool newGame)
level.flags2 |= LEVEL2_DUMMYSWITCHES; level.flags2 |= LEVEL2_DUMMYSWITCHES;
} }
FBehavior::StaticLoadDefaultModules (); FBehavior::StaticLoadDefaultModules();
#ifndef NO_EDATA #ifndef NO_EDATA
LoadMapinfoACSLump(); LoadMapinfoACSLump();
#endif #endif
P_LoadStrifeConversations (map, lumpname); P_LoadStrifeConversations(map, lumpname);
FMissingTextureTracker missingtex; FMissingTextureTracker missingtex;
if (!map->isText) if (!map->isText)
{ {
times[0].Clock(); times[0].Clock();
P_LoadVertexes (map); P_LoadVertexes(map);
times[0].Unclock(); times[0].Unclock();
// Check for maps without any BSP data at all (e.g. SLIGE) // Check for maps without any BSP data at all (e.g. SLIGE)
times[1].Clock(); times[1].Clock();
P_LoadSectors (map, missingtex); P_LoadSectors(map, missingtex);
times[1].Unclock(); times[1].Unclock();
times[2].Clock(); times[2].Clock();
@ -3834,23 +3822,23 @@ void P_SetupLevel (const char *lumpname, int position, bool newGame)
times[3].Clock(); times[3].Clock();
if (!map->HasBehavior) if (!map->HasBehavior)
P_LoadLineDefs (map); P_LoadLineDefs(map);
else else
P_LoadLineDefs2 (map); // [RH] Load Hexen-style linedefs P_LoadLineDefs2(map); // [RH] Load Hexen-style linedefs
times[3].Unclock(); times[3].Unclock();
times[4].Clock(); times[4].Clock();
P_LoadSideDefs2 (map, missingtex); P_LoadSideDefs2(map, missingtex);
times[4].Unclock(); times[4].Unclock();
times[5].Clock(); times[5].Clock();
P_FinishLoadingLineDefs (); P_FinishLoadingLineDefs();
times[5].Unclock(); times[5].Unclock();
if (!map->HasBehavior) if (!map->HasBehavior)
P_LoadThings (map); P_LoadThings(map);
else else
P_LoadThings2 (map); // [RH] Load Hexen-style things P_LoadThings2(map); // [RH] Load Hexen-style things
} }
else else
{ {
@ -3862,7 +3850,7 @@ void P_SetupLevel (const char *lumpname, int position, bool newGame)
SetCompatibilityParams(checksum); SetCompatibilityParams(checksum);
times[6].Clock(); times[6].Clock();
P_LoopSidedefs (true); P_LoopSidedefs(true);
times[6].Unclock(); times[6].Unclock();
linemap.Clear(); linemap.Clear();
@ -3881,36 +3869,36 @@ void P_SetupLevel (const char *lumpname, int position, bool newGame)
{ {
// Check for compressed nodes first, then uncompressed nodes // Check for compressed nodes first, then uncompressed nodes
FileReader *fr = nullptr; 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) if (map->Size(ML_ZNODES) != 0)
{ {
// Test normal nodes first // Test normal nodes first
fr = &map->Reader(ML_ZNODES); fr = &map->Reader(ML_ZNODES);
idcheck = MAKE_ID('Z','N','O','D'); idcheck = MAKE_ID('Z', 'N', 'O', 'D');
idcheck2 = MAKE_ID('X','N','O','D'); idcheck2 = MAKE_ID('X', 'N', 'O', 'D');
} }
else if (map->Size(ML_GLZNODES) != 0) else if (map->Size(ML_GLZNODES) != 0)
{ {
fr = &map->Reader(ML_GLZNODES); fr = &map->Reader(ML_GLZNODES);
idcheck = MAKE_ID('Z','G','L','N'); idcheck = MAKE_ID('Z', 'G', 'L', 'N');
idcheck2 = MAKE_ID('Z','G','L','2'); idcheck2 = MAKE_ID('Z', 'G', 'L', '2');
idcheck3 = MAKE_ID('Z','G','L','3'); idcheck3 = MAKE_ID('Z', 'G', 'L', '3');
idcheck4 = MAKE_ID('X','G','L','N'); idcheck4 = MAKE_ID('X', 'G', 'L', 'N');
idcheck5 = MAKE_ID('X','G','L','2'); idcheck5 = MAKE_ID('X', 'G', 'L', '2');
idcheck6 = MAKE_ID('X','G','L','3'); 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)) if (id != 0 && (id == idcheck || id == idcheck2 || id == idcheck3 || id == idcheck4 || id == idcheck5 || id == idcheck6))
{ {
try try
{ {
P_LoadZNodes (*fr, id); P_LoadZNodes(*fr, id);
} }
catch (CRecoverableError &error) catch (CRecoverableError &error)
{ {
Printf ("Error loading nodes: %s\n", error.GetMessage()); Printf("Error loading nodes: %s\n", error.GetMessage());
ForceNodeBuild = true; ForceNodeBuild = true;
level.subsectors.Clear(); level.subsectors.Clear();
@ -3927,29 +3915,29 @@ void P_SetupLevel (const char *lumpname, int position, bool newGame)
if (!P_CheckV4Nodes(map)) if (!P_CheckV4Nodes(map))
{ {
times[7].Clock(); times[7].Clock();
P_LoadSubsectors<mapsubsector_t, mapseg_t> (map); P_LoadSubsectors<mapsubsector_t, mapseg_t>(map);
times[7].Unclock(); times[7].Unclock();
times[8].Clock(); times[8].Clock();
if (!ForceNodeBuild) P_LoadNodes<mapnode_t, mapsubsector_t> (map); if (!ForceNodeBuild) P_LoadNodes<mapnode_t, mapsubsector_t>(map);
times[8].Unclock(); times[8].Unclock();
times[9].Clock(); times[9].Clock();
if (!ForceNodeBuild) P_LoadSegs<mapseg_t> (map); if (!ForceNodeBuild) P_LoadSegs<mapseg_t>(map);
times[9].Unclock(); times[9].Unclock();
} }
else else
{ {
times[7].Clock(); times[7].Clock();
P_LoadSubsectors<mapsubsector4_t, mapseg4_t> (map); P_LoadSubsectors<mapsubsector4_t, mapseg4_t>(map);
times[7].Unclock(); times[7].Unclock();
times[8].Clock(); times[8].Clock();
if (!ForceNodeBuild) P_LoadNodes<mapnode4_t, mapsubsector4_t> (map); if (!ForceNodeBuild) P_LoadNodes<mapnode4_t, mapsubsector4_t>(map);
times[8].Unclock(); times[8].Unclock();
times[9].Clock(); times[9].Clock();
if (!ForceNodeBuild) P_LoadSegs<mapseg4_t> (map); if (!ForceNodeBuild) P_LoadSegs<mapseg4_t>(map);
times[9].Unclock(); 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 loading the regular nodes failed try GL nodes before considering a rebuild
if (ForceNodeBuild) if (ForceNodeBuild)
{ {
if (P_LoadGLNodes(map)) if (P_LoadGLNodes(map))
{ {
ForceNodeBuild = false; ForceNodeBuild = false;
reloop = true; reloop = true;
@ -3969,16 +3957,16 @@ void P_SetupLevel (const char *lumpname, int position, bool newGame)
} }
else reloop = true; else reloop = true;
uint64_t startTime=0, endTime=0; uint64_t startTime = 0, endTime = 0;
bool BuildGLNodes; bool BuildGLNodes;
if (ForceNodeBuild) if (ForceNodeBuild)
{ {
BuildGLNodes = RequireGLNodes || multiplayer || demoplayback || demorecording || genglnodes; BuildGLNodes = RequireGLNodes || multiplayer || demoplayback || demorecording || genglnodes;
startTime = I_msTime (); startTime = I_msTime();
TArray<FNodeBuilder::FPolyStart> polyspots, anchors; TArray<FNodeBuilder::FPolyStart> polyspots, anchors;
P_GetPolySpots (map, polyspots, anchors); P_GetPolySpots(map, polyspots, anchors);
FNodeBuilder::FLevel leveldata = FNodeBuilder::FLevel leveldata =
{ {
&level.vertexes[0], (int)level.vertexes.Size(), &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(), &level.lines[0], (int)level.lines.Size(),
0, 0, 0, 0 0, 0, 0, 0
}; };
leveldata.FindMapBounds (); leveldata.FindMapBounds();
// We need GL nodes if am_textured is on. // 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 // In case a sync critical game mode is started, also build GL nodes to avoid problems
// if the different machines' am_textured setting differs. // if the different machines' am_textured setting differs.
FNodeBuilder builder (leveldata, polyspots, anchors, BuildGLNodes); FNodeBuilder builder(leveldata, polyspots, anchors, BuildGLNodes);
builder.Extract (level); builder.Extract(level);
endTime = I_msTime (); endTime = I_msTime();
DPrintf (DMSG_NOTIFY, "BSP generation took %.3f sec (%d segs)\n", (endTime - startTime) * 0.001, level.segs.Size()); DPrintf(DMSG_NOTIFY, "BSP generation took %.3f sec (%d segs)\n", (endTime - startTime) * 0.001, level.segs.Size());
oldvertextable = builder.GetOldVertexTable(); oldvertextable = builder.GetOldVertexTable();
reloop = true; reloop = true;
} }
@ -4001,14 +3989,14 @@ void P_SetupLevel (const char *lumpname, int position, bool newGame)
{ {
BuildGLNodes = false; BuildGLNodes = false;
// Older ZDBSPs had problems with compressed sidedefs and assigned wrong sides to the segs if both sides were the same sidedef. // 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) if (seg.backsector == seg.frontsector && seg.linedef)
{ {
double d1 = (seg.v1->fPos() - seg.linedef->v1->fPos()).LengthSquared(); double d1 = (seg.v1->fPos() - seg.linedef->v1->fPos()).LengthSquared();
double d2 = (seg.v2->fPos() - seg.linedef->v1->fPos()).LengthSquared(); double d2 = (seg.v2->fPos() - seg.linedef->v1->fPos()).LengthSquared();
if (d2<d1) // backside if (d2 < d1) // backside
{ {
seg.sidedef = seg.linedef->sidedef[1]; seg.sidedef = seg.linedef->sidedef[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. // 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(); times[10].Clock();
P_LoadBlockMap (map); P_LoadBlockMap(map);
times[10].Unclock(); times[10].Unclock();
times[11].Clock(); times[11].Clock();
P_LoadReject (map, buildmap); P_LoadReject(map, buildmap);
times[11].Unclock(); times[11].Unclock();
times[12].Clock(); times[12].Clock();
P_GroupLines (buildmap); P_GroupLines(buildmap);
times[12].Unclock(); times[12].Unclock();
times[13].Clock(); times[13].Clock();
P_FloodZones (); P_FloodZones();
times[13].Unclock(); times[13].Unclock();
if (hasglnodes) if (hasglnodes)
@ -4061,8 +4049,8 @@ void P_SetupLevel (const char *lumpname, int position, bool newGame)
} }
bodyqueslot = 0; bodyqueslot = 0;
// phares 8/10/98: Clear body queue so the corpses from previous games are // phares 8/10/98: Clear body queue so the corpses from previous games are
// not assumed to be from this one. // not assumed to be from this one.
for (i = 0; i < BODYQUESIZE; i++) for (i = 0; i < BODYQUESIZE; i++)
bodyque[i] = NULL; bodyque[i] = NULL;
@ -4072,7 +4060,7 @@ void P_SetupLevel (const char *lumpname, int position, bool newGame)
if (!buildmap) if (!buildmap)
{ {
// [RH] Spawn slope creating things first. // [RH] Spawn slope creating things first.
P_SpawnSlopeMakers (&MapThingsConverted[0], &MapThingsConverted[MapThingsConverted.Size()], oldvertextable); P_SpawnSlopeMakers(&MapThingsConverted[0], &MapThingsConverted[MapThingsConverted.Size()], oldvertextable);
P_CopySlopes(); P_CopySlopes();
// Spawn 3d floors - must be done before spawning things so it can't be done in P_SpawnSpecials // 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(); times[15].Clock();
if (!map->HasBehavior && !map->isText) if (!map->HasBehavior && !map->isText)
P_TranslateTeleportThings (); // [RH] Assign teleport destination TIDs P_TranslateTeleportThings(); // [RH] Assign teleport destination TIDs
times[15].Unclock(); times[15].Unclock();
} }
#if 0 // There is no such thing as a build map. #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) for (i = 0; i < numbuildthings; ++i)
{ {
SpawnMapThing (i, &buildthings[i], 0); SpawnMapThing(i, &buildthings[i], 0);
} }
delete[] buildthings; delete[] buildthings;
} }
@ -4110,7 +4098,7 @@ void P_SetupLevel (const char *lumpname, int position, bool newGame)
} }
// set up world state // set up world state
P_SpawnSpecials (); P_SpawnSpecials();
// disable reflective planes on sloped sectors. // disable reflective planes on sloped sectors.
for (auto &sec : level.sectors) for (auto &sec : level.sectors)
@ -4133,8 +4121,8 @@ void P_SetupLevel (const char *lumpname, int position, bool newGame)
P_InitHealthGroups(); P_InitHealthGroups();
times[16].Clock(); times[16].Clock();
if (reloop) P_LoopSidedefs (false); if (reloop) P_LoopSidedefs(false);
PO_Init (); // Initialize the polyobjs PO_Init(); // Initialize the polyobjs
if (!level.IsReentering()) if (!level.IsReentering())
P_FinalizePortals(); // finalize line portals after polyobjects have been initialized. This info is needed for properly flagging them. P_FinalizePortals(); // finalize line portals after polyobjects have been initialized. This info is needed for properly flagging them.
times[16].Unclock(); 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, randomly spawn the active players
if (deathmatch) if (deathmatch)
{ {
for (i=0 ; i<MAXPLAYERS ; i++) for (i = 0; i < MAXPLAYERS; i++)
{ {
if (playeringame[i]) if (playeringame[i])
{ {
players[i].mo = NULL; players[i].mo = NULL;
G_DeathMatchSpawnPlayer (i); G_DeathMatchSpawnPlayer(i);
} }
} }
} }
@ -4171,7 +4159,7 @@ void P_SetupLevel (const char *lumpname, int position, bool newGame)
// [SP] move unfriendly players around // [SP] move unfriendly players around
// horribly hacky - yes, this needs rewritten. // horribly hacky - yes, this needs rewritten.
if (level.deathmatchstarts.Size () > 0) if (level.deathmatchstarts.Size() > 0)
{ {
for (i = 0; i < MAXPLAYERS; ++i) 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)) if (!(players[i].mo->flags & MF_FRIENDLY))
{ {
AActor * oldSpawn = players[i].mo; AActor * oldSpawn = players[i].mo;
G_DeathMatchSpawnPlayer (i); G_DeathMatchSpawnPlayer(i);
oldSpawn->Destroy(); oldSpawn->Destroy();
} }
} }
@ -4194,11 +4182,11 @@ void P_SetupLevel (const char *lumpname, int position, bool newGame)
TThinkerIterator<AActor> it; TThinkerIterator<AActor> it;
AActor * mo; AActor * mo;
while ((mo=it.Next())) while ((mo = it.Next()))
{ {
if (mo->flags & MF_COUNTKILL) 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(); mo->ClearCounters();
} }
@ -4214,20 +4202,20 @@ void P_SetupLevel (const char *lumpname, int position, bool newGame)
R_OldBlend = 0xffffffff; R_OldBlend = 0xffffffff;
// [RH] Remove all particles // [RH] Remove all particles
P_ClearParticles (); P_ClearParticles();
times[17].Clock(); times[17].Clock();
// preload graphics and sounds // preload graphics and sounds
if (precache) if (precache)
{ {
P_PrecacheLevel (); P_PrecacheLevel();
S_PrecacheLevel (); S_PrecacheLevel();
} }
times[17].Unclock(); times[17].Unclock();
if (deathmatch) if (deathmatch)
{ {
AnnounceGameStart (); AnnounceGameStart();
} }
// This check was previously done at run time each time the heightsec was checked. // 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()); //Printf ("free memory: 0x%x\n", Z_FreeMemory());
if (showloadtimes) if (showloadtimes)
{ {
Printf ("---Total load times---\n"); Printf("---Total load times---\n");
for (i = 0; i < 18; ++i) for (i = 0; i < 18; ++i)
{ {
static const char *timenames[] = static const char *timenames[] =
@ -4276,7 +4264,7 @@ void P_SetupLevel (const char *lumpname, int position, bool newGame)
"init polys", "init polys",
"precache" "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(); 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])); memcpy(&level.loadsides[0], &level.sides[0], level.sides.Size() * sizeof(level.sides[0]));
} }
// //
// P_Init // P_Init
// //

View file

@ -104,6 +104,13 @@ public:
} }
} }
TArray<uint8_t> Read(unsigned lumpindex)
{
TArray<uint8_t> buffer(Size(lumpindex), true);
Read(lumpindex, buffer.Data(), (int)buffer.Size());
return buffer;
}
uint32_t Size(unsigned int lumpindex) uint32_t Size(unsigned int lumpindex)
{ {
if (lumpindex<countof(MapLumps) && MapLumps[lumpindex].Reader.isOpen()) if (lumpindex<countof(MapLumps) && MapLumps[lumpindex].Reader.isOpen())

View file

@ -434,10 +434,13 @@ void P_RemoveThing(AActor * actor)
bool P_Thing_Raise(AActor *thing, AActor *raiser, int nocheck) bool P_Thing_Raise(AActor *thing, AActor *raiser, int nocheck)
{ {
if (!thing)
return false;
FState * RaiseState = thing->GetRaiseState(); FState * RaiseState = thing->GetRaiseState();
if (RaiseState == NULL) 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 (); AActor *info = thing->GetDefault ();
@ -460,6 +463,8 @@ bool P_Thing_Raise(AActor *thing, AActor *raiser, int nocheck)
return false; return false;
} }
if (!P_CanResurrect(thing, raiser))
return false;
S_Sound (thing, CHAN_BODY, "vile/raise", 1, ATTN_IDLE); S_Sound (thing, CHAN_BODY, "vile/raise", 1, ATTN_IDLE);

View file

@ -1223,6 +1223,7 @@ public:
{ {
FName key = ParseKey(); FName key = ParseKey();
switch(key) switch(key)
{ {
case NAME_Offsetx: case NAME_Offsetx:
texOfs[0] = CheckInt(key); texOfs[0] = CheckInt(key);
@ -1334,6 +1335,79 @@ public:
Flag(sd->Flags, WALLF_NOAUTODECALS, key); Flag(sd->Flags, WALLF_NOAUTODECALS, key);
continue; 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: default:
break; break;
@ -2045,15 +2119,11 @@ public:
void ParseTextMap(MapData *map) void ParseTextMap(MapData *map)
{ {
char *buffer = new char[map->Size(ML_TEXTMAP)];
isTranslated = true; isTranslated = true;
isExtended = false; isExtended = false;
floordrop = false; floordrop = false;
map->Read(ML_TEXTMAP, buffer); sc.OpenMem(Wads.GetLumpFullName(map->lumpnum), map->Read(ML_TEXTMAP));
sc.OpenMem(Wads.GetLumpFullName(map->lumpnum), buffer, map->Size(ML_TEXTMAP));
delete [] buffer;
sc.SetCMode(true); sc.SetCMode(true);
if (sc.CheckString("namespace")) if (sc.CheckString("namespace"))
{ {

View file

@ -473,10 +473,7 @@ class USDFParser : public UDMFParserBase
public: public:
bool Parse(int lumpnum, FileReader &lump, int lumplen) bool Parse(int lumpnum, FileReader &lump, int lumplen)
{ {
char *buffer = new char[lumplen]; sc.OpenMem(Wads.GetLumpFullName(lumpnum), lump.Read(lumplen));
lump.Read(buffer, lumplen);
sc.OpenMem(Wads.GetLumpFullName(lumpnum), buffer, lumplen);
delete [] buffer;
sc.SetCMode(true); sc.SetCMode(true);
// Namespace must be the first field because everything else depends on it. // Namespace must be the first field because everything else depends on it.
if (sc.CheckString("namespace")) if (sc.CheckString("namespace"))

View file

@ -323,15 +323,12 @@ void FParseContext::ParseLump(const char *lumpname)
} }
// Read the lump into a buffer and add a 0-terminator // Read the lump into a buffer and add a 0-terminator
int lumplen = Wads.LumpLength(lumpno); auto lumpdata = Wads.ReadLumpIntoArray(lumpno, 1);
char *lumpdata = new char[lumplen+1];
Wads.ReadLump(lumpno, lumpdata);
lumpdata[lumplen] = 0;
SourceLine = 0; SourceLine = 0;
SourceFile = lumpname; SourceFile = lumpname;
char *sourcep = lumpdata; char *sourcep = (char*)lumpdata.Data();
while ( (tokentype = GetToken(sourcep, &token)) ) while ( (tokentype = GetToken(sourcep, &token)) )
{ {
// It is much easier to handle include statements outside the main parser. // 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); Parse(pParser, tokentype, token, this);
} }
} }
delete [] lumpdata;
SourceLine = SavedSourceLine; SourceLine = SavedSourceLine;
SourceFile = SavedSourceFile; SourceFile = SavedSourceFile;
} }

View file

@ -88,7 +88,6 @@ bool RenderPolyWall::RenderLine(PolyRenderThread *thread, seg_t *line, sector_t
wall.Line = line->linedef; wall.Line = line->linedef;
wall.Side = line->sidedef; wall.Side = line->sidedef;
wall.LineSegLine = line->linedef; wall.LineSegLine = line->linedef;
wall.Colormap = GetColorTable(frontsector->Colormap, frontsector->SpecialColors[sector_t::walltop]);
wall.Masked = false; wall.Masked = false;
wall.SubsectorDepth = subsectorDepth; wall.SubsectorDepth = subsectorDepth;
wall.StencilValue = stencilValue; wall.StencilValue = stencilValue;
@ -102,6 +101,7 @@ bool RenderPolyWall::RenderLine(PolyRenderThread *thread, seg_t *line, sector_t
wall.TopTexZ = topTexZ; wall.TopTexZ = topTexZ;
wall.BottomTexZ = bottomTexZ; wall.BottomTexZ = bottomTexZ;
wall.Wallpart = side_t::mid; 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.Texture = GetTexture(wall.Line, wall.Side, side_t::mid);
wall.Polyportal = polyportal; wall.Polyportal = polyportal;
wall.Render(thread); wall.Render(thread);
@ -140,6 +140,7 @@ bool RenderPolyWall::RenderLine(PolyRenderThread *thread, seg_t *line, sector_t
wall.TopTexZ = topTexZ; wall.TopTexZ = topTexZ;
wall.BottomTexZ = MIN(MIN(backceilz1, frontceilz1), MIN(backceilz2, frontceilz2)); wall.BottomTexZ = MIN(MIN(backceilz1, frontceilz1), MIN(backceilz2, frontceilz2));
wall.Wallpart = side_t::top; 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.Texture = GetTexture(wall.Line, wall.Side, side_t::top);
wall.Render(thread); wall.Render(thread);
} }
@ -152,6 +153,7 @@ bool RenderPolyWall::RenderLine(PolyRenderThread *thread, seg_t *line, sector_t
wall.UnpeggedCeil1 = topceilz1; wall.UnpeggedCeil1 = topceilz1;
wall.UnpeggedCeil2 = topceilz2; wall.UnpeggedCeil2 = topceilz2;
wall.Wallpart = side_t::bottom; 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.Texture = GetTexture(wall.Line, wall.Side, side_t::bottom);
wall.Render(thread); wall.Render(thread);
} }
@ -162,6 +164,7 @@ bool RenderPolyWall::RenderLine(PolyRenderThread *thread, seg_t *line, sector_t
wall.TopTexZ = MAX(middleceilz1, middleceilz2); wall.TopTexZ = MAX(middleceilz1, middleceilz2);
wall.BottomTexZ = MIN(middlefloorz1, middlefloorz2); wall.BottomTexZ = MIN(middlefloorz1, middlefloorz2);
wall.Wallpart = side_t::mid; 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.Texture = GetTexture(wall.Line, wall.Side, side_t::mid);
wall.Masked = true; wall.Masked = true;
wall.Additive = !!(wall.Line->flags & ML_ADDTRANS); 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.LineSegLine = line->linedef;
wall.Line = fakeFloor->master; wall.Line = fakeFloor->master;
wall.Side = fakeFloor->master->sidedef[0]; wall.Side = fakeFloor->master->sidedef[0];
wall.Colormap = GetColorTable(frontsector->Colormap, frontsector->SpecialColors[sector_t::walltop]);
wall.SectorLightLevel = frontsector->lightlevel; wall.SectorLightLevel = frontsector->lightlevel;
wall.Additive = !!(fakeFloor->flags & FF_ADDITIVETRANS); wall.Additive = !!(fakeFloor->flags & FF_ADDITIVETRANS);
if (!wall.Additive && fakeFloor->alpha == 255) if (!wall.Additive && fakeFloor->alpha == 255)
@ -231,6 +233,7 @@ void RenderPolyWall::Render3DFloorLine(PolyRenderThread *thread, seg_t *line, se
wall.TopTexZ = topTexZ; wall.TopTexZ = topTexZ;
wall.BottomTexZ = bottomTexZ; wall.BottomTexZ = bottomTexZ;
wall.Wallpart = side_t::mid; wall.Wallpart = side_t::mid;
wall.Colormap = GetColorTable(frontsector->Colormap, wall.Side->GetSpecialColor(wall.Wallpart, side_t::walltop, frontsector));
if (fakeFloor->flags & FF_UPPERTEXTURE) if (fakeFloor->flags & FF_UPPERTEXTURE)
wall.Texture = GetTexture(line->linedef, line->sidedef, side_t::top); wall.Texture = GetTexture(line->linedef, line->sidedef, side_t::top);
else if (fakeFloor->flags & FF_LOWERTEXTURE) else if (fakeFloor->flags & FF_LOWERTEXTURE)

View file

@ -64,6 +64,7 @@ struct WorkSection
int sectorindex; int sectorindex;
int mapsection; int mapsection;
bool hasminisegs; bool hasminisegs;
bool bad; // Did not produce a proper area and cannot be triangulated by tesselation.
TArray<WorkSectionLine*>segments; TArray<WorkSectionLine*>segments;
TArray<side_t *> originalSides; // The segs will lose some of these while working on them. TArray<side_t *> originalSides; // The segs will lose some of these while working on them.
TArray<int> subsectors; TArray<int> subsectors;
@ -184,6 +185,33 @@ public:
{ {
CompileSections(pair->Value, rawsections); 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(); subsectormap.Clear();
return rawsections; return rawsections;
} }
@ -253,8 +281,7 @@ public:
{ {
MakeOutline(list, lineForSeg); MakeOutline(list, lineForSeg);
} }
rawsections.Clear(); rawsections.Reset();
rawsections.ShrinkToFit();
// Assign partners after everything has been collected // Assign partners after everything has been collected
for (auto &section : sections) for (auto &section : sections)
@ -281,6 +308,7 @@ public:
TArray<seg_t *> outersegs; TArray<seg_t *> outersegs;
TArray<seg_t *> loopedsegs; TArray<seg_t *> loopedsegs;
bool hasminisegs = false; bool hasminisegs = false;
bool bad = false;
// Collect all the segs that make up the outline of this section. // Collect all the segs that make up the outline of this section.
for (auto j : rawsection) 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. // 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. // 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; seg = nullptr;
loopedsegs.Push(nullptr); // A separator is not really needed but useful for debugging. loopedsegs.Push(nullptr); // A separator is not really needed but useful for debugging.
@ -402,6 +431,7 @@ public:
section.sectorindex = sector; section.sectorindex = sector;
section.mapsection = mapsec; section.mapsection = mapsec;
section.hasminisegs = hasminisegs; section.hasminisegs = hasminisegs;
section.bad = bad;
section.originalSides = std::move(foundsides); section.originalSides = std::move(foundsides);
section.segments = std::move(sectionlines); section.segments = std::move(sectionlines);
section.subsectors = std::move(rawsection); section.subsectors = std::move(rawsection);
@ -720,8 +750,59 @@ public:
curgroup++; 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 &section : sections)
{
if (bestfit == nullptr)
{
bestfit = &section;
}
else if (bestfit->mapsection != section.mapsection && section.mapsection == mapsection)
{
bestfit = &section;
}
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 = &section;
}
}
}
// 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.FindOuterLoops();
creat.GroupSections(); creat.GroupSections();
creat.ConstructOutput(container); creat.ConstructOutput(container);
creat.FixMissingReferences();
} }
CCMD(printsections) CCMD(printsections)

View file

@ -325,7 +325,7 @@ public:
return !normal.XY().isZero(); return !normal.XY().isZero();
} }
DVector3 Normal() const const DVector3 &Normal() const
{ {
return normal; return normal;
} }
@ -645,8 +645,6 @@ public:
void SetColor(int r, int g, int b, int desat); void SetColor(int r, int g, int b, int desat);
void SetFade(int r, int g, int b); void SetFade(int r, int g, int b);
void SetFogDensity(int dens); 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; void ClosestPoint(const DVector2 &pos, DVector2 &out) const;
int GetFloorLight () const; int GetFloorLight () const;
int GetCeilingLight () const; int GetCeilingLight () const;
@ -917,6 +915,17 @@ public:
Flags &= ~SECF_SPECIALFLAGS; 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 PortalBlocksView(int plane);
inline bool PortalBlocksSight(int plane); inline bool PortalBlocksSight(int plane);
inline bool PortalBlocksMovement(int plane); inline bool PortalBlocksMovement(int plane);
@ -1138,16 +1147,31 @@ struct side_t
{ {
top=0, top=0,
mid=1, 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 struct part
{ {
enum EPartFlags
{
NoGradient = 1,
FlipGradient = 2,
ClampGradient = 4,
UseOwnColors = 8,
};
double xOffset; double xOffset;
double yOffset; double yOffset;
double xScale; double xScale;
double yScale; double yScale;
TObjPtr<DInterpolation*> interpolation; TObjPtr<DInterpolation*> interpolation;
FTextureID texture; FTextureID texture;
int flags;
PalEntry SpecialColors[2];
void InitFrom(const part &other) void InitFrom(const part &other)
{ {
@ -1270,6 +1294,28 @@ struct side_t
textures[which].yScale *= delta; 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); DInterpolation *SetInterpolation(int position);
void StopInterpolation(int position); void StopInterpolation(int position);

View file

@ -230,7 +230,7 @@ bool F7ZFile::Open(bool quiet)
Archive = NULL; Archive = NULL;
if (!quiet) if (!quiet)
{ {
Printf("\n" TEXTCOLOR_RED "%s: ", Filename); Printf("\n" TEXTCOLOR_RED "%s: ", FileName.GetChars());
if (res == SZ_ERROR_UNSUPPORTED) if (res == SZ_ERROR_UNSUPPORTED)
{ {
Printf("Decoder does not support this archive\n"); 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 (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; return false;
} }
} }

View file

@ -102,9 +102,9 @@ FDirectory::FDirectory(const char * directory)
#ifdef _WIN32 #ifdef _WIN32
free((void *)directory); free((void *)directory);
#endif #endif
dirname.ReplaceChars('\\', '/'); FixPathSeperator(dirname);
if (dirname[dirname.Len()-1] != '/') dirname += '/'; if (dirname[dirname.Len()-1] != '/') dirname += '/';
Filename = copystring(dirname); FileName = dirname;
} }
@ -195,7 +195,7 @@ int FDirectory::AddDirectory(const char *dirpath)
return 0; return 0;
} }
const size_t namepos = strlen(Filename); const size_t namepos = strlen(FileName);
FString pathfix; FString pathfix;
while ((ent = fts_read(fts)) != NULL) while ((ent = fts_read(fts)) != NULL)
@ -248,7 +248,7 @@ int FDirectory::AddDirectory(const char *dirpath)
bool FDirectory::Open(bool quiet) bool FDirectory::Open(bool quiet)
{ {
NumLumps = AddDirectory(Filename); NumLumps = AddDirectory(FileName);
if (!quiet) Printf(", %d lumps\n", NumLumps); if (!quiet) Printf(", %d lumps\n", NumLumps);
PostProcessArchive(&Lumps[0], sizeof(FDirectoryLump)); PostProcessArchive(&Lumps[0], sizeof(FDirectoryLump));
return true; return true;
@ -268,7 +268,7 @@ void FDirectory::AddEntry(const char *fullpath, int size)
lump_p->mFullPath = fullpath; lump_p->mFullPath = fullpath;
// [mxd] Convert name to lowercase // [mxd] Convert name to lowercase
FString name = fullpath + strlen(Filename); FString name = fullpath + strlen(FileName);
name.ToLower(); name.ToLower();
// The lump's name is only the part relative to the main directory // The lump's name is only the part relative to the main directory

View file

@ -85,7 +85,6 @@ public:
FGrpFile::FGrpFile(const char *filename, FileReader &file) FGrpFile::FGrpFile(const char *filename, FileReader &file)
: FUncompressedFile(filename, file) : FUncompressedFile(filename, file)
{ {
Lumps = NULL;
} }
//========================================================================== //==========================================================================
@ -104,7 +103,7 @@ bool FGrpFile::Open(bool quiet)
GrpLump *fileinfo = new GrpLump[NumLumps]; GrpLump *fileinfo = new GrpLump[NumLumps];
Reader.Read (fileinfo, NumLumps * sizeof(GrpLump)); Reader.Read (fileinfo, NumLumps * sizeof(GrpLump));
Lumps = new FUncompressedLump[NumLumps]; Lumps.Resize(NumLumps);
int Position = sizeof(GrpInfo) + NumLumps * sizeof(GrpLump); int Position = sizeof(GrpInfo) + NumLumps * sizeof(GrpLump);

View file

@ -69,17 +69,17 @@ FLumpFile::FLumpFile(const char *filename, FileReader &file)
bool FLumpFile::Open(bool quiet) bool FLumpFile::Open(bool quiet)
{ {
FString name(ExtractFileBase (Filename)); FString name(ExtractFileBase (FileName));
Lumps = new FUncompressedLump[1]; // must use array allocator Lumps.Resize(1);
uppercopy(Lumps->Name, name); uppercopy(Lumps[0].Name, name);
Lumps->Name[8] = 0; Lumps[0].Name[8] = 0;
Lumps->Owner = this; Lumps[0].Owner = this;
Lumps->Position = 0; Lumps[0].Position = 0;
Lumps->LumpSize = (int)Reader.GetLength(); Lumps[0].LumpSize = (int)Reader.GetLength();
Lumps->Namespace = ns_global; Lumps[0].Namespace = ns_global;
Lumps->Flags = 0; Lumps[0].Flags = 0;
Lumps->FullName = NULL; Lumps[0].FullName = NULL;
NumLumps = 1; NumLumps = 1;
if (!quiet) if (!quiet)
{ {

View file

@ -80,7 +80,6 @@ public:
FPakFile::FPakFile(const char *filename, FileReader &file) FPakFile::FPakFile(const char *filename, FileReader &file)
: FUncompressedFile(filename, file) : FUncompressedFile(filename, file)
{ {
Lumps = NULL;
} }
//========================================================================== //==========================================================================
@ -101,7 +100,7 @@ bool FPakFile::Open(bool quiet)
Reader.Seek (header.dirofs, FileReader::SeekSet); Reader.Seek (header.dirofs, FileReader::SeekSet);
Reader.Read (fileinfo, NumLumps * sizeof(dpackfile_t)); Reader.Read (fileinfo, NumLumps * sizeof(dpackfile_t));
Lumps = new FUncompressedLump[NumLumps]; Lumps.Resize(NumLumps);
if (!quiet && !batchrun) Printf(", %d lumps\n", NumLumps); if (!quiet && !batchrun) Printf(", %d lumps\n", NumLumps);

View file

@ -165,7 +165,7 @@ bool FWadFile::Open(bool quiet)
// Check again to detect broken wads // Check again to detect broken wads
if (InfoTableOfs + NumLumps*sizeof(wadlump_t) > (unsigned)wadSize) 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) 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].Name[0] = 0;
} }
Lumps[i].LumpSize = Lumps[i].Position = 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" "The maps in %s will not be loaded because it has a skin.\n"
TEXTCOLOR_BLUE TEXTCOLOR_BLUE
"You should remove the skin from the wad to play these maps.\n", "You should remove the skin from the wad to play these maps.\n",
Filename); FileName.GetChars());
} }
} }

View file

@ -181,7 +181,7 @@ bool FZipFile::Open(bool quiet)
if (centraldir == 0) 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; return false;
} }
@ -193,7 +193,7 @@ bool FZipFile::Open(bool quiet)
if (info.NumEntries != info.NumEntriesOnAllDisks || if (info.NumEntries != info.NumEntriesOnAllDisks ||
info.FirstDisk != 0 || info.DiskNumber != 0) 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; 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. if (dirptr > ((char*)directory) + dirsize) // This directory entry goes beyond the end of the file.
{ {
free(directory); 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; 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. if (dirptr > ((char*)directory) + dirsize) // This directory entry goes beyond the end of the file.
{ {
free(directory); 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; return false;
} }
@ -320,7 +320,7 @@ bool FZipFile::Open(bool quiet)
zip_fh->Method != METHOD_IMPLODE && zip_fh->Method != METHOD_IMPLODE &&
zip_fh->Method != METHOD_SHRINK) 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++; skipped++;
continue; continue;
} }
@ -328,7 +328,7 @@ bool FZipFile::Open(bool quiet)
zip_fh->Flags = LittleShort(zip_fh->Flags); zip_fh->Flags = LittleShort(zip_fh->Flags);
if (zip_fh->Flags & ZF_ENCRYPTED) 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++; skipped++;
continue; continue;
} }

View file

@ -156,7 +156,7 @@ static bool IsWadInFolder(const FResourceFile* const archive, const char* const
return false; return false;
} }
const FString dirName = ExtractFileBase(archive->Filename); const FString dirName = ExtractFileBase(archive->FileName);
const FString fileName = ExtractFileBase(resPath, true); const FString fileName = ExtractFileBase(resPath, true);
const FString filePath = dirName + '/' + fileName; const FString filePath = dirName + '/' + fileName;
@ -323,9 +323,8 @@ FResourceFile *FResourceFile::OpenDirectory(const char *filename, bool quiet)
//========================================================================== //==========================================================================
FResourceFile::FResourceFile(const char *filename) FResourceFile::FResourceFile(const char *filename)
: FileName(filename)
{ {
if (filename != NULL) Filename = copystring(filename);
else Filename = NULL;
} }
FResourceFile::FResourceFile(const char *filename, FileReader &r) FResourceFile::FResourceFile(const char *filename, FileReader &r)
@ -336,7 +335,6 @@ FResourceFile::FResourceFile(const char *filename, FileReader &r)
FResourceFile::~FResourceFile() FResourceFile::~FResourceFile()
{ {
if (Filename != NULL) delete [] Filename;
} }
int lumpcmp(const void * a, const void * b) int lumpcmp(const void * a, const void * b)
@ -653,12 +651,6 @@ FUncompressedFile::FUncompressedFile(const char *filename, FileReader &r)
: FResourceFile(filename, r) : FResourceFile(filename, r)
{} {}
FUncompressedFile::~FUncompressedFile()
{
if (Lumps != NULL) delete [] Lumps;
}
//========================================================================== //==========================================================================
// //
@ -667,9 +659,8 @@ FUncompressedFile::~FUncompressedFile()
//========================================================================== //==========================================================================
FExternalLump::FExternalLump(const char *_filename, int filesize) FExternalLump::FExternalLump(const char *_filename, int filesize)
: Filename(_filename)
{ {
filename = _filename? copystring(_filename) : NULL;
if (filesize == -1) if (filesize == -1)
{ {
FileReader f; 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 // Caches a lump's content and increases the reference counter
@ -707,7 +693,7 @@ int FExternalLump::FillCache()
Cache = new char[LumpSize]; Cache = new char[LumpSize];
FileReader f; FileReader f;
if (f.OpenFile(filename)) if (f.OpenFile(Filename))
{ {
f.Read(Cache, LumpSize); f.Read(Cache, LumpSize);
} }
@ -722,19 +708,19 @@ int FExternalLump::FillCache()
bool FMemoryFile::Open(bool quiet) bool FMemoryFile::Open(bool quiet)
{ {
FString name(ExtractFileBase(Filename)); FString name(ExtractFileBase(FileName));
FString fname(ExtractFileBase(Filename, true)); FString fname(ExtractFileBase(FileName, true));
Lumps = new FUncompressedLump[1]; // must use array allocator Lumps.Resize(1);
uppercopy(Lumps->Name, name); uppercopy(Lumps[0].Name, name);
Lumps->Name[8] = 0; Lumps[0].Name[8] = 0;
Lumps->FullName = fname; Lumps[0].FullName = fname;
Lumps->Owner = this; Lumps[0].Owner = this;
Lumps->Position = 0; Lumps[0].Position = 0;
Lumps->LumpSize = (int)Reader.GetLength(); Lumps[0].LumpSize = (int)Reader.GetLength();
Lumps->Namespace = ns_global; Lumps[0].Namespace = ns_global;
Lumps->Flags = 0; Lumps[0].Flags = 0;
Lumps->FullName = NULL; Lumps[0].FullName = nullptr;
NumLumps = 1; NumLumps = 1;
return true; return true;
} }

View file

@ -82,7 +82,7 @@ class FResourceFile
{ {
public: public:
FileReader Reader; FileReader Reader;
const char *Filename; FString FileName;
protected: protected:
uint32_t NumLumps; uint32_t NumLumps;
@ -133,21 +133,19 @@ struct FUncompressedLump : public FResourceLump
class FUncompressedFile : public FResourceFile class FUncompressedFile : public FResourceFile
{ {
protected: protected:
FUncompressedLump * Lumps = nullptr; TArray<FUncompressedLump> Lumps;
FUncompressedFile(const char *filename); FUncompressedFile(const char *filename);
FUncompressedFile(const char *filename, FileReader &r); FUncompressedFile(const char *filename, FileReader &r);
virtual ~FUncompressedFile();
virtual FResourceLump *GetLump(int no) { return ((unsigned)no < NumLumps)? &Lumps[no] : NULL; } virtual FResourceLump *GetLump(int no) { return ((unsigned)no < NumLumps)? &Lumps[no] : NULL; }
}; };
struct FExternalLump : public FResourceLump 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(const char *_filename, int filesize = -1);
~FExternalLump();
virtual int FillCache(); virtual int FillCache();
}; };

View file

@ -21,6 +21,10 @@ public:
void Open(const char *lumpname); void Open(const char *lumpname);
bool OpenFile(const char *filename); bool OpenFile(const char *filename);
void OpenMem(const char *name, const char *buffer, int size); void OpenMem(const char *name, const char *buffer, int size);
void OpenMem(const char *name, const TArray<uint8_t> &buffer)
{
OpenMem(name, (const char*)buffer.Data(), buffer.Size());
}
void OpenString(const char *name, FString buffer); void OpenString(const char *name, FString buffer);
void OpenLumpNum(int lump); void OpenLumpNum(int lump);
void Close(); void Close();

View file

@ -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 the parser fails, there is no point starting the compiler, because it'd only flood the output with endless errors.
if (FScriptPosition::ErrorCounter > 0) 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 #ifndef NDEBUG
@ -457,7 +457,7 @@ static void DoParse(int lumpnum)
if (Args->CheckParm("-dumpast")) if (Args->CheckParm("-dumpast"))
{ {
FString ast = ZCC_PrintAST(state.TopNode); FString ast = ZCC_PrintAST(state.TopNode);
FString filename = Wads.GetLumpFullPath(lumpnum); FString filename = Wads.GetLumpFullPath(baselump);
filename.ReplaceChars(":\\/?|", '.'); filename.ReplaceChars(":\\/?|", '.');
filename << ".ast"; filename << ".ast";
FileWriter *ff = FileWriter::Open(filename); FileWriter *ff = FileWriter::Open(filename);
@ -469,19 +469,19 @@ static void DoParse(int lumpnum)
} }
PSymbolTable symtable; PSymbolTable symtable;
auto newns = Wads.GetLumpFile(lumpnum) == 0 ? Namespaces.GlobalNamespace : Namespaces.NewNamespace(Wads.GetLumpFile(lumpnum)); auto newns = Wads.GetLumpFile(baselump) == 0 ? Namespaces.GlobalNamespace : Namespaces.NewNamespace(Wads.GetLumpFile(baselump));
ZCCCompiler cc(state, NULL, symtable, newns, lumpnum, state.ParseVersion); ZCCCompiler cc(state, NULL, symtable, newns, baselump, state.ParseVersion);
cc.Compile(); cc.Compile();
if (FScriptPosition::ErrorCounter > 0) if (FScriptPosition::ErrorCounter > 0)
{ {
// Abort if the compiler produced any errors. Also do not compile further lumps, because they very likely miss some stuff. // 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) else if (FScriptPosition::WarnCounter > 0)
{ {
// If we got warnings, but no errors, print the information but continue. // 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());
} }
} }

View file

@ -157,14 +157,14 @@ public:
Count = 0; Count = 0;
Array = NULL; Array = NULL;
} }
TArray (int max, bool reserve = false) TArray (size_t max, bool reserve = false)
{ {
Most = max; Most = (unsigned)max;
Count = reserve? max : 0; Count = (unsigned)(reserve? max : 0);
Array = (T *)M_Malloc (sizeof(T)*max); 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<T,TT> &other) TArray (const TArray<T,TT> &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 () void ShrinkToFit ()
{ {
if (Most > Count) if (Most > Count)
@ -411,10 +400,7 @@ public:
{ {
// Adding new entries // Adding new entries
Grow (amount - Count); Grow (amount - Count);
for (unsigned int i = Count; i < amount; ++i) ConstructEmpty(Count, amount - 1);
{
::new((void *)&Array[i]) T;
}
} }
else if (Count != amount) else if (Count != amount)
{ {
@ -423,6 +409,18 @@ public:
} }
Count = amount; 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) void Alloc(unsigned int amount)
{ {
// first destroys all content and then rebuilds the array. // 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 // Reserves amount entries at the end of the array, but does nothing
// with them. // with them.
unsigned int Reserve (unsigned int amount) unsigned int Reserve (size_t amount)
{ {
Grow (amount); Grow ((unsigned)amount);
unsigned int place = Count; unsigned int place = Count;
Count += amount; Count += (unsigned)amount;
for (unsigned int i = place; i < Count; ++i) if (Count > 0) ConstructEmpty(place, Count - 1);
{
::new((void *)&Array[i]) T;
}
return place; return place;
} }
unsigned int Size () const unsigned int Size () const
@ -463,7 +458,12 @@ public:
void Reset() void Reset()
{ {
Clear(); Clear();
ShrinkToFit(); Most = 0;
if (Array != nullptr)
{
M_Free(Array);
Array = nullptr;
}
} }
private: private:
T *Array; T *Array;
@ -501,6 +501,15 @@ private:
Array[i].~T(); 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 ----------------------------------------------------------- // TDeletingArray -----------------------------------------------------------

View file

@ -419,7 +419,8 @@ void F2DDrawer::AddShape( FTexture *img, DShape2D *shape, DrawParms &parms )
void F2DDrawer::AddPoly(FTexture *texture, FVector2 *points, int npoints, void F2DDrawer::AddPoly(FTexture *texture, FVector2 *points, int npoints,
double originx, double originy, double scalex, double scaley, 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 // 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.mIndexIndex = mIndices.Size();
poly.mIndexCount += (npoints - 2) * 3; 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); AddCommand(&poly);

View file

@ -130,7 +130,7 @@ public:
void AddShape(FTexture *img, DShape2D *shape, DrawParms &parms); void AddShape(FTexture *img, DShape2D *shape, DrawParms &parms);
void AddPoly(FTexture *texture, FVector2 *points, int npoints, void AddPoly(FTexture *texture, FVector2 *points, int npoints,
double originx, double originy, double scalex, double scaley, 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 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); void AddColorOnlyQuad(int left, int top, int width, int height, PalEntry color, FRenderStyle *style);

View file

@ -1253,9 +1253,9 @@ DEFINE_ACTION_FUNCTION(_Screen, Dim)
void DFrameBuffer::FillSimplePoly(FTexture *tex, FVector2 *points, int npoints, void DFrameBuffer::FillSimplePoly(FTexture *tex, FVector2 *points, int npoints,
double originx, double originy, double scalex, double scaley, DAngle rotation, 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);
} }
//========================================================================== //==========================================================================

View file

@ -529,7 +529,7 @@ public:
// Fill a simple polygon with a texture // Fill a simple polygon with a texture
void FillSimplePoly(FTexture *tex, FVector2 *points, int npoints, void FillSimplePoly(FTexture *tex, FVector2 *points, int npoints,
double originx, double originy, double scalex, double scaley, DAngle rotation, 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 // Set an area to a specified color
void Clear(int left, int top, int right, int bottom, int palcolor, uint32_t color); void Clear(int left, int top, int right, int bottom, int palcolor, uint32_t color);

View file

@ -1281,6 +1281,30 @@ void FWadCollection::ReadLump (int lump, void *dest)
} }
} }
//==========================================================================
//
// W_ReadLump
//
// Loads the lump into a TArray and returns it.
//
//==========================================================================
TArray<uint8_t> FWadCollection::ReadLumpIntoArray(int lump, int pad)
{
auto lumpr = OpenLumpReader(lump);
auto size = lumpr.GetLength();
TArray<uint8_t> 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 // ReadLump - variant 2
@ -1389,7 +1413,7 @@ const char *FWadCollection::GetWadName (int wadnum) const
return NULL; return NULL;
} }
name = Files[wadnum]->Filename; name = Files[wadnum]->FileName;
slash = strrchr (name, '/'); slash = strrchr (name, '/');
return slash != NULL ? slash+1 : name; return slash != NULL ? slash+1 : name;
} }
@ -1452,10 +1476,10 @@ const char *FWadCollection::GetWadFullName (int wadnum) const
{ {
if ((unsigned int)wadnum >= Files.Size()) if ((unsigned int)wadnum >= Files.Size())
{ {
return NULL; return nullptr;
} }
return Files[wadnum]->Filename; return Files[wadnum]->FileName;
} }

View file

@ -148,6 +148,7 @@ public:
void ReadLump (int lump, void *dest); void ReadLump (int lump, void *dest);
TArray<uint8_t> 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 (int lump);
FMemLump ReadLump (const char *name) { return ReadLump (GetNumForName (name)); } FMemLump ReadLump (const char *name) { return ReadLump (GetNumForName (name)); }

View file

@ -1,5 +1,6 @@
in vec4 pixelpos; in vec4 pixelpos;
in vec3 glowdist; in vec3 glowdist;
in vec3 gradientdist;
in vec4 vWorldNormal; in vec4 vWorldNormal;
in vec4 vEyeNormal; in vec4 vEyeNormal;
@ -111,7 +112,7 @@ vec4 getTexel(vec2 st)
} }
if (uObjectColor2.a == 0.0) texel *= uObjectColor; if (uObjectColor2.a == 0.0) texel *= uObjectColor;
else texel *= mix(uObjectColor, uObjectColor2, glowdist.z); else texel *= mix(uObjectColor, uObjectColor2, gradientdist.z);
return desaturate(texel); return desaturate(texel);
} }

View file

@ -7,6 +7,7 @@ layout(location = 3) in vec4 aVertex2;
layout(location = 4) in vec4 aNormal; layout(location = 4) in vec4 aNormal;
out vec4 pixelpos; out vec4 pixelpos;
out vec3 glowdist; out vec3 glowdist;
out vec3 gradientdist;
out vec4 vWorldNormal; out vec4 vWorldNormal;
out vec4 vEyeNormal; out vec4 vEyeNormal;
@ -37,16 +38,28 @@ void main()
pixelpos.xyz = worldcoord.xyz; pixelpos.xyz = worldcoord.xyz;
pixelpos.w = -eyeCoordPos.z/eyeCoordPos.w; pixelpos.w = -eyeCoordPos.z/eyeCoordPos.w;
float topatpoint = -((uGlowTopPlane.w + uGlowTopPlane.x * worldcoord.x + uGlowTopPlane.y * worldcoord.z) * uGlowTopPlane.z); if (uGlowTopColor.a > 0 || uGlowBottomColor.a > 0)
float bottomatpoint = -((uGlowBottomPlane.w + uGlowBottomPlane.x * worldcoord.x + uGlowBottomPlane.y * worldcoord.z) * uGlowBottomPlane.z); {
glowdist.x = topatpoint - worldcoord.y; float topatpoint = (uGlowTopPlane.w + uGlowTopPlane.x * worldcoord.x + uGlowTopPlane.y * worldcoord.z) * uGlowTopPlane.z;
glowdist.y = worldcoord.y - bottomatpoint; float bottomatpoint = (uGlowBottomPlane.w + uGlowBottomPlane.x * worldcoord.x + uGlowBottomPlane.y * worldcoord.z) * uGlowBottomPlane.z;
glowdist.z = clamp(glowdist.x / (topatpoint - bottomatpoint), 0.0, 1.0); 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) if (uSplitBottomPlane.z != 0.0)
{ {
gl_ClipDistance[3] = -((uSplitTopPlane.w + uSplitTopPlane.x * worldcoord.x + uSplitTopPlane.y * worldcoord.z) * uSplitTopPlane.z) - worldcoord.y; 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[4] = worldcoord.y - ((uSplitBottomPlane.w + uSplitBottomPlane.x * worldcoord.x + uSplitBottomPlane.y * worldcoord.z) * uSplitBottomPlane.z);
} }
vWorldNormal = NormalModelMatrix * vec4(normalize(aNormal.xyz), 1.0); vWorldNormal = NormalModelMatrix * vec4(normalize(aNormal.xyz), 1.0);

View file

@ -445,6 +445,13 @@ class Actor : Thinker native
return true; 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. // Called when an actor is to be reflected by a disc of repulsion.
// Returns true to continue normal blast processing. // Returns true to continue normal blast processing.
virtual bool SpecialBlastHandling (Actor source, double strength) 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_RaiseChildren(int flags = 0);
native void A_RaiseSiblings(int flags = 0); native void A_RaiseSiblings(int flags = 0);
native bool A_RaiseSelf(int flags = 0); native bool A_RaiseSelf(int flags = 0);
native bool RaiseActor(Actor other, int flags = 0);
native bool CanRaise(); native bool CanRaise();
native void Revive(); native void Revive();
action native bool, Actor A_ThrowGrenade(class<Actor> itemtype, double zheight = 0, double xyvel = 0, double zvel = 0, bool useammo = true); action native bool, Actor A_ThrowGrenade(class<Actor> itemtype, double zheight = 0, double xyvel = 0, double zvel = 0, bool useammo = true);

View file

@ -940,6 +940,7 @@ enum EDmgFlags
DMG_USEANGLE = 512, DMG_USEANGLE = 512,
DMG_NO_PAIN = 1024, DMG_NO_PAIN = 1024,
DMG_EXPLOSION = 2048, DMG_EXPLOSION = 2048,
DMG_NO_ENHANCE = 4096,
} }
enum EReplace enum EReplace

View file

@ -45,6 +45,12 @@ struct Side native play
bottom=2 bottom=2
}; };
enum EColorPos
{
walltop = 0,
wallbottom = 1
}
enum EWallFlags enum EWallFlags
{ {
WALLF_ABSLIGHTING = 1, // Light is absolute instead of relative 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. WALLF_LIGHT_FOG = 128, // This wall's Light is used even in fog.
}; };
native readonly Sector sector; // Sector the SideDef is facing. native readonly Sector sector; // Sector the SideDef is facing.
//DBaseDecal* AttachedDecals; // [RH] Decals bound to the wall //DBaseDecal* AttachedDecals; // [RH] Decals bound to the wall
native readonly Line linedef; native readonly Line linedef;
@ -77,6 +84,7 @@ struct Side native play
native void SetTextureYScale(int which, double scale); native void SetTextureYScale(int which, double scale);
native double GetTextureYScale(int which); native double GetTextureYScale(int which);
native void MultiplyTextureYScale(int which, double delta); native void MultiplyTextureYScale(int which, double delta);
native void SetSpecialColor(int tier, int position, Color scolor);
//native DInterpolation *SetInterpolation(int position); //native DInterpolation *SetInterpolation(int position);
//native void StopInterpolation(int position); //native void StopInterpolation(int position);