mirror of
https://github.com/ZDoom/gzdoom.git
synced 2025-02-16 17:21:10 +00:00
Reworked view offsetting
View offsets are now added after the base position and angles (accounting for interpolation) are calculated. Behavior was centralized into a singular tracer that all view offsets now use to prevent clipping out of the map. Cleaned up camera rendering behavior. Angles are now properly normalized after all offsetting is accounted for. The chase cam can now update in real-time instead of forcing interpolation.
This commit is contained in:
parent
08a093ffda
commit
b469770ecc
7 changed files with 366 additions and 489 deletions
|
@ -125,11 +125,11 @@ enum
|
|||
|
||||
struct FQuakeJiggers
|
||||
{
|
||||
DVector3 Intensity;
|
||||
DVector3 RelIntensity;
|
||||
DVector3 Offset;
|
||||
DVector3 RelOffset;
|
||||
double RollIntensity, RollWave;
|
||||
DVector3 Intensity = {};
|
||||
DVector3 RelIntensity = {};
|
||||
DVector3 Offset = {};
|
||||
DVector3 RelOffset = {};
|
||||
double RollIntensity = 0.0, RollWave = 0.0;
|
||||
};
|
||||
|
||||
class DEarthquake : public DThinker
|
||||
|
|
|
@ -770,7 +770,7 @@ public:
|
|||
Flags = f;
|
||||
}
|
||||
|
||||
bool isZero()
|
||||
bool isZero() const
|
||||
{
|
||||
return Offset.isZero();
|
||||
}
|
||||
|
|
|
@ -393,11 +393,8 @@ bool P_CheckMissileSpawn(AActor *missile, double maxdist);
|
|||
|
||||
void P_PlaySpawnSound(AActor *missile, AActor *spawner);
|
||||
|
||||
// [RH] Position the chasecam
|
||||
void P_AimCamera (AActor *t1, DVector3 &, DAngle &, sector_t *&sec, bool &unlinked);
|
||||
|
||||
// [MC] Aiming for ViewPos
|
||||
void P_AdjustViewPos(AActor *t1, DVector3 orig, DVector3 &, sector_t *&sec, bool &unlinked, FRenderViewpoint *view);
|
||||
// [RH] Position the cam's view offsets.
|
||||
void R_OffsetView(FRenderViewpoint& viewPoint, const DVector3& dir, const double distance);
|
||||
|
||||
|
||||
// [RH] Means of death
|
||||
|
|
|
@ -5573,77 +5573,39 @@ void P_RailAttack(FRailParams *p)
|
|||
CVAR(Float, chase_height, -8.f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
CVAR(Float, chase_dist, 90.f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
|
||||
void P_AimCamera(AActor *t1, DVector3 &campos, DAngle &camangle, sector_t *&CameraSector, bool &unlinked)
|
||||
void R_OffsetView(FRenderViewpoint& viewPoint, const DVector3& dir, const double distance)
|
||||
{
|
||||
double distance = clamp<double>(chase_dist, 0, 30000);
|
||||
DAngle angle = t1->Angles.Yaw - DAngle::fromDeg(180);
|
||||
DAngle pitch = t1->Angles.Pitch;
|
||||
FTraceResults trace;
|
||||
DVector3 vvec;
|
||||
double sz;
|
||||
|
||||
double pc = pitch.Cos();
|
||||
|
||||
vvec = { pc * angle.Cos(), pc * angle.Sin(), pitch.Sin() };
|
||||
sz = t1->Top() - t1->Floorclip + clamp<double>(chase_height, -1000, 1000);
|
||||
|
||||
if (Trace(t1->PosAtZ(sz), t1->Sector, vvec, distance, 0, 0, NULL, trace) &&
|
||||
trace.Distance > 10)
|
||||
const DAngle baseYaw = dir.Angle();
|
||||
FTraceResults trace = {};
|
||||
if (Trace(viewPoint.Pos, viewPoint.sector, dir, distance, 0u, 0u, nullptr, trace))
|
||||
{
|
||||
// Position camera slightly in front of hit thing
|
||||
campos = t1->PosAtZ(sz) + vvec *(trace.Distance - 5);
|
||||
viewPoint.Pos = trace.HitPos - trace.HitVector * min<double>(5.0, trace.Distance);
|
||||
viewPoint.sector = viewPoint.ViewLevel->PointInRenderSubsector(viewPoint.Pos)->sector;
|
||||
}
|
||||
else
|
||||
{
|
||||
campos = trace.HitPos - trace.HitVector * 1/256.;
|
||||
viewPoint.Pos = trace.HitPos;
|
||||
viewPoint.sector = trace.Sector;
|
||||
}
|
||||
CameraSector = trace.Sector;
|
||||
unlinked = trace.unlinked;
|
||||
camangle = trace.SrcAngleFromTarget - DAngle::fromDeg(180.);
|
||||
}
|
||||
|
||||
struct ViewPosPortal
|
||||
{
|
||||
int counter;
|
||||
};
|
||||
|
||||
static ETraceStatus VPos_CheckPortal(FTraceResults &res, void *userdata)
|
||||
{
|
||||
//[MC] Mirror how third person works.
|
||||
ViewPosPortal *pc = (ViewPosPortal *)userdata;
|
||||
|
||||
if (res.HitType == TRACE_CrossingPortal)
|
||||
viewPoint.Angles.Yaw += deltaangle(baseYaw, trace.SrcAngleFromTarget);
|
||||
// TODO: Why does this even need to be done? Please fix tracers already.
|
||||
if (dir.Z < 0.0)
|
||||
{
|
||||
res.HitType = TRACE_HitNone; // Needed to force the trace to continue appropriately.
|
||||
pc->counter++;
|
||||
return TRACE_Skip;
|
||||
while (!viewPoint.sector->PortalBlocksMovement(sector_t::floor) && viewPoint.Pos.Z < viewPoint.sector->GetPortalPlaneZ(sector_t::floor))
|
||||
{
|
||||
viewPoint.Pos += viewPoint.sector->GetPortalDisplacement(sector_t::floor);
|
||||
viewPoint.sector = viewPoint.sector->GetPortal(sector_t::floor)->mDestination;
|
||||
}
|
||||
}
|
||||
if (res.HitType == TRACE_HitActor)
|
||||
else if (dir.Z > 0.0)
|
||||
{
|
||||
return TRACE_Skip;
|
||||
while (!viewPoint.sector->PortalBlocksMovement(sector_t::ceiling) && viewPoint.Pos.Z > viewPoint.sector->GetPortalPlaneZ(sector_t::ceiling))
|
||||
{
|
||||
viewPoint.Pos += viewPoint.sector->GetPortalDisplacement(sector_t::ceiling);
|
||||
viewPoint.sector = viewPoint.sector->GetPortal(sector_t::ceiling)->mDestination;
|
||||
}
|
||||
}
|
||||
return TRACE_Stop;
|
||||
}
|
||||
|
||||
// [MC] Used for ViewPos. Uses code borrowed from P_AimCamera.
|
||||
void P_AdjustViewPos(AActor *t1, DVector3 orig, DVector3 &campos, sector_t *&CameraSector, bool &unlinked, FRenderViewpoint *view)
|
||||
{
|
||||
FTraceResults trace;
|
||||
ViewPosPortal pc;
|
||||
pc.counter = 0;
|
||||
const DVector3 vvec = campos - orig;
|
||||
const double distance = vvec.Length();
|
||||
|
||||
// Trace handles all of the portal crossing, which is why there is no usage of Vec#Offset(Z).
|
||||
if (Trace(orig, CameraSector, vvec.Unit(), distance, 0, 0, t1, trace, TRACE_ReportPortals, VPos_CheckPortal, &pc) &&
|
||||
trace.Distance > 5)
|
||||
campos = orig + vvec.Unit() * (trace.Distance - 5);
|
||||
else
|
||||
campos = trace.HitPos - trace.HitVector * 1 / 256.;
|
||||
|
||||
|
||||
CameraSector = trace.Sector;
|
||||
unlinked = trace.unlinked;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
|
|
@ -800,7 +800,7 @@ void HWSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t
|
|||
// Some added checks if the camera actor is not supposed to be seen. It can happen that some portal setup has this actor in view in which case it may not be skipped here
|
||||
if (viewmaster == camera && !vp.showviewer)
|
||||
{
|
||||
if (vp.noviewer || (viewmaster->player && viewmaster->player->crossingPortal)) return;
|
||||
if (vp.bForceNoViewer || (viewmaster->player && viewmaster->player->crossingPortal)) return;
|
||||
DVector3 vieworigin = viewmaster->Pos();
|
||||
if (thruportal == 1) vieworigin += di->Level->Displacements.getOffset(viewmaster->Sector->PortalGroup, sector->PortalGroup);
|
||||
if (fabs(vieworigin.X - vp.ActorPos.X) < 2 && fabs(vieworigin.Y - vp.ActorPos.Y) < 2) return;
|
||||
|
|
|
@ -83,8 +83,10 @@ struct InterpolationViewer
|
|||
DRotator ViewAngles;
|
||||
};
|
||||
|
||||
AActor *ViewActor;
|
||||
int otic;
|
||||
AActor* ViewActor;
|
||||
DVector3 ViewOffset, RelativeViewOffset; // This has to be a separate field since it needs the real-time mouse angles.
|
||||
DRotator AngleOffsets;
|
||||
int prevTic;
|
||||
instance Old, New;
|
||||
};
|
||||
|
||||
|
@ -443,18 +445,18 @@ EXTERN_CVAR (Bool, cl_noprediction)
|
|||
|
||||
bool P_NoInterpolation(player_t const *player, AActor const *actor)
|
||||
{
|
||||
return player != NULL &&
|
||||
!(player->cheats & CF_INTERPVIEW) &&
|
||||
player - players == consoleplayer &&
|
||||
actor == player->mo &&
|
||||
!demoplayback &&
|
||||
!(player->cheats & (CF_TOTALLYFROZEN | CF_FROZEN)) &&
|
||||
player->playerstate == PST_LIVE &&
|
||||
player->mo->reactiontime == 0 &&
|
||||
!NoInterpolateView &&
|
||||
!paused &&
|
||||
(!netgame || !cl_noprediction) &&
|
||||
!LocalKeyboardTurner;
|
||||
return player != nullptr
|
||||
&& !(player->cheats & CF_INTERPVIEW)
|
||||
&& player - players == consoleplayer
|
||||
&& actor == player->mo
|
||||
&& !demoplayback
|
||||
&& !(player->cheats & (CF_TOTALLYFROZEN | CF_FROZEN))
|
||||
&& player->playerstate == PST_LIVE
|
||||
&& player->mo->reactiontime == 0
|
||||
&& !NoInterpolateView
|
||||
&& !paused
|
||||
&& (!netgame || !cl_noprediction)
|
||||
&& !LocalKeyboardTurner;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -463,146 +465,178 @@ bool P_NoInterpolation(player_t const *player, AActor const *actor)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
void R_InterpolateView (FRenderViewpoint &viewpoint, player_t *player, double Frac, InterpolationViewer *iview)
|
||||
void R_InterpolateView(FRenderViewpoint& viewPoint, const player_t* const player, const double ticFrac, InterpolationViewer* const iView)
|
||||
{
|
||||
if (NoInterpolateView)
|
||||
{
|
||||
InterpolationPath.Clear();
|
||||
NoInterpolateView = false;
|
||||
iview->Old = iview->New;
|
||||
iView->Old = iView->New;
|
||||
}
|
||||
auto Level = viewpoint.ViewLevel;
|
||||
int oldgroup = Level->PointInRenderSubsector(iview->Old.Pos)->sector->PortalGroup;
|
||||
int newgroup = Level->PointInRenderSubsector(iview->New.Pos)->sector->PortalGroup;
|
||||
|
||||
DAngle oviewangle = iview->Old.Angles.Yaw;
|
||||
DAngle nviewangle = iview->New.Angles.Yaw;
|
||||
const double inverseTicFrac = 1.0 - ticFrac;
|
||||
const auto viewLvl = viewPoint.ViewLevel;
|
||||
|
||||
DAngle prevYaw = iView->Old.Angles.Yaw;
|
||||
DAngle curYaw = iView->New.Angles.Yaw;
|
||||
if (!cl_capfps)
|
||||
{
|
||||
if ((iview->Old.Pos.X != iview->New.Pos.X || iview->Old.Pos.Y != iview->New.Pos.Y) && InterpolationPath.Size() > 0)
|
||||
if ((iView->Old.Pos.X != iView->New.Pos.X || iView->Old.Pos.Y != iView->New.Pos.Y) && InterpolationPath.Size() > 0)
|
||||
{
|
||||
DVector3 view = iview->New.Pos;
|
||||
|
||||
// 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 or viewpos.
|
||||
if (!viewpoint.showviewer && !viewpoint.NoPortalPath)
|
||||
double totalPathLength = 0.0;
|
||||
double totalZDiff = 0.0;
|
||||
DAngle totalYawDiff = nullAngle;
|
||||
DVector3a oldPos = { { iView->Old.Pos.X, iView->Old.Pos.Y, 0.0 }, nullAngle };
|
||||
DVector3a newPos = { { iView->New.Pos.X, iView->New.Pos.Y, 0.0 }, nullAngle };
|
||||
InterpolationPath.Push(newPos); // Add this to the array to simplify the loops below.
|
||||
|
||||
for (size_t i = 0u; i < InterpolationPath.Size(); i += 2u)
|
||||
{
|
||||
double pathlen = 0;
|
||||
double zdiff = 0;
|
||||
double totalzdiff = 0;
|
||||
DAngle adiff = nullAngle;
|
||||
DAngle totaladiff = nullAngle;
|
||||
double oviewz = iview->Old.Pos.Z;
|
||||
double nviewz = iview->New.Pos.Z;
|
||||
DVector3a oldpos = { { iview->Old.Pos.X, iview->Old.Pos.Y, 0 }, nullAngle };
|
||||
DVector3a newpos = { { iview->New.Pos.X, iview->New.Pos.Y, 0 }, nullAngle };
|
||||
InterpolationPath.Push(newpos); // add this to the array to simplify the loops below
|
||||
|
||||
for (unsigned i = 0; i < InterpolationPath.Size(); i += 2)
|
||||
{
|
||||
DVector3a &start = i == 0 ? oldpos : InterpolationPath[i - 1];
|
||||
DVector3a &end = InterpolationPath[i];
|
||||
pathlen += (end.pos - start.pos).Length();
|
||||
totalzdiff += start.pos.Z;
|
||||
totaladiff += start.angle;
|
||||
}
|
||||
double interpolatedlen = Frac * pathlen;
|
||||
|
||||
for (unsigned i = 0; i < InterpolationPath.Size(); i += 2)
|
||||
{
|
||||
DVector3a &start = i == 0 ? oldpos : InterpolationPath[i - 1];
|
||||
DVector3a &end = InterpolationPath[i];
|
||||
double fraglen = (end.pos - start.pos).Length();
|
||||
zdiff += start.pos.Z;
|
||||
adiff += start.angle;
|
||||
if (fraglen <= interpolatedlen)
|
||||
{
|
||||
interpolatedlen -= fraglen;
|
||||
}
|
||||
else
|
||||
{
|
||||
double fragfrac = interpolatedlen / fraglen;
|
||||
oviewz += zdiff;
|
||||
nviewz -= totalzdiff - zdiff;
|
||||
oviewangle += adiff;
|
||||
nviewangle -= totaladiff - adiff;
|
||||
DVector2 viewpos = start.pos.XY() + (fragfrac * (end.pos - start.pos).XY());
|
||||
viewpoint.Pos = { viewpos, oviewz + Frac * (nviewz - oviewz) };
|
||||
break;
|
||||
}
|
||||
}
|
||||
InterpolationPath.Pop();
|
||||
viewpoint.Path[0] = iview->Old.Pos;
|
||||
viewpoint.Path[1] = viewpoint.Path[0] + (InterpolationPath[0].pos - viewpoint.Path[0]).XY().MakeResize(pathlen);
|
||||
const DVector3a& start = !i ? oldPos : InterpolationPath[i - 1u];
|
||||
const DVector3a& end = InterpolationPath[i];
|
||||
totalPathLength += (end.pos - start.pos).Length();
|
||||
totalZDiff += start.pos.Z;
|
||||
totalYawDiff += start.angle;
|
||||
}
|
||||
|
||||
double interpolatedLength = totalPathLength * ticFrac;
|
||||
double zDiff = 0.0;
|
||||
DAngle yawDiff = nullAngle;
|
||||
double prevViewZ = iView->Old.Pos.Z;
|
||||
double curViewZ = iView->New.Pos.Z;
|
||||
for (size_t i = 0u; i < InterpolationPath.Size(); i += 2u)
|
||||
{
|
||||
const DVector3a& start = !i ? oldPos : InterpolationPath[i - 1u];
|
||||
const DVector3a& end = InterpolationPath[i];
|
||||
const double fragmentLength = (end.pos - start.pos).Length();
|
||||
zDiff += start.pos.Z;
|
||||
yawDiff += start.angle;
|
||||
|
||||
if (fragmentLength <= interpolatedLength)
|
||||
{
|
||||
interpolatedLength -= fragmentLength;
|
||||
}
|
||||
else
|
||||
{
|
||||
prevViewZ += zDiff;
|
||||
curViewZ -= totalZDiff - zDiff;
|
||||
prevYaw += yawDiff;
|
||||
curYaw -= totalYawDiff - yawDiff;
|
||||
|
||||
const DVector2 viewPos = start.pos.XY() + ((interpolatedLength / fragmentLength) * (end.pos - start.pos).XY());
|
||||
viewPoint.Pos = { viewPos, prevViewZ * inverseTicFrac + curViewZ * ticFrac };
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
InterpolationPath.Pop();
|
||||
viewPoint.Path[0] = iView->Old.Pos;
|
||||
viewPoint.Path[1] = viewPoint.Path[0] + (InterpolationPath[0].pos - viewPoint.Path[0]).XY().MakeResize(totalPathLength);
|
||||
}
|
||||
else
|
||||
{
|
||||
DVector2 disp = viewpoint.ViewLevel->Displacements.getOffset(oldgroup, newgroup);
|
||||
viewpoint.Pos = iview->Old.Pos + (iview->New.Pos - iview->Old.Pos - disp) * Frac;
|
||||
viewpoint.Path[0] = viewpoint.Path[1] = iview->New.Pos;
|
||||
const int prevPortalGroup = viewLvl->PointInRenderSubsector(iView->Old.Pos)->sector->PortalGroup;
|
||||
const int curPortalGroup = viewLvl->PointInRenderSubsector(iView->New.Pos)->sector->PortalGroup;
|
||||
|
||||
const DVector2 portalOffset = viewLvl->Displacements.getOffset(prevPortalGroup, curPortalGroup);
|
||||
viewPoint.Pos = iView->Old.Pos * inverseTicFrac + (iView->New.Pos - portalOffset) * ticFrac;
|
||||
viewPoint.Path[0] = viewPoint.Path[1] = iView->New.Pos;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
viewpoint.Pos = iview->New.Pos;
|
||||
viewpoint.Path[0] = viewpoint.Path[1] = iview->New.Pos;
|
||||
}
|
||||
if (P_NoInterpolation(player, viewpoint.camera) &&
|
||||
// TODO: This is only temporarily disabled until R_SetupFrame can be reworked to take up-to-date angles into account.
|
||||
!(player->cheats & CF_CHASECAM) && (!r_deathcamera || viewpoint.camera->health > 0) &&
|
||||
iview->New.Pos.X == viewpoint.ActorPos.X &&
|
||||
iview->New.Pos.Y == viewpoint.ActorPos.Y)
|
||||
{
|
||||
viewpoint.Angles.Yaw = (nviewangle + DAngle::fromBam(LocalViewAngle)).Normalized180();
|
||||
DAngle delta = player->centering ? nullAngle : DAngle::fromBam(LocalViewPitch);
|
||||
viewpoint.Angles.Pitch = clamp<DAngle>((iview->New.Angles.Pitch - delta).Normalized180(), player->MinPitch, player->MaxPitch);
|
||||
viewpoint.Angles.Roll = iview->New.Angles.Roll.Normalized180();
|
||||
}
|
||||
else
|
||||
{
|
||||
viewpoint.Angles.Pitch = (iview->Old.Angles.Pitch + deltaangle(iview->Old.Angles.Pitch, iview->New.Angles.Pitch) * Frac).Normalized180();
|
||||
viewpoint.Angles.Yaw = (oviewangle + deltaangle(oviewangle, nviewangle) * Frac).Normalized180();
|
||||
viewpoint.Angles.Roll = (iview->Old.Angles.Roll + deltaangle(iview->Old.Angles.Roll, iview->New.Angles.Roll) * Frac).Normalized180();
|
||||
}
|
||||
|
||||
// [MR] Apply the view angles as an offset if ABSVIEWANGLES isn't specified.
|
||||
if (!(viewpoint.camera->flags8 & MF8_ABSVIEWANGLES))
|
||||
{
|
||||
viewpoint.Angles += (!player || (player->cheats & CF_INTERPVIEWANGLES)) ? interpolatedvalue(iview->Old.ViewAngles, iview->New.ViewAngles, Frac) : iview->New.ViewAngles;
|
||||
viewPoint.Pos = iView->New.Pos;
|
||||
viewPoint.Path[0] = viewPoint.Path[1] = iView->New.Pos;
|
||||
}
|
||||
|
||||
// Due to interpolation this is not necessarily the same as the sector the camera is in.
|
||||
viewpoint.sector = Level->PointInRenderSubsector(viewpoint.Pos)->sector;
|
||||
viewPoint.sector = viewLvl->PointInRenderSubsector(viewPoint.Pos)->sector;
|
||||
bool moved = false;
|
||||
while (!viewpoint.sector->PortalBlocksMovement(sector_t::ceiling))
|
||||
while (!viewPoint.sector->PortalBlocksMovement(sector_t::ceiling))
|
||||
{
|
||||
if (viewpoint.Pos.Z > viewpoint.sector->GetPortalPlaneZ(sector_t::ceiling))
|
||||
if (viewPoint.Pos.Z > viewPoint.sector->GetPortalPlaneZ(sector_t::ceiling))
|
||||
{
|
||||
viewpoint.Pos += viewpoint.sector->GetPortalDisplacement(sector_t::ceiling);
|
||||
viewpoint.ActorPos += viewpoint.sector->GetPortalDisplacement(sector_t::ceiling);
|
||||
viewpoint.sector = Level->PointInRenderSubsector(viewpoint.Pos)->sector;
|
||||
const DVector2 offset = viewPoint.sector->GetPortalDisplacement(sector_t::ceiling);
|
||||
viewPoint.Pos += offset;
|
||||
viewPoint.ActorPos += offset;
|
||||
viewPoint.sector = viewPoint.sector->GetPortal(sector_t::ceiling)->mDestination;
|
||||
moved = true;
|
||||
}
|
||||
else break;
|
||||
}
|
||||
if (!moved)
|
||||
{
|
||||
while (!viewpoint.sector->PortalBlocksMovement(sector_t::floor))
|
||||
else
|
||||
{
|
||||
if (viewpoint.Pos.Z < viewpoint.sector->GetPortalPlaneZ(sector_t::floor))
|
||||
{
|
||||
viewpoint.Pos += viewpoint.sector->GetPortalDisplacement(sector_t::floor);
|
||||
viewpoint.ActorPos += viewpoint.sector->GetPortalDisplacement(sector_t::floor);
|
||||
viewpoint.sector = Level->PointInRenderSubsector(viewpoint.Pos)->sector;
|
||||
moved = true;
|
||||
}
|
||||
else break;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (moved) viewpoint.noviewer = true;
|
||||
|
||||
if (!moved)
|
||||
{
|
||||
while (!viewPoint.sector->PortalBlocksMovement(sector_t::floor))
|
||||
{
|
||||
if (viewPoint.Pos.Z < viewPoint.sector->GetPortalPlaneZ(sector_t::floor))
|
||||
{
|
||||
const DVector2 offset = viewPoint.sector->GetPortalDisplacement(sector_t::floor);
|
||||
viewPoint.Pos += offset;
|
||||
viewPoint.ActorPos += offset;
|
||||
viewPoint.sector = viewPoint.sector->GetPortal(sector_t::floor)->mDestination;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (P_NoInterpolation(player, viewPoint.camera))
|
||||
{
|
||||
viewPoint.Angles.Yaw = curYaw + DAngle::fromBam(LocalViewAngle);
|
||||
const DAngle delta = player->centering ? nullAngle : DAngle::fromBam(LocalViewPitch);
|
||||
viewPoint.Angles.Pitch = clamp<DAngle>((iView->New.Angles.Pitch - delta).Normalized180(), player->MinPitch, player->MaxPitch);
|
||||
viewPoint.Angles.Roll = iView->New.Angles.Roll;
|
||||
}
|
||||
else
|
||||
{
|
||||
viewPoint.Angles.Pitch = iView->Old.Angles.Pitch * inverseTicFrac + iView->New.Angles.Pitch * ticFrac;
|
||||
viewPoint.Angles.Yaw = prevYaw * inverseTicFrac + curYaw * ticFrac;
|
||||
viewPoint.Angles.Roll = iView->Old.Angles.Roll * inverseTicFrac + iView->New.Angles.Roll * ticFrac;
|
||||
}
|
||||
|
||||
// Now that the base position and angles are set, add offsets.
|
||||
|
||||
DVector3 posOfs = iView->ViewOffset;
|
||||
if (!iView->RelativeViewOffset.isZero())
|
||||
posOfs += DQuaternion::FromAngles(viewPoint.Angles.Yaw, viewPoint.Angles.Pitch, viewPoint.Angles.Roll) * iView->RelativeViewOffset;
|
||||
|
||||
// Now that we have the current interpolated position, offset from that directly (for view offset + chase cam).
|
||||
if (!posOfs.isZero())
|
||||
{
|
||||
const double distance = posOfs.Length();
|
||||
posOfs /= distance;
|
||||
R_OffsetView(viewPoint, posOfs, distance);
|
||||
}
|
||||
|
||||
viewPoint.Angles += iView->AngleOffsets;
|
||||
|
||||
// [MR] Apply the view angles as an offset if ABSVIEWANGLES isn't specified.
|
||||
if (!(viewPoint.camera->flags8 & MF8_ABSVIEWANGLES))
|
||||
{
|
||||
if (player == nullptr || (player->cheats & CF_INTERPVIEWANGLES))
|
||||
{
|
||||
viewPoint.Angles.Yaw += iView->Old.ViewAngles.Yaw * inverseTicFrac + iView->New.ViewAngles.Yaw * ticFrac;
|
||||
viewPoint.Angles.Pitch += iView->Old.ViewAngles.Pitch * inverseTicFrac + iView->New.ViewAngles.Pitch * ticFrac;
|
||||
viewPoint.Angles.Roll += iView->Old.ViewAngles.Roll * inverseTicFrac + iView->New.ViewAngles.Roll * ticFrac;
|
||||
}
|
||||
else
|
||||
{
|
||||
viewPoint.Angles += iView->New.ViewAngles;
|
||||
}
|
||||
}
|
||||
|
||||
viewPoint.Angles.Yaw = viewPoint.Angles.Yaw.Normalized180();
|
||||
viewPoint.Angles.Pitch = viewPoint.Angles.Pitch.Normalized180();
|
||||
viewPoint.Angles.Roll = viewPoint.Angles.Roll.Normalized180();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -619,24 +653,23 @@ void R_ResetViewInterpolation ()
|
|||
|
||||
//==========================================================================
|
||||
//
|
||||
// R_SetViewAngle
|
||||
// sets all values derived from the view angle.
|
||||
// R_SetViewAngle
|
||||
// sets all values derived from the view yaw.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FRenderViewpoint::SetViewAngle (const FViewWindow &viewwindow)
|
||||
void FRenderViewpoint::SetViewAngle(const FViewWindow& viewWindow)
|
||||
{
|
||||
Sin = Angles.Yaw.Sin();
|
||||
Cos = Angles.Yaw.Cos();
|
||||
|
||||
TanSin = viewwindow.FocalTangent * Sin;
|
||||
TanCos = viewwindow.FocalTangent * Cos;
|
||||
TanSin = viewWindow.FocalTangent * Sin;
|
||||
TanCos = viewWindow.FocalTangent * Cos;
|
||||
|
||||
DVector2 v = Angles.Yaw.ToVector();
|
||||
const DVector2 v = Angles.Yaw.ToVector();
|
||||
ViewVector.X = v.X;
|
||||
ViewVector.Y = v.Y;
|
||||
HWAngles.Yaw = FAngle::fromDeg(270.0 - Angles.Yaw.Degrees());
|
||||
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -659,7 +692,7 @@ static InterpolationViewer *FindPastViewer (AActor *actor)
|
|||
InterpolationViewer iview;
|
||||
memset(&iview, 0, sizeof(iview));
|
||||
iview.ViewActor = actor;
|
||||
iview.otic = -1;
|
||||
iview.prevTic = -1;
|
||||
InterpolationPath.Clear();
|
||||
return &PastViewers[PastViewers.Push (iview)];
|
||||
}
|
||||
|
@ -800,368 +833,263 @@ static void R_DoActorTickerAngleChanges(player_t* const player, DRotator& angles
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
void R_SetupFrame (FRenderViewpoint &viewpoint, FViewWindow &viewwindow, AActor *actor)
|
||||
EXTERN_CVAR(Float, chase_dist)
|
||||
EXTERN_CVAR(Float, chase_height)
|
||||
|
||||
void R_SetupFrame(FRenderViewpoint& viewPoint, const FViewWindow& viewWindow, AActor* const actor)
|
||||
{
|
||||
if (actor == NULL)
|
||||
viewPoint.TicFrac = I_GetTimeFrac();
|
||||
if (cl_capfps || r_NoInterpolate)
|
||||
viewPoint.TicFrac = 1.0;
|
||||
|
||||
const int curTic = I_GetTime();
|
||||
|
||||
if (actor == nullptr)
|
||||
I_Error("Tried to render from a null actor.");
|
||||
|
||||
viewPoint.ViewLevel = actor->Level;
|
||||
|
||||
player_t* player = actor->player;
|
||||
if (player != nullptr && player->mo == actor)
|
||||
{
|
||||
I_Error ("Tried to render from a NULL actor.");
|
||||
}
|
||||
viewpoint.ViewLevel = actor->Level;
|
||||
if (player->camera == nullptr)
|
||||
player->camera = player->mo;
|
||||
|
||||
player_t *player = actor->player;
|
||||
unsigned int newblend;
|
||||
InterpolationViewer *iview;
|
||||
bool unlinked = false;
|
||||
|
||||
if (player != NULL && player->mo == actor)
|
||||
{ // [RH] Use camera instead of viewplayer
|
||||
viewpoint.camera = player->camera;
|
||||
if (viewpoint.camera == NULL)
|
||||
{
|
||||
viewpoint.camera = player->camera = player->mo;
|
||||
}
|
||||
viewPoint.camera = player->camera; // [RH] Use camera instead of view player.
|
||||
}
|
||||
else
|
||||
{
|
||||
viewpoint.camera = actor;
|
||||
viewPoint.camera = actor;
|
||||
}
|
||||
|
||||
if (viewpoint.camera == NULL)
|
||||
{
|
||||
I_Error ("You lost your body. Bad dehacked work is likely to blame.");
|
||||
}
|
||||
if (viewPoint.camera == nullptr)
|
||||
I_Error("You lost your body. Bad dehacked work is likely to blame.");
|
||||
|
||||
iview = FindPastViewer (viewpoint.camera);
|
||||
|
||||
int nowtic = I_GetTime ();
|
||||
if (iview->otic != -1 && nowtic > iview->otic)
|
||||
InterpolationViewer* const iView = FindPastViewer(viewPoint.camera);
|
||||
// Always reset these back to zero.
|
||||
iView->ViewOffset.Zero();
|
||||
iView->RelativeViewOffset.Zero();
|
||||
iView->AngleOffsets.Zero();
|
||||
if (iView->prevTic != -1 && curTic > iView->prevTic)
|
||||
{
|
||||
iview->otic = nowtic;
|
||||
iview->Old = iview->New;
|
||||
iView->prevTic = curTic;
|
||||
iView->Old = iView->New;
|
||||
}
|
||||
|
||||
const auto& mainView = r_viewpoint;
|
||||
AActor* const client = players[consoleplayer].mo;
|
||||
const bool matchPlayer = gamestate != GS_TITLELEVEL && viewpoint.camera->player == nullptr && (viewpoint.camera->renderflags2 & RF2_CAMFOLLOWSPLAYER);
|
||||
const bool matchPlayer = gamestate != GS_TITLELEVEL && viewPoint.camera->player == nullptr && (viewPoint.camera->renderflags2 & RF2_CAMFOLLOWSPLAYER);
|
||||
const bool usePawn = matchPlayer ? mainView.camera != client : false;
|
||||
//==============================================================================================
|
||||
// Handles offsetting the camera with ChaseCam and/or viewpos.
|
||||
// Sets up the view position offset.
|
||||
{
|
||||
AActor *mo = viewpoint.camera;
|
||||
DViewPosition *VP = mo->ViewPos;
|
||||
DVector3 orig;
|
||||
AActor* const mo = viewPoint.camera;
|
||||
const DViewPosition* const viewOffset = mo->ViewPos;
|
||||
DVector3 camPos;
|
||||
if (matchPlayer)
|
||||
{
|
||||
if (usePawn)
|
||||
{
|
||||
orig = DVector3(client->Pos().XY(), client->player->viewz);
|
||||
camPos = DVector3(client->Pos().XY(), client->player->viewz);
|
||||
const DViewPosition* const pawnVP = client->ViewPos;
|
||||
if (pawnVP != nullptr)
|
||||
{
|
||||
// Avoid portal checking for now until the need for more accuracy arises.
|
||||
// Add these directly to the view position offset (not 100% accurate but close enough).
|
||||
if (pawnVP->Flags & VPSF_ABSOLUTEPOS)
|
||||
orig = pawnVP->Offset;
|
||||
camPos = pawnVP->Offset;
|
||||
else if (pawnVP->Flags & VPSF_ABSOLUTEOFFSET)
|
||||
orig += pawnVP->Offset;
|
||||
iView->ViewOffset = pawnVP->Offset;
|
||||
else
|
||||
orig += DQuaternion::FromAngles(client->Angles.Yaw, client->Angles.Pitch, client->Angles.Roll) * pawnVP->Offset;
|
||||
iView->ViewOffset = DQuaternion::FromAngles(client->Angles.Yaw, client->Angles.Pitch, client->Angles.Roll) * pawnVP->Offset;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
orig = mainView.Pos;
|
||||
camPos = mainView.Pos;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
orig = { mo->Pos().XY(), mo->player ? mo->player->viewz : mo->Z() + mo->GetCameraHeight() };
|
||||
camPos = { mo->Pos().XY(), mo->player != nullptr ? mo->player->viewz : mo->Z() + mo->GetCameraHeight() };
|
||||
}
|
||||
|
||||
viewpoint.ActorPos = orig;
|
||||
viewPoint.showviewer = false;
|
||||
viewPoint.bForceNoViewer = matchPlayer;
|
||||
|
||||
bool DefaultDraw = true;
|
||||
|
||||
sector_t *oldsector = viewpoint.ViewLevel->PointInRenderSubsector(iview->Old.Pos)->sector;
|
||||
if (gamestate != GS_TITLELEVEL &&
|
||||
((player && (player->cheats & CF_CHASECAM)) || (r_deathcamera && viewpoint.camera->health <= 0)))
|
||||
((player != nullptr && (player->cheats & CF_CHASECAM)) || (r_deathcamera && (viewPoint.camera->flags6 & MF6_KILLED))))
|
||||
{
|
||||
// [RH] Use chasecam view
|
||||
DefaultDraw = false;
|
||||
DVector3 campos;
|
||||
DAngle camangle;
|
||||
P_AimCamera(viewpoint.camera, campos, camangle, viewpoint.sector, unlinked); // fixme: This needs to translate the angle, too.
|
||||
iview->New.Pos = campos;
|
||||
iview->New.Angles.Yaw = camangle;
|
||||
|
||||
viewpoint.showviewer = true;
|
||||
// Interpolating this is a very complicated thing because nothing keeps track of the aim camera's movement, so whenever we detect a portal transition
|
||||
// it's probably best to just reset the interpolation for this move.
|
||||
// Note that this can still cause problems with unusually linked portals
|
||||
if (viewpoint.sector->PortalGroup != oldsector->PortalGroup || (unlinked && ((iview->New.Pos.XY() - iview->Old.Pos.XY()).LengthSquared()) > 256 * 256))
|
||||
viewpoint.camera->renderflags |= RF_NOINTERPOLATEVIEW;
|
||||
|
||||
viewpoint.ActorPos = campos;
|
||||
// The cam Actor should probably be visible in third person.
|
||||
viewPoint.showviewer = true;
|
||||
camPos.Z = mo->Top() - mo->Floorclip;
|
||||
iView->ViewOffset.Z = clamp<double>(chase_height, -1000.0, 1000.0);
|
||||
iView->RelativeViewOffset.X = -clamp<double>(chase_dist, 0.0, 30000.0);
|
||||
}
|
||||
else if (VP) // No chase/death cam and player is alive, wants viewpos.
|
||||
else if (viewOffset != nullptr)
|
||||
{
|
||||
viewpoint.showviewer = false;
|
||||
|
||||
// [MC] Ignores all portal portal transitions since it's meant to be absolute.
|
||||
// Modders must handle performing offsetting with the appropriate functions to get it to work.
|
||||
// Hint: Check P_AdjustViewPos.
|
||||
if (VP->Flags & VPSF_ABSOLUTEPOS)
|
||||
// No chase/death cam, so use the view offset.
|
||||
if (!viewPoint.bForceNoViewer)
|
||||
viewPoint.bForceNoViewer = (viewOffset->Flags & VPSF_ABSOLUTEPOS) || !viewOffset->Offset.isZero();
|
||||
|
||||
if (viewOffset->Flags & VPSF_ABSOLUTEPOS)
|
||||
{
|
||||
iview->New.Pos = VP->Offset;
|
||||
DefaultDraw = false;
|
||||
viewpoint.sector = viewpoint.ViewLevel->PointInRenderSubsector(iview->New.Pos.XY())->sector;
|
||||
viewpoint.showviewer = viewpoint.NoPortalPath = false;
|
||||
viewpoint.noviewer = true;
|
||||
if (!matchPlayer)
|
||||
camPos = viewOffset->Offset;
|
||||
}
|
||||
else if (viewOffset->Flags & VPSF_ABSOLUTEOFFSET)
|
||||
{
|
||||
iView->ViewOffset += viewOffset->Offset;
|
||||
}
|
||||
else
|
||||
{
|
||||
viewpoint.sector = viewpoint.ViewLevel->PointInRenderSubsector(iview->New.Pos.XY())->sector;
|
||||
DVector3 next = orig;
|
||||
|
||||
if (VP->isZero())
|
||||
{
|
||||
// Since viewpos isn't being used, it's safe to enable path interpolation
|
||||
viewpoint.NoPortalPath = false;
|
||||
}
|
||||
else if (VP->Flags & VPSF_ABSOLUTEOFFSET)
|
||||
{
|
||||
// No relativity added from angles.
|
||||
next += VP->Offset;
|
||||
}
|
||||
else
|
||||
{
|
||||
// [MC] Do NOT handle portals here! Trace must have the unportaled (absolute) position to
|
||||
// get the correct angle and distance. Trace automatically handles portals by itself.
|
||||
// Note: viewpos does not include view angles, and ViewZ/CameraHeight are applied before this.
|
||||
next += DQuaternion::FromAngles(mo->Angles.Yaw, mo->Angles.Pitch, mo->Angles.Roll) * VP->Offset;
|
||||
}
|
||||
|
||||
if (next != orig)
|
||||
{
|
||||
// [MC] Disable interpolation if the camera view is crossing through a portal. Sometimes
|
||||
// the player is made visible when crossing a portal and it's extremely jarring.
|
||||
// Also, disable the portal interpolation pathing entirely when using the viewpos feature.
|
||||
// Interpolation still happens with everything else though and seems to work fine.
|
||||
DefaultDraw = false;
|
||||
viewpoint.noviewer = true;
|
||||
viewpoint.NoPortalPath = true;
|
||||
P_AdjustViewPos(mo, orig, next, viewpoint.sector, unlinked, &viewpoint);
|
||||
iview->New.Pos = next;
|
||||
|
||||
if (viewpoint.sector->PortalGroup != oldsector->PortalGroup || (unlinked && ((iview->New.Pos.XY() - iview->Old.Pos.XY()).LengthSquared()) > 256 * 256))
|
||||
viewpoint.camera->renderflags |= RF_NOINTERPOLATEVIEW;
|
||||
}
|
||||
iView->RelativeViewOffset = viewOffset->Offset;
|
||||
}
|
||||
|
||||
viewpoint.ActorPos = iview->New.Pos;
|
||||
}
|
||||
|
||||
if (DefaultDraw)
|
||||
{
|
||||
iview->New.Pos = orig;
|
||||
viewpoint.sector = viewpoint.camera->Sector;
|
||||
viewpoint.showviewer = viewpoint.NoPortalPath = false;
|
||||
}
|
||||
}
|
||||
|
||||
// [MR] Apply view angles as the viewpoint angles if asked to do so.
|
||||
if (matchPlayer)
|
||||
iview->New.Angles = usePawn ? (client->flags8 & MF8_ABSVIEWANGLES ? client->ViewAngles : client->Angles + client->ViewAngles) : mainView.Angles;
|
||||
else
|
||||
iview->New.Angles = !(viewpoint.camera->flags8 & MF8_ABSVIEWANGLES) ? viewpoint.camera->Angles : viewpoint.camera->ViewAngles;
|
||||
|
||||
iview->New.ViewAngles = viewpoint.camera->ViewAngles;
|
||||
// [MR] Process player angle changes if permitted to do so.
|
||||
if (player && (player->cheats & CF_SCALEDNOLERP) && P_NoInterpolation(player, viewpoint.camera))
|
||||
R_DoActorTickerAngleChanges(player, iview->New.Angles, viewpoint.TicFrac);
|
||||
|
||||
// If currently tracking the player's real view, don't do any sort of interpolating.
|
||||
if (matchPlayer && !usePawn)
|
||||
viewpoint.camera->renderflags |= RF_NOINTERPOLATEVIEW;
|
||||
|
||||
if (viewpoint.camera->player != 0)
|
||||
{
|
||||
player = viewpoint.camera->player;
|
||||
}
|
||||
|
||||
if (iview->otic == -1 || r_NoInterpolate || (viewpoint.camera->renderflags & RF_NOINTERPOLATEVIEW))
|
||||
{
|
||||
viewpoint.camera->renderflags &= ~RF_NOINTERPOLATEVIEW;
|
||||
R_ResetViewInterpolation ();
|
||||
iview->otic = nowtic;
|
||||
}
|
||||
|
||||
viewpoint.TicFrac = I_GetTimeFrac ();
|
||||
if (cl_capfps || r_NoInterpolate)
|
||||
{
|
||||
viewpoint.TicFrac = 1.;
|
||||
}
|
||||
R_InterpolateView (viewpoint, player, viewpoint.TicFrac, iview);
|
||||
|
||||
viewpoint.SetViewAngle (viewwindow);
|
||||
|
||||
// Keep the view within the sector's floor and ceiling
|
||||
if (viewpoint.sector->PortalBlocksMovement(sector_t::ceiling))
|
||||
{
|
||||
double theZ = viewpoint.sector->ceilingplane.ZatPoint(viewpoint.Pos) - 4;
|
||||
if (viewpoint.Pos.Z > theZ)
|
||||
{
|
||||
viewpoint.Pos.Z = theZ;
|
||||
}
|
||||
}
|
||||
|
||||
if (viewpoint.sector->PortalBlocksMovement(sector_t::floor))
|
||||
{
|
||||
double theZ = viewpoint.sector->floorplane.ZatPoint(viewpoint.Pos) + 4;
|
||||
if (viewpoint.Pos.Z < theZ)
|
||||
{
|
||||
viewpoint.Pos.Z = theZ;
|
||||
}
|
||||
viewPoint.ActorPos = iView->New.Pos = camPos;
|
||||
viewPoint.sector = viewPoint.ViewLevel->PointInRenderSubsector(camPos)->sector;
|
||||
}
|
||||
|
||||
if (!paused)
|
||||
{
|
||||
FQuakeJiggers jiggers;
|
||||
|
||||
memset(&jiggers, 0, sizeof(jiggers));
|
||||
if (DEarthquake::StaticGetQuakeIntensities(viewpoint.TicFrac, viewpoint.camera, jiggers) > 0)
|
||||
if (DEarthquake::StaticGetQuakeIntensities(viewPoint.TicFrac, viewPoint.camera, jiggers) > 0)
|
||||
{
|
||||
double quakefactor = r_quakeintensity;
|
||||
DVector3 pos; pos.Zero();
|
||||
if (jiggers.RollIntensity != 0 || jiggers.RollWave != 0)
|
||||
{
|
||||
viewpoint.Angles.Roll += DAngle::fromDeg(QuakePower(quakefactor, jiggers.RollIntensity, jiggers.RollWave));
|
||||
}
|
||||
if (jiggers.RelIntensity.X != 0 || jiggers.RelOffset.X != 0)
|
||||
{
|
||||
pos.X += QuakePower(quakefactor, jiggers.RelIntensity.X, jiggers.RelOffset.X);
|
||||
}
|
||||
if (jiggers.RelIntensity.Y != 0 || jiggers.RelOffset.Y != 0)
|
||||
{
|
||||
pos.Y += QuakePower(quakefactor, jiggers.RelIntensity.Y, jiggers.RelOffset.Y);
|
||||
}
|
||||
if (jiggers.RelIntensity.Z != 0 || jiggers.RelOffset.Z != 0)
|
||||
{
|
||||
pos.Z += QuakePower(quakefactor, jiggers.RelIntensity.Z, jiggers.RelOffset.Z);
|
||||
}
|
||||
// [MC] Tremendous thanks to Marisa Kirisame for helping me with this.
|
||||
// Use a rotation matrix to make the view relative.
|
||||
if (!pos.isZero())
|
||||
{
|
||||
DAngle yaw = viewpoint.camera->Angles.Yaw;
|
||||
DAngle pitch = viewpoint.camera->Angles.Pitch;
|
||||
DAngle roll = viewpoint.camera->Angles.Roll;
|
||||
DVector3 relx, rely, relz;
|
||||
DMatrix3x3 rot =
|
||||
DMatrix3x3(DVector3(0., 0., 1.), yaw.Cos(), yaw.Sin()) *
|
||||
DMatrix3x3(DVector3(0., 1., 0.), pitch.Cos(), pitch.Sin()) *
|
||||
DMatrix3x3(DVector3(1., 0., 0.), roll.Cos(), roll.Sin());
|
||||
relx = DVector3(1., 0., 0.)*rot;
|
||||
rely = DVector3(0., 1., 0.)*rot;
|
||||
relz = DVector3(0., 0., 1.)*rot;
|
||||
viewpoint.Pos += relx * pos.X + rely * pos.Y + relz * pos.Z;
|
||||
}
|
||||
const double quakeFactor = r_quakeintensity;
|
||||
if (jiggers.RollIntensity || jiggers.RollWave)
|
||||
iView->AngleOffsets.Roll = DAngle::fromDeg(QuakePower(quakeFactor, jiggers.RollIntensity, jiggers.RollWave));
|
||||
|
||||
if (jiggers.Intensity.X != 0 || jiggers.Offset.X != 0)
|
||||
{
|
||||
viewpoint.Pos.X += QuakePower(quakefactor, jiggers.Intensity.X, jiggers.Offset.X);
|
||||
}
|
||||
if (jiggers.Intensity.Y != 0 || jiggers.Offset.Y != 0)
|
||||
{
|
||||
viewpoint.Pos.Y += QuakePower(quakefactor, jiggers.Intensity.Y, jiggers.Offset.Y);
|
||||
}
|
||||
if (jiggers.Intensity.Z != 0 || jiggers.Offset.Z != 0)
|
||||
{
|
||||
viewpoint.Pos.Z += QuakePower(quakefactor, jiggers.Intensity.Z, jiggers.Offset.Z);
|
||||
}
|
||||
if (jiggers.RelIntensity.X || jiggers.RelOffset.X)
|
||||
iView->RelativeViewOffset.X += QuakePower(quakeFactor, jiggers.RelIntensity.X, jiggers.RelOffset.X);
|
||||
if (jiggers.RelIntensity.Y || jiggers.RelOffset.Y)
|
||||
iView->RelativeViewOffset.Y += QuakePower(quakeFactor, jiggers.RelIntensity.Y, jiggers.RelOffset.Y);
|
||||
if (jiggers.RelIntensity.Z || jiggers.RelOffset.Z)
|
||||
iView->RelativeViewOffset.Z += QuakePower(quakeFactor, jiggers.RelIntensity.Z, jiggers.RelOffset.Z);
|
||||
|
||||
if (jiggers.Intensity.X || jiggers.Offset.X)
|
||||
iView->ViewOffset.X += QuakePower(quakeFactor, jiggers.Intensity.X, jiggers.Offset.X);
|
||||
if (jiggers.Intensity.Y || jiggers.Offset.Y)
|
||||
iView->ViewOffset.Y += QuakePower(quakeFactor, jiggers.Intensity.Y, jiggers.Offset.Y);
|
||||
if (jiggers.Intensity.Z || jiggers.Offset.Z)
|
||||
iView->ViewOffset.Z += QuakePower(quakeFactor, jiggers.Intensity.Z, jiggers.Offset.Z);
|
||||
}
|
||||
}
|
||||
|
||||
viewpoint.extralight = viewpoint.camera->player ? viewpoint.camera->player->extralight : 0;
|
||||
// [MR] Apply view angles as the viewpoint angles if asked to do so.
|
||||
if (matchPlayer)
|
||||
iView->New.Angles = usePawn ? (client->flags8 & MF8_ABSVIEWANGLES ? client->ViewAngles : client->Angles + client->ViewAngles) : mainView.Angles;
|
||||
else
|
||||
iView->New.Angles = !(viewPoint.camera->flags8 & MF8_ABSVIEWANGLES) ? viewPoint.camera->Angles : viewPoint.camera->ViewAngles;
|
||||
|
||||
iView->New.ViewAngles = viewPoint.camera->ViewAngles;
|
||||
// [MR] Process player angle changes if permitted to do so.
|
||||
if (player != nullptr && (player->cheats & CF_SCALEDNOLERP) && P_NoInterpolation(player, viewPoint.camera))
|
||||
R_DoActorTickerAngleChanges(player, iView->New.Angles, viewPoint.TicFrac);
|
||||
|
||||
// If currently tracking the player's real view, don't do any sort of interpolating.
|
||||
if (matchPlayer && !usePawn)
|
||||
viewPoint.camera->renderflags |= RF_NOINTERPOLATEVIEW;
|
||||
|
||||
if (viewPoint.camera->player != nullptr)
|
||||
player = viewPoint.camera->player;
|
||||
|
||||
if (iView->prevTic == -1 || r_NoInterpolate || (viewPoint.camera->renderflags & RF_NOINTERPOLATEVIEW))
|
||||
{
|
||||
viewPoint.camera->renderflags &= ~RF_NOINTERPOLATEVIEW;
|
||||
R_ResetViewInterpolation();
|
||||
iView->prevTic = curTic;
|
||||
}
|
||||
|
||||
R_InterpolateView(viewPoint, player, viewPoint.TicFrac, iView);
|
||||
|
||||
viewPoint.SetViewAngle(viewWindow);
|
||||
|
||||
// Keep the view within the sector's floor and ceiling
|
||||
if (viewPoint.sector->PortalBlocksMovement(sector_t::ceiling))
|
||||
{
|
||||
const double z = viewPoint.sector->ceilingplane.ZatPoint(viewPoint.Pos) - 4.0;
|
||||
if (viewPoint.Pos.Z > z)
|
||||
viewPoint.Pos.Z = z;
|
||||
}
|
||||
|
||||
if (viewPoint.sector->PortalBlocksMovement(sector_t::floor))
|
||||
{
|
||||
const double z = viewPoint.sector->floorplane.ZatPoint(viewPoint.Pos) + 4.0;
|
||||
if (viewPoint.Pos.Z < z)
|
||||
viewPoint.Pos.Z = z;
|
||||
}
|
||||
|
||||
viewPoint.extralight = viewPoint.camera->player != nullptr ? viewPoint.camera->player->extralight : 0;
|
||||
|
||||
// killough 3/20/98, 4/4/98: select colormap based on player status
|
||||
// [RH] Can also select a blend
|
||||
newblend = 0;
|
||||
|
||||
TArray<lightlist_t> &lightlist = viewpoint.sector->e->XFloor.lightlist;
|
||||
unsigned int newBlend = 0u;
|
||||
const TArray<lightlist_t>& lightlist = viewPoint.sector->e->XFloor.lightlist;
|
||||
if (lightlist.Size() > 0)
|
||||
{
|
||||
for(unsigned int i = 0; i < lightlist.Size(); i++)
|
||||
for (size_t i = 0u; i < lightlist.Size(); ++i)
|
||||
{
|
||||
secplane_t *plane;
|
||||
int viewside;
|
||||
plane = (i < lightlist.Size()-1) ? &lightlist[i+1].plane : &viewpoint.sector->floorplane;
|
||||
viewside = plane->PointOnSide(viewpoint.Pos);
|
||||
const secplane_t& plane = (i < lightlist.Size() - 1u) ? lightlist[i + 1u].plane : viewPoint.sector->floorplane;
|
||||
int viewSide = plane.PointOnSide(viewPoint.Pos);
|
||||
|
||||
// Reverse the direction of the test if the plane was downward facing.
|
||||
// We want to know if the view is above it, whatever its orientation may be.
|
||||
if (plane->fC() < 0)
|
||||
viewside = -viewside;
|
||||
if (viewside > 0)
|
||||
{
|
||||
// 3d floor 'fog' is rendered as a blending value
|
||||
PalEntry blendv = lightlist[i].blend;
|
||||
if (plane.fC() < 0.0)
|
||||
viewSide = -viewSide;
|
||||
|
||||
// If no alpha is set, use 50%
|
||||
if (blendv.a==0 && blendv!=0) blendv.a=128;
|
||||
newblend = blendv.d;
|
||||
if (viewSide > 0)
|
||||
{
|
||||
// 3d floor 'fog' is rendered as a blending value.
|
||||
PalEntry blend = lightlist[i].blend;
|
||||
|
||||
// If no alpha is set, use 50%.
|
||||
if (!blend.a && blend != 0)
|
||||
blend.a = 128u;
|
||||
|
||||
newBlend = blend.d;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const sector_t *s = viewpoint.sector->GetHeightSec();
|
||||
if (s != NULL)
|
||||
const sector_t* const sec = viewPoint.sector->GetHeightSec();
|
||||
if (sec != nullptr)
|
||||
{
|
||||
newblend = s->floorplane.PointOnSide(viewpoint.Pos) < 0
|
||||
? s->bottommap
|
||||
: s->ceilingplane.PointOnSide(viewpoint.Pos) < 0
|
||||
? s->topmap
|
||||
: s->midmap;
|
||||
if (APART(newblend) == 0 && newblend >= fakecmaps.Size())
|
||||
newblend = 0;
|
||||
newBlend = sec->floorplane.PointOnSide(viewPoint.Pos) < 0
|
||||
? sec->bottommap
|
||||
: sec->ceilingplane.PointOnSide(viewPoint.Pos) < 0
|
||||
? sec->topmap
|
||||
: sec->midmap;
|
||||
|
||||
if (APART(newBlend) == 0u && newBlend >= fakecmaps.Size())
|
||||
newBlend = 0u;
|
||||
}
|
||||
}
|
||||
|
||||
// [RH] Don't override testblend unless entering a sector with a
|
||||
// blend different from the previous sector's. Same goes with
|
||||
// NormalLight's maps pointer.
|
||||
if (R_OldBlend != newblend)
|
||||
{
|
||||
R_OldBlend = newblend;
|
||||
}
|
||||
if (R_OldBlend != newBlend)
|
||||
R_OldBlend = newBlend;
|
||||
|
||||
validcount++;
|
||||
++validcount;
|
||||
|
||||
if (r_clearbuffer != 0)
|
||||
{
|
||||
int color;
|
||||
int color = 0;
|
||||
int hom = r_clearbuffer;
|
||||
|
||||
if (hom == 3)
|
||||
{
|
||||
hom = ((screen->FrameTime / 128) & 1) + 1;
|
||||
}
|
||||
if (hom == 1)
|
||||
{
|
||||
color = GPalette.BlackIndex;
|
||||
}
|
||||
else if (hom == 2)
|
||||
{
|
||||
color = GPalette.WhiteIndex;
|
||||
}
|
||||
else if (hom == 4)
|
||||
{
|
||||
color = (screen->FrameTime / 32) & 255;
|
||||
}
|
||||
else
|
||||
{
|
||||
color = pr_hom();
|
||||
}
|
||||
|
||||
screen->SetClearColor(color);
|
||||
SWRenderer->SetClearColor(color);
|
||||
}
|
||||
|
@ -1175,25 +1103,16 @@ void R_SetupFrame (FRenderViewpoint &viewpoint, FViewWindow &viewwindow, AActor
|
|||
|
||||
// Scale the pitch to account for the pixel stretching, because the playsim doesn't know about this and treats it as 1:1.
|
||||
// However, to set up a projection matrix this needs to be adjusted.
|
||||
double radPitch = viewpoint.Angles.Pitch.Normalized180().Radians();
|
||||
double angx = cos(radPitch);
|
||||
double angy = sin(radPitch) * actor->Level->info->pixelstretch;
|
||||
double alen = sqrt(angx*angx + angy*angy);
|
||||
viewpoint.HWAngles.Pitch = FAngle::fromRad((float)asin(angy / alen));
|
||||
|
||||
viewpoint.HWAngles.Roll = FAngle::fromDeg(viewpoint.Angles.Roll.Degrees()); // copied for convenience.
|
||||
|
||||
// ViewActor only gets set, if the camera actor should not be rendered
|
||||
if (actor->player && actor->player - players == consoleplayer &&
|
||||
((actor->player->cheats & CF_CHASECAM) || (r_deathcamera && actor->health <= 0)) && actor == actor->player->mo)
|
||||
{
|
||||
viewpoint.ViewActor = nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
viewpoint.ViewActor = actor;
|
||||
}
|
||||
const double radPitch = viewPoint.Angles.Pitch.Normalized180().Radians();
|
||||
const double angx = cos(radPitch);
|
||||
const double angy = sin(radPitch) * actor->Level->info->pixelstretch;
|
||||
const double alen = sqrt(angx*angx + angy*angy);
|
||||
|
||||
viewPoint.HWAngles.Pitch = FAngle::fromRad((float)asin(angy / alen));
|
||||
viewPoint.HWAngles.Roll = FAngle::fromDeg(viewPoint.Angles.Roll.Degrees());
|
||||
|
||||
// ViewActor only gets set if the camera actor shouldn't be rendered.
|
||||
viewPoint.ViewActor = viewPoint.showviewer ? nullptr : actor;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -43,9 +43,8 @@ struct FRenderViewpoint
|
|||
|
||||
int extralight; // extralight to be added to this viewpoint
|
||||
bool showviewer; // show the camera actor?
|
||||
bool NoPortalPath; // Disable portal interpolation path for actor viewpos.
|
||||
bool noviewer; // Force camera sprite off for first person.
|
||||
void SetViewAngle(const FViewWindow &viewwindow);
|
||||
bool bForceNoViewer; // Never show the camera Actor.
|
||||
void SetViewAngle(const FViewWindow& viewWindow);
|
||||
|
||||
};
|
||||
|
||||
|
@ -118,7 +117,7 @@ void R_ClearInterpolationPath();
|
|||
void R_AddInterpolationPoint(const DVector3a &vec);
|
||||
void R_SetViewSize (int blocks);
|
||||
void R_SetFOV (FRenderViewpoint &viewpoint, DAngle fov);
|
||||
void R_SetupFrame (FRenderViewpoint &viewpoint, FViewWindow &viewwindow, AActor * camera);
|
||||
void R_SetupFrame(FRenderViewpoint& viewPoint, const FViewWindow& viewWindow, AActor* const camera);
|
||||
void R_SetViewAngle (FRenderViewpoint &viewpoint, const FViewWindow &viewwindow);
|
||||
|
||||
// Called by startup code.
|
||||
|
|
Loading…
Reference in a new issue