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 yt1, yt2;

View file

@ -325,6 +325,7 @@ public:
class FPathTraverse
{
protected:
static TArray<intercept_t> intercepts;
divline_t trace;
@ -332,17 +333,39 @@ 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);
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);
}
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()
{
}
};
//

View file

@ -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<FLinePortal> linePortals;
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_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

View file

@ -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<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
@ -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

View file

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

View file

@ -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)";

View file

@ -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