diff --git a/MUNGA/ENTITY.cpp b/MUNGA/ENTITY.cpp index 1631a0a..af7c005 100644 --- a/MUNGA/ENTITY.cpp +++ b/MUNGA/ENTITY.cpp @@ -1425,6 +1425,20 @@ static Logical return enabled ? True : False; } +void + Entity::SnapshotRenderOrigin() +{ + Check(this); + renderPreviousOrigin = localOrigin; +} + +void + Entity::SetRenderStepFraction(Scalar fraction) +{ + Check(this); + renderStepFraction = fraction; +} + void Entity::GetRenderToWorld(LinearMatrix *out) { diff --git a/MUNGA/ENTITY.h b/MUNGA/ENTITY.h index e6a1f34..ea7787d 100644 --- a/MUNGA/ENTITY.h +++ b/MUNGA/ENTITY.h @@ -186,6 +186,15 @@ public: void GetRenderToWorld(LinearMatrix *out); + // + // Filled by Simulation::PerformTo around each fixed step, for locally + // simulated entities and replicants alike. + // + void + SnapshotRenderOrigin(); + void + SetRenderStepFraction(Scalar fraction); + int GetDamageZoneIndex(const CString &damage_zone_name) const; diff --git a/MUNGA/MOVER.cpp b/MUNGA/MOVER.cpp index 2060331..2b0095b 100644 --- a/MUNGA/MOVER.cpp +++ b/MUNGA/MOVER.cpp @@ -699,19 +699,6 @@ void localAcceleration = Motion::Identity; previousOrigin = localOrigin; - // - // The same snapshot again, for DRAWING. Deliberately not previousOrigin - // itself: that one belongs to the physics, and rendering must not be - // aliased to a member the simulation is free to repurpose. - // - // This runs AFTER a VTV's scheduled respawn has teleported localOrigin, - // because VTV::BeginStep applies the respawn and then calls us. So a - // respawn leaves the two equal and the blend has nothing to travel - a - // teleport stays a cut instead of becoming a 300-metre slide across the - // map. See entity.h. - // - renderPreviousOrigin = localOrigin; - if (++normalizeCount >= 20) { localOrigin.angularPosition.Normalize(); diff --git a/MUNGA/SIMULATE.cpp b/MUNGA/SIMULATE.cpp index b86a1f1..d07bc3c 100644 --- a/MUNGA/SIMULATE.cpp +++ b/MUNGA/SIMULATE.cpp @@ -774,6 +774,13 @@ void while (behind >= step && taken < max_steps) { + // + // Where this step STARTED, for drawing. Taken here rather than + // in BeginStep so it covers replicants too, and taken after any + // BeginStep teleport (a VTV's scheduled respawn) so a jump + // stays a cut instead of becoming a slide. + // + SnapshotRenderOrigin(); Perform(step); ++gPhysicsStepsTaken; lastPerformance += step; @@ -781,6 +788,19 @@ void ++taken; } + // + // How far past the last completed step the frame being drawn falls. + // Entity::PerformAndWatch computes this again from the FRAME's till + // after its interleave, because there this function is called once + // per step and sees no leftover at all. + // + { + Scalar fraction = behind / step; + if (fraction < (Scalar) 0) fraction = (Scalar) 0; + if (fraction > (Scalar) 1) fraction = (Scalar) 1; + SetRenderStepFraction(fraction); + } + // // A machine that cannot keep up must not try to buy back the whole // backlog next frame - that costs more time, which makes a bigger @@ -808,6 +828,18 @@ void // nothing by default - see the header } +void + Simulation::SnapshotRenderOrigin() +{ + // nothing by default - only an Entity has an origin to snapshot +} + +void + Simulation::SetRenderStepFraction(Scalar) +{ + // nothing by default - see the header +} + void Simulation::WatchAndWrite(MemoryStream *update_stream) { diff --git a/MUNGA/SIMULATE.h b/MUNGA/SIMULATE.h index 0c844b1..69fe855 100644 --- a/MUNGA/SIMULATE.h +++ b/MUNGA/SIMULATE.h @@ -170,6 +170,23 @@ public: virtual void BeginStep(); + // + // Render interpolation hooks, called by PerformTo around the fixed + // step. They live HERE rather than on the entity interleave because a + // REPLICANT never runs that interleave - it reaches PerformTo through + // Simulation::PerformAndWatch instead - and a replicant is exactly what + // every remote pod is. Hanging the snapshot off BeginStep left the + // watched car uninterpolated while the camera watching it was smooth, + // which is most of the way to nowhere. + // + // Defaults do nothing; Entity overrides them because it owns the + // origin. See Entity::GetRenderToWorld. + // + virtual void + SnapshotRenderOrigin(); + virtual void + SetRenderStepFraction(Scalar fraction); + // // The fixed step in seconds, 0 when frame-coupled. Global on purpose: // a mixed-rate simulation would be a worse bug than either mode.