From 0f871a1d210966ccb816731622c50e02ec343ccf Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 25 Feb 2016 09:27:30 +0100 Subject: [PATCH 1/3] - fixed some language issues with the menu. --- wadsrc/static/language.enu | 4 ++-- wadsrc/static/menudef.txt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/wadsrc/static/language.enu b/wadsrc/static/language.enu index 2dd1c3da2..7dc132895 100644 --- a/wadsrc/static/language.enu +++ b/wadsrc/static/language.enu @@ -1749,7 +1749,7 @@ JOYMNU_CONFIG = "CONFIGURE CONTROLLER"; JOYMNU_OPTIONS = "CONTROLLER OPTIONS"; // Player Setup Menu -PLYRMNU_PLAYERSETUP = "PLAYER SETUP"; +MNU_PLAYERSETUP = "PLAYER SETUP"; PLYRMNU_NAME = "Name"; PLYRMNU_TEAM = "Team"; PLYRMNU_PLAYERCOLOR = "Color"; @@ -2258,7 +2258,7 @@ OPTVAL_FOO_DUMB = "foo_dumb"; OPTVAL_ALIASING = "Aliasing"; OPTVAL_LINEAR = "Linear"; OPTVAL_CUBIC = "Cubic"; -OPTVAL_BLEP = "Band-limited step" +OPTVAL_BLEP = "Band-limited step"; OPTVAL_LINEARSLOW = "Linear (Slower)"; OPTVAL_BLAM = "Band-limited linear"; OPTVAL_CUBICSLOW = "Cubic (Slower)"; diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt index 43fa473c3..28b3fd4c7 100644 --- a/wadsrc/static/menudef.txt +++ b/wadsrc/static/menudef.txt @@ -366,7 +366,7 @@ OptionValue "Gender" ListMenu "PlayerMenu" { - StaticTextCentered 160, 6, "$PLYRMNU_PLAYERSETUP" + StaticTextCentered 160, 6, "$MNU_PLAYERSETUP" Font "SmallFont" Linespacing 14 Position 48, 36 From a9db9987001cd402c78b2af3c1b93932460bbcfc Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 25 Feb 2016 09:54:09 +0100 Subject: [PATCH 2/3] - did some refactoring on FPathTraverse to allow inheriting from that class with different collection functions. This will be needed to implement an efficient portal checker that doesn't run through the entire blockmap to find the portals. --- src/p_maputl.cpp | 2 +- src/p_maputl.h | 14 ++++++++++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/p_maputl.cpp b/src/p_maputl.cpp index 2835896f9..eee5167ce 100644 --- a/src/p_maputl.cpp +++ b/src/p_maputl.cpp @@ -1398,7 +1398,7 @@ intercept_t *FPathTraverse::Next() // //=========================================================================== -FPathTraverse::FPathTraverse (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, int flags) +void FPathTraverse::init (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, int flags) { fixed_t xt1, xt2; fixed_t yt1, yt2; diff --git a/src/p_maputl.h b/src/p_maputl.h index 452f99b3d..415d4b83b 100644 --- a/src/p_maputl.h +++ b/src/p_maputl.h @@ -325,6 +325,7 @@ public: class FPathTraverse { +protected: static TArray intercepts; divline_t trace; @@ -332,14 +333,19 @@ class FPathTraverse unsigned int intercept_count; unsigned int count; - void AddLineIntercepts(int bx, int by); - void AddThingIntercepts(int bx, int by, FBlockThingsIterator &it, bool compatible); + virtual void AddLineIntercepts(int bx, int by); + virtual void AddThingIntercepts(int bx, int by, FBlockThingsIterator &it, bool compatible); + void init(fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, int flags); + FPathTraverse() {} public: intercept_t *Next(); - FPathTraverse(fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, int flags); - ~FPathTraverse(); + FPathTraverse(fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, int flags) + { + init(x1, y1, x2, y2, flags); + } + virtual ~FPathTraverse(); const divline_t &Trace() const { return trace; } }; From c7bce8b34601927a0cf4abdc7f1cd36dc7e6d4a4 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 25 Feb 2016 13:00:23 +0100 Subject: [PATCH 3/3] - added a special portal blockmap. This only contains all lines which have a crossable line portal assigned. This is to speed up offset calculations because those are quite frequent and would be too inefficient with the full blockmap. - made some minor changes to FPathTraverse so that the Add*Intercepts methods can be virtually overridden. - removed the PortalTracer class because in its existing form it was too costly. Replaced with a P_GetOffsetPosition function that does the minimum required work to get to the translated destination and that's better suited for being called from the Vec*Offset methods. Other use cases will require some changes to FPathTraverse anyway, or some wrapping class like the FMultiBlock iterators. --- src/p_maputl.h | 19 +++- src/portal.cpp | 233 +++++++++++++++++++++++++++---------------------- src/portal.h | 81 +++++++++-------- src/r_defs.h | 5 ++ 4 files changed, 197 insertions(+), 141 deletions(-) diff --git a/src/p_maputl.h b/src/p_maputl.h index 415d4b83b..838c4e775 100644 --- a/src/p_maputl.h +++ b/src/p_maputl.h @@ -335,7 +335,6 @@ protected: virtual void AddLineIntercepts(int bx, int by); virtual void AddThingIntercepts(int bx, int by, FBlockThingsIterator &it, bool compatible); - void init(fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, int flags); FPathTraverse() {} public: @@ -345,10 +344,28 @@ public: { init(x1, y1, x2, y2, flags); } + void init(fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, int flags); virtual ~FPathTraverse(); const divline_t &Trace() const { return trace; } }; +//============================================================================ +// +// A traverser that uses the portal blockmap +// This should be in portal.h but that'd create circular dependencies. +// +//============================================================================ + +class FLinePortalTraverse : public FPathTraverse +{ + void AddLineIntercepts(int bx, int by); + +public: + FLinePortalTraverse() + { + } +}; + // diff --git a/src/portal.cpp b/src/portal.cpp index ef22eade3..8c8032f7e 100644 --- a/src/portal.cpp +++ b/src/portal.cpp @@ -38,6 +38,7 @@ #include "p_local.h" +#include "p_blockmap.h" #include "p_lnspec.h" #include "r_bsp.h" #include "r_segs.h" @@ -57,6 +58,7 @@ CVAR(Int, sv_portal_recursions, 4, CVAR_ARCHIVE|CVAR_SERVERINFO) FDisplacementTable Displacements; +FPortalBlockmap PortalBlockmap; TArray linePortals; TArray linkedPortals; // only the linked portals, this is used to speed up looking for them in P_CollectConnectedGroups. @@ -93,7 +95,85 @@ struct FPortalBits } }; +//============================================================================ +// +// BuildBlockmap +// +//============================================================================ +static void BuildBlockmap() +{ + PortalBlockmap.Clear(); + PortalBlockmap.Create(bmapwidth, bmapheight); + for (int y = 0; y < bmapheight; y++) + { + for (int x = 0; x < bmapwidth; x++) + { + int offset = y*bmapwidth + x; + int *list = blockmaplump + *(blockmap + offset) + 1; + FPortalBlock &block = PortalBlockmap(x, y); + + while (*list != -1) + { + line_t *ld = &lines[*list++]; + + if (ld->isLinePortal()) + { + PortalBlockmap.containsLines = true; + block.portallines.Push(ld); + } + } + } + } + if (!PortalBlockmap.containsLines) PortalBlockmap.Clear(); +} + +//=========================================================================== +// +// FLinePortalTraverse :: AddLineIntercepts. +// +// Similar to AddLineIntercepts but checks the portal blockmap for line-to-line portals +// +//=========================================================================== + +void FLinePortalTraverse::AddLineIntercepts(int bx, int by) +{ + FPortalBlock &block = PortalBlockmap(bx, by); + + for (unsigned i = 0; ivalidcount == validcount) continue; // already processed + + if (P_PointOnDivlineSidePrecise (ld->v1->x, ld->v1->y, &trace) == + P_PointOnDivlineSidePrecise (ld->v2->x, ld->v2->y, &trace)) + { + continue; // line isn't crossed + } + P_MakeDivline (ld, &dl); + if (P_PointOnDivlineSidePrecise (trace.x, trace.y, &dl) != 0 || + P_PointOnDivlineSidePrecise (trace.x+trace.dx, trace.y+trace.dy, &dl) != 1) + { + continue; // line isn't crossed from the front side + } + + // hit the line + P_MakeDivline(ld, &dl); + frac = P_InterceptVector(&trace, &dl); + if (frac < 0 || frac > FRACUNIT) continue; // behind source + + intercept_t newintercept; + + newintercept.frac = frac; + newintercept.isaline = true; + newintercept.done = false; + newintercept.d.line = ld; + intercepts.Push(newintercept); + } +} //============================================================================ // @@ -301,6 +381,7 @@ void P_FinalizePortals() P_UpdatePortal(port); } P_CollectLinkedPortals(); + BuildBlockmap(); } //============================================================================ @@ -601,124 +682,72 @@ void P_NormalizeVXVY(fixed_t& vx, fixed_t& vy) //============================================================================ // -// portal tracer code +// P_GetOffsetPosition +// +// Offsets a given coordinate if the trace from the origin crosses an +// interactive line-to-line portal. // //============================================================================ -PortalTracer::PortalTracer(fixed_t startx, fixed_t starty, fixed_t endx, fixed_t endy) +fixedvec2 P_GetOffsetPosition(AActor *actor, fixed_t dx, fixed_t dy) { - this->startx = startx; - this->starty = starty; - this->endx = endx; - this->endy = endy; - intx = endx; - inty = endy; - intxIn = intx; - intyIn = inty; - z = 0; - angle = 0; - depth = 0; - frac = 0; - in = NULL; - out = NULL; - vx = 0; - vy = 0; -} - -bool PortalTracer::TraceStep() -{ - if (depth > sv_portal_recursions) - return false; - - this->in = NULL; - this->out = NULL; - this->vx = 0; - this->vy = 0; - - int oDepth = depth; - - fixed_t dirx = endx-startx; - fixed_t diry = endy-starty; - P_NormalizeVXVY(dirx, diry); - - dirx = 0; - diry = 0; - - FPathTraverse it(startx-dirx, starty-diry, endx+dirx, endy+diry, PT_ADDLINES | PT_COMPATIBLE); - - intercept_t *in; - while ((in = it.Next())) + fixedvec3 dest = { actor->X() + dx, actor->Y() + dy }; + if (PortalBlockmap.containsLines && actor->Sector->PortalGroup != 0) { - line_t* li; - - if (in->isaline) + fixed_t actx = actor->X(), acty = actor->Y(); + FLinePortalTraverse it; + bool repeat; + do { - li = in->d.line; + it.init(actx, acty, dx, dy, PT_ADDLINES); + intercept_t *in; - if (li->isLinePortal()) + repeat = false; + while ((in = it.Next())) { - if (P_PointOnLineSide(startx-dirx, starty-diry, li)) - continue; // we're at the back side of this line + // hit a portal line. + line_t *line = in->d.line; + FLinePortal *port = line->getPortal(); + line_t* out = port->mDestination; - line_t* out = li->getPortalDestination(); - - this->in = li; - this->out = out; - - // we only know that we crossed it, but we also need to know WHERE we crossed it - fixed_t vx = it.Trace().dx; - fixed_t vy = it.Trace().dy; - - fixed_t x = it.Trace().x + FixedMul(vx, in->frac); - fixed_t y = it.Trace().y + FixedMul(vy, in->frac); - - P_NormalizeVXVY(vx, vy); - - this->vx = vx; - this->vy = vy; - - // teleport our trace - - if (!out->backsector) + // Teleport portals are intentionally ignored since skipping this stuff is their entire reason for existence. + if (port->mFlags & PORTF_INTERACTIVE) { - intx = x + vx; - inty = y + vy; - } - else - { - intx = x - vx; - inty = y - vy; + fixed_t hitdx = FixedMul(it.Trace().dx, in->frac); + fixed_t hitdy = FixedMul(it.Trace().dy, in->frac); + + if (port->mType == PORTT_LINKED) + { + // optimized handling for linked portals where we only need to add an offset. + actx = it.Trace().x + hitdx + port->mXDisplacement; + acty = it.Trace().y + hitdy + port->mYDisplacement; + dest.x += port->mXDisplacement; + dest.y += port->mYDisplacement; + } + else + { + // interactive ones are more complex because the vector may be rotated. + // Note: There is no z-translation here, there's just too much code in the engine that wouldn't be able to handle interactive portals with a height difference. + actx = it.Trace().x + hitdx; + acty = it.Trace().y + hitdy; + + P_TranslatePortalXY(line, out, actx, acty); + P_TranslatePortalXY(line, out, dest.x, dest.y); + } + // update the fields, end this trace and restart from the new position + dx = dest.x - actx; + dy = dest.y - acty; + repeat = true; } - //P_TranslateCoordinatesAndAngle(li, out, startx, starty, noangle); - //P_TranslateCoordinatesAndAngle(li, out, endx, endy, angle); - //if (hdeltaZ) - // P_TranslateZ(li, out, deltaZ); - //P_TranslateCoordinatesAndAngle(li, out, vx, vy, noangle); - - P_TranslatePortalXY(li, out, startx, starty); - P_TranslatePortalVXVY(li, out, this->vx, this->vy); - intxIn = intx; - intyIn = inty; - P_TranslatePortalXY(li, out, intx, inty); - P_TranslatePortalXY(li, out, endx, endy); - P_TranslatePortalAngle(li, out, angle); - P_TranslatePortalZ(li, out, z); - frac += in->frac; - depth++; - break; // breaks to outer loop + break; } - - if (!(li->flags & ML_TWOSIDED) || (li->flags & ML_BLOCKEVERYTHING)) - return false; // stop tracing, 2D blocking line - } + } while (repeat); } - - //Printf("returning %d; vx = %.2f; vy = %.2f\n", (oDepth != depth), FIXED2DBL(this->vx), FIXED2DBL(this->vy)); - - return (oDepth != depth); // if a portal has been found, return false + return dest; } + //============================================================================ // // CollectSectors diff --git a/src/portal.h b/src/portal.h index 5ea0293ac..942a44c4a 100644 --- a/src/portal.h +++ b/src/portal.h @@ -62,6 +62,49 @@ struct FDisplacementTable extern FDisplacementTable Displacements; + +//============================================================================ +// +// A blockmap that only contains crossable portals +// This is used for quick checks if a vector crosses through one. +// +//============================================================================ + +struct FPortalBlock +{ + TArray portallines; +}; + +struct FPortalBlockmap +{ + TArray data; + int dx, dy; + bool containsLines; + + void Create(int blockx, int blocky) + { + data.Resize(blockx*blocky); + dx = blockx; + dy = blocky; + } + + void Clear() + { + data.Clear(); + data.ShrinkToFit(); + dx = dy = 0; + containsLines = false; + } + + FPortalBlock &operator()(int x, int y) + { + return data[x + dx*y]; + } +}; + +extern FPortalBlockmap PortalBlockmap; + + //============================================================================ // // Flags and types for linedef portals @@ -143,44 +186,6 @@ void P_TranslatePortalVXVY(line_t* src, line_t* dst, fixed_t& vx, fixed_t& vy); void P_TranslatePortalAngle(line_t* src, line_t* dst, angle_t& angle); void P_TranslatePortalZ(line_t* src, line_t* dst, fixed_t& z); void P_NormalizeVXVY(fixed_t& vx, fixed_t& vy); - -//============================================================================ -// -// basically, this is a teleporting tracer function, -// which can be used by itself (to calculate portal-aware offsets, say, for projectiles) -// or to teleport normal tracers (like hitscan, railgun, autoaim tracers) -// -//============================================================================ - -class PortalTracer -{ -public: - PortalTracer(fixed_t startx, fixed_t starty, fixed_t endx, fixed_t endy); - - // trace to next portal - bool TraceStep(); - // trace to last available portal on the path - void TraceAll() { while (TraceStep()) continue; } - - int depth; - fixed_t startx; - fixed_t starty; - fixed_t intx; - fixed_t inty; - fixed_t intxIn; - fixed_t intyIn; - fixed_t endx; - fixed_t endy; - angle_t angle; - fixed_t z; - fixed_t frac; - line_t* in; - line_t* out; - fixed_t vx; - fixed_t vy; -}; - -/* new code */ fixed_t P_PointLineDistance(line_t* line, fixed_t x, fixed_t y); #endif \ No newline at end of file diff --git a/src/r_defs.h b/src/r_defs.h index 78c61ec90..2222fbe05 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -1092,6 +1092,11 @@ struct line_t int locknumber; // [Dusk] lock number for special unsigned portalindex; + FLinePortal *getPortal() const + { + return portalindex >= linePortals.Size() ? (FLinePortal*)NULL : &linePortals[portalindex]; + } + // returns true if the portal is crossable by actors bool isLinePortal() const {