Added A_SetViewPos(Vector3 Offset, int Flags = -1)

- Offset: The offset from the actor's view to move the camera about.
 - Flags: (Default is -1, which means don't change flags)
  - VPSF_ABSOLUTEOFFSET: Don't include actor angles in calculation.
  - VPSF_ABSOLUTEPOS: Position is absolute, and disables all transformations. Modders are responsible for being portal aware!

Notes:
- `ViewPos` in Actor will be `null` until A_SetViewPos is called for the first time.

**Issues:**
- Hiding sprite while in portal incomplete.
This commit is contained in:
Major Cooke 2021-12-05 13:51:47 -06:00 committed by Rachael Alexanderson
commit 4e8d59951b
10 changed files with 283 additions and 29 deletions

View file

@ -654,6 +654,63 @@ struct FDropItem
int Amount;
};
enum EViewPosFlags // [MC] Flags for SetViewPos.
{
VPSF_ABSOLUTEOFFSET = 1 << 1, // Don't include angles.
VPSF_ABSOLUTEPOS = 1 << 2, // Use absolute position.
};
class FViewPosition : public DObject
{
DECLARE_CLASS(FViewPosition, DObject);
public:
// Variables
// Exposed to ZScript
DVector3 Offset;
int Flags;
// Engine only.
// Used to do a backwards trace to disable rendering over portals.
bool isUsed;
DVector3 PlrPos,
CamPos;
double Distance;
sector_t *CamSec;
// Functions
FViewPosition()
{
Offset = PlrPos = CamPos = { 0,0,0 };
isUsed = false;
Distance = 0.0;
CamSec = nullptr;
}
void Set(DVector3 &off, int f = -1)
{
Offset = off;
if (f > -1)
Flags = f;
}
bool isZero()
{
return Offset.isZero();
}
void ResetTraceInfo()
{
isUsed = false;
PlrPos = CamPos = {0,0,0};
Distance = 0.;
CamSec = nullptr;
}
bool TraceBack(AActor *Owner);
};
const double MinVel = EQUAL_EPSILON;
// Map Object definition.
@ -974,7 +1031,8 @@ public:
DAngle SpriteAngle;
DAngle SpriteRotation;
DRotator Angles;
DRotator ViewAngles; // Offsets for cameras
DRotator ViewAngles; // Angle offsets for cameras
FViewPosition *ViewPos; // Position offsets for cameras
DVector2 Scale; // Scaling values; 1 is normal size
double Alpha; // Since P_CheckSight makes an alpha check this can't be a float. It has to be a double.

View file

@ -50,6 +50,7 @@ struct secplane_t;
struct FCheckPosition;
struct FTranslatedLineTarget;
struct FLinePortal;
class FViewPosition;
#include <stdlib.h>
@ -392,6 +393,10 @@ 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, FViewPosition *VP);
// [RH] Means of death
enum
{

View file

@ -5423,6 +5423,62 @@ void P_AimCamera(AActor *t1, DVector3 &campos, DAngle &camangle, sector_t *&Came
camangle = trace.SrcAngleFromTarget - 180.;
}
// [MC] Used for ViewPos. Uses code borrowed from P_AimCamera.
void P_AdjustViewPos(AActor *t1, DVector3 orig, DVector3 &campos, sector_t *&CameraSector, bool &unlinked, FViewPosition *VP)
{
FTraceResults trace;
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, t1->Sector, vvec.Unit(), distance, 0, 0, t1, trace) &&
trace.Distance > 5)
{
// Position camera slightly in front of hit thing
campos = orig + vvec.Unit() * (trace.Distance - 5);
}
else
{
campos = trace.HitPos - trace.HitVector * 1 / 256.;
}
// DVector3 cpos = campos;
CameraSector = trace.Sector;
unlinked = trace.unlinked;
// Save the info for the renderers. Needed to disable sprites across portals.
VP->Distance = distance;
VP->isUsed = true;
}
struct EViewPosFinder
{
AActor *Owner;
};
static ETraceStatus TraceToOwner(FTraceResults &res, void *userdata)
{
// Try to guarantee hitting the owner if possible.
if (res.HitType != TRACE_HitActor)
return TRACE_Skip;
EViewPosFinder *data = (EViewPosFinder *)userdata;
ETraceStatus ret = (res.Actor == data->Owner) ? TRACE_Stop : TRACE_Skip;
return ret;
}
bool FViewPosition::TraceBack(AActor *Owner)
{
if (!isUsed || !Owner)
return false;
DVector3 vvec = (CamPos - PlrPos).Unit() * -1.0;
FTraceResults res;
EViewPosFinder TrcBack = {Owner};
bool ret = Trace(CamPos, CamSec, vvec, Distance, 0, 0, nullptr, res, TRACE_ReportPortals, TraceToOwner, &TrcBack);
return ret;
}
//==========================================================================
//

View file

@ -369,6 +369,7 @@ void AActor::Serialize(FSerializer &arc)
A("spawnorder", SpawnOrder)
A("friction", Friction)
A("SpriteOffset", SpriteOffset)
("viewpos", ViewPos)
A("userlights", UserLights);
SerializeTerrain(arc, "floorterrain", floorterrain, &def->floorterrain);
@ -4952,6 +4953,12 @@ void AActor::OnDestroy ()
UnlinkFromWorld (nullptr);
flags |= MF_NOSECTOR|MF_NOBLOCKMAP;
if (ViewPos != nullptr)
{
ViewPos->Destroy();
ViewPos = nullptr;
}
// Transform any playing sound into positioned, non-actor sounds.
S_RelinkSound (this, NULL);