This commit is contained in:
Christoph Oelckers 2016-02-25 13:01:51 +01:00
commit 205bbac411
7 changed files with 210 additions and 148 deletions

View file

@ -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 xt1, xt2;
fixed_t yt1, yt2; fixed_t yt1, yt2;

View file

@ -325,6 +325,7 @@ public:
class FPathTraverse class FPathTraverse
{ {
protected:
static TArray<intercept_t> intercepts; static TArray<intercept_t> intercepts;
divline_t trace; divline_t trace;
@ -332,17 +333,39 @@ class FPathTraverse
unsigned int intercept_count; unsigned int intercept_count;
unsigned int count; unsigned int count;
void AddLineIntercepts(int bx, int by); virtual void AddLineIntercepts(int bx, int by);
void AddThingIntercepts(int bx, int by, FBlockThingsIterator &it, bool compatible); virtual void AddThingIntercepts(int bx, int by, FBlockThingsIterator &it, bool compatible);
FPathTraverse() {}
public: public:
intercept_t *Next(); intercept_t *Next();
FPathTraverse(fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, int flags); FPathTraverse(fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, int flags)
~FPathTraverse(); {
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; } 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()
{
}
};
// //

View file

@ -38,6 +38,7 @@
#include "p_local.h" #include "p_local.h"
#include "p_blockmap.h"
#include "p_lnspec.h" #include "p_lnspec.h"
#include "r_bsp.h" #include "r_bsp.h"
#include "r_segs.h" #include "r_segs.h"
@ -57,6 +58,7 @@
CVAR(Int, sv_portal_recursions, 4, CVAR_ARCHIVE|CVAR_SERVERINFO) CVAR(Int, sv_portal_recursions, 4, CVAR_ARCHIVE|CVAR_SERVERINFO)
FDisplacementTable Displacements; FDisplacementTable Displacements;
FPortalBlockmap PortalBlockmap;
TArray<FLinePortal> linePortals; TArray<FLinePortal> linePortals;
TArray<FLinePortal*> linkedPortals; // only the linked portals, this is used to speed up looking for them in P_CollectConnectedGroups. TArray<FLinePortal*> 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; i<block.portallines.Size(); i++)
{
line_t *ld = block.portallines[i];
fixed_t frac;
divline_t dl;
if (ld->validcount == 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_UpdatePortal(port);
} }
P_CollectLinkedPortals(); 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; fixedvec3 dest = { actor->X() + dx, actor->Y() + dy };
this->starty = starty; if (PortalBlockmap.containsLines && actor->Sector->PortalGroup != 0)
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()))
{ {
line_t* li; fixed_t actx = actor->X(), acty = actor->Y();
FLinePortalTraverse it;
if (in->isaline) 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)) // hit a portal line.
continue; // we're at the back side of this line line_t *line = in->d.line;
FLinePortal *port = line->getPortal();
line_t* out = port->mDestination;
line_t* out = li->getPortalDestination(); // Teleport portals are intentionally ignored since skipping this stuff is their entire reason for existence.
if (port->mFlags & PORTF_INTERACTIVE)
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)
{ {
intx = x + vx; fixed_t hitdx = FixedMul(it.Trace().dx, in->frac);
inty = y + vy; fixed_t hitdy = FixedMul(it.Trace().dy, in->frac);
}
else if (port->mType == PORTT_LINKED)
{ {
intx = x - vx; // optimized handling for linked portals where we only need to add an offset.
inty = y - vy; 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); break;
//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
} }
} while (repeat);
if (!(li->flags & ML_TWOSIDED) || (li->flags & ML_BLOCKEVERYTHING))
return false; // stop tracing, 2D blocking line
}
} }
return dest;
//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
} }
//============================================================================ //============================================================================
// //
// CollectSectors // CollectSectors

View file

@ -62,6 +62,49 @@ struct FDisplacementTable
extern FDisplacementTable Displacements; 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<line_t*> portallines;
};
struct FPortalBlockmap
{
TArray<FPortalBlock> 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 // 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_TranslatePortalAngle(line_t* src, line_t* dst, angle_t& angle);
void P_TranslatePortalZ(line_t* src, line_t* dst, fixed_t& z); void P_TranslatePortalZ(line_t* src, line_t* dst, fixed_t& z);
void P_NormalizeVXVY(fixed_t& vx, fixed_t& vy); 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); fixed_t P_PointLineDistance(line_t* line, fixed_t x, fixed_t y);
#endif #endif

View file

@ -1183,6 +1183,11 @@ struct line_t
unsigned portalindex; unsigned portalindex;
TObjPtr<ASkyViewpoint> skybox; TObjPtr<ASkyViewpoint> skybox;
FLinePortal *getPortal() const
{
return portalindex >= linePortals.Size() ? (FLinePortal*)NULL : &linePortals[portalindex];
}
// returns true if the portal is crossable by actors // returns true if the portal is crossable by actors
bool isLinePortal() const bool isLinePortal() const
{ {

View file

@ -1749,7 +1749,7 @@ JOYMNU_CONFIG = "CONFIGURE CONTROLLER";
JOYMNU_OPTIONS = "CONTROLLER OPTIONS"; JOYMNU_OPTIONS = "CONTROLLER OPTIONS";
// Player Setup Menu // Player Setup Menu
PLYRMNU_PLAYERSETUP = "PLAYER SETUP"; MNU_PLAYERSETUP = "PLAYER SETUP";
PLYRMNU_NAME = "Name"; PLYRMNU_NAME = "Name";
PLYRMNU_TEAM = "Team"; PLYRMNU_TEAM = "Team";
PLYRMNU_PLAYERCOLOR = "Color"; PLYRMNU_PLAYERCOLOR = "Color";
@ -2258,7 +2258,7 @@ OPTVAL_FOO_DUMB = "foo_dumb";
OPTVAL_ALIASING = "Aliasing"; OPTVAL_ALIASING = "Aliasing";
OPTVAL_LINEAR = "Linear"; OPTVAL_LINEAR = "Linear";
OPTVAL_CUBIC = "Cubic"; OPTVAL_CUBIC = "Cubic";
OPTVAL_BLEP = "Band-limited step" OPTVAL_BLEP = "Band-limited step";
OPTVAL_LINEARSLOW = "Linear (Slower)"; OPTVAL_LINEARSLOW = "Linear (Slower)";
OPTVAL_BLAM = "Band-limited linear"; OPTVAL_BLAM = "Band-limited linear";
OPTVAL_CUBICSLOW = "Cubic (Slower)"; OPTVAL_CUBICSLOW = "Cubic (Slower)";

View file

@ -366,7 +366,7 @@ OptionValue "Gender"
ListMenu "PlayerMenu" ListMenu "PlayerMenu"
{ {
StaticTextCentered 160, 6, "$PLYRMNU_PLAYERSETUP" StaticTextCentered 160, 6, "$MNU_PLAYERSETUP"
Font "SmallFont" Font "SmallFont"
Linespacing 14 Linespacing 14
Position 48, 36 Position 48, 36