From 8429fc812439c4da52975ecd4b2242d5774f8958 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Wed, 14 Nov 2018 10:08:04 +0100 Subject: [PATCH 1/5] - fix missing type check when using Push or Insert for typed arrays --- src/namedef.h | 2 ++ src/scripting/backend/codegen.cpp | 13 +++++++++++++ 2 files changed, 15 insertions(+) diff --git a/src/namedef.h b/src/namedef.h index 5744ef486..184c58fd0 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -896,6 +896,8 @@ xx(DamageFunction) xx(Length) xx(Unit) xx(Size) +xx(Push) +xx(Insert) xx(Copy) xx(Move) xx(Voidptr) diff --git a/src/scripting/backend/codegen.cpp b/src/scripting/backend/codegen.cpp index b6059a49c..79b48953a 100644 --- a/src/scripting/backend/codegen.cpp +++ b/src/scripting/backend/codegen.cpp @@ -8240,7 +8240,9 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) { auto elementType = static_cast(Self->ValueType)->ElementType; Self->ValueType = static_cast(Self->ValueType)->BackingType; + bool isDynArrayObj = elementType->isObjectPointer(); // this requires some added type checks for the passed types. + int idx = 0; for (auto &a : ArgList) { a = a->Resolve(ctx); @@ -8249,6 +8251,16 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) delete this; return nullptr; } + if (isDynArrayObj && ((MethodName == NAME_Push && idx == 0) || (MethodName == NAME_Insert && idx == 1))) + { + // The DynArray_Obj declaration in dynarrays.txt doesn't support generics yet. Check the type here as if it did. + if (!static_cast(elementType)->PointedClass()->IsAncestorOf(static_cast(a->ValueType)->PointedClass())) + { + ScriptPosition.Message(MSG_ERROR, "Type mismatch in function argument"); + delete this; + return nullptr; + } + } if (a->IsDynamicArray()) { // Copy and Move must turn their parameter into a pointer to the backing struct type. @@ -8288,6 +8300,7 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) return nullptr; } } + idx++; } } } From a23d1c2d2522f52a57787b94483d05d310b1b5a5 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 14 Nov 2018 20:59:24 +0100 Subject: [PATCH 2/5] - went back to the original portal stencil setup from 3.4.0. The main reason is to unify the portal hierarchy again. The split into a hardware independent and a hardware dependent part turned out to be unnecessary and complicated matters. Another issue was that the new stencil setup code was having a few subtle problems, so this recreates the original ones with indirect API calls. --- src/gl/renderer/gl_renderstate.cpp | 17 +++- src/gl/renderer/gl_renderstate.h | 1 + src/hwrenderer/scene/hw_drawinfo.cpp | 4 +- src/hwrenderer/scene/hw_drawinfo.h | 2 +- src/hwrenderer/scene/hw_portal.cpp | 130 ++++++++++++++++---------- src/hwrenderer/scene/hw_portal.h | 117 +++++++++-------------- src/hwrenderer/scene/hw_renderstate.h | 8 +- src/hwrenderer/scene/hw_skyportal.cpp | 4 +- src/hwrenderer/scene/hw_walls.cpp | 14 +-- src/portal.h | 3 +- 10 files changed, 156 insertions(+), 144 deletions(-) diff --git a/src/gl/renderer/gl_renderstate.cpp b/src/gl/renderer/gl_renderstate.cpp index 76e8ba892..883231bc4 100644 --- a/src/gl/renderer/gl_renderstate.cpp +++ b/src/gl/renderer/gl_renderstate.cpp @@ -436,22 +436,29 @@ void FGLRenderState::SetDepthRange(float min, float max) glDepthRange(min, max); } +void FGLRenderState::SetColorMask(bool r, bool g, bool b, bool a) +{ + glColorMask(r, g, b, a); +} + void FGLRenderState::EnableDrawBufferAttachments(bool on) { EnableDrawBuffers(on ? GetPassDrawBufferCount() : 1); } -void FGLRenderState::SetStencil(int offs, int op, int flags) +void FGLRenderState::SetStencil(int offs, int op, int flags = -1) { static int op2gl[] = { GL_KEEP, GL_INCR, GL_DECR }; glStencilFunc(GL_EQUAL, screen->stencilValue + offs, ~0); // draw sky into stencil glStencilOp(GL_KEEP, GL_KEEP, op2gl[op]); // this stage doesn't modify the stencil - bool cmon = !(flags & SF_ColorMaskOff); - bool cmalpha = cmon || (flags & SF_ColorMaskAlpha); - glColorMask(cmon, cmon, cmon, cmalpha); // don't write to the graphics buffer - glDepthMask(!(flags & SF_DepthMaskOff)); + if (flags != -1) + { + bool cmon = !(flags & SF_ColorMaskOff); + glColorMask(cmon, cmon, cmon, cmon); // don't write to the graphics buffer + glDepthMask(!(flags & SF_DepthMaskOff)); + } } void FGLRenderState::ToggleState(int state, bool on) diff --git a/src/gl/renderer/gl_renderstate.h b/src/gl/renderer/gl_renderstate.h index 7f6ac8af1..25b4420f3 100644 --- a/src/gl/renderer/gl_renderstate.h +++ b/src/gl/renderer/gl_renderstate.h @@ -153,6 +153,7 @@ public: void SetDepthMask(bool on) override; void SetDepthFunc(int func) override; void SetDepthRange(float min, float max) override; + void SetColorMask(bool r, bool g, bool b, bool a) override; void EnableDrawBufferAttachments(bool on) override; void SetStencil(int offs, int op, int flags) override; void SetCulling(int mode) override; diff --git a/src/hwrenderer/scene/hw_drawinfo.cpp b/src/hwrenderer/scene/hw_drawinfo.cpp index 803b70c12..f3fbbff37 100644 --- a/src/hwrenderer/scene/hw_drawinfo.cpp +++ b/src/hwrenderer/scene/hw_drawinfo.cpp @@ -667,10 +667,10 @@ void HWDrawInfo::AddSubsectorToPortal(FSectorPortalGroup *ptg, subsector_t *sub) auto portal = FindPortal(ptg); if (!portal) { - portal = new HWScenePortal(screen->mPortalState, new HWSectorStackPortal(ptg)); + portal = new HWSectorStackPortal(screen->mPortalState, ptg); Portals.Push(portal); } - auto ptl = static_cast(static_cast(portal)->mScene); + auto ptl = static_cast(portal); ptl->AddSubsector(sub); } diff --git a/src/hwrenderer/scene/hw_drawinfo.h b/src/hwrenderer/scene/hw_drawinfo.h index 24d6c2218..5913ca97b 100644 --- a/src/hwrenderer/scene/hw_drawinfo.h +++ b/src/hwrenderer/scene/hw_drawinfo.h @@ -144,7 +144,7 @@ struct HWDrawInfo HWDrawInfo * outer = nullptr; int FullbrightFlags; std::atomic spriteindex; - HWScenePortalBase *mClipPortal; + HWPortal *mClipPortal; HWPortal *mCurrentPortal; //FRotator mAngles; Clipper *mClipper; diff --git a/src/hwrenderer/scene/hw_portal.cpp b/src/hwrenderer/scene/hw_portal.cpp index 6426e4213..d951a7e64 100644 --- a/src/hwrenderer/scene/hw_portal.cpp +++ b/src/hwrenderer/scene/hw_portal.cpp @@ -26,7 +26,6 @@ */ #include "c_dispatch.h" -#include "portal.h" #include "p_maputl.h" #include "hw_portal.h" #include "hw_clipper.h" @@ -172,13 +171,14 @@ void HWPortal::DrawPortalStencil(FRenderState &state, int pass) if (mPrimIndices.Size() == 0) { mPrimIndices.Resize(2 * lines.Size()); - + for (unsigned int i = 0; i < lines.Size(); i++) { mPrimIndices[i * 2] = lines[i].vertindex; mPrimIndices[i * 2 + 1] = lines[i].vertcount; } } + for (unsigned int i = 0; i < mPrimIndices.Size(); i += 2) { state.Draw(DT_TriangleFan, mPrimIndices[i], mPrimIndices[i + 1], i == 0); @@ -187,12 +187,13 @@ void HWPortal::DrawPortalStencil(FRenderState &state, int pass) { // The cap's depth handling needs special treatment so that it won't block further portal caps. if (pass == STP_DepthRestore) state.SetDepthRange(1, 1); - state.Draw(DT_TriangleFan, FFlatVertexBuffer::STENCILTOP_INDEX, 4); - state.Draw(DT_TriangleFan, FFlatVertexBuffer::STENCILBOTTOM_INDEX, 4); + state.Draw(DT_TriangleFan, FFlatVertexBuffer::STENCILTOP_INDEX, 4, false); + state.Draw(DT_TriangleFan, FFlatVertexBuffer::STENCILBOTTOM_INDEX, 4, false); if (pass == STP_DepthRestore) state.SetDepthRange(0, 1); } } + //----------------------------------------------------------------------------- // // Start @@ -204,53 +205,60 @@ void HWPortal::SetupStencil(HWDrawInfo *di, FRenderState &state, bool usestencil Clocker c(PortalAll); rendered_portals++; + if (usestencil) { - // Create stencil + // Create stencil + state.SetStencil(0, SOP_Increment); // create stencil, increment stencil of valid pixels + state.SetColorMask(false); state.SetEffect(EFF_STENCIL); state.EnableTexture(false); state.ResetColor(); - + state.SetDepthFunc(DF_Less); + if (NeedDepthBuffer()) { - state.SetStencil(0, SOP_Increment, SF_ColorMaskOff | SF_DepthMaskOff); - state.SetDepthFunc(DF_Less); + state.SetDepthMask(false); // don't write to Z-buffer! + DrawPortalStencil(state, STP_Stencil); - + // Clear Z-buffer - state.SetStencil(1, SOP_Keep, SF_ColorMaskOff); + state.SetStencil(1, SOP_Keep); // draw sky into stencil. This stage doesn't modify the stencil. + state.SetDepthMask(true); // enable z-buffer again state.SetDepthRange(1, 1); state.SetDepthFunc(DF_Always); DrawPortalStencil(state, STP_DepthClear); - + // set normal drawing mode state.EnableTexture(true); - state.SetStencil(1, SOP_Keep, SF_AllOn); state.SetDepthRange(0, 1); state.SetDepthFunc(DF_Less); + state.SetColorMask(true); state.SetEffect(EFF_NONE); } else { // No z-buffer is needed therefore we can skip all the complicated stuff that is involved // Note: We must draw the stencil with z-write enabled here because there is no second pass! - state.SetStencil(0, SOP_Increment, SF_ColorMaskOff); - state.SetDepthFunc(DF_Less); + + state.SetDepthMask(true); DrawPortalStencil(state, STP_AllInOne); - - state.SetStencil(1, SOP_Keep, SF_DepthMaskOff); - state.EnableDepthTest(false); + state.SetStencil(1, SOP_Keep); // draw sky into stencil. This stage doesn't modify the stencil. state.EnableTexture(true); + state.SetColorMask(true); state.SetEffect(EFF_NONE); + state.EnableDepthTest(false); + state.SetDepthMask(false); // don't write to Z-buffer! } - screen->stencilValue++; + + } else { if (!NeedDepthBuffer()) { - state.SetStencil(0, SOP_Keep, SF_DepthMaskOff); + state.SetDepthMask(false); state.EnableDepthTest(false); } } @@ -259,6 +267,12 @@ void HWPortal::SetupStencil(HWDrawInfo *di, FRenderState &state, bool usestencil savedvisibility = di->Viewpoint.camera ? di->Viewpoint.camera->renderflags & RF_MAYBEINVISIBLE : ActorRenderFlags::FromInt(0); } + +//----------------------------------------------------------------------------- +// +// End +// +//----------------------------------------------------------------------------- void HWPortal::RemoveStencil(HWDrawInfo *di, FRenderState &state, bool usestencil) { Clocker c(PortalAll); @@ -268,53 +282,73 @@ void HWPortal::RemoveStencil(HWDrawInfo *di, FRenderState &state, bool usestenci auto &vp = di->Viewpoint; if (vp.camera != nullptr) vp.camera->renderflags = (vp.camera->renderflags & ~RF_MAYBEINVISIBLE) | savedvisibility; - state.EnableDepthTest(true); if (usestencil) { + + state.SetColorMask(false); // no graphics state.SetEffect(EFF_NONE); state.ResetColor(); state.EnableTexture(false); - + if (needdepth) { // first step: reset the depth buffer to max. depth - state.SetStencil(0, SOP_Keep, SF_ColorMaskOff); state.SetDepthRange(1, 1); // always state.SetDepthFunc(DF_Always); // write the farthest depth value DrawPortalStencil(state, STP_DepthClear); } - + else + { + state.EnableDepthTest(true); + } + // second step: restore the depth buffer to the previous values and reset the stencil - state.SetStencil(0, SOP_Decrement, SF_ColorMaskOff); - state.SetDepthRange(0, 1); state.SetDepthFunc(DF_LEqual); + state.SetDepthRange(0, 1); + state.SetStencil(0, SOP_Decrement); DrawPortalStencil(state, STP_DepthRestore); - + state.SetDepthFunc(DF_Less); + + state.EnableTexture(true); state.SetEffect(EFF_NONE); + state.SetColorMask(true); screen->stencilValue--; + + // restore old stencil op. + state.SetStencil(0, SOP_Keep); } else { + if (needdepth) + { + state.Clear(CT_Depth); + } + else + { + state.EnableDepthTest(true); + state.SetDepthMask(true); + } + + // This draws a valid z-buffer into the stencil's contents to ensure it + // doesn't get overwritten by the level's geometry. + state.ResetColor(); + state.SetDepthFunc(DF_LEqual); + state.SetDepthRange(0, 1); + state.SetColorMask(0, 0, 0, 1); // mark portal in alpha channel but don't touch color state.SetEffect(EFF_STENCIL); state.EnableTexture(false); state.SetRenderStyle(STYLE_Source); - - state.SetStencil(0, SOP_Keep, SF_ColorMaskOff | SF_ColorMaskAlpha); // SSAO needs the alpha channel as a marker. - if (needdepth) state.Clear(CT_Depth); - state.SetDepthRange(0, 1); - state.SetDepthFunc(DF_LEqual); DrawPortalStencil(state, STP_DepthRestore); - state.SetEffect(EFF_NONE); state.EnableTexture(true); + state.SetColorMask(true); + state.SetDepthFunc(DF_Less); } - state.SetStencil(0, SOP_Keep, SF_AllOn); } - //----------------------------------------------------------------------------- // // @@ -328,7 +362,6 @@ void HWScenePortalBase::ClearClipper(HWDrawInfo *di, Clipper *clipper) clipper->Clear(); - auto &lines = mOwner->lines; // Set the clipper to the minimal visible area clipper->SafeAddClipRange(0, 0xffffffff); for (unsigned int i = 0; i < lines.Size(); i++) @@ -409,7 +442,7 @@ int HWLinePortal::ClipPoint(const DVector2 &pos) bool HWMirrorPortal::Setup(HWDrawInfo *di, FRenderState &rstate, Clipper *clipper) { - auto state = mOwner->mState; + auto state = mState; if (state->renderdepth > r_mirror_recursions) { return false; @@ -490,7 +523,7 @@ bool HWMirrorPortal::Setup(HWDrawInfo *di, FRenderState &rstate, Clipper *clippe void HWMirrorPortal::Shutdown(HWDrawInfo *di, FRenderState &rstate) { - mOwner->mState->MirrorFlag--; + mState->MirrorFlag--; } const char *HWMirrorPortal::GetName() { return "Mirror"; } @@ -513,7 +546,7 @@ const char *HWMirrorPortal::GetName() { return "Mirror"; } bool HWLineToLinePortal::Setup(HWDrawInfo *di, FRenderState &rstate, Clipper *clipper) { // TODO: Handle recursion more intelligently - auto &state = mOwner->mState; + auto &state = mState; if (state->renderdepth>r_mirror_recursions) { return false; @@ -543,7 +576,6 @@ bool HWLineToLinePortal::Setup(HWDrawInfo *di, FRenderState &rstate, Clipper *cl } } - auto &lines = mOwner->lines; for (unsigned i = 0; i < lines.Size(); i++) { @@ -589,10 +621,10 @@ const char *HWLineToLinePortal::GetName() { return "LineToLine"; } bool HWSkyboxPortal::Setup(HWDrawInfo *di, FRenderState &rstate, Clipper *clipper) { - auto state = mOwner->mState; + auto state = mState; old_pm = state->PlaneMirrorMode; - if (mOwner->mState->skyboxrecursion >= 3) + if (mState->skyboxrecursion >= 3) { return false; } @@ -631,7 +663,7 @@ void HWSkyboxPortal::Shutdown(HWDrawInfo *di, FRenderState &rstate) { rstate.SetDepthClamp(oldclamp); - auto state = mOwner->mState; + auto state = mState; portal->mFlags &= ~PORTSF_INSKYBOX; state->inskybox = false; state->skyboxrecursion--; @@ -699,7 +731,7 @@ void HWSectorStackPortal::SetupCoverage(HWDrawInfo *di) //----------------------------------------------------------------------------- bool HWSectorStackPortal::Setup(HWDrawInfo *di, FRenderState &rstate, Clipper *clipper) { - auto state = mOwner->mState; + auto state = mState; FSectorPortalGroup *portal = origin; auto &vp = di->Viewpoint; @@ -751,7 +783,7 @@ const char *HWSectorStackPortal::GetName() { return "Sectorstack"; } bool HWPlaneMirrorPortal::Setup(HWDrawInfo *di, FRenderState &rstate, Clipper *clipper) { - auto state = mOwner->mState; + auto state = mState; if (state->renderdepth > r_mirror_recursions) { return false; @@ -781,7 +813,7 @@ bool HWPlaneMirrorPortal::Setup(HWDrawInfo *di, FRenderState &rstate, Clipper *c void HWPlaneMirrorPortal::Shutdown(HWDrawInfo *di, FRenderState &rstate) { - auto state = mOwner->mState; + auto state = mState; state->PlaneMirrorFlag--; state->PlaneMirrorMode = old_pm; std::swap(screen->instack[sector_t::floor], screen->instack[sector_t::ceiling]); @@ -800,8 +832,8 @@ const char *HWPlaneMirrorPortal::GetName() { return origin->fC() < 0? "Planemirr //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- -HWHorizonPortal::HWHorizonPortal(FPortalSceneState *s, GLHorizonInfo * pt, FRenderViewpoint &vp, HWDrawInfo *di, bool local) - : HWPortal(s, local) +HWHorizonPortal::HWHorizonPortal(FPortalSceneState *s, GLHorizonInfo * pt, FRenderViewpoint &vp, bool local) +: HWPortal(s, local) { origin = pt; @@ -960,7 +992,7 @@ void HWEEHorizonPortal::DrawContents(HWDrawInfo *di, FRenderState &state) { horz.plane.Texheight = vp.Pos.Z + fabs(horz.plane.Texheight); } - HWHorizonPortal ceil(mState, &horz, di->Viewpoint, di, true); + HWHorizonPortal ceil(mState, &horz, di->Viewpoint, true); ceil.DrawContents(di, state); } if (sector->GetTexture(sector_t::floor) != skyflatnum) @@ -974,7 +1006,7 @@ void HWEEHorizonPortal::DrawContents(HWDrawInfo *di, FRenderState &state) { horz.plane.Texheight = vp.Pos.Z - fabs(horz.plane.Texheight); } - HWHorizonPortal floor(mState, &horz, di->Viewpoint, di, true); + HWHorizonPortal floor(mState, &horz, di->Viewpoint, true); floor.DrawContents(di, state); } } diff --git a/src/hwrenderer/scene/hw_portal.h b/src/hwrenderer/scene/hw_portal.h index 35629b89a..42d71434d 100644 --- a/src/hwrenderer/scene/hw_portal.h +++ b/src/hwrenderer/scene/hw_portal.h @@ -1,13 +1,13 @@ #pragma once -#include "portal.h" +#include "tarray.h" +#include "r_utility.h" #include "actor.h" -#include "hw_drawinfo.h" -#include "hw_drawstructs.h" +#include "hwrenderer/scene/hw_drawinfo.h" +#include "hwrenderer/scene/hw_drawstructs.h" +#include "hw_renderstate.h" #include "hwrenderer/textures/hw_material.h" -#include "hwrenderer/scene/hw_renderstate.h" -class FSkyVertexBuffer; struct GLSkyInfo { @@ -62,11 +62,14 @@ public: FPortalSceneState * mState; TArray lines; - HWPortal(FPortalSceneState *s, bool local); - void SetupStencil(HWDrawInfo *di, FRenderState &state, bool usestencil); - void RemoveStencil(HWDrawInfo *di, FRenderState &state, bool usestencil); - - virtual ~HWPortal() {} + HWPortal(FPortalSceneState *s, bool local = false) : mState(s) + { + } + virtual ~HWPortal() {} + virtual int ClipSeg(seg_t *seg, const DVector3 &viewpos) { return PClip_Inside; } + virtual int ClipSubsector(subsector_t *sub) { return PClip_Inside; } + virtual int ClipPoint(const DVector2 &pos) { return PClip_Inside; } + virtual line_t *ClipLine() { return nullptr; } virtual void * GetSource() const = 0; // GetSource MUST be implemented! virtual const char *GetName() = 0; virtual bool IsSky() { return false; } @@ -74,6 +77,8 @@ public: virtual bool NeedDepthBuffer() { return true; } virtual void DrawContents(HWDrawInfo *di, FRenderState &state) = 0; virtual void RenderAttached(HWDrawInfo *di) {} + void SetupStencil(HWDrawInfo *di, FRenderState &state, bool usestencil); + void RemoveStencil(HWDrawInfo *di, FRenderState &state, bool usestencil); void AddLine(GLWall * l) { @@ -83,6 +88,7 @@ public: }; + struct FPortalSceneState { int MirrorFlag = 0; @@ -116,37 +122,28 @@ struct FPortalSceneState void RenderPortal(HWPortal *p, FRenderState &state, bool usestencil, HWDrawInfo *outer_di); }; -inline HWPortal::HWPortal(FPortalSceneState *s, bool local) : mState(s) -{ - //if (!local) s->portals.Push(this); -} - - -class HWScenePortalBase + +class HWScenePortalBase : public HWPortal { protected: - HWPortal *mOwner; + HWScenePortalBase(FPortalSceneState *state) : HWPortal(state, false) + { + + } public: - HWScenePortalBase() {} - virtual ~HWScenePortalBase() {} - void SetOwner(HWPortal *p) { mOwner = p; } void ClearClipper(HWDrawInfo *di, Clipper *clipper); - - virtual int ClipSeg(seg_t *seg, const DVector3 &viewpos) { return PClip_Inside; } - virtual int ClipSubsector(subsector_t *sub) { return PClip_Inside; } - virtual int ClipPoint(const DVector2 &pos) { return PClip_Inside; } - virtual line_t *ClipLine() { return nullptr; } - - virtual bool IsSky() { return false; } - virtual bool NeedCap() { return false; } virtual bool NeedDepthBuffer() { return true; } - virtual void * GetSource() const = 0; // GetSource MUST be implemented! - virtual const char *GetName() = 0; - + virtual void DrawContents(HWDrawInfo *di, FRenderState &state) + { + if (Setup(di, state, di->mClipper)) + { + di->DrawScene(di, DM_PORTAL); + Shutdown(di, state); + } + else state.ClearScreen(); + } virtual bool Setup(HWDrawInfo *di, FRenderState &rstate, Clipper *clipper) = 0; virtual void Shutdown(HWDrawInfo *di, FRenderState &rstate) {} - virtual void RenderAttached(HWDrawInfo *di) {} - }; struct HWLinePortal : public HWScenePortalBase @@ -157,14 +154,14 @@ struct HWLinePortal : public HWScenePortalBase angle_t angv1, angv2; // for quick comparisons with a line or subsector - HWLinePortal(line_t *line) + HWLinePortal(FPortalSceneState *state, line_t *line) : HWScenePortalBase(state) { v1 = line->v1; v2 = line->v2; CalcDelta(); } - HWLinePortal(FLinePortalSpan *line) + HWLinePortal(FPortalSceneState *state, FLinePortalSpan *line) : HWScenePortalBase(state) { if (line->lines[0]->mType != PORTT_LINKED || line->v1 == nullptr) { @@ -212,8 +209,8 @@ protected: public: - HWMirrorPortal(line_t * line) - : HWLinePortal(line) + HWMirrorPortal(FPortalSceneState *state, line_t * line) + : HWLinePortal(state, line) { linedef = line; } @@ -232,8 +229,8 @@ protected: public: - HWLineToLinePortal(FLinePortalSpan *ll) - : HWLinePortal(ll) + HWLineToLinePortal(FPortalSceneState *state, FLinePortalSpan *ll) + : HWLinePortal(state, ll) { glport = ll; } @@ -256,7 +253,7 @@ protected: public: - HWSkyboxPortal(FSectorPortal * pt) + HWSkyboxPortal(FPortalSceneState *state, FSectorPortal * pt) : HWScenePortalBase(state) { portal = pt; } @@ -277,7 +274,7 @@ protected: public: - HWSectorStackPortal(FSectorPortalGroup *pt) + HWSectorStackPortal(FPortalSceneState *state, FSectorPortalGroup *pt) : HWScenePortalBase(state) { origin = pt; } @@ -301,7 +298,7 @@ protected: public: - HWPlaneMirrorPortal(secplane_t * pt) + HWPlaneMirrorPortal(FPortalSceneState *state, secplane_t * pt) : HWScenePortalBase(state) { origin = pt; } @@ -309,34 +306,6 @@ public: }; -class HWScenePortal : public HWPortal -{ -public: - HWScenePortalBase *mScene; - HWScenePortal(FPortalSceneState *state, HWScenePortalBase *handler) : HWPortal(state, false) - { - mScene = handler; - handler->SetOwner(this); - } - ~HWScenePortal() { delete mScene; } - virtual void * GetSource() const { return mScene->GetSource(); } - virtual const char *GetName() { return mScene->GetName(); } - virtual bool IsSky() { return mScene->IsSky(); } - virtual bool NeedCap() { return true; } - virtual bool NeedDepthBuffer() { return true; } - virtual void DrawContents(HWDrawInfo *di, FRenderState &state) - { - if (mScene->Setup(di, state, di->mClipper)) - { - di->DrawScene(di, DM_PORTAL); - mScene->Shutdown(di, state); - } - else state.ClearScreen(); - } - virtual void RenderAttached(HWDrawInfo *di) { return mScene->RenderAttached(di); } -}; - - struct HWHorizonPortal : public HWPortal { GLHorizonInfo * origin; @@ -352,8 +321,8 @@ protected: virtual const char *GetName(); public: - - HWHorizonPortal(FPortalSceneState *state, GLHorizonInfo * pt, FRenderViewpoint &vp, HWDrawInfo *di, bool local = false); + + HWHorizonPortal(FPortalSceneState *state, GLHorizonInfo * pt, FRenderViewpoint &vp, bool local = false); }; struct HWEEHorizonPortal : public HWPortal @@ -369,7 +338,7 @@ protected: public: - HWEEHorizonPortal(FPortalSceneState *state, FSectorPortal *pt, HWDrawInfo *di) : HWPortal(state, false) + HWEEHorizonPortal(FPortalSceneState *state, FSectorPortal *pt) : HWPortal(state) { portal = pt; } diff --git a/src/hwrenderer/scene/hw_renderstate.h b/src/hwrenderer/scene/hw_renderstate.h index 66f7ccff3..f494df34a 100644 --- a/src/hwrenderer/scene/hw_renderstate.h +++ b/src/hwrenderer/scene/hw_renderstate.h @@ -57,7 +57,6 @@ enum EStencilFlags SF_AllOn = 0, SF_ColorMaskOff = 1, SF_DepthMaskOff = 2, - SF_ColorMaskAlpha = 4, // hack value for SSAO }; enum EStencilOp @@ -507,8 +506,9 @@ public: virtual void SetDepthMask(bool on) = 0; // Used by decals and indirectly by portal setup. virtual void SetDepthFunc(int func) = 0; // Used by models, portals and mirror surfaces. virtual void SetDepthRange(float min, float max) = 0; // Used by portal setup. + virtual void SetColorMask(bool r, bool g, bool b, bool a) = 0; // Used by portals. virtual void EnableDrawBufferAttachments(bool on) = 0; // Used by fog boundary drawer. - virtual void SetStencil(int offs, int op, int flags) = 0; // Used by portal setup and render hacks. + virtual void SetStencil(int offs, int op, int flags=-1) = 0; // Used by portal setup and render hacks. virtual void SetCulling(int mode) = 0; // Used by model drawer only. virtual void EnableClipDistance(int num, bool state) = 0; // Use by sprite sorter for vertical splits. virtual void Clear(int targets) = 0; // not used during normal rendering @@ -519,6 +519,10 @@ public: virtual void EnableMultisampling(bool on) = 0; // only active for 2D virtual void EnableLineSmooth(bool on) = 0; // constant setting for each 2D drawer operation + void SetColorMask(bool on) + { + SetColorMask(on, on, on, on); + } }; diff --git a/src/hwrenderer/scene/hw_skyportal.cpp b/src/hwrenderer/scene/hw_skyportal.cpp index 9da564e63..cb04c1e86 100644 --- a/src/hwrenderer/scene/hw_skyportal.cpp +++ b/src/hwrenderer/scene/hw_skyportal.cpp @@ -104,9 +104,9 @@ void HWSkyPortal::RenderBox(HWDrawInfo *di, FRenderState &state, FTextureID texn state.mModelMatrix.loadIdentity(); if (!sky2) - state.mModelMatrix.rotate(-180.0f+x_offset, level.info->skyrotatevector.X, level.info->skyrotatevector.Z, level.info->skyrotatevector.Y); + state.mModelMatrix.rotate(-180.0f+x_offset, ::level.info->skyrotatevector.X, ::level.info->skyrotatevector.Z, ::level.info->skyrotatevector.Y); else - state.mModelMatrix.rotate(-180.0f+x_offset, level.info->skyrotatevector2.X, level.info->skyrotatevector2.Z, level.info->skyrotatevector2.Y); + state.mModelMatrix.rotate(-180.0f+x_offset, ::level.info->skyrotatevector2.X, ::level.info->skyrotatevector2.Z, ::level.info->skyrotatevector2.Y); if (sb->faces[5]) { diff --git a/src/hwrenderer/scene/hw_walls.cpp b/src/hwrenderer/scene/hw_walls.cpp index 0622553f7..cffecb0af 100644 --- a/src/hwrenderer/scene/hw_walls.cpp +++ b/src/hwrenderer/scene/hw_walls.cpp @@ -498,7 +498,7 @@ void GLWall::PutPortal(HWDrawInfo *di, int ptype) portal = di->FindPortal(horizon); if (!portal) { - portal = new HWHorizonPortal(pstate, horizon, di->Viewpoint, di); + portal = new HWHorizonPortal(pstate, horizon, di->Viewpoint); di->Portals.Push(portal); } portal->AddLine(this); @@ -509,10 +509,10 @@ void GLWall::PutPortal(HWDrawInfo *di, int ptype) if (!portal) { // either a regular skybox or an Eternity-style horizon - if (secportal->mType != PORTS_SKYVIEWPOINT) portal = new HWEEHorizonPortal(pstate, secportal, di); + if (secportal->mType != PORTS_SKYVIEWPOINT) portal = new HWEEHorizonPortal(pstate, secportal); else { - portal = new HWScenePortal(pstate, new HWSkyboxPortal(secportal)); + portal = new HWSkyboxPortal(pstate, secportal); di->Portals.Push(portal); } } @@ -523,7 +523,7 @@ void GLWall::PutPortal(HWDrawInfo *di, int ptype) portal = di->FindPortal(this->portal); if (!portal) { - portal = new HWScenePortal(pstate, new HWSectorStackPortal(this->portal)); + portal = new HWSectorStackPortal(pstate, this->portal); di->Portals.Push(portal); } portal->AddLine(this); @@ -537,7 +537,7 @@ void GLWall::PutPortal(HWDrawInfo *di, int ptype) portal = di->FindPortal(planemirror); if (!portal) { - portal = new HWScenePortal(pstate, new HWPlaneMirrorPortal(planemirror)); + portal = new HWPlaneMirrorPortal(pstate, planemirror); di->Portals.Push(portal); } portal->AddLine(this); @@ -548,7 +548,7 @@ void GLWall::PutPortal(HWDrawInfo *di, int ptype) portal = di->FindPortal(seg->linedef); if (!portal) { - portal = new HWScenePortal(pstate, new HWMirrorPortal(seg->linedef)); + portal = new HWMirrorPortal(pstate, seg->linedef); di->Portals.Push(portal); } portal->AddLine(this); @@ -570,7 +570,7 @@ void GLWall::PutPortal(HWDrawInfo *di, int ptype) { di->ProcessActorsInPortal(otherside->getPortal()->mGroup, di->in_area); } - portal = new HWScenePortal(pstate, new HWLineToLinePortal(lineportal)); + portal = new HWLineToLinePortal(pstate, lineportal); di->Portals.Push(portal); } portal->AddLine(this); diff --git a/src/portal.h b/src/portal.h index 01b17fc8b..daeb784f6 100644 --- a/src/portal.h +++ b/src/portal.h @@ -249,7 +249,6 @@ struct FSectorPortal // //============================================================================ -struct GLSectorStackPortal; struct FSectorPortalGroup { DVector2 mDisplacement; @@ -286,4 +285,4 @@ DVector2 P_GetOffsetPosition(double x, double y, double dx, double dy); void InitPortalGroups(); -#endif \ No newline at end of file +#endif From 9f6091519f62ffdb9cd773bab48249dbf1945c80 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 14 Nov 2018 23:30:46 +0100 Subject: [PATCH 3/5] - changed the stencil cap drawer to only cover the area which is actually used by the portal. This will now both exclude floor caps when only ceiling elements are used and everything outside the bounding box of active portal lines. Hopefully this is enough to fix the issues with portal caps but of course it is not foolproof if someone just makes the right setup. --- src/hwrenderer/scene/hw_drawstructs.h | 2 +- src/hwrenderer/scene/hw_portal.cpp | 31 ++++++++++++++++++++++++-- src/hwrenderer/scene/hw_portal.h | 6 ++++- src/hwrenderer/scene/hw_sky.cpp | 6 ++--- src/hwrenderer/scene/hw_walls.cpp | 20 ++++++++++------- src/r_data/r_sections.cpp | 10 ++++----- src/r_data/r_sections.h | 32 +++++++++++++++++++++++---- 7 files changed, 83 insertions(+), 24 deletions(-) diff --git a/src/hwrenderer/scene/hw_drawstructs.h b/src/hwrenderer/scene/hw_drawstructs.h index d500e6795..ae89d65de 100644 --- a/src/hwrenderer/scene/hw_drawstructs.h +++ b/src/hwrenderer/scene/hw_drawstructs.h @@ -201,7 +201,7 @@ public: //private: void PutWall(HWDrawInfo *di, bool translucent); - void PutPortal(HWDrawInfo *di, int ptype); + void PutPortal(HWDrawInfo *di, int ptype, int plane); void CheckTexturePosition(FTexCoordInfo *tci); void Put3DWall(HWDrawInfo *di, lightlist_t * lightlist, bool translucent); diff --git a/src/hwrenderer/scene/hw_portal.cpp b/src/hwrenderer/scene/hw_portal.cpp index d951a7e64..9cb35c696 100644 --- a/src/hwrenderer/scene/hw_portal.cpp +++ b/src/hwrenderer/scene/hw_portal.cpp @@ -140,6 +140,14 @@ bool FPortalSceneState::RenderFirstSkyPortal(int recursion, HWDrawInfo *outer_di best = p; bestindex = i; } + + // If the portal area contains the current camera viewpoint, let's always use it because it's likely to give the largest area. + if (p->boundingBox.contains(outer_di->Viewpoint.Pos)) + { + best = p; + bestindex = i; + break; + } } } @@ -187,8 +195,27 @@ void HWPortal::DrawPortalStencil(FRenderState &state, int pass) { // The cap's depth handling needs special treatment so that it won't block further portal caps. if (pass == STP_DepthRestore) state.SetDepthRange(1, 1); - state.Draw(DT_TriangleFan, FFlatVertexBuffer::STENCILTOP_INDEX, 4, false); - state.Draw(DT_TriangleFan, FFlatVertexBuffer::STENCILBOTTOM_INDEX, 4, false); + + if (planesused & (1 << sector_t::floor)) + { + auto verts = screen->mVertexData->AllocVertices(4); + auto ptr = verts.first; + ptr[0].Set((float)boundingBox.left, -32767.f, (float)boundingBox.top, 0, 0); + ptr[1].Set((float)boundingBox.right, -32767.f, (float)boundingBox.top, 0, 0); + ptr[2].Set((float)boundingBox.left, -32767.f, (float)boundingBox.bottom, 0, 0); + ptr[3].Set((float)boundingBox.right, -32767.f, (float)boundingBox.bottom, 0, 0); + state.Draw(DT_TriangleStrip, verts.second, 4, false); + } + if (planesused & (1 << sector_t::ceiling)) + { + auto verts = screen->mVertexData->AllocVertices(4); + auto ptr = verts.first; + ptr[0].Set((float)boundingBox.left, 32767.f, (float)boundingBox.top, 0, 0); + ptr[1].Set((float)boundingBox.right, 32767.f, (float)boundingBox.top, 0, 0); + ptr[2].Set((float)boundingBox.left, 32767.f, (float)boundingBox.bottom, 0, 0); + ptr[3].Set((float)boundingBox.right, 32767.f, (float)boundingBox.bottom, 0, 0); + state.Draw(DT_TriangleStrip, verts.second, 4, false); + } if (pass == STP_DepthRestore) state.SetDepthRange(0, 1); } } diff --git a/src/hwrenderer/scene/hw_portal.h b/src/hwrenderer/scene/hw_portal.h index 42d71434d..f9d9e243c 100644 --- a/src/hwrenderer/scene/hw_portal.h +++ b/src/hwrenderer/scene/hw_portal.h @@ -61,8 +61,10 @@ class HWPortal public: FPortalSceneState * mState; TArray lines; + BoundingRect boundingBox; + int planesused = 0; - HWPortal(FPortalSceneState *s, bool local = false) : mState(s) + HWPortal(FPortalSceneState *s, bool local = false) : mState(s), boundingBox(false) { } virtual ~HWPortal() {} @@ -83,6 +85,8 @@ public: void AddLine(GLWall * l) { lines.Push(*l); + boundingBox.addVertex(l->glseg.x1, l->glseg.y1); + boundingBox.addVertex(l->glseg.x2, l->glseg.y2); } diff --git a/src/hwrenderer/scene/hw_sky.cpp b/src/hwrenderer/scene/hw_sky.cpp index 57eeb0eee..695321312 100644 --- a/src/hwrenderer/scene/hw_sky.cpp +++ b/src/hwrenderer/scene/hw_sky.cpp @@ -122,7 +122,7 @@ void GLWall::SkyPlane(HWDrawInfo *di, sector_t *sector, int plane, bool allowref skyinfo.init(sector->sky, Colormap.FadeColor); ptype = PORTALTYPE_SKY; sky = &skyinfo; - PutPortal(di, ptype); + PutPortal(di, ptype, plane); } else if (sportal != nullptr) { @@ -162,7 +162,7 @@ void GLWall::SkyPlane(HWDrawInfo *di, sector_t *sector, int plane, bool allowref } if (ptype != -1) { - PutPortal(di, ptype); + PutPortal(di, ptype, plane); } } @@ -197,7 +197,7 @@ void GLWall::SkyLine(HWDrawInfo *di, sector_t *fs, line_t *line) ztop[1] = zceil[1]; zbottom[0] = zfloor[0]; zbottom[1] = zfloor[1]; - PutPortal(di, ptype); + PutPortal(di, ptype, -1); } diff --git a/src/hwrenderer/scene/hw_walls.cpp b/src/hwrenderer/scene/hw_walls.cpp index cffecb0af..70ca0f633 100644 --- a/src/hwrenderer/scene/hw_walls.cpp +++ b/src/hwrenderer/scene/hw_walls.cpp @@ -483,10 +483,10 @@ void GLWall::PutWall(HWDrawInfo *di, bool translucent) // //========================================================================== -void GLWall::PutPortal(HWDrawInfo *di, int ptype) +void GLWall::PutPortal(HWDrawInfo *di, int ptype, int plane) { auto pstate = screen->mPortalState; - HWPortal * portal; + HWPortal * portal = nullptr; MakeVertices(di, false); switch (ptype) @@ -532,7 +532,6 @@ void GLWall::PutPortal(HWDrawInfo *di, int ptype) case PORTALTYPE_PLANEMIRROR: if (pstate->PlaneMirrorMode * planemirror->fC() <= 0) { - //@sync-portal planemirror = pstate->UniquePlaneMirrors.Get(planemirror); portal = di->FindPortal(planemirror); if (!portal) @@ -588,6 +587,11 @@ void GLWall::PutPortal(HWDrawInfo *di, int ptype) break; } vertcount = 0; + + if (plane != -1 && portal) + { + portal->planesused |= (1<isFullbrightScene()) hi.colormap.Clear(); horizon = &hi; - PutPortal(di, PORTALTYPE_HORIZON); + PutPortal(di, PORTALTYPE_HORIZON, -1); } ztop[1] = ztop[0] = zbottom[0]; } @@ -878,7 +882,7 @@ bool GLWall::DoHorizon(HWDrawInfo *di, seg_t * seg,sector_t * fs, vertex_t * v1, if (di->isFullbrightScene()) hi.colormap.Clear(); horizon = &hi; - PutPortal(di, PORTALTYPE_HORIZON); + PutPortal(di, PORTALTYPE_HORIZON, -1); } } return true; @@ -1135,7 +1139,7 @@ void GLWall::DoTexture(HWDrawInfo *di, int _type,seg_t * seg, int peg, if (seg->linedef->special == Line_Mirror && _type == RENDERWALL_M1S && gl_mirrors) { - PutPortal(di, PORTALTYPE_MIRROR); + PutPortal(di, PORTALTYPE_MIRROR, -1); } else { @@ -1970,7 +1974,7 @@ void GLWall::Process(HWDrawInfo *di, seg_t *seg, sector_t * frontsector, sector_ ztop[1] = zceil[1]; zbottom[0] = zfloor[0]; zbottom[1] = zfloor[1]; - PutPortal(di, PORTALTYPE_LINETOLINE); + PutPortal(di, PORTALTYPE_LINETOLINE, -1); } else if (seg->linedef->GetTransferredPortal()) { @@ -2077,7 +2081,7 @@ void GLWall::Process(HWDrawInfo *di, seg_t *seg, sector_t * frontsector, sector_ ztop[1] = bch2; zbottom[0] = bfh1; zbottom[1] = bfh2; - PutPortal(di, PORTALTYPE_LINETOLINE); + PutPortal(di, PORTALTYPE_LINETOLINE, -1); } else if (backsector->e->XFloor.ffloors.Size() || frontsector->e->XFloor.ffloors.Size()) { diff --git a/src/r_data/r_sections.cpp b/src/r_data/r_sections.cpp index 74b89f9a5..8f10f2fb3 100644 --- a/src/r_data/r_sections.cpp +++ b/src/r_data/r_sections.cpp @@ -495,9 +495,9 @@ public: auto §ion = sections[i]; auto &work = triangles[i]; - BoundingRect bounds = { 1e32, 1e32, -1e32, -1e32 }; - BoundingRect loopBounds = { 1e32, 1e32, -1e32, -1e32 }; - BoundingRect outermostBounds = { 1e32, 1e32, -1e32, -1e32 }; + BoundingRect bounds(false); + BoundingRect loopBounds(false); + BoundingRect outermostBounds(false); unsigned outermoststart = ~0u; unsigned loopstart = 0; bool ispolyorg = false; @@ -519,7 +519,7 @@ public: outermoststart = loopstart; loopstart = i + 1; } - loopBounds = { 1e32, 1e32, -1e32, -1e32 }; + loopBounds.setEmpty(); } } work.boundingLoopStart = outermoststart; @@ -716,7 +716,7 @@ public: dest.subsectors.Set(&output.allSubsectors[numsubsectors], group.subsectors.Size()); dest.vertexindex = -1; dest.vertexcount = 0; - dest.bounds = {1e32, 1e32, -1e32, -1e32}; + dest.bounds.setEmpty(); numsegments += group.segments.Size(); if (output.firstSectionForSectorPtr[dest.sector->Index()] == -1) diff --git a/src/r_data/r_sections.h b/src/r_data/r_sections.h index 96ab3c250..35f61cb7c 100644 --- a/src/r_data/r_sections.h +++ b/src/r_data/r_sections.h @@ -25,12 +25,35 @@ struct BoundingRect { double left, top, right, bottom; - bool contains(const BoundingRect & other) + BoundingRect() = default; + BoundingRect(bool) + { + setEmpty(); + } + + void setEmpty() + { + left = top = 1e38; + bottom = right = -1e38; + } + + bool contains(const BoundingRect & other) const { return left <= other.left && top <= other.top && right >= other.right && bottom >= other.bottom; } - bool intersects(const BoundingRect & other) + bool contains(double x, double y) const + { + return left <= x && top <= y && right >= x && bottom >= y; + } + + template + bool contains(const T &vec) const + { + return left <= vec.X && top <= vec.Y && right >= vec.X && bottom >= vec.Y; + } + + bool intersects(const BoundingRect & other) const { return !(other.left > right || other.right < left || @@ -46,7 +69,7 @@ struct BoundingRect if (other.bottom > bottom) bottom = other.bottom; } - double distanceTo(const BoundingRect &other) + double distanceTo(const BoundingRect &other) const { if (intersects(other)) return 0; return std::max(std::min(fabs(left - other.right), fabs(right - other.left)), @@ -61,10 +84,11 @@ struct BoundingRect if (y > bottom) bottom = y; } - bool operator == (const BoundingRect &other) + bool operator == (const BoundingRect &other) const { return left == other.left && top == other.top && right == other.right && bottom == other.bottom; } + }; From 0a21d1972363cea3452ce2e7da4653e21155ec2f Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 15 Nov 2018 09:03:54 +0100 Subject: [PATCH 4/5] Added a run time check for calling a state action from the wrong actor type. This can happen if a state that's retrieved with FindState gets used with a different actor type and can lead to hard to trace problems if not checked. --- src/info.cpp | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/info.cpp b/src/info.cpp index ffae037f7..5a1606088 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -118,6 +118,7 @@ void FState::SetAction(const char *name) ActionFunc = FindVMFunction(RUNTIME_CLASS(AActor), name); } + bool FState::CallAction(AActor *self, AActor *stateowner, FStateParamInfo *info, FState **stateret) { if (ActionFunc != nullptr) @@ -140,6 +141,34 @@ bool FState::CallAction(AActor *self, AActor *stateowner, FStateParamInfo *info, } try { + auto CheckType = [=](AActor *check, PType *requiredType) + { + // This should really never happen. Any valid action function must have actor pointers here. + if (!requiredType->isObjectPointer()) + { + ThrowAbortException(X_OTHER, "Bad function prototype in function call to %s", ActionFunc->PrintableName.GetChars()); + } + auto cls = static_cast(requiredType)->PointedClass(); + if (!check->IsKindOf(cls)) + { + ThrowAbortException(X_OTHER, "Invalid class %s in function call to %s. %s expected", check->GetClass()->TypeName.GetChars(), ActionFunc->PrintableName.GetChars(), cls->TypeName.GetChars()); + } + }; + + if (ActionFunc->ImplicitArgs >= 1) + { + auto argtypes = ActionFunc->Proto->ArgumentTypes; + + CheckType(self, argtypes[0]); + + if (ActionFunc->ImplicitArgs >= 2) + { + CheckType(stateowner, argtypes[1]); + } + + } + + if (stateret == nullptr) { VMCall(ActionFunc, params, ActionFunc->ImplicitArgs, nullptr, 0); From cf590d73e42ee58cc98892c52a6630a265d5cd85 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 15 Nov 2018 09:24:17 +0100 Subject: [PATCH 5/5] - extended state caller check to work on CustomInventory items as well Since CallStateChain is a public member in CustomInventory we cannot really be sure that the given state is valid so it needs checking as well. --- .gitignore | 1 + src/info.cpp | 58 +++++++++++++++++++++------------------ src/info.h | 3 ++ src/p_actionfunctions.cpp | 1 + 4 files changed, 36 insertions(+), 27 deletions(-) diff --git a/.gitignore b/.gitignore index 094a390e7..c72578915 100644 --- a/.gitignore +++ b/.gitignore @@ -56,3 +56,4 @@ /mapfiles_release/*.map .DS_Store /build_vc2017-32 +/build2 diff --git a/src/info.cpp b/src/info.cpp index 5a1606088..87332fd2b 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -119,6 +119,36 @@ void FState::SetAction(const char *name) } +void FState::CheckCallerType(AActor *self, AActor *stateowner) +{ + auto CheckType = [=](AActor *check, PType *requiredType) + { + // This should really never happen. Any valid action function must have actor pointers here. + if (!requiredType->isObjectPointer()) + { + ThrowAbortException(X_OTHER, "Bad function prototype in function call to %s", ActionFunc->PrintableName.GetChars()); + } + auto cls = static_cast(requiredType)->PointedClass(); + if (!check->IsKindOf(cls)) + { + ThrowAbortException(X_OTHER, "Invalid class %s in function call to %s. %s expected", check->GetClass()->TypeName.GetChars(), ActionFunc->PrintableName.GetChars(), cls->TypeName.GetChars()); + } + }; + + if (ActionFunc->ImplicitArgs >= 1) + { + auto argtypes = ActionFunc->Proto->ArgumentTypes; + + CheckType(self, argtypes[0]); + + if (ActionFunc->ImplicitArgs >= 2) + { + CheckType(stateowner, argtypes[1]); + } + } +} + + bool FState::CallAction(AActor *self, AActor *stateowner, FStateParamInfo *info, FState **stateret) { if (ActionFunc != nullptr) @@ -141,33 +171,7 @@ bool FState::CallAction(AActor *self, AActor *stateowner, FStateParamInfo *info, } try { - auto CheckType = [=](AActor *check, PType *requiredType) - { - // This should really never happen. Any valid action function must have actor pointers here. - if (!requiredType->isObjectPointer()) - { - ThrowAbortException(X_OTHER, "Bad function prototype in function call to %s", ActionFunc->PrintableName.GetChars()); - } - auto cls = static_cast(requiredType)->PointedClass(); - if (!check->IsKindOf(cls)) - { - ThrowAbortException(X_OTHER, "Invalid class %s in function call to %s. %s expected", check->GetClass()->TypeName.GetChars(), ActionFunc->PrintableName.GetChars(), cls->TypeName.GetChars()); - } - }; - - if (ActionFunc->ImplicitArgs >= 1) - { - auto argtypes = ActionFunc->Proto->ArgumentTypes; - - CheckType(self, argtypes[0]); - - if (ActionFunc->ImplicitArgs >= 2) - { - CheckType(stateowner, argtypes[1]); - } - - } - + CheckCallerType(self, stateowner); if (stateret == nullptr) { diff --git a/src/info.h b/src/info.h index 69912534f..184313a0e 100644 --- a/src/info.h +++ b/src/info.h @@ -175,10 +175,13 @@ public: void ClearAction() { ActionFunc = NULL; } void SetAction(const char *name); bool CallAction(AActor *self, AActor *stateowner, FStateParamInfo *stateinfo, FState **stateret); + void CheckCallerType(AActor *self, AActor *stateowner); + static PClassActor *StaticFindStateOwner (const FState *state); static PClassActor *StaticFindStateOwner (const FState *state, PClassActor *info); static FString StaticGetStateName(const FState *state); static FRandom pr_statetics; + }; struct FStateLabels; diff --git a/src/p_actionfunctions.cpp b/src/p_actionfunctions.cpp index 60771a469..6e6e16500 100644 --- a/src/p_actionfunctions.cpp +++ b/src/p_actionfunctions.cpp @@ -169,6 +169,7 @@ bool AStateProvider::CallStateChain (AActor *actor, FState *state) } try { + state->CheckCallerType(actor, this); VMCall(state->ActionFunc, params, state->ActionFunc->ImplicitArgs, wantret, numret); } catch (CVMAbortException &err)