This commit is contained in:
Christoph Oelckers 2016-04-16 19:42:12 +02:00
commit 6db95182cf
9 changed files with 295 additions and 310 deletions

View file

@ -621,19 +621,65 @@ void P_DrawSplash2 (int count, const DVector3 &pos, DAngle angle, int updown, in
} }
} }
void P_DrawRailTrail(AActor *source, const DVector3 &start, TArray<SPortalHit> &portalhits, const DVector3 &end, int color1, int color2, double maxdiff_d, int flags, PClassActor *spawnclass, DAngle angle, int duration, double sparsity, double drift, int SpiralOffset) struct TrailSegment
{ {
double length, lengthsquared; DVector3 start;
DVector3 dir;
DVector3 extend;
DVector2 soundpos;
double length;
double sounddist;
};
void P_DrawRailTrail(AActor *source, TArray<SPortalHit> &portalhits, int color1, int color2, double maxdiff, int flags, PClassActor *spawnclass, DAngle angle, int duration, double sparsity, double drift, int SpiralOffset)
{
double length = 0;
int steps, i; int steps, i;
TArray<TrailSegment> trail;
TAngle<double> deg; TAngle<double> deg;
DVector3 step, dir, pos, extend; DVector3 pos;
bool fullbright; bool fullbright;
float maxdiff = (float)maxdiff_d; unsigned segment;
double lencount;
for (unsigned i = 0; i < portalhits.Size() - 1; i++)
{
TrailSegment seg;
seg.start = portalhits[i].ContPos;
seg.dir = portalhits[i].OutDir;
seg.length = (portalhits[i + 1].HitPos - seg.start).Length();
//Calculate PerpendicularVector (extend, dir):
double minelem = 1;
int epos;
int ii;
for (epos = 0, ii = 0; ii < 3; ++ii)
{
if (fabs(seg.dir[ii]) < minelem)
{
epos = ii;
minelem = fabs(seg.dir[ii]);
}
}
DVector3 tempvec(0, 0, 0);
tempvec[epos] = 1;
seg.extend = (tempvec - (seg.dir | tempvec) * seg.dir) * 3;
length += seg.length;
// Only consider sound in 2D (for now, anyway)
// [BB] You have to divide by lengthsquared here, not multiply with it.
AActor *mo = players[consoleplayer].camera;
double r = ((seg.start.Y - mo->Y()) * (-seg.dir.Y) - (seg.start.X - mo->X()) * (seg.dir.X)) / (seg.length * seg.length);
r = clamp<double>(r, 0., 1.);
seg.soundpos = seg.start + r * seg.dir;
seg.sounddist = (seg.soundpos - mo->Pos()).LengthSquared();
trail.Push(seg);
}
dir = end - start;
lengthsquared = dir | dir;
length = g_sqrt(lengthsquared);
steps = xs_FloorToInt(length / 3); steps = xs_FloorToInt(length / 3);
fullbright = !!(flags & RAF_FULLBRIGHT); fullbright = !!(flags & RAF_FULLBRIGHT);
@ -652,30 +698,19 @@ void P_DrawRailTrail(AActor *source, const DVector3 &start, TArray<SPortalHit> &
// The railgun's sound is special. It gets played from the // The railgun's sound is special. It gets played from the
// point on the slug's trail that is closest to the hearing player. // point on the slug's trail that is closest to the hearing player.
AActor *mo = players[consoleplayer].camera; AActor *mo = players[consoleplayer].camera;
DVector3 point;
double r;
double dirz;
if (fabs(mo->X() - start.X) < 20 if (fabs(mo->X() - trail[0].start.X) < 20 && fabs(mo->Y() - trail[0].start.Y) < 20)
&& fabs(mo->Y() - start.Y) < 20)
{ // This player (probably) fired the railgun { // This player (probably) fired the railgun
S_Sound (mo, CHAN_WEAPON, sound, 1, ATTN_NORM); S_Sound (mo, CHAN_WEAPON, sound, 1, ATTN_NORM);
} }
else else
{ {
TrailSegment *shortest = NULL;
// Only consider sound in 2D (for now, anyway) for (auto &seg : trail)
// [BB] You have to divide by lengthsquared here, not multiply with it. {
if (shortest == NULL || shortest->sounddist > seg.sounddist) shortest = &seg;
r = ((start.Y - mo->Y()) * (-dir.Y) - (start.X - mo->X()) * (dir.X)) / lengthsquared; }
r = clamp<double>(r, 0., 1.); S_Sound (DVector3(shortest->soundpos, ViewPos.Z), CHAN_WEAPON, sound, 1, ATTN_NORM);
dirz = dir.Z;
dir.Z = 0;
point = start + r * dir;
dir.Z = dirz;
S_Sound (DVector3(point.X, point.Y, ViewPos.Z), CHAN_WEAPON, sound, 1, ATTN_NORM);
} }
} }
} }
@ -685,35 +720,16 @@ void P_DrawRailTrail(AActor *source, const DVector3 &start, TArray<SPortalHit> &
return; return;
} }
dir /= length;
//Calculate PerpendicularVector (extend, dir):
double minelem = 1;
int epos;
for (epos = 0, i = 0; i < 3; ++i)
{
if (fabs(dir[i]) < minelem)
{
epos = i;
minelem = fabs(dir[i]);
}
}
DVector3 tempvec(0, 0, 0);
tempvec[epos] = 1;
extend = tempvec - (dir | tempvec) * dir;
//
extend *= 3;
step = dir * 3;
// Create the outer spiral. // Create the outer spiral.
if (color1 != -1 && (!r_rail_smartspiral || color2 == -1) && r_rail_spiralsparsity > 0 && (spawnclass == NULL)) if (color1 != -1 && (!r_rail_smartspiral || color2 == -1) && r_rail_spiralsparsity > 0 && (spawnclass == NULL))
{ {
DVector3 spiral_step = step * r_rail_spiralsparsity * sparsity; double stepsize = 3 * r_rail_spiralsparsity * sparsity;
int spiral_steps = (int)(steps * r_rail_spiralsparsity / sparsity); int spiral_steps = (int)(steps * r_rail_spiralsparsity / sparsity);
segment = 0;
lencount = trail[0].length;
color1 = color1 == 0 ? -1 : ParticleColor(color1); color1 = color1 == 0 ? -1 : ParticleColor(color1);
pos = start; pos = trail[0].start;
deg = (double)SpiralOffset; deg = (double)SpiralOffset;
for (i = spiral_steps; i; i--) for (i = spiral_steps; i; i--)
{ {
@ -731,12 +747,12 @@ void P_DrawRailTrail(AActor *source, const DVector3 &start, TArray<SPortalHit> &
p->size = 3; p->size = 3;
p->bright = fullbright; p->bright = fullbright;
tempvec = DMatrix3x3(dir, deg) * extend; tempvec = DMatrix3x3(trail[segment].dir, deg) * trail[segment].extend;
p->Vel = tempvec * drift / 16.; p->Vel = tempvec * drift / 16.;
p->Pos = tempvec + pos; p->Pos = tempvec + pos;
pos += spiral_step; pos += trail[segment].dir * stepsize;
deg += double(r_rail_spiralsparsity * 14); deg += double(r_rail_spiralsparsity * 14);
lencount -= stepsize;
if (color1 == -1) if (color1 == -1)
{ {
int rand = M_Random(); int rand = M_Random();
@ -754,19 +770,36 @@ void P_DrawRailTrail(AActor *source, const DVector3 &start, TArray<SPortalHit> &
{ {
p->color = color1; p->color = color1;
} }
if (lencount <= 0)
{
segment++;
if (segment < trail.Size())
{
pos = trail[segment].start - trail[segment].dir * lencount;
lencount += trail[segment].length;
}
else
{
// should never happen but if something goes wrong, just terminate the loop.
break;
}
}
} }
} }
// Create the inner trail. // Create the inner trail.
if (color2 != -1 && r_rail_trailsparsity > 0 && spawnclass == NULL) if (color2 != -1 && r_rail_trailsparsity > 0 && spawnclass == NULL)
{ {
DVector3 trail_step = step * r_rail_trailsparsity * sparsity; double stepsize = 3 * r_rail_spiralsparsity * sparsity;
int trail_steps = xs_FloorToInt(steps * r_rail_trailsparsity / sparsity); int trail_steps = xs_FloorToInt(steps * r_rail_trailsparsity / sparsity);
color2 = color2 == 0 ? -1 : ParticleColor(color2); color2 = color2 == 0 ? -1 : ParticleColor(color2);
DVector3 diff(0, 0, 0); DVector3 diff(0, 0, 0);
pos = start; pos = trail[0].start;
lencount = trail[0].length;
segment = 0;
for (i = trail_steps; i; i--) for (i = trail_steps; i; i--)
{ {
// [XA] inner trail uses a different default duration (33). // [XA] inner trail uses a different default duration (33).
@ -793,8 +826,8 @@ void P_DrawRailTrail(AActor *source, const DVector3 &start, TArray<SPortalHit> &
p->Pos = postmp; p->Pos = postmp;
if (color1 != -1) if (color1 != -1)
p->Acc.Z -= 1./4096; p->Acc.Z -= 1./4096;
pos += trail_step; pos += trail[segment].dir * stepsize;
lencount -= stepsize;
p->bright = fullbright; p->bright = fullbright;
if (color2 == -1) if (color2 == -1)
@ -812,6 +845,21 @@ void P_DrawRailTrail(AActor *source, const DVector3 &start, TArray<SPortalHit> &
{ {
p->color = color2; p->color = color2;
} }
if (lencount <= 0)
{
segment++;
if (segment < trail.Size())
{
pos = trail[segment].start - trail[segment].dir * lencount;
lencount += trail[segment].length;
}
else
{
// should never happen but if something goes wrong, just terminate the loop.
break;
}
}
} }
} }
// create actors // create actors
@ -820,11 +868,14 @@ void P_DrawRailTrail(AActor *source, const DVector3 &start, TArray<SPortalHit> &
if (sparsity < 1) if (sparsity < 1)
sparsity = 32; sparsity = 32;
DVector3 trail_step = (step / 3) * sparsity; double stepsize = 3 * r_rail_spiralsparsity * sparsity;
int trail_steps = (int)((steps * 3) / sparsity); int trail_steps = (int)((steps * 3) / sparsity);
DVector3 diff(0, 0, 0); DVector3 diff(0, 0, 0);
pos = start; pos = trail[0].start;
lencount = trail[0].length;
segment = 0;
for (i = trail_steps; i; i--) for (i = trail_steps; i; i--)
{ {
if (maxdiff > 0) if (maxdiff > 0)
@ -840,7 +891,22 @@ void P_DrawRailTrail(AActor *source, const DVector3 &start, TArray<SPortalHit> &
AActor *thing = Spawn (spawnclass, pos + diff, ALLOW_REPLACE); AActor *thing = Spawn (spawnclass, pos + diff, ALLOW_REPLACE);
if (thing) if (thing)
thing->Angles.Yaw = angle; thing->Angles.Yaw = angle;
pos += trail_step; pos += trail[segment].dir * stepsize;
lencount -= stepsize;
if (lencount <= 0)
{
segment++;
if (segment < trail.Size())
{
pos = trail[segment].start - trail[segment].dir * lencount;
lencount += trail[segment].length;
}
else
{
// should never happen but if something goes wrong, just terminate the loop.
break;
}
}
} }
} }
} }

View file

@ -97,7 +97,7 @@ struct SPortalHit
DVector3 OutDir; DVector3 OutDir;
}; };
void P_DrawRailTrail(AActor *source, const DVector3 &start, TArray<SPortalHit> &portalhits, const DVector3 &end, int color1, int color2, double maxdiff = 0, int flags = 0, PClassActor *spawnclass = NULL, DAngle angle = 0., int duration = 35, double sparsity = 1.0, double drift = 1.0, int SpiralOffset = 270); void P_DrawRailTrail(AActor *source, TArray<SPortalHit> &portalhits, int color1, int color2, double maxdiff = 0, int flags = 0, PClassActor *spawnclass = NULL, DAngle angle = 0., int duration = 35, double sparsity = 1.0, double drift = 1.0, int SpiralOffset = 270);
void P_DrawSplash (int count, const DVector3 &pos, DAngle angle, int kind); void P_DrawSplash (int count, const DVector3 &pos, DAngle angle, int kind);
void P_DrawSplash2 (int count, const DVector3 &pos, DAngle angle, int updown, int kind); void P_DrawSplash2 (int count, const DVector3 &pos, DAngle angle, int updown, int kind);
void P_DisconnectEffect (AActor *actor); void P_DisconnectEffect (AActor *actor);

View file

@ -4598,15 +4598,8 @@ void P_RailAttack(FRailParams *p)
rail_data.StopAtInvul = (puffDefaults->flags3 & MF3_FOILINVUL) ? false : true; rail_data.StopAtInvul = (puffDefaults->flags3 & MF3_FOILINVUL) ? false : true;
rail_data.ThruSpecies = (puffDefaults->flags6 & MF6_MTHRUSPECIES) ? true : false; rail_data.ThruSpecies = (puffDefaults->flags6 & MF6_MTHRUSPECIES) ? true : false;
// to make things easier, push the start position and directional vector onto the PortalHits array as its first element
SPortalHit phit = { start, start, vec };
rail_data.PortalHits.Push(phit);
Trace(start, source->Sector, vec, p->distance, MF_SHOOTABLE, ML_BLOCKEVERYTHING, source, trace, flags, ProcessRailHit, &rail_data); Trace(start, source->Sector, vec, p->distance, MF_SHOOTABLE, ML_BLOCKEVERYTHING, source, trace, flags, ProcessRailHit, &rail_data);
// and push the hit position, too, so that the array contains the entire trace with all transition points.
phit = { trace.HitPos, trace.HitPos, trace.HitVector };
rail_data.PortalHits.Push(phit);
// Hurt anything the trace hit // Hurt anything the trace hit
unsigned int i; unsigned int i;
FName damagetype = (puffDefaults == NULL || puffDefaults->DamageType == NAME_None) ? FName(NAME_Railgun) : puffDefaults->DamageType; FName damagetype = (puffDefaults == NULL || puffDefaults->DamageType == NAME_None) ? FName(NAME_Railgun) : puffDefaults->DamageType;
@ -4709,7 +4702,7 @@ void P_RailAttack(FRailParams *p)
} }
// Draw the slug's trail. // Draw the slug's trail.
P_DrawRailTrail(source, start, rail_data.PortalHits, trace.HitPos, p->color1, p->color2, p->maxdiff, p->flags, p->spawnclass, angle, p->duration, p->sparsity, p->drift, p->SpiralOffset); P_DrawRailTrail(source, rail_data.PortalHits, p->color1, p->color2, p->maxdiff, p->flags, p->spawnclass, angle, p->duration, p->sparsity, p->drift, p->SpiralOffset);
} }
//========================================================================== //==========================================================================

View file

@ -450,13 +450,13 @@ void AActor::LinkToWorld(bool spawningmapthing, sector_t *sector)
// link into blockmap (inert things don't need to be in the blockmap) // link into blockmap (inert things don't need to be in the blockmap)
if (!(flags & MF_NOBLOCKMAP)) if (!(flags & MF_NOBLOCKMAP))
{ {
FPortalGroupArray check(FPortalGroupArray::PGA_NoSectorPortals); FPortalGroupArray check;
P_CollectConnectedGroups(Sector->PortalGroup, Pos(), Top(), radius, check); P_CollectConnectedGroups(Sector->PortalGroup, Pos(), Top(), radius, check);
for (int i = -1; i < (int)check.Size(); i++) for (int i = -1; i < (int)check.Size(); i++)
{ {
DVector3 pos = i==-1? Pos() : PosRelative(check[i]); DVector3 pos = i==-1? Pos() : PosRelative(check[i] & ~FPortalGroupArray::FLAT);
int x1 = GetBlockX(pos.X - radius); int x1 = GetBlockX(pos.X - radius);
int x2 = GetBlockX(pos.X + radius); int x2 = GetBlockX(pos.X + radius);
@ -1616,12 +1616,22 @@ int FPathTraverse::PortalRelocate(intercept_t *in, int flags, DVector3 *optpos)
P_TranslatePortalXY(in->d.line, optpos->X, optpos->Y); P_TranslatePortalXY(in->d.line, optpos->X, optpos->Y);
P_TranslatePortalZ(in->d.line, optpos->Z); P_TranslatePortalZ(in->d.line, optpos->Z);
} }
line_t *saved = in->d.line; // this gets overwriitten by the init call. line_t *saved = in->d.line; // this gets overwritten by the init call.
intercepts.Resize(intercept_index); intercepts.Resize(intercept_index);
init(hitx, hity, endx, endy, flags, in->frac); init(hitx, hity, endx, endy, flags, in->frac + EQUAL_EPSILON);
return saved->getPortal()->mType == PORTT_LINKED? 1:-1; return saved->getPortal()->mType == PORTT_LINKED? 1:-1;
} }
void FPathTraverse::PortalRelocate(AActor *portalthing, int flags, double hitfrac)
{
double hitx = trace.x + portalthing->Scale.X;
double hity = trace.y + portalthing->Scale.Y;
double endx = hitx + trace.dx;
double endy = hity + trace.dy;
intercepts.Resize(intercept_index);
init(hitx, hity, endx, endy, flags, hitfrac);
}
//=========================================================================== //===========================================================================
// //
// //

View file

@ -373,6 +373,7 @@ public:
} }
void init(double x1, double y1, double x2, double y2, int flags, double startfrac = 0); void init(double x1, double y1, double x2, double y2, int flags, double startfrac = 0);
int PortalRelocate(intercept_t *in, int flags, DVector3 *optpos = NULL); int PortalRelocate(intercept_t *in, int flags, DVector3 *optpos = NULL);
void PortalRelocate(AActor *portalthing, int flags, double hitfrac);
virtual ~FPathTraverse(); virtual ~FPathTraverse();
const divline_t &Trace() const { return trace; } const divline_t &Trace() const { return trace; }

View file

@ -55,7 +55,6 @@ struct FTraceInfo
DWORD WallMask; DWORD WallMask;
AActor *IgnoreThis; AActor *IgnoreThis;
FTraceResults *Results; FTraceResults *Results;
FTraceResults *TempResults;
sector_t *CurSector; sector_t *CurSector;
double MaxDist; double MaxDist;
double EnterDist; double EnterDist;
@ -64,10 +63,8 @@ struct FTraceInfo
DWORD TraceFlags; DWORD TraceFlags;
int inshootthrough; int inshootthrough;
double startfrac; double startfrac;
int aimdir;
double limitz; double limitz;
double lastfloorportalheight; int ptflags;
double lastceilingportalheight;
// These are required for 3D-floor checking // These are required for 3D-floor checking
// to create a fake sector with a floor // to create a fake sector with a floor
@ -76,12 +73,12 @@ struct FTraceInfo
int sectorsel; int sectorsel;
void Setup3DFloors(); void Setup3DFloors();
bool LineCheck(intercept_t *in); bool LineCheck(intercept_t *in, double dist, DVector3 hit);
bool ThingCheck(intercept_t *in); bool ThingCheck(intercept_t *in, double dist, DVector3 hit);
bool TraceTraverse (int ptflags); bool TraceTraverse (int ptflags);
bool CheckPlane(const secplane_t &plane); bool CheckPlane(const secplane_t &plane);
int EnterLinePortal(line_t *li, double frac); void EnterLinePortal(FPathTraverse &pt, intercept_t *in);
void EnterSectorPortal(int position, double frac, sector_t *entersec); void EnterSectorPortal(FPathTraverse &pt, int position, double frac, sector_t *entersec);
bool CheckSectorPlane(const sector_t *sector, bool checkFloor) bool CheckSectorPlane(const sector_t *sector, bool checkFloor)
@ -107,6 +104,38 @@ struct FTraceInfo
static bool EditTraceResult (DWORD flags, FTraceResults &res); static bool EditTraceResult (DWORD flags, FTraceResults &res);
static void GetPortalTransition(DVector3 &pos, sector_t *&sec)
{
bool moved = false;
double testz = pos.Z;
while (!sec->PortalBlocksMovement(sector_t::ceiling))
{
AActor *port = sec->SkyBoxes[sector_t::ceiling];
if (pos.Z > port->specialf1)
{
pos += port->Scale;
sec = P_PointInSector(pos);
moved = true;
}
else break;
}
if (!moved)
{
while (!sec->PortalBlocksMovement(sector_t::floor))
{
AActor *port = sec->SkyBoxes[sector_t::floor];
if (pos.Z <= port->specialf1)
{
pos += port->Scale;
sec = P_PointInSector(pos);
}
else break;
}
}
}
//========================================================================== //==========================================================================
// //
// Trace entry point // Trace entry point
@ -117,16 +146,15 @@ bool Trace(const DVector3 &start, sector_t *sector, const DVector3 &direction, d
ActorFlags actorMask, DWORD wallMask, AActor *ignore, FTraceResults &res, DWORD flags, ActorFlags actorMask, DWORD wallMask, AActor *ignore, FTraceResults &res, DWORD flags,
ETraceStatus(*callback)(FTraceResults &res, void *), void *callbackdata) ETraceStatus(*callback)(FTraceResults &res, void *), void *callbackdata)
{ {
int ptflags;
FTraceInfo inf; FTraceInfo inf;
FTraceResults tempResult; FTraceResults tempResult;
memset(&tempResult, 0, sizeof(tempResult)); memset(&tempResult, 0, sizeof(tempResult));
tempResult.Fraction = tempResult.Distance = NO_VALUE; tempResult.Fraction = tempResult.Distance = NO_VALUE;
ptflags = actorMask ? PT_ADDLINES|PT_ADDTHINGS|PT_COMPATIBLE : PT_ADDLINES;
inf.Start = start; inf.Start = start;
GetPortalTransition(inf.Start, sector);
inf.ptflags = actorMask ? PT_ADDLINES|PT_ADDTHINGS|PT_COMPATIBLE : PT_ADDLINES;
inf.Vec = direction; inf.Vec = direction;
inf.ActorMask = actorMask; inf.ActorMask = actorMask;
inf.WallMask = wallMask; inf.WallMask = wallMask;
@ -138,15 +166,30 @@ bool Trace(const DVector3 &start, sector_t *sector, const DVector3 &direction, d
inf.TraceCallbackData = callbackdata; inf.TraceCallbackData = callbackdata;
inf.TraceFlags = flags; inf.TraceFlags = flags;
inf.Results = &res; inf.Results = &res;
inf.TempResults = &tempResult;
inf.inshootthrough = true; inf.inshootthrough = true;
inf.sectorsel=0; inf.sectorsel=0;
inf.aimdir = -1;
inf.startfrac = 0; inf.startfrac = 0;
inf.lastfloorportalheight = inf.lastceilingportalheight = start.Z; inf.limitz = inf.Start.Z;
memset(&res, 0, sizeof(res)); memset(&res, 0, sizeof(res));
if (inf.TraceTraverse (ptflags)) if ((flags & TRACE_ReportPortals) && callback != NULL)
{
tempResult.HitType = TRACE_CrossingPortal;
tempResult.HitPos = tempResult.SrcFromTarget = inf.Start;
tempResult.HitVector = inf.Vec;
callback(tempResult, inf.TraceCallbackData);
}
bool reslt = inf.TraceTraverse(inf.ptflags);
if ((flags & TRACE_ReportPortals) && callback != NULL)
{
tempResult.HitType = TRACE_CrossingPortal;
tempResult.HitPos = tempResult.SrcFromTarget = inf.Results->HitPos;
tempResult.HitVector = inf.Vec;
callback(tempResult, inf.TraceCallbackData);
}
if (reslt)
{ {
return flags ? EditTraceResult(flags, res) : true; return flags ? EditTraceResult(flags, res) : true;
} }
@ -163,48 +206,32 @@ bool Trace(const DVector3 &start, sector_t *sector, const DVector3 &direction, d
// //
//============================================================================ //============================================================================
void FTraceInfo::EnterSectorPortal(int position, double frac, sector_t *entersec) void FTraceInfo::EnterSectorPortal(FPathTraverse &pt, int position, double frac, sector_t *entersec)
{ {
if (aimdir != -1 && aimdir != position) return;
AActor *portal = entersec->SkyBoxes[position]; AActor *portal = entersec->SkyBoxes[position];
if (aimdir == sector_t::ceiling && portal->specialf1 < limitz) return;
else if (aimdir == sector_t::floor && portal->specialf1 > limitz) return;
FTraceInfo newtrace;
FTraceResults results;
memset(&results, 0, sizeof(results));
newtrace.Start += portal->Scale;
frac += 1 / MaxDist;
double enterdist = MaxDist * frac; double enterdist = MaxDist * frac;
DVector2 enter = newtrace.Start.XY() + enterdist * Vec.XY(); DVector3 exit = Start + enterdist * Vec;
DVector3 enter = exit + portal->Scale;
newtrace.Vec = Vec; Start += portal->Scale;
newtrace.ActorMask = ActorMask; CurSector = P_PointInSector(enter);
newtrace.WallMask = WallMask; inshootthrough = true;
newtrace.IgnoreThis = IgnoreThis; startfrac = frac;
newtrace.Results = &results; EnterDist = enterdist;
newtrace.TempResults = TempResults; pt.PortalRelocate(portal, ptflags, frac);
newtrace.CurSector = P_PointInSector(enter);
newtrace.MaxDist = MaxDist;
newtrace.EnterDist = EnterDist;
newtrace.TraceCallback = TraceCallback;
newtrace.TraceCallbackData = TraceCallbackData;
newtrace.TraceFlags = TraceFlags;
newtrace.inshootthrough = true;
newtrace.startfrac = frac;
newtrace.aimdir = position;
newtrace.limitz = portal->specialf1;
newtrace.sectorsel = 0;
newtrace.lastfloorportalheight = newtrace.lastceilingportalheight = limitz;
if (newtrace.TraceTraverse(ActorMask ? PT_ADDLINES | PT_ADDTHINGS | PT_COMPATIBLE : PT_ADDLINES)) if ((TraceFlags & TRACE_ReportPortals) && TraceCallback != NULL)
{ {
TempResults->CopyIfCloser(newtrace.Results); enterdist = MaxDist * frac;
Results->HitType = TRACE_CrossingPortal;
Results->HitPos = exit;
Results->SrcFromTarget = enter;
Results->HitVector = Vec;
TraceCallback(*Results, TraceCallbackData);
} }
Setup3DFloors();
} }
//============================================================================ //============================================================================
@ -213,59 +240,38 @@ void FTraceInfo::EnterSectorPortal(int position, double frac, sector_t *entersec
// //
//============================================================================ //============================================================================
int FTraceInfo::EnterLinePortal(line_t *li, double frac) void FTraceInfo::EnterLinePortal(FPathTraverse &pt, intercept_t *in)
{ {
line_t *li = in->d.line;
FLinePortal *port = li->getPortal(); FLinePortal *port = li->getPortal();
// The caller cannot handle portals without global offset. double frac = in->frac + EQUAL_EPSILON;
if (port->mType != PORTT_LINKED && (TraceFlags & TRACE_PortalRestrict)) return -1; double enterdist = MaxDist * frac;
DVector3 exit = Start + MaxDist * in->frac * Vec;
FTraceInfo newtrace; P_TranslatePortalXY(li, Start.X, Start.Y);
P_TranslatePortalZ(li, Start.Z);
P_TranslatePortalVXVY(li, Vec.X, Vec.Y);
P_TranslatePortalZ(li, limitz);
newtrace.Start = Start; CurSector = P_PointInSector(Start + enterdist * Vec);
newtrace.Vec = Vec; EnterDist = enterdist;
inshootthrough = true;
P_TranslatePortalXY(li, newtrace.Start.X, newtrace.Start.Y); startfrac = frac;
P_TranslatePortalZ(li, newtrace.Start.Z); Results->unlinked |= (port->mType != PORTT_LINKED);
P_TranslatePortalVXVY(li, newtrace.Vec.X, newtrace.Vec.Y); pt.PortalRelocate(in, ptflags);
frac += 1 / MaxDist;
double enterdist = MaxDist / frac;
DVector3 enter = newtrace.Start + enterdist * Vec;
newtrace.ActorMask = ActorMask;
newtrace.WallMask = WallMask;
newtrace.IgnoreThis = IgnoreThis;
newtrace.Results = Results;
newtrace.TempResults = TempResults;
newtrace.CurSector = P_PointInSector(enter);
newtrace.MaxDist = MaxDist;
newtrace.EnterDist = EnterDist;
newtrace.TraceCallback = TraceCallback;
newtrace.TraceCallbackData = TraceCallbackData;
newtrace.TraceFlags = TraceFlags;
newtrace.inshootthrough = true;
newtrace.startfrac = frac;
newtrace.aimdir = aimdir;
newtrace.limitz = limitz;
P_TranslatePortalZ(li, newtrace.limitz);
newtrace.lastfloorportalheight = newtrace.lastceilingportalheight = newtrace.limitz;
newtrace.sectorsel = 0;
Results->unlinked = true;
if ((TraceFlags & TRACE_ReportPortals) && TraceCallback != NULL) if ((TraceFlags & TRACE_ReportPortals) && TraceCallback != NULL)
{ {
enterdist = MaxDist * in->frac;
Results->HitType = TRACE_CrossingPortal; Results->HitType = TRACE_CrossingPortal;
Results->HitPos = enter; Results->HitPos = exit;
P_TranslatePortalXY(li, enter.X, enter.Y); P_TranslatePortalXY(li, exit.X, exit.Y);
P_TranslatePortalZ(li, enter.Z); P_TranslatePortalZ(li, exit.Z);
Results->SrcFromTarget = enter; Results->SrcFromTarget = exit;
Results->HitVector = newtrace.Vec; Results->HitVector = Vec;
TraceCallback(*Results, TraceCallbackData); TraceCallback(*Results, TraceCallbackData);
} }
return newtrace.TraceTraverse(ActorMask ? PT_ADDLINES | PT_ADDTHINGS | PT_COMPATIBLE : PT_ADDLINES);
} }
//========================================================================== //==========================================================================
@ -355,14 +361,6 @@ void FTraceInfo::Setup3DFloors()
} }
} }
} }
if (!CurSector->PortalBlocksMovement(sector_t::ceiling))
{
EnterSectorPortal(sector_t::ceiling, startfrac, CurSector);
}
if (!CurSector->PortalBlocksMovement(sector_t::floor))
{
EnterSectorPortal(sector_t::floor, startfrac, CurSector);
}
} }
@ -372,14 +370,11 @@ void FTraceInfo::Setup3DFloors()
// //
//========================================================================== //==========================================================================
bool FTraceInfo::LineCheck(intercept_t *in) bool FTraceInfo::LineCheck(intercept_t *in, double dist, DVector3 hit)
{ {
int lineside; int lineside;
sector_t *entersector; sector_t *entersector;
double dist = MaxDist * in->frac;
DVector3 hit = Start + Vec * dist;
double ff, fc, bf = 0, bc = 0; double ff, fc, bf = 0, bc = 0;
if (in->d.line->frontsector->sectornum == CurSector->sectornum) if (in->d.line->frontsector->sectornum == CurSector->sectornum)
@ -454,78 +449,15 @@ bool FTraceInfo::LineCheck(intercept_t *in)
if (hit.Z <= ff) if (hit.Z <= ff)
{ {
if (CurSector->PortalBlocksMovement(sector_t::floor)) // hit floor in front of wall
{ Results->HitType = TRACE_HitFloor;
// hit floor in front of wall Results->HitTexture = CurSector->GetTexture(sector_t::floor);
Results->HitType = TRACE_HitFloor;
Results->HitTexture = CurSector->GetTexture(sector_t::floor);
}
else
{
if ((TraceFlags & TRACE_ReportPortals) && lastfloorportalheight > fc)
{
lastfloorportalheight = fc;
if (TraceCallback != NULL)
{
Results->HitType = TRACE_CrossingPortal;
double hitz = CurSector->SkyBoxes[sector_t::floor]->specialf1;
Results->HitPos = Start + Vec * (hitz - Start.Z) / Vec.Z;
Results->SrcFromTarget = Results->HitPos + CurSector->SkyBoxes[sector_t::floor]->Scale;
Results->HitVector = Vec;
TraceCallback(*Results, TraceCallbackData);
}
}
if (entersector == NULL || entersector->PortalBlocksMovement(sector_t::floor))
{
// hit beyond a portal plane. This needs to be taken care of by the trace spawned on the other side.
Results->HitType = TRACE_HitNone;
return false;
}
}
} }
else if (hit.Z >= fc) else if (hit.Z >= fc)
{ {
if (CurSector->PortalBlocksMovement(sector_t::ceiling)) // hit ceiling in front of wall
{ Results->HitType = TRACE_HitCeiling;
// hit ceiling in front of wall Results->HitTexture = CurSector->GetTexture(sector_t::ceiling);
Results->HitType = TRACE_HitCeiling;
Results->HitTexture = CurSector->GetTexture(sector_t::ceiling);
}
else
{
if ((TraceFlags & TRACE_ReportPortals) && lastceilingportalheight < fc)
{
lastceilingportalheight = fc;
if (TraceCallback != NULL)
{
Results->HitType = TRACE_CrossingPortal;
double hitz = CurSector->SkyBoxes[sector_t::ceiling]->specialf1;
Results->HitPos = Start + Vec * (hitz - Start.Z) / Vec.Z;
Results->SrcFromTarget = Results->HitPos + CurSector->SkyBoxes[sector_t::ceiling]->Scale;
Results->HitVector = Vec;
TraceCallback(*Results, TraceCallbackData);
}
}
if (entersector == NULL || entersector->PortalBlocksMovement(sector_t::ceiling))
{
// hit beyond a portal plane. This needs to be taken care of by the trace spawned on the other side.
Results->HitType = TRACE_HitNone;
return false;
}
}
}
else if (in->d.line->isLinePortal())
{
if (entersector == NULL || (hit.Z >= bf && hit.Z <= bc))
{
int res = EnterLinePortal(in->d.line, in->frac);
if (res != -1)
{
aimdir = INT_MAX; // flag for ending the traverse
return !!res;
}
}
goto normalline; // hit upper or lower tier.
} }
else if (entersector == NULL || else if (entersector == NULL ||
hit.Z < bf || hit.Z > bc || hit.Z < bf || hit.Z > bc ||
@ -610,15 +542,6 @@ normalline:
// we need to as well, for compatibility // we need to as well, for compatibility
P_ActivateLine(in->d.line, IgnoreThis, lineside, SPAC_Impact); P_ActivateLine(in->d.line, IgnoreThis, lineside, SPAC_Impact);
} }
if (!entersector->PortalBlocksMovement(sector_t::ceiling))
{
EnterSectorPortal(sector_t::ceiling, in->frac, entersector);
}
if (!entersector->PortalBlocksMovement(sector_t::floor))
{
EnterSectorPortal(sector_t::floor, in->frac, entersector);
}
} }
cont: cont:
@ -696,11 +619,8 @@ cont:
// //
//========================================================================== //==========================================================================
bool FTraceInfo::ThingCheck(intercept_t *in) bool FTraceInfo::ThingCheck(intercept_t *in, double dist, DVector3 hit)
{ {
double dist = MaxDist * in->frac;
DVector3 hit = Start + Vec * dist;
if (hit.Z > in->d.thing->Top()) if (hit.Z > in->d.thing->Top())
{ {
// trace enters above actor // trace enters above actor
@ -834,49 +754,59 @@ bool FTraceInfo::TraceTraverse (int ptflags)
lastsplashsector = CurSector->sectornum; lastsplashsector = CurSector->sectornum;
} }
// We have something closer in the storage for portal subtraces. double dist = MaxDist * in->frac;
if (TempResults->HitType != TRACE_HitNone && in->frac > TempResults->Fraction) DVector3 hit = Start + Vec * dist;
// Crossed a floor portal?
if (Vec.Z < 0 && !CurSector->PortalBlocksMovement(sector_t::floor))
{ {
break; // calculate position where the portal is crossed
double portz = CurSector->SkyBoxes[sector_t::floor]->specialf1;
if (hit.Z < portz && limitz > portz)
{
limitz = portz;
EnterSectorPortal(it, sector_t::floor, (portz - Start.Z) / (Vec.Z * MaxDist), CurSector);
continue;
}
} }
else if (in->isaline) // ... or a ceiling portal?
else if (Vec.Z > 0 && !CurSector->PortalBlocksMovement(sector_t::ceiling))
{ {
bool res = LineCheck(in); // calculate position where the portal is crossed
if (aimdir == INT_MAX) return res; // signal for immediate abort double portz = CurSector->SkyBoxes[sector_t::ceiling]->specialf1;
if (!res) break; if (hit.Z > portz && limitz < portz)
{
limitz = portz;
EnterSectorPortal(it, sector_t::ceiling, (portz - Start.Z) / (Vec.Z * MaxDist), CurSector);
continue;
}
}
if (in->isaline)
{
if (in->d.line->isLinePortal() && P_PointOnLineSidePrecise(Start, in->d.line) == 0)
{
sector_t *entersector = in->d.line->backsector;
if (entersector == NULL || (hit.Z >= entersector->floorplane.ZatPoint(hit) && hit.Z <= entersector->ceilingplane.ZatPoint(hit)))
{
FLinePortal *port = in->d.line->getPortal();
// The caller cannot handle portals without global offset.
if (port->mType == PORTT_LINKED || !(TraceFlags & TRACE_PortalRestrict))
{
EnterLinePortal(it, in);
continue;
}
}
}
if (!LineCheck(in, dist, hit)) break;
} }
else if ((in->d.thing->flags & ActorMask) && in->d.thing != IgnoreThis) else if ((in->d.thing->flags & ActorMask) && in->d.thing != IgnoreThis)
{ {
if (!ThingCheck(in)) break; if (!ThingCheck(in, dist, hit)) break;
} }
} }
// Check if one subtrace through a portal yielded a better result. if (Results->HitType == TRACE_HitNone)
if (TempResults->HitType != TRACE_HitNone &&
(Results->HitType == TRACE_HitNone || Results->Fraction > TempResults->Fraction))
{
// We still need to do a water check here or this may get missed on occasion
if (Results->CrossedWater == NULL &&
CurSector->heightsec != NULL &&
CurSector->heightsec->floorplane.ZatPoint(Results->HitPos) >= Results->HitPos.Z)
{
// Save the result so that the water check doesn't destroy it.
FTraceResults *res = Results;
FTraceResults hsecResult;
Results = &hsecResult;
if (CheckSectorPlane(CurSector->heightsec, true))
{
Results->CrossedWater = &sectors[CurSector->sectornum];
Results->CrossedWaterPos = Results->HitPos;
}
Results = res;
}
Results->CopyIfCloser(TempResults);
return true;
}
else if (Results->HitType == TRACE_HitNone)
{ {
if (CurSector->PortalBlocksMovement(sector_t::floor) && CheckSectorPlane(CurSector, true)) if (CurSector->PortalBlocksMovement(sector_t::floor) && CheckSectorPlane(CurSector, true))
{ {

View file

@ -87,24 +87,6 @@ struct FTraceResults
DVector3 CrossedWaterPos; // remember the position so that we can use it for spawning the splash DVector3 CrossedWaterPos; // remember the position so that we can use it for spawning the splash
F3DFloor *Crossed3DWater; // For 3D floor-based deep water F3DFloor *Crossed3DWater; // For 3D floor-based deep water
DVector3 Crossed3DWaterPos; DVector3 Crossed3DWaterPos;
void CopyIfCloser(FTraceResults *other)
{
if (other->Distance < Distance || HitType == TRACE_HitNone)
{
memcpy(this, other, myoffsetof(FTraceResults, CrossedWater));
}
if (CrossedWater == NULL && other->CrossedWater != NULL)
{
CrossedWater = other->CrossedWater;
CrossedWaterPos = other->CrossedWaterPos;
}
if (Crossed3DWater == NULL && other->Crossed3DWater != NULL)
{
Crossed3DWater = other->Crossed3DWater;
Crossed3DWaterPos = other->Crossed3DWaterPos;
}
}
}; };

View file

@ -1157,7 +1157,8 @@ bool FPolyObj::CheckMobjBlocking (side_t *sd)
performBlockingThrust = true; performBlockingThrust = true;
} }
FBoundingBox box(mobj->X(), mobj->Y(), mobj->radius); DVector2 pos = mobj->PosRelative(ld);
FBoundingBox box(pos.X, pos.Y, mobj->radius);
if (!box.inRange(ld) || box.BoxOnLineSide(ld) != -1) if (!box.inRange(ld) || box.BoxOnLineSide(ld) != -1)
{ {

View file

@ -661,10 +661,10 @@ DVector2 P_GetOffsetPosition(double x, double y, double dx, double dy)
if (blockx < 0 || blocky < 0 || blockx >= bmapwidth || blocky >= bmapheight || !PortalBlockmap(blockx, blocky).neighborContainsLines) return dest; if (blockx < 0 || blocky < 0 || blockx >= bmapwidth || blocky >= bmapheight || !PortalBlockmap(blockx, blocky).neighborContainsLines) return dest;
} }
FLinePortalTraverse it;
bool repeat; bool repeat;
do do
{ {
FLinePortalTraverse it;
it.init(actx, acty, dx, dy, PT_ADDLINES|PT_DELTA); it.init(actx, acty, dx, dy, PT_ADDLINES|PT_DELTA);
intercept_t *in; intercept_t *in;
@ -696,6 +696,8 @@ DVector2 P_GetOffsetPosition(double x, double y, double dx, double dy)
// update the fields, end this trace and restart from the new position // update the fields, end this trace and restart from the new position
dx = dest.X - hit.X; dx = dest.X - hit.X;
dy = dest.Y - hit.Y; dy = dest.Y - hit.Y;
actx = hit.X;
acty = hit.Y;
repeat = true; repeat = true;
} }