Merge branch 'master' of https://github.com/ZDoom/gzdoom
This commit is contained in:
commit
74a27be3fd
114 changed files with 3366 additions and 1677 deletions
|
|
@ -391,19 +391,32 @@ void HWSprite::DrawSprite(HWDrawInfo *di, FRenderState &state, bool translucent)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
bool HWSprite::CalculateVertices(HWDrawInfo *di, FVector3 *v, DVector3 *vp)
|
||||
void HandleSpriteOffsets(Matrix3x4 *mat, const FRotator *HW, FVector2 *offset, bool XYBillboard)
|
||||
{
|
||||
const auto &HWAngles = di->Viewpoint.HWAngles;
|
||||
FAngle zero = FAngle::fromDeg(0);
|
||||
FAngle pitch = (XYBillboard) ? HW->Pitch : zero;
|
||||
FAngle yaw = FAngle::fromDeg(270.) - HW->Yaw;
|
||||
|
||||
FQuaternion quat = FQuaternion::FromAngles(yaw, pitch, zero);
|
||||
FVector3 sideVec = quat * FVector3(0, 1, 0);
|
||||
FVector3 upVec = quat * FVector3(0, 0, 1);
|
||||
FVector3 res = sideVec * offset->X + upVec * offset->Y;
|
||||
mat->Translate(res.X, res.Z, res.Y);
|
||||
}
|
||||
|
||||
bool HWSprite::CalculateVertices(HWDrawInfo* di, FVector3* v, DVector3* vp)
|
||||
{
|
||||
FVector3 center = FVector3((x1 + x2) * 0.5, (y1 + y2) * 0.5, (z1 + z2) * 0.5);
|
||||
const auto& HWAngles = di->Viewpoint.HWAngles;
|
||||
Matrix3x4 mat;
|
||||
if (actor != nullptr && (actor->renderflags & RF_SPRITETYPEMASK) == RF_FLATSPRITE)
|
||||
{
|
||||
Matrix3x4 mat;
|
||||
mat.MakeIdentity();
|
||||
|
||||
// [MC] Rotate around the center or offsets given to the sprites.
|
||||
// Counteract any existing rotations, then rotate the angle.
|
||||
// Tilt the actor up or down based on pitch (increase 'somersaults' forward).
|
||||
// Then counteract the roll and DO A BARREL ROLL.
|
||||
|
||||
mat.MakeIdentity();
|
||||
FAngle pitch = FAngle::fromDeg(-Angles.Pitch.Degrees());
|
||||
pitch.Normalized180();
|
||||
|
||||
|
|
@ -413,12 +426,9 @@ bool HWSprite::CalculateVertices(HWDrawInfo *di, FVector3 *v, DVector3 *vp)
|
|||
|
||||
if (actor->renderflags & RF_ROLLCENTER)
|
||||
{
|
||||
float cx = (x1 + x2) * 0.5;
|
||||
float cy = (y1 + y2) * 0.5;
|
||||
|
||||
mat.Translate(cx - x, 0, cy - y);
|
||||
mat.Translate(center.X - x, 0, center.Y - y);
|
||||
mat.Rotate(0, 1, 0, - Angles.Roll.Degrees());
|
||||
mat.Translate(-cx, -z, -cy);
|
||||
mat.Translate(-center.X, -z, -center.Y);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -444,51 +454,45 @@ bool HWSprite::CalculateVertices(HWDrawInfo *di, FVector3 *v, DVector3 *vp)
|
|||
|
||||
// [Nash] has +ROLLSPRITE
|
||||
const bool drawRollSpriteActor = (actor != nullptr && actor->renderflags & RF_ROLLSPRITE);
|
||||
|
||||
const bool drawRollParticle = (particle != nullptr && particle->flags & SPF_ROLL);
|
||||
|
||||
const bool doRoll = (drawRollSpriteActor || drawRollParticle);
|
||||
|
||||
// [fgsfds] check sprite type mask
|
||||
uint32_t spritetype = (uint32_t)-1;
|
||||
if (actor != nullptr) spritetype = actor->renderflags & RF_SPRITETYPEMASK;
|
||||
|
||||
// [Nash] is a flat sprite
|
||||
const bool isFlatSprite = (actor != nullptr) && (spritetype == RF_WALLSPRITE);
|
||||
const bool isWallSprite = (actor != nullptr) && (spritetype == RF_WALLSPRITE);
|
||||
const bool useOffsets = (actor != nullptr) && !(actor->renderflags & RF_ROLLCENTER);
|
||||
|
||||
FVector2 offset = FVector2( offx, offy );
|
||||
|
||||
// Account for +ROLLCENTER flag. Takes the embedded image offsets and adds them in with SpriteOffsets.
|
||||
if (drawRollSpriteActor && useOffsets)
|
||||
{
|
||||
offset.X += center.X - x;
|
||||
offset.Y += center.Z - z;
|
||||
}
|
||||
|
||||
// [Nash] check for special sprite drawing modes
|
||||
if (drawWithXYBillboard || drawBillboardFacingCamera || drawRollSpriteActor || drawRollParticle || isFlatSprite)
|
||||
if (drawWithXYBillboard || isWallSprite)
|
||||
{
|
||||
// Compute center of sprite
|
||||
float xcenter = (x1 + x2)*0.5;
|
||||
float ycenter = (y1 + y2)*0.5;
|
||||
float zcenter = (z1 + z2)*0.5;
|
||||
float xx = -xcenter + x;
|
||||
float zz = -zcenter + z;
|
||||
float yy = -ycenter + y;
|
||||
Matrix3x4 mat;
|
||||
mat.MakeIdentity();
|
||||
mat.Translate(xcenter, zcenter, ycenter); // move to sprite center
|
||||
mat.Translate(center.X, center.Z, center.Y); // move to sprite center
|
||||
|
||||
// [MC] Sprite offsets. These must be calculated separately in their own matrix,
|
||||
// otherwise "face sprites" would cause some issues whenever enabled. We don't
|
||||
// want those calculations here. Credit to PhantomBeta for this.
|
||||
if (offx || offy)
|
||||
{
|
||||
FQuaternion quat = FQuaternion::FromAngles(FAngle::fromDeg(270) - di->Viewpoint.HWAngles.Yaw, di->Viewpoint.HWAngles.Pitch, FAngle::fromDeg(0));
|
||||
FVector3 sideVec = quat * FVector3(0, 1, 0);
|
||||
FVector3 upVec = quat * FVector3(0, 0, 1);
|
||||
FVector3 res = sideVec * -offx + upVec * -offy;
|
||||
mat.Translate(res.X, res.Z, res.Y);
|
||||
}
|
||||
|
||||
// [MC] Sprite offsets.
|
||||
if (!offset.isZero())
|
||||
HandleSpriteOffsets(&mat, &HWAngles, &offset, true);
|
||||
|
||||
// Order of rotations matters. Perform yaw rotation (Y, face camera) before pitch (X, tilt up/down).
|
||||
if (drawBillboardFacingCamera && !isFlatSprite)
|
||||
if (drawBillboardFacingCamera && !isWallSprite)
|
||||
{
|
||||
// [CMB] Rotate relative to camera XY position, not just camera direction,
|
||||
// which is nicer in VR
|
||||
float xrel = xcenter - vp->X;
|
||||
float yrel = ycenter - vp->Y;
|
||||
float xrel = center.X - vp->X;
|
||||
float yrel = center.Y - vp->Y;
|
||||
float absAngleDeg = atan2(-yrel, xrel) * (180 / M_PI);
|
||||
float counterRotationDeg = 270. - HWAngles.Yaw.Degrees(); // counteracts existing sprite rotation
|
||||
float relAngleDeg = counterRotationDeg + absAngleDeg;
|
||||
|
|
@ -497,32 +501,27 @@ bool HWSprite::CalculateVertices(HWDrawInfo *di, FVector3 *v, DVector3 *vp)
|
|||
}
|
||||
|
||||
// [fgsfds] calculate yaw vectors
|
||||
float rollDegrees = 0;
|
||||
float rollDegrees = doRoll ? Angles.Roll.Degrees() : 0;
|
||||
float angleRad = (FAngle::fromDeg(270.) - HWAngles.Yaw).Radians();
|
||||
if (actor || drawRollParticle) rollDegrees = Angles.Roll.Degrees();
|
||||
|
||||
// [fgsfds] Rotate the sprite about the sight vector (roll)
|
||||
if (spritetype == RF_WALLSPRITE)
|
||||
if (isWallSprite)
|
||||
{
|
||||
float yawvecX = Angles.Yaw.Cos();
|
||||
float yawvecY = Angles.Yaw.Sin();
|
||||
mat.Rotate(0, 1, 0, 0);
|
||||
if (drawRollSpriteActor)
|
||||
{
|
||||
if (useOffsets) mat.Translate(xx, zz, yy);
|
||||
mat.Rotate(yawvecX, 0, yawvecY, rollDegrees);
|
||||
if (useOffsets) mat.Translate(-xx, -zz, -yy);
|
||||
}
|
||||
}
|
||||
else if (drawRollSpriteActor || drawRollParticle)
|
||||
else if (doRoll)
|
||||
{
|
||||
if (useOffsets) mat.Translate(xx, zz, yy);
|
||||
if (drawWithXYBillboard)
|
||||
{
|
||||
mat.Rotate(-sin(angleRad), 0, cos(angleRad), -HWAngles.Pitch.Degrees());
|
||||
}
|
||||
mat.Rotate(cos(angleRad), 0, sin(angleRad), rollDegrees);
|
||||
if (useOffsets) mat.Translate(-xx, -zz, -yy);
|
||||
}
|
||||
else if (drawWithXYBillboard)
|
||||
{
|
||||
|
|
@ -532,8 +531,8 @@ bool HWSprite::CalculateVertices(HWDrawInfo *di, FVector3 *v, DVector3 *vp)
|
|||
mat.Rotate(-sin(angleRad), 0, cos(angleRad), -HWAngles.Pitch.Degrees());
|
||||
}
|
||||
|
||||
mat.Translate(-xcenter, -zcenter, -ycenter); // retreat from sprite center
|
||||
|
||||
mat.Translate(-center.X, -center.Z, -center.Y); // retreat from sprite center
|
||||
|
||||
v[0] = mat * FVector3(x1, z1, y1);
|
||||
v[1] = mat * FVector3(x2, z1, y2);
|
||||
v[2] = mat * FVector3(x1, z2, y1);
|
||||
|
|
@ -541,10 +540,38 @@ bool HWSprite::CalculateVertices(HWDrawInfo *di, FVector3 *v, DVector3 *vp)
|
|||
}
|
||||
else // traditional "Y" billboard mode
|
||||
{
|
||||
v[0] = FVector3(x1, z1, y1);
|
||||
v[1] = FVector3(x2, z1, y2);
|
||||
v[2] = FVector3(x1, z2, y1);
|
||||
v[3] = FVector3(x2, z2, y2);
|
||||
if (doRoll || !offset.isZero())
|
||||
{
|
||||
mat.MakeIdentity();
|
||||
|
||||
if (!offset.isZero())
|
||||
HandleSpriteOffsets(&mat, &HWAngles, &offset, false);
|
||||
|
||||
if (doRoll)
|
||||
{
|
||||
// Compute center of sprite
|
||||
float angleRad = (FAngle::fromDeg(270.) - HWAngles.Yaw).Radians();
|
||||
float rollDegrees = Angles.Roll.Degrees();
|
||||
|
||||
mat.Translate(center.X, center.Z, center.Y);
|
||||
mat.Rotate(cos(angleRad), 0, sin(angleRad), rollDegrees);
|
||||
mat.Translate(-center.X, -center.Z, -center.Y);
|
||||
}
|
||||
|
||||
v[0] = mat * FVector3(x1, z1, y1);
|
||||
v[1] = mat * FVector3(x2, z1, y2);
|
||||
v[2] = mat * FVector3(x1, z2, y1);
|
||||
v[3] = mat * FVector3(x2, z2, y2);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
v[0] = FVector3(x1, z1, y1);
|
||||
v[1] = FVector3(x2, z1, y2);
|
||||
v[2] = FVector3(x1, z2, y1);
|
||||
v[3] = FVector3(x2, z2, y2);
|
||||
}
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
@ -831,7 +858,7 @@ void HWSprite::Process(HWDrawInfo *di, FRenderState& state, AActor* thing, secto
|
|||
// 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;
|
||||
|
|
@ -992,8 +1019,8 @@ void HWSprite::Process(HWDrawInfo *di, FRenderState& state, AActor* thing, secto
|
|||
if (!tex || !tex->isValid()) return;
|
||||
auto& spi = tex->GetSpritePositioning(type == RF_FACESPRITE);
|
||||
|
||||
offx = (float)thing->SpriteOffset.X;
|
||||
offy = (float)thing->SpriteOffset.Y;
|
||||
offx = (float)thing->GetSpriteOffset(false);
|
||||
offy = (float)thing->GetSpriteOffset(true);
|
||||
|
||||
vt = spi.GetSpriteVT();
|
||||
vb = spi.GetSpriteVB();
|
||||
|
|
@ -1299,7 +1326,6 @@ void HWSprite::Process(HWDrawInfo *di, FRenderState& state, AActor* thing, secto
|
|||
{
|
||||
lightlist = nullptr;
|
||||
}
|
||||
|
||||
PutSprite(di, state, hw_styleflags != STYLEHW_Solid);
|
||||
rendered_sprites++;
|
||||
}
|
||||
|
|
@ -1512,8 +1538,8 @@ void HWSprite::AdjustVisualThinker(HWDrawInfo* di, DVisualThinker* spr, sector_t
|
|||
y = interp.Y;
|
||||
z = interp.Z;
|
||||
|
||||
offx = (float)spr->Offset.X;
|
||||
offy = (float)spr->Offset.Y;
|
||||
offx = (float)spr->GetOffset(false);
|
||||
offy = (float)spr->GetOffset(true);
|
||||
|
||||
if (spr->PT.flags & SPF_ROLL)
|
||||
Angles.Roll = TAngle<double>::fromDeg(spr->InterpolatedRoll(timefrac));
|
||||
|
|
|
|||
|
|
@ -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,144 +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) &&
|
||||
iview->New.Pos.X == viewpoint.camera->X() &&
|
||||
iview->New.Pos.Y == viewpoint.camera->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();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
|
@ -617,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());
|
||||
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
|
@ -657,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)];
|
||||
}
|
||||
|
|
@ -783,26 +818,12 @@ static double QuakePower(double factor, double intensity, double offset)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
static void R_DoActorTickerAngleChanges(player_t* const player, AActor* const actor, const double scale)
|
||||
static void R_DoActorTickerAngleChanges(player_t* const player, DRotator& angles, const double scale)
|
||||
{
|
||||
for (unsigned i = 0; i < 3; i++)
|
||||
{
|
||||
if (player->angleTargets[i].Sgn())
|
||||
{
|
||||
// Calculate scaled amount of target and add to the accumlation buffer.
|
||||
DAngle addition = player->angleTargets[i] * scale;
|
||||
player->angleAppliedAmounts[i] += addition;
|
||||
|
||||
// Test whether we're now reached/exceeded our target.
|
||||
if (abs(player->angleAppliedAmounts[i]) >= abs(player->angleTargets[i]))
|
||||
{
|
||||
addition -= player->angleAppliedAmounts[i] - player->angleTargets[i];
|
||||
player->angleTargets[i] = player->angleAppliedAmounts[i] = nullAngle;
|
||||
}
|
||||
|
||||
// Apply the scaled addition to the angle.
|
||||
actor->Angles[i] += addition;
|
||||
}
|
||||
if (fabs(player->angleOffsetTargets[i].Degrees()) >= EQUAL_EPSILON)
|
||||
angles[i] += player->angleOffsetTargets[i] * scale;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -812,346 +833,263 @@ static void R_DoActorTickerAngleChanges(player_t* const player, AActor* const ac
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
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)
|
||||
if (viewPoint.camera == nullptr)
|
||||
I_Error("You lost your body. Bad dehacked work is likely to blame.");
|
||||
|
||||
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)
|
||||
{
|
||||
I_Error ("You lost your body. Bad dehacked work is likely to blame.");
|
||||
iView->prevTic = curTic;
|
||||
iView->Old = iView->New;
|
||||
}
|
||||
|
||||
// [MR] Get the input fraction, even if we don't need it this frame. Must run every frame.
|
||||
const auto scaleAdjust = I_GetInputFrac();
|
||||
|
||||
// [MR] Process player angle changes if permitted to do so.
|
||||
if (player && (player->cheats & CF_SCALEDNOLERP) && P_NoInterpolation(player, viewpoint.camera))
|
||||
{
|
||||
R_DoActorTickerAngleChanges(player, viewpoint.camera, scaleAdjust);
|
||||
}
|
||||
|
||||
iview = FindPastViewer (viewpoint.camera);
|
||||
|
||||
int nowtic = I_GetTime ();
|
||||
if (iview->otic != -1 && nowtic > iview->otic)
|
||||
{
|
||||
iview->otic = nowtic;
|
||||
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 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;
|
||||
const DVector3 orig = { mo->Pos().XY(), mo->player ? mo->player->viewz : mo->Z() + mo->GetCameraHeight() };
|
||||
viewpoint.ActorPos = orig;
|
||||
|
||||
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)))
|
||||
AActor* const mo = viewPoint.camera;
|
||||
const DViewPosition* const viewOffset = mo->ViewPos;
|
||||
DVector3 camPos;
|
||||
if (matchPlayer)
|
||||
{
|
||||
// [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))
|
||||
if (usePawn)
|
||||
{
|
||||
iview->otic = nowtic;
|
||||
iview->Old = iview->New;
|
||||
r_NoInterpolate = true;
|
||||
}
|
||||
viewpoint.ActorPos = campos;
|
||||
}
|
||||
else if (VP) // No chase/death cam and player is alive, wants viewpos.
|
||||
{
|
||||
viewpoint.sector = viewpoint.ViewLevel->PointInRenderSubsector(iview->New.Pos.XY())->sector;
|
||||
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)
|
||||
{
|
||||
iview->New.Pos = VP->Offset;
|
||||
camPos = DVector3(client->Pos().XY(), client->player->viewz);
|
||||
const DViewPosition* const pawnVP = client->ViewPos;
|
||||
if (pawnVP != nullptr)
|
||||
{
|
||||
// Add these directly to the view position offset (not 100% accurate but close enough).
|
||||
if (pawnVP->Flags & VPSF_ABSOLUTEPOS)
|
||||
camPos = pawnVP->Offset;
|
||||
else if (pawnVP->Flags & VPSF_ABSOLUTEOFFSET)
|
||||
iView->ViewOffset = pawnVP->Offset;
|
||||
else
|
||||
iView->ViewOffset = DQuaternion::FromAngles(client->Angles.Yaw, client->Angles.Pitch, client->Angles.Roll) * pawnVP->Offset;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
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.
|
||||
|
||||
DAngle yaw = mo->Angles.Yaw;
|
||||
DAngle pitch = mo->Angles.Pitch;
|
||||
DAngle roll = mo->Angles.Roll;
|
||||
DVector3 relx, rely, relz, Off = VP->Offset;
|
||||
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;
|
||||
next += relx * Off.X + rely * Off.Y + relz * Off.Z;
|
||||
}
|
||||
|
||||
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.NoPortalPath = true;
|
||||
P_AdjustViewPos(mo, orig, next, viewpoint.sector, unlinked, VP, &viewpoint);
|
||||
|
||||
if (viewpoint.sector->PortalGroup != oldsector->PortalGroup || (unlinked && ((iview->New.Pos.XY() - iview->Old.Pos.XY()).LengthSquared()) > 256 * 256))
|
||||
{
|
||||
iview->otic = nowtic;
|
||||
iview->Old = iview->New;
|
||||
r_NoInterpolate = true;
|
||||
}
|
||||
iview->New.Pos = next;
|
||||
}
|
||||
camPos = mainView.Pos;
|
||||
}
|
||||
}
|
||||
|
||||
if (DefaultDraw)
|
||||
else
|
||||
{
|
||||
iview->New.Pos = orig;
|
||||
viewpoint.sector = viewpoint.camera->Sector;
|
||||
viewpoint.showviewer = viewpoint.NoPortalPath = false;
|
||||
camPos = { mo->Pos().XY(), mo->player != nullptr ? mo->player->viewz : mo->Z() + mo->GetCameraHeight() };
|
||||
}
|
||||
}
|
||||
|
||||
// [MR] Apply view angles as the viewpoint angles if asked to do so.
|
||||
iview->New.Angles = !(viewpoint.camera->flags8 & MF8_ABSVIEWANGLES) ? viewpoint.camera->Angles : viewpoint.camera->ViewAngles;
|
||||
iview->New.ViewAngles = viewpoint.camera->ViewAngles;
|
||||
viewPoint.showviewer = false;
|
||||
viewPoint.bForceNoViewer = matchPlayer;
|
||||
|
||||
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)
|
||||
if (gamestate != GS_TITLELEVEL &&
|
||||
((player != nullptr && (player->cheats & CF_CHASECAM)) || (r_deathcamera && (viewPoint.camera->flags6 & MF6_KILLED))))
|
||||
{
|
||||
viewpoint.Pos.Z = theZ;
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
if (viewpoint.sector->PortalBlocksMovement(sector_t::floor))
|
||||
{
|
||||
double theZ = viewpoint.sector->floorplane.ZatPoint(viewpoint.Pos) + 4;
|
||||
if (viewpoint.Pos.Z < theZ)
|
||||
else if (viewOffset != nullptr)
|
||||
{
|
||||
viewpoint.Pos.Z = theZ;
|
||||
// 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)
|
||||
{
|
||||
if (!matchPlayer)
|
||||
camPos = viewOffset->Offset;
|
||||
}
|
||||
else if (viewOffset->Flags & VPSF_ABSOLUTEOFFSET)
|
||||
{
|
||||
iView->ViewOffset += viewOffset->Offset;
|
||||
}
|
||||
else
|
||||
{
|
||||
iView->RelativeViewOffset = viewOffset->Offset;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
@ -1165,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.
|
||||
|
|
|
|||
|
|
@ -1046,7 +1046,7 @@ namespace swrenderer
|
|||
// The X offsetting (SpriteOffset.X) is performed in r_sprite.cpp, in RenderSprite::Project().
|
||||
sprite.pos = thing->InterpolatedPosition(Thread->Viewport->viewpoint.TicFrac);
|
||||
sprite.pos += thing->WorldOffset;
|
||||
sprite.pos.Z += thing->GetBobOffset(Thread->Viewport->viewpoint.TicFrac) - thing->SpriteOffset.Y;
|
||||
sprite.pos.Z += thing->GetBobOffset(Thread->Viewport->viewpoint.TicFrac) + thing->GetSpriteOffset(true);
|
||||
sprite.spritenum = thing->sprite;
|
||||
sprite.tex = nullptr;
|
||||
sprite.voxel = nullptr;
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ namespace swrenderer
|
|||
const double thingxscalemul = spriteScale.X / tex->GetScale().X;
|
||||
|
||||
// Calculate billboard line for the sprite
|
||||
double SpriteOffX = (thing) ? thing->SpriteOffset.X : 0.;
|
||||
double SpriteOffX = (thing) ? -thing->GetSpriteOffset(false) : 0.;
|
||||
DVector2 dir = { viewport->viewpoint.Sin, -viewport->viewpoint.Cos };
|
||||
DVector2 trs = pos.XY() - viewport->viewpoint.Pos.XY();
|
||||
trs = { trs.X + SpriteOffX * dir.X, trs.Y + SpriteOffX * dir.Y };
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue