From 26c33afafb7d644d44247c20f37966ba3f3fc389 Mon Sep 17 00:00:00 2001
From: Christoph Oelckers <coelckers@zdoom.fake>
Date: Wed, 30 Dec 2009 12:20:47 +0000
Subject: [PATCH] - fixed: Movement performed by actor movers was not
 interpolated because   it happened outside the moved actor's Tick function.
 This got particularly   obvious with moving skybox viewpoints (See Daedalus's
 MAP21 intro for a good   example.)

SVN r2059 (trunk)
---
 docs/rh-log.txt                   |  6 +++++
 src/actor.h                       |  6 +++++
 src/g_shared/a_fastprojectile.cpp |  1 +
 src/g_shared/a_movingcamera.cpp   |  1 +
 src/p_enemy.cpp                   | 10 +++----
 src/p_map.cpp                     |  6 ++---
 src/p_mobj.cpp                    | 43 ++++++++++++++++++++++---------
 src/p_things.cpp                  |  6 ++---
 src/r_plane.cpp                   | 10 ++++---
 9 files changed, 62 insertions(+), 27 deletions(-)

diff --git a/docs/rh-log.txt b/docs/rh-log.txt
index ab9dbf4dd..a7a16b7ba 100644
--- a/docs/rh-log.txt
+++ b/docs/rh-log.txt
@@ -1,3 +1,9 @@
+December 30, 2009  (Changes by Graf Zahl)
+- fixed: Movement performed by actor movers was not interpolated because
+  it happened outside the moved actor's Tick function. This got particularly
+  obvious with moving skybox viewpoints (See Daedalus's MAP21 intro for a good
+  example.)
+
 December 28, 2009
 - Fixed: Shooting up and down with AArtiPoisonBag3::Use() was completely
   broken. I don't know what I thinking when I plugged in 2*finesine[pitch]
diff --git a/src/actor.h b/src/actor.h
index be6046f0e..90f80be1e 100644
--- a/src/actor.h
+++ b/src/actor.h
@@ -570,6 +570,7 @@ public:
 
 	// BeginPlay: Called just after the actor is created
 	virtual void BeginPlay ();
+	virtual void PostBeginPlay ();
 	// LevelSpawned: Called after BeginPlay if this actor was spawned by the world
 	virtual void LevelSpawned ();
 	// Translates SpawnFlags into in-game flags.
@@ -579,6 +580,7 @@ public:
 	virtual void Deactivate (AActor *activator);
 
 	virtual void Tick ();
+	void DoTick ();
 
 	// Smallest yaw interval for a mapthing to be spawned with
 	virtual angle_t AngleIncrements ();
@@ -868,6 +870,10 @@ public:
 
 	// [RH] Used to interpolate the view to get >35 FPS
 	fixed_t PrevX, PrevY, PrevZ;
+	angle_t PrevAngle;
+
+	fixed_t LastX, LastY, LastZ;
+	angle_t LastAngle;
 
 	// ThingIDs
 	static void ClearTIDHashes ();
diff --git a/src/g_shared/a_fastprojectile.cpp b/src/g_shared/a_fastprojectile.cpp
index 5829fc167..64b1451bb 100644
--- a/src/g_shared/a_fastprojectile.cpp
+++ b/src/g_shared/a_fastprojectile.cpp
@@ -26,6 +26,7 @@ void AFastProjectile::Tick ()
 	PrevX = x;
 	PrevY = y;
 	PrevZ = z;
+	PrevAngle = angle;
 
 	if (!(flags5 & MF5_NOTIMEFREEZE))
 	{
diff --git a/src/g_shared/a_movingcamera.cpp b/src/g_shared/a_movingcamera.cpp
index 0e704c95a..55316dbf1 100644
--- a/src/g_shared/a_movingcamera.cpp
+++ b/src/g_shared/a_movingcamera.cpp
@@ -585,6 +585,7 @@ void AActorMover::Activate (AActor *activator)
 	tracer->PrevX = tracer->x;
 	tracer->PrevY = tracer->y;
 	tracer->PrevZ = tracer->z;
+	tracer->PrevAngle = tracer->angle;
 }
 
 void AActorMover::Deactivate (AActor *activator)
diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp
index 4b80d5b68..0b5c29137 100644
--- a/src/p_enemy.cpp
+++ b/src/p_enemy.cpp
@@ -523,9 +523,9 @@ bool P_Move (AActor *actor)
 	// so make it switchable
 	if (nomonsterinterpolation)
 	{
-		actor->PrevX = actor->x;
-		actor->PrevY = actor->y;
-		actor->PrevZ = actor->z;
+		actor->LastX = actor->PrevX = actor->x;
+		actor->LastY = actor->PrevY = actor->y;
+		actor->LastZ = actor->PrevZ = actor->z;
 	}
 
 	if (try_ok && friction > ORIG_FRICTION)
@@ -2435,8 +2435,8 @@ void A_DoChase (AActor *actor, bool fastchase, FState *meleestate, FState *missi
 			{
 				if (nomonsterinterpolation)
 				{
-					actor->PrevX = oldX;
-					actor->PrevY = oldY;
+					actor->LastX = actor->PrevX = oldX;
+					actor->LastY = actor->PrevY = oldY;
 				}
 			}
 			P_NewChaseDir (actor);
diff --git a/src/p_map.cpp b/src/p_map.cpp
index dc056972f..0750050e9 100644
--- a/src/p_map.cpp
+++ b/src/p_map.cpp
@@ -392,9 +392,9 @@ bool P_TeleportMove (AActor *thing, fixed_t x, fixed_t y, fixed_t z, bool telefr
 		R_ResetViewInterpolation ();
 	}
 
-	thing->PrevX = x;
-	thing->PrevY = y;
-	thing->PrevZ = z;
+	thing->LastX = thing->PrevX = x;
+	thing->LastY = thing->PrevY = y;
+	thing->LastZ = thing->PrevZ = z;
 
 	return true;
 }
diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp
index 29480a7ee..82d8120b7 100644
--- a/src/p_mobj.cpp
+++ b/src/p_mobj.cpp
@@ -434,9 +434,10 @@ void AActor::Serialize (FArchive &arc)
 				Speed = GetDefault()->Speed;
 			}
 		}
-		PrevX = x;
-		PrevY = y;
-		PrevZ = z;
+		LastX = PrevX = x;
+		LastY = PrevY = y;
+		LastZ = PrevZ = z;
+		LastAngle = PrevAngle = angle;
 		UpdateWaterLevel(z, false);
 	}
 }
@@ -2805,7 +2806,7 @@ void AActor::SetShade (int r, int g, int b)
 //
 // P_MobjThinker
 //
-void AActor::Tick ()
+void AActor::DoTick ()
 {
 	// [RH] Data for Heretic/Hexen scrolling sectors
 	static const BYTE HexenScrollDirs[8] = { 64, 0, 192, 128, 96, 32, 224, 160 };
@@ -2835,10 +2836,6 @@ void AActor::Tick ()
 		return;
 	}
 
-	PrevX = x;
-	PrevY = y;
-	PrevZ = z;
-
 	if (flags5 & MF5_NOINTERACTION)
 	{
 		// only do the minimally necessary things here to save time:
@@ -3378,6 +3375,23 @@ void AActor::Tick ()
 	}
 }
 
+void AActor::Tick()
+{
+	// This is necessary to properly interpolate movement outside this function
+	// like from an ActorMover
+	PrevX = LastX;
+	PrevY = LastY;
+	PrevZ = LastZ;
+	PrevAngle = LastAngle;
+
+	DoTick();
+
+	LastX = x;
+	LastY = y;
+	LastZ = z;
+	LastAngle = angle;
+}
+
 //==========================================================================
 //
 // AActor::UpdateWaterLevel
@@ -3517,9 +3531,9 @@ AActor *AActor::StaticSpawn (const PClass *type, fixed_t ix, fixed_t iy, fixed_t
 	
 	actor = static_cast<AActor *>(const_cast<PClass *>(type)->CreateNew ());
 
-	actor->x = actor->PrevX = ix;
-	actor->y = actor->PrevY = iy;
-	actor->z = actor->PrevZ = iz;
+	actor->x = actor->LastX = actor->PrevX = ix;
+	actor->y = actor->LastY = actor->PrevY = iy;
+	actor->z = actor->LastZ = actor->PrevZ = iz;
 	actor->picnum.SetInvalid();
 	actor->health = actor->SpawnHealth();
 
@@ -3735,6 +3749,11 @@ void AActor::BeginPlay ()
 	}
 }
 
+void AActor::PostBeginPlay ()
+{
+	PrevAngle = angle;
+}
+
 bool AActor::isFast()
 {
 	if (flags5&MF5_ALWAYSFAST) return true;
@@ -4399,7 +4418,7 @@ AActor *P_SpawnMapThing (FMapThing *mthing, int position)
 	mobj->tid = mthing->thingid;
 	mobj->AddToHash ();
 
-	mobj->angle = (DWORD)((mthing->angle * UCONST64(0x100000000)) / 360);
+	mobj->LastAngle = mobj->PrevAngle = mobj->angle = (DWORD)((mthing->angle * UCONST64(0x100000000)) / 360);
 	mobj->BeginPlay ();
 	if (!(mobj->ObjectFlags & OF_EuthanizeMe))
 	{
diff --git a/src/p_things.cpp b/src/p_things.cpp
index 109b2d698..46c46be99 100644
--- a/src/p_things.cpp
+++ b/src/p_things.cpp
@@ -142,9 +142,9 @@ bool P_MoveThing(AActor *source, fixed_t x, fixed_t y, fixed_t z, bool fog)
 			Spawn<ATeleportFog> (x, y, z + TELEFOGHEIGHT, ALLOW_REPLACE);
 			Spawn<ATeleportFog> (oldx, oldy, oldz + TELEFOGHEIGHT, ALLOW_REPLACE);
 		}
-		source->PrevX=x;
-		source->PrevY=y;
-		source->PrevZ=z;
+		source->LastX = source->PrevX = x;
+		source->LastY = source->PrevY = y;
+		source->LastZ = source->PrevZ = z;
 		return true;
 	}
 	else
diff --git a/src/r_plane.cpp b/src/r_plane.cpp
index c9612c24c..aae870fbe 100644
--- a/src/r_plane.cpp
+++ b/src/r_plane.cpp
@@ -1105,10 +1105,12 @@ void R_DrawSkyBoxes ()
 			// Don't let gun flashes brighten the sky box
 			extralight = 0;
 			R_SetVisibility (sky->args[0] * 0.25f);
-			viewx = sky->x;
-			viewy = sky->y;
-			viewz = sky->z;
-			viewangle = savedangle + sky->angle;
+
+			viewx = sky->PrevX + FixedMul(r_TicFrac, sky->x - sky->PrevX);
+			viewy = sky->PrevY + FixedMul(r_TicFrac, sky->y - sky->PrevY);
+			viewz = sky->PrevZ + FixedMul(r_TicFrac, sky->z - sky->PrevZ);
+			viewangle = savedangle + sky->PrevAngle + FixedMul(r_TicFrac, sky->angle - sky->PrevAngle);
+
 			R_CopyStackedViewParameters();
 		}
 		else