mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-11 23:32:02 +00:00
- implemented line portal transition. Not yet tested for arbitrary portals but for static ones it is working - including camera interpolation.
This commit is contained in:
parent
451cac457b
commit
8d58d63b60
5 changed files with 217 additions and 21 deletions
|
@ -243,6 +243,7 @@ extern msecnode_t *sector_list; // phares 3/16/98
|
||||||
struct spechit_t
|
struct spechit_t
|
||||||
{
|
{
|
||||||
line_t *line;
|
line_t *line;
|
||||||
|
fixedvec2 oldrefpos;
|
||||||
fixedvec2 refpos;
|
fixedvec2 refpos;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
139
src/p_map.cpp
139
src/p_map.cpp
|
@ -969,12 +969,14 @@ bool PIT_CheckLine(FMultiBlockLinesIterator &mit, FMultiBlockLinesIterator::Chec
|
||||||
{
|
{
|
||||||
spec.line = ld;
|
spec.line = ld;
|
||||||
spec.refpos = cres.position;
|
spec.refpos = cres.position;
|
||||||
|
spec.oldrefpos = tm.thing->PosRelative(ld);
|
||||||
spechit.Push(spec);
|
spechit.Push(spec);
|
||||||
}
|
}
|
||||||
if (ld->portalindex >= 0 && ld->portalindex != UINT_MAX)
|
if (ld->portalindex >= 0 && ld->portalindex != UINT_MAX)
|
||||||
{
|
{
|
||||||
spec.line = ld;
|
spec.line = ld;
|
||||||
spec.refpos = cres.position;
|
spec.refpos = cres.position;
|
||||||
|
spec.oldrefpos = tm.thing->PosRelative(ld);
|
||||||
portalhit.Push(spec);
|
portalhit.Push(spec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1526,7 +1528,6 @@ bool P_CheckPosition(AActor *thing, fixed_t x, fixed_t y, FCheckPosition &tm, bo
|
||||||
tm.touchmidtex = false;
|
tm.touchmidtex = false;
|
||||||
tm.abovemidtex = false;
|
tm.abovemidtex = false;
|
||||||
validcount++;
|
validcount++;
|
||||||
spechit.Clear();
|
|
||||||
|
|
||||||
if ((thing->flags & MF_NOCLIP) && !(thing->flags & MF_SKULLFLY))
|
if ((thing->flags & MF_NOCLIP) && !(thing->flags & MF_SKULLFLY))
|
||||||
return true;
|
return true;
|
||||||
|
@ -1604,6 +1605,8 @@ bool P_CheckPosition(AActor *thing, fixed_t x, fixed_t y, FCheckPosition &tm, bo
|
||||||
// a pickup they cannot get, because their validcount will prevent them from
|
// a pickup they cannot get, because their validcount will prevent them from
|
||||||
// being considered for collision with the player.
|
// being considered for collision with the player.
|
||||||
validcount++;
|
validcount++;
|
||||||
|
spechit.Clear();
|
||||||
|
portalhit.Clear();
|
||||||
|
|
||||||
thing->BlockingMobj = NULL;
|
thing->BlockingMobj = NULL;
|
||||||
thing->height = realheight;
|
thing->height = realheight;
|
||||||
|
@ -2132,22 +2135,125 @@ bool P_TryMove(AActor *thing, fixed_t x, fixed_t y,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// the move is ok, so link the thing into its new position
|
|
||||||
thing->UnlinkFromWorld();
|
|
||||||
|
|
||||||
oldpos = thing->Pos();
|
// Check for crossed portals
|
||||||
oldsector = thing->Sector;
|
bool portalcrossed = false;
|
||||||
thing->floorz = tm.floorz;
|
|
||||||
thing->ceilingz = tm.ceilingz;
|
|
||||||
thing->dropoffz = tm.dropoffz; // killough 11/98: keep track of dropoffs
|
|
||||||
thing->floorpic = tm.floorpic;
|
|
||||||
thing->floorterrain = tm.floorterrain;
|
|
||||||
thing->floorsector = tm.floorsector;
|
|
||||||
thing->ceilingpic = tm.ceilingpic;
|
|
||||||
thing->ceilingsector = tm.ceilingsector;
|
|
||||||
thing->SetXY(x, y);
|
|
||||||
|
|
||||||
thing->LinkToWorld();
|
while (true)
|
||||||
|
{
|
||||||
|
fixed_t bestfrac = FIXED_MAX;
|
||||||
|
spechit_t *besthit = NULL;
|
||||||
|
// find the portal nearest to the crossing actor
|
||||||
|
for (auto &spec : portalhit)
|
||||||
|
{
|
||||||
|
line_t *ld = spec.line;
|
||||||
|
if (ld->frontsector->PortalGroup != thing->Sector->PortalGroup) continue; // must be in the same group to be considered valid.
|
||||||
|
|
||||||
|
// see if the line was crossed
|
||||||
|
oldside = P_PointOnLineSide(spec.oldrefpos.x, spec.oldrefpos.y, ld);
|
||||||
|
side = P_PointOnLineSide(spec.refpos.x, spec.refpos.y, ld);
|
||||||
|
if (oldside == 0 && side == 1)
|
||||||
|
{
|
||||||
|
divline_t dl2 = { ld->v1->x, ld->v1->y, ld->dx, ld->dy };
|
||||||
|
divline_t dl1 = { spec.oldrefpos.x, spec.oldrefpos.y, spec.refpos.x - spec.oldrefpos.x, spec.refpos.y - spec.oldrefpos.y };
|
||||||
|
fixed_t frac = P_InterceptVector(&dl1, &dl2);
|
||||||
|
if (frac < bestfrac)
|
||||||
|
{
|
||||||
|
besthit = &spec;
|
||||||
|
bestfrac = frac;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bestfrac < FIXED_MAX)
|
||||||
|
{
|
||||||
|
line_t *ld = besthit->line;
|
||||||
|
FLinePortal *port = ld->getPortal();
|
||||||
|
if (port->mType == PORTT_LINKED)
|
||||||
|
{
|
||||||
|
thing->UnlinkFromWorld();
|
||||||
|
thing->SetXY(tm.x + port->mXDisplacement, tm.y + port->mYDisplacement);
|
||||||
|
thing->PrevX += port->mXDisplacement;
|
||||||
|
thing->PrevY += port->mYDisplacement;
|
||||||
|
thing->LinkToWorld();
|
||||||
|
P_FindFloorCeiling(thing);
|
||||||
|
portalcrossed = true;
|
||||||
|
}
|
||||||
|
else if (!portalcrossed)
|
||||||
|
{
|
||||||
|
line_t *out = port->mDestination;
|
||||||
|
fixedvec3 pos = { tm.x, tm.y, thing->Z() };
|
||||||
|
fixedvec3 oldthingpos = thing->Pos();
|
||||||
|
fixedvec2 thingpos = oldthingpos;
|
||||||
|
|
||||||
|
// This gets a bit tricky because we want to catch all line specials the actor crosses on the other side, too.
|
||||||
|
// So we have to translate the old Actor xy and temporarily set this as the actor's current position for the P_CheckPosition call,
|
||||||
|
// so that the spechit array gets proper positions assigned that can be evaluated later.
|
||||||
|
P_TranslatePortalXY(ld, out, pos.x, pos.y);
|
||||||
|
P_TranslatePortalXY(ld, out, thingpos.x, thingpos.y);
|
||||||
|
P_TranslatePortalVXVY(ld, out, thing->velx, thing->vely);
|
||||||
|
P_TranslatePortalAngle(ld, out, thing->angle);
|
||||||
|
P_TranslatePortalZ(ld, out, pos.z);
|
||||||
|
thing->SetXYZ(thingpos.x, thingpos.y, pos.z);
|
||||||
|
if (!P_CheckPosition(thing, pos.x, pos.y))
|
||||||
|
{
|
||||||
|
thing->SetXYZ(oldthingpos);
|
||||||
|
thing->flags6 &= ~MF6_INTRYMOVE;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
thing->UnlinkFromWorld();
|
||||||
|
thing->SetXYZ(pos);
|
||||||
|
thing->LinkToWorld();
|
||||||
|
P_FindFloorCeiling(thing);
|
||||||
|
thing->ClearInterpolation();
|
||||||
|
}
|
||||||
|
// if this is the current camera we need to store the point where the portal was crossed and the exit
|
||||||
|
// so that the renderer can properly calculate an interpolated position along the movement path.
|
||||||
|
if (thing == players[consoleplayer].camera)
|
||||||
|
{
|
||||||
|
divline_t dl1 = { besthit->oldrefpos.x,besthit-> oldrefpos.y, besthit->refpos.x - besthit->oldrefpos.x, besthit->refpos.y - besthit->oldrefpos.y };
|
||||||
|
fixedvec3 hit = { dl1.x + FixedMul(dl1.dx, bestfrac), dl1.y + FixedMul(dl1.dy, bestfrac), 0 };
|
||||||
|
line_t *out = port->mDestination;
|
||||||
|
|
||||||
|
R_AddInterpolationPoint(hit);
|
||||||
|
if (port->mType == PORTT_LINKED)
|
||||||
|
{
|
||||||
|
hit.x += port->mXDisplacement;
|
||||||
|
hit.y += port->mYDisplacement;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
P_TranslatePortalXY(ld, out, hit.x, hit.y);
|
||||||
|
P_TranslatePortalZ(ld, out, hit.z);
|
||||||
|
}
|
||||||
|
R_AddInterpolationPoint(hit);
|
||||||
|
}
|
||||||
|
if (port->mType == PORTT_LINKED) continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (!portalcrossed)
|
||||||
|
{
|
||||||
|
// the move is ok, so link the thing into its new position
|
||||||
|
thing->UnlinkFromWorld();
|
||||||
|
|
||||||
|
oldpos = thing->Pos();
|
||||||
|
oldsector = thing->Sector;
|
||||||
|
thing->floorz = tm.floorz;
|
||||||
|
thing->ceilingz = tm.ceilingz;
|
||||||
|
thing->dropoffz = tm.dropoffz; // killough 11/98: keep track of dropoffs
|
||||||
|
thing->floorpic = tm.floorpic;
|
||||||
|
thing->floorterrain = tm.floorterrain;
|
||||||
|
thing->floorsector = tm.floorsector;
|
||||||
|
thing->ceilingpic = tm.ceilingpic;
|
||||||
|
thing->ceilingsector = tm.ceilingsector;
|
||||||
|
thing->SetXY(x, y);
|
||||||
|
|
||||||
|
thing->LinkToWorld();
|
||||||
|
}
|
||||||
|
|
||||||
if (thing->flags2 & MF2_FLOORCLIP)
|
if (thing->flags2 & MF2_FLOORCLIP)
|
||||||
{
|
{
|
||||||
|
@ -2161,10 +2267,9 @@ bool P_TryMove(AActor *thing, fixed_t x, fixed_t y,
|
||||||
while (spechit.Pop(spec))
|
while (spechit.Pop(spec))
|
||||||
{
|
{
|
||||||
line_t *ld = spec.line;
|
line_t *ld = spec.line;
|
||||||
fixedvec3 oldrelpos = PosRelative(oldpos, ld, oldsector);
|
|
||||||
// see if the line was crossed
|
// see if the line was crossed
|
||||||
side = P_PointOnLineSide(spec.refpos.x, spec.refpos.y, ld);
|
side = P_PointOnLineSide(spec.refpos.x, spec.refpos.y, ld);
|
||||||
oldside = P_PointOnLineSide(oldrelpos.x, oldrelpos.y, ld);
|
oldside = P_PointOnLineSide(spec.oldrefpos.x, spec.oldrefpos.y, ld);
|
||||||
if (side != oldside && ld->special && !(thing->flags6 & MF6_NOTRIGGER))
|
if (side != oldside && ld->special && !(thing->flags6 & MF6_NOTRIGGER))
|
||||||
{
|
{
|
||||||
if (thing->player && (thing->player->cheats & CF_PREDICTING))
|
if (thing->player && (thing->player->cheats & CF_PREDICTING))
|
||||||
|
|
|
@ -112,6 +112,7 @@ void P_Ticker (void)
|
||||||
S_ResumeSound (false);
|
S_ResumeSound (false);
|
||||||
|
|
||||||
P_ResetSightCounters (false);
|
P_ResetSightCounters (false);
|
||||||
|
R_ClearInterpolationPath();
|
||||||
|
|
||||||
// Since things will be moving, it's okay to interpolate them in the renderer.
|
// Since things will be moving, it's okay to interpolate them in the renderer.
|
||||||
r_NoInterpolate = false;
|
r_NoInterpolate = false;
|
||||||
|
|
|
@ -81,6 +81,7 @@ static TArray<InterpolationViewer> PastViewers;
|
||||||
static FRandom pr_torchflicker ("TorchFlicker");
|
static FRandom pr_torchflicker ("TorchFlicker");
|
||||||
static FRandom pr_hom;
|
static FRandom pr_hom;
|
||||||
static bool NoInterpolateView;
|
static bool NoInterpolateView;
|
||||||
|
static TArray<fixedvec3> InterpolationPath;
|
||||||
|
|
||||||
// PUBLIC DATA DEFINITIONS -------------------------------------------------
|
// PUBLIC DATA DEFINITIONS -------------------------------------------------
|
||||||
|
|
||||||
|
@ -574,6 +575,7 @@ void R_InterpolateView (player_t *player, fixed_t frac, InterpolationViewer *ivi
|
||||||
// frac = tf;
|
// frac = tf;
|
||||||
if (NoInterpolateView)
|
if (NoInterpolateView)
|
||||||
{
|
{
|
||||||
|
InterpolationPath.Clear();
|
||||||
NoInterpolateView = false;
|
NoInterpolateView = false;
|
||||||
iview->oviewx = iview->nviewx;
|
iview->oviewx = iview->nviewx;
|
||||||
iview->oviewy = iview->nviewy;
|
iview->oviewy = iview->nviewy;
|
||||||
|
@ -583,10 +585,67 @@ void R_InterpolateView (player_t *player, fixed_t frac, InterpolationViewer *ivi
|
||||||
}
|
}
|
||||||
int oldgroup = R_PointInSubsector(iview->oviewx, iview->oviewy)->sector->PortalGroup;
|
int oldgroup = R_PointInSubsector(iview->oviewx, iview->oviewy)->sector->PortalGroup;
|
||||||
int newgroup = R_PointInSubsector(iview->nviewx, iview->nviewy)->sector->PortalGroup;
|
int newgroup = R_PointInSubsector(iview->nviewx, iview->nviewy)->sector->PortalGroup;
|
||||||
fixedvec2 disp = Displacements.getOffset(oldgroup, newgroup);
|
|
||||||
viewx = iview->oviewx + FixedMul (frac, iview->nviewx - iview->oviewx - disp.x);
|
if ((iview->oviewx != iview->nviewx || iview->oviewy != iview->nviewy) && InterpolationPath.Size() > 0)
|
||||||
viewy = iview->oviewy + FixedMul (frac, iview->nviewy - iview->oviewy - disp.y);
|
{
|
||||||
viewz = iview->oviewz + FixedMul (frac, iview->nviewz - iview->oviewz);
|
viewx = iview->nviewx;
|
||||||
|
viewy = iview->nviewy;
|
||||||
|
viewz = iview->nviewz;
|
||||||
|
|
||||||
|
// Interpolating through line portals is a messy affair.
|
||||||
|
// What needs be done is to store the portal transitions of the camera actor as waypoints
|
||||||
|
// and then find out on which part of the path the current view lies.
|
||||||
|
// Needless to say, this doesn't work for chasecam mode.
|
||||||
|
if (!r_showviewer)
|
||||||
|
{
|
||||||
|
fixed_t pathlen = 0;
|
||||||
|
fixed_t zdiff = 0;
|
||||||
|
fixed_t totalzdiff = 0;
|
||||||
|
fixed_t oviewz = iview->oviewz;
|
||||||
|
fixed_t nviewz = iview->nviewz;
|
||||||
|
fixedvec3 oldpos = { iview->oviewx, iview->oviewy, 0 };
|
||||||
|
fixedvec3 newpos = { iview->nviewx, iview->nviewy, 0 };
|
||||||
|
InterpolationPath.Push(newpos); // add this to the array to simplify the loops below
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < InterpolationPath.Size(); i += 2)
|
||||||
|
{
|
||||||
|
fixedvec3 &start = i == 0 ? oldpos : InterpolationPath[i - 1];
|
||||||
|
fixedvec3 &end = InterpolationPath[i];
|
||||||
|
pathlen += xs_CRoundToInt(TVector2<double>(end.x - start.x, end.y - start.y).Length());
|
||||||
|
totalzdiff += start.z;
|
||||||
|
}
|
||||||
|
fixed_t interpolatedlen = FixedMul(frac, pathlen);
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < InterpolationPath.Size(); i += 2)
|
||||||
|
{
|
||||||
|
fixedvec3 &start = i == 0 ? oldpos : InterpolationPath[i - 1];
|
||||||
|
fixedvec3 &end = InterpolationPath[i];
|
||||||
|
fixed_t fraglen = xs_CRoundToInt(TVector2<double>(end.x - start.x, end.y - start.y).Length());
|
||||||
|
zdiff += start.z;
|
||||||
|
if (fraglen <= interpolatedlen)
|
||||||
|
{
|
||||||
|
interpolatedlen -= fraglen;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fixed_t fragfrac = FixedDiv(interpolatedlen, fraglen);
|
||||||
|
oviewz += zdiff;
|
||||||
|
nviewz -= totalzdiff - zdiff;
|
||||||
|
viewx = start.x + FixedMul(fragfrac, end.x - start.x);
|
||||||
|
viewy = start.y + FixedMul(fragfrac, end.y - start.y);
|
||||||
|
viewz = oviewz + FixedMul(frac, nviewz - oviewz);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
InterpolationPath.Pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fixedvec2 disp = Displacements.getOffset(oldgroup, newgroup);
|
||||||
|
viewx = iview->oviewx + FixedMul(frac, iview->nviewx - iview->oviewx - disp.x);
|
||||||
|
viewy = iview->oviewy + FixedMul(frac, iview->nviewy - iview->oviewy - disp.y);
|
||||||
|
viewz = iview->oviewz + FixedMul(frac, iview->nviewz - iview->oviewz);
|
||||||
|
}
|
||||||
if (player != NULL &&
|
if (player != NULL &&
|
||||||
!(player->cheats & CF_INTERPVIEW) &&
|
!(player->cheats & CF_INTERPVIEW) &&
|
||||||
player - players == consoleplayer &&
|
player - players == consoleplayer &&
|
||||||
|
@ -678,6 +737,7 @@ void R_InterpolateView (player_t *player, fixed_t frac, InterpolationViewer *ivi
|
||||||
|
|
||||||
void R_ResetViewInterpolation ()
|
void R_ResetViewInterpolation ()
|
||||||
{
|
{
|
||||||
|
InterpolationPath.Clear();
|
||||||
NoInterpolateView = true;
|
NoInterpolateView = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -718,6 +778,7 @@ static InterpolationViewer *FindPastViewer (AActor *actor)
|
||||||
InterpolationViewer iview = { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
InterpolationViewer iview = { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||||
iview.ViewActor = actor;
|
iview.ViewActor = actor;
|
||||||
iview.otic = -1;
|
iview.otic = -1;
|
||||||
|
InterpolationPath.Clear();
|
||||||
return &PastViewers[PastViewers.Push (iview)];
|
return &PastViewers[PastViewers.Push (iview)];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -729,6 +790,7 @@ static InterpolationViewer *FindPastViewer (AActor *actor)
|
||||||
|
|
||||||
void R_FreePastViewers ()
|
void R_FreePastViewers ()
|
||||||
{
|
{
|
||||||
|
InterpolationPath.Clear();
|
||||||
PastViewers.Clear ();
|
PastViewers.Clear ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -742,6 +804,7 @@ void R_FreePastViewers ()
|
||||||
|
|
||||||
void R_ClearPastViewer (AActor *actor)
|
void R_ClearPastViewer (AActor *actor)
|
||||||
{
|
{
|
||||||
|
InterpolationPath.Clear();
|
||||||
for (unsigned int i = 0; i < PastViewers.Size(); ++i)
|
for (unsigned int i = 0; i < PastViewers.Size(); ++i)
|
||||||
{
|
{
|
||||||
if (PastViewers[i].ViewActor == actor)
|
if (PastViewers[i].ViewActor == actor)
|
||||||
|
@ -781,6 +844,7 @@ void R_RebuildViewInterpolation(player_t *player)
|
||||||
iview->oviewz = iview->nviewz;
|
iview->oviewz = iview->nviewz;
|
||||||
iview->oviewpitch = iview->nviewpitch;
|
iview->oviewpitch = iview->nviewpitch;
|
||||||
iview->oviewangle = iview->nviewangle;
|
iview->oviewangle = iview->nviewangle;
|
||||||
|
InterpolationPath.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
@ -794,6 +858,29 @@ bool R_GetViewInterpolationStatus()
|
||||||
return NoInterpolateView;
|
return NoInterpolateView;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// R_ClearInterpolationPath
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
void R_ClearInterpolationPath()
|
||||||
|
{
|
||||||
|
InterpolationPath.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// R_AddInterpolationPoint
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
void R_AddInterpolationPoint(const fixedvec3 &vec)
|
||||||
|
{
|
||||||
|
InterpolationPath.Push(vec);
|
||||||
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
// QuakePower
|
// QuakePower
|
||||||
|
|
|
@ -68,6 +68,8 @@ fixed_t R_PointToDist2 (fixed_t dx, fixed_t dy);
|
||||||
void R_ResetViewInterpolation ();
|
void R_ResetViewInterpolation ();
|
||||||
void R_RebuildViewInterpolation(player_t *player);
|
void R_RebuildViewInterpolation(player_t *player);
|
||||||
bool R_GetViewInterpolationStatus();
|
bool R_GetViewInterpolationStatus();
|
||||||
|
void R_ClearInterpolationPath();
|
||||||
|
void R_AddInterpolationPoint(const fixedvec3 &vec);
|
||||||
void R_SetViewSize (int blocks);
|
void R_SetViewSize (int blocks);
|
||||||
void R_SetFOV (float fov);
|
void R_SetFOV (float fov);
|
||||||
float R_GetFOV ();
|
float R_GetFOV ();
|
||||||
|
|
Loading…
Reference in a new issue