diff --git a/.gitignore b/.gitignore index 094a390e7a..c725789157 100644 --- a/.gitignore +++ b/.gitignore @@ -56,3 +56,4 @@ /mapfiles_release/*.map .DS_Store /build_vc2017-32 +/build2 diff --git a/src/gl/renderer/gl_renderstate.cpp b/src/gl/renderer/gl_renderstate.cpp index 76e8ba892e..883231bc49 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 7f6ac8af1b..25b4420f38 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 803b70c121..f3fbbff37a 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 24d6c22180..5913ca97bf 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_drawstructs.h b/src/hwrenderer/scene/hw_drawstructs.h index d500e67957..ae89d65de9 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 6426e4213c..9cb35c696c 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" @@ -141,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; + } } } @@ -172,13 +179,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 +195,32 @@ 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); + + 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); } } + //----------------------------------------------------------------------------- // // Start @@ -204,53 +232,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 +294,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 +309,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 +389,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 +469,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 +550,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 +573,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 +603,6 @@ bool HWLineToLinePortal::Setup(HWDrawInfo *di, FRenderState &rstate, Clipper *cl } } - auto &lines = mOwner->lines; for (unsigned i = 0; i < lines.Size(); i++) { @@ -589,10 +648,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 +690,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 +758,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 +810,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 +840,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 +859,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 +1019,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 +1033,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 35629b89ab..f9d9e243c6 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 { @@ -61,12 +61,17 @@ class HWPortal public: FPortalSceneState * mState; TArray lines; + BoundingRect boundingBox; + int planesused = 0; - 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), boundingBox(false) + { + } + 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,15 +79,20 @@ 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) { lines.Push(*l); + boundingBox.addVertex(l->glseg.x1, l->glseg.y1); + boundingBox.addVertex(l->glseg.x2, l->glseg.y2); } }; + struct FPortalSceneState { int MirrorFlag = 0; @@ -116,37 +126,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 +158,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 +213,8 @@ protected: public: - HWMirrorPortal(line_t * line) - : HWLinePortal(line) + HWMirrorPortal(FPortalSceneState *state, line_t * line) + : HWLinePortal(state, line) { linedef = line; } @@ -232,8 +233,8 @@ protected: public: - HWLineToLinePortal(FLinePortalSpan *ll) - : HWLinePortal(ll) + HWLineToLinePortal(FPortalSceneState *state, FLinePortalSpan *ll) + : HWLinePortal(state, ll) { glport = ll; } @@ -256,7 +257,7 @@ protected: public: - HWSkyboxPortal(FSectorPortal * pt) + HWSkyboxPortal(FPortalSceneState *state, FSectorPortal * pt) : HWScenePortalBase(state) { portal = pt; } @@ -277,7 +278,7 @@ protected: public: - HWSectorStackPortal(FSectorPortalGroup *pt) + HWSectorStackPortal(FPortalSceneState *state, FSectorPortalGroup *pt) : HWScenePortalBase(state) { origin = pt; } @@ -301,7 +302,7 @@ protected: public: - HWPlaneMirrorPortal(secplane_t * pt) + HWPlaneMirrorPortal(FPortalSceneState *state, secplane_t * pt) : HWScenePortalBase(state) { origin = pt; } @@ -309,34 +310,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 +325,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 +342,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 66f7ccff3f..f494df34a0 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_sky.cpp b/src/hwrenderer/scene/hw_sky.cpp index 57eeb0eee3..695321312a 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_skyportal.cpp b/src/hwrenderer/scene/hw_skyportal.cpp index 9da564e635..cb04c1e866 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 0622553f75..70ca0f6335 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) @@ -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); @@ -532,12 +532,11 @@ 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) { - portal = new HWScenePortal(pstate, new HWPlaneMirrorPortal(planemirror)); + portal = new HWPlaneMirrorPortal(pstate, planemirror); di->Portals.Push(portal); } portal->AddLine(this); @@ -548,7 +547,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 +569,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); @@ -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/info.cpp b/src/info.cpp index ffae037f74..87332fd2b2 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -118,6 +118,37 @@ void FState::SetAction(const char *name) ActionFunc = FindVMFunction(RUNTIME_CLASS(AActor), 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) @@ -140,6 +171,8 @@ bool FState::CallAction(AActor *self, AActor *stateowner, FStateParamInfo *info, } try { + CheckCallerType(self, stateowner); + if (stateret == nullptr) { VMCall(ActionFunc, params, ActionFunc->ImplicitArgs, nullptr, 0); diff --git a/src/info.h b/src/info.h index 69912534fa..184313a0eb 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/namedef.h b/src/namedef.h index 5744ef4869..184c58fd0b 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/p_actionfunctions.cpp b/src/p_actionfunctions.cpp index 60771a469c..6e6e165008 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) diff --git a/src/portal.h b/src/portal.h index 01b17fc8be..daeb784f60 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 diff --git a/src/r_data/r_sections.cpp b/src/r_data/r_sections.cpp index 74b89f9a59..8f10f2fb33 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 96ab3c2500..35f61cb7cd 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; } + }; diff --git a/src/scripting/backend/codegen.cpp b/src/scripting/backend/codegen.cpp index b6059a49c6..79b48953a4 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++; } } }