From 2aa34f027390f4f774cf2a606120a5def1fd0a4f Mon Sep 17 00:00:00 2001
From: Eidolon <furyhunter600@gmail.com>
Date: Tue, 12 Apr 2022 22:22:16 -0500
Subject: [PATCH] Add Polyobj interpolator

---
 src/p_polyobj.c | 25 ++++++++++++++++++++++
 src/r_fps.c     | 55 +++++++++++++++++++++++++++++++++++++++++++++++--
 src/r_fps.h     |  9 ++++++++
 3 files changed, 87 insertions(+), 2 deletions(-)

diff --git a/src/p_polyobj.c b/src/p_polyobj.c
index 6d7ef39990..a553ca2350 100644
--- a/src/p_polyobj.c
+++ b/src/p_polyobj.c
@@ -24,6 +24,7 @@
 #include "p_tick.h"
 #include "p_local.h"
 #include "p_polyobj.h"
+#include "r_fps.h"
 #include "r_main.h"
 #include "r_state.h"
 #include "r_defs.h"
@@ -2049,6 +2050,9 @@ boolean EV_DoPolyObjRotate(polyrotdata_t *prdata)
 
 	oldpo = po;
 
+	// interpolation
+	R_CreateInterpolator_Polyobj(&th->thinker, po);
+
 	th->turnobjs = prdata->turnobjs;
 
 	// apply action to mirroring polyobjects as well
@@ -2110,6 +2114,9 @@ boolean EV_DoPolyObjMove(polymovedata_t *pmdata)
 
 	oldpo = po;
 
+	// interpolation
+	R_CreateInterpolator_Polyobj(&th->thinker, po);
+
 	// apply action to mirroring polyobjects as well
 	start = 0;
 	while ((po = Polyobj_GetChild(oldpo, &start)))
@@ -2177,6 +2184,9 @@ boolean EV_DoPolyObjWaypoint(polywaypointdata_t *pwdata)
 		th->continuous = false;
 	}
 
+	// interpolation
+	R_CreateInterpolator_Polyobj(&th->thinker, po);
+
 	th->pointnum = first->health;
 
 	return true;
@@ -2225,6 +2235,9 @@ static void Polyobj_doSlideDoor(polyobj_t *po, polydoordata_t *doordata)
 
 	oldpo = po;
 
+	// interpolation
+	R_CreateInterpolator_Polyobj(&th->thinker, po);
+
 	// start action on mirroring polyobjects as well
 	start = 0;
 	while ((po = Polyobj_GetChild(oldpo, &start)))
@@ -2265,6 +2278,9 @@ static void Polyobj_doSwingDoor(polyobj_t *po, polydoordata_t *doordata)
 
 	oldpo = po;
 
+	// interpolation
+	R_CreateInterpolator_Polyobj(&th->thinker, po);
+
 	// start action on mirroring polyobjects as well
 	start = 0;
 	while ((po = Polyobj_GetChild(oldpo, &start)))
@@ -2336,6 +2352,9 @@ boolean EV_DoPolyObjDisplace(polydisplacedata_t *prdata)
 
 	oldpo = po;
 
+	// interpolation
+	R_CreateInterpolator_Polyobj(&th->thinker, po);
+
 	// apply action to mirroring polyobjects as well
 	start = 0;
 	while ((po = Polyobj_GetChild(oldpo, &start)))
@@ -2382,6 +2401,9 @@ boolean EV_DoPolyObjRotDisplace(polyrotdisplacedata_t *prdata)
 
 	oldpo = po;
 
+	// interpolation
+	R_CreateInterpolator_Polyobj(&th->thinker, po);
+
 	// apply action to mirroring polyobjects as well
 	start = 0;
 	while ((po = Polyobj_GetChild(oldpo, &start)))
@@ -2486,6 +2508,9 @@ boolean EV_DoPolyObjFlag(polyflagdata_t *pfdata)
 
 	oldpo = po;
 
+	// interpolation
+	R_CreateInterpolator_Polyobj(&th->thinker, po);
+
 	// apply action to mirroring polyobjects as well
 	start = 0;
 	while ((po = Polyobj_GetChild(oldpo, &start)))
diff --git a/src/r_fps.c b/src/r_fps.c
index e42e8745da..d2a31a6e64 100644
--- a/src/r_fps.c
+++ b/src/r_fps.c
@@ -284,6 +284,24 @@ void R_CreateInterpolator_SideScroll(thinker_t *thinker, side_t *side)
 	interp->sidescroll.oldrowoffset = interp->sidescroll.bakrowoffset = side->rowoffset;
 }
 
+void R_CreateInterpolator_Polyobj(thinker_t *thinker, polyobj_t *polyobj)
+{
+	levelinterpolator_t *interp = CreateInterpolator(LVLINTERP_Polyobj, thinker);
+	interp->polyobj.polyobj = polyobj;
+	interp->polyobj.vertices_size = polyobj->numVertices;
+
+	interp->polyobj.oldvertices = Z_CallocAlign(sizeof(fixed_t) * 2 * polyobj->numVertices, PU_LEVEL, NULL, 32);
+	interp->polyobj.bakvertices = Z_CallocAlign(sizeof(fixed_t) * 2 * polyobj->numVertices, PU_LEVEL, NULL, 32);
+	for (size_t i = 0; i < polyobj->numVertices; i++)
+	{
+		interp->polyobj.oldvertices[i * 2    ] = interp->polyobj.bakvertices[i * 2    ] = polyobj->vertices[i]->x;
+		interp->polyobj.oldvertices[i * 2 + 1] = interp->polyobj.bakvertices[i * 2 + 1] = polyobj->vertices[i]->y;
+	}
+
+	interp->polyobj.oldcx = interp->polyobj.bakcx = polyobj->centerPt.x;
+	interp->polyobj.oldcy = interp->polyobj.bakcy = polyobj->centerPt.y;
+}
+
 void R_InitializeLevelInterpolators(void)
 {
 	levelinterpolators_len = 0;
@@ -293,6 +311,8 @@ void R_InitializeLevelInterpolators(void)
 
 static void UpdateLevelInterpolatorState(levelinterpolator_t *interp)
 {
+	size_t i;
+
 	switch (interp->type)
 	{
 	case LVLINTERP_SectorPlane:
@@ -311,6 +331,19 @@ static void UpdateLevelInterpolatorState(levelinterpolator_t *interp)
 		interp->sidescroll.oldrowoffset = interp->sidescroll.bakrowoffset;
 		interp->sidescroll.bakrowoffset = interp->sidescroll.side->rowoffset;
 		break;
+	case LVLINTERP_Polyobj:
+		for (i = 0; i < interp->polyobj.vertices_size; i++)
+		{
+			interp->polyobj.oldvertices[i * 2    ] = interp->polyobj.bakvertices[i * 2    ];
+			interp->polyobj.oldvertices[i * 2 + 1] = interp->polyobj.bakvertices[i * 2 + 1];
+			interp->polyobj.bakvertices[i * 2    ] = interp->polyobj.polyobj->vertices[i]->x;
+			interp->polyobj.bakvertices[i * 2 + 1] = interp->polyobj.polyobj->vertices[i]->y;
+		}
+		interp->polyobj.oldcx = interp->polyobj.bakcx;
+		interp->polyobj.oldcy = interp->polyobj.bakcy;
+		interp->polyobj.bakcx = interp->polyobj.polyobj->centerPt.x;
+		interp->polyobj.bakcy = interp->polyobj.polyobj->centerPt.y;
+		break;
 	}
 }
 
@@ -346,7 +379,7 @@ void R_ClearLevelInterpolatorState(thinker_t *thinker)
 
 void R_ApplyLevelInterpolators(fixed_t frac)
 {
-	size_t i;
+	size_t i, ii;
 
 	for (i = 0; i < levelinterpolators_len; i++)
 	{
@@ -380,13 +413,22 @@ void R_ApplyLevelInterpolators(fixed_t frac)
 			interp->sidescroll.side->textureoffset = R_LerpFixed(interp->sidescroll.oldtextureoffset, interp->sidescroll.baktextureoffset, frac);
 			interp->sidescroll.side->rowoffset = R_LerpFixed(interp->sidescroll.oldrowoffset, interp->sidescroll.bakrowoffset, frac);
 			break;
+		case LVLINTERP_Polyobj:
+			for (ii = 0; ii < interp->polyobj.vertices_size; ii++)
+			{
+				interp->polyobj.polyobj->vertices[ii]->x = R_LerpFixed(interp->polyobj.oldvertices[ii * 2    ], interp->polyobj.bakvertices[ii * 2    ], frac);
+				interp->polyobj.polyobj->vertices[ii]->y = R_LerpFixed(interp->polyobj.oldvertices[ii * 2 + 1], interp->polyobj.bakvertices[ii * 2 + 1], frac);
+			}
+			interp->polyobj.polyobj->centerPt.x = R_LerpFixed(interp->polyobj.oldcx, interp->polyobj.bakcx, frac);
+			interp->polyobj.polyobj->centerPt.y = R_LerpFixed(interp->polyobj.oldcy, interp->polyobj.bakcy, frac);
+			break;
 		}
 	}
 }
 
 void R_RestoreLevelInterpolators(void)
 {
-	size_t i;
+	size_t i, ii;
 
 	for (i = 0; i < levelinterpolators_len; i++)
 	{
@@ -420,6 +462,15 @@ void R_RestoreLevelInterpolators(void)
 			interp->sidescroll.side->textureoffset = interp->sidescroll.baktextureoffset;
 			interp->sidescroll.side->rowoffset = interp->sidescroll.bakrowoffset;
 			break;
+		case LVLINTERP_Polyobj:
+			for (ii = 0; ii < interp->polyobj.vertices_size; ii++)
+			{
+				interp->polyobj.polyobj->vertices[ii]->x = interp->polyobj.bakvertices[ii * 2    ];
+				interp->polyobj.polyobj->vertices[ii]->y = interp->polyobj.bakvertices[ii * 2 + 1];
+			}
+			interp->polyobj.polyobj->centerPt.x = interp->polyobj.bakcx;
+			interp->polyobj.polyobj->centerPt.y = interp->polyobj.bakcy;
+			break;
 		}
 	}
 }
diff --git a/src/r_fps.h b/src/r_fps.h
index 0210a24f26..af9baa9620 100644
--- a/src/r_fps.h
+++ b/src/r_fps.h
@@ -58,6 +58,7 @@ typedef enum {
 	LVLINTERP_SectorPlane,
 	LVLINTERP_SectorScroll,
 	LVLINTERP_SideScroll,
+	LVLINTERP_Polyobj,
 } levelinterpolator_type_e;
 
 // Tagged union of a level interpolator
@@ -80,6 +81,13 @@ typedef struct levelinterpolator_s {
 			side_t *side;
 			fixed_t oldtextureoffset, oldrowoffset, baktextureoffset, bakrowoffset;
 		} sidescroll;
+		struct {
+			polyobj_t *polyobj;
+			fixed_t *oldvertices;
+			fixed_t *bakvertices;
+			size_t vertices_size;
+			fixed_t oldcx, oldcy, bakcx, bakcy;
+		} polyobj;
 	};
 } levelinterpolator_t;
 
@@ -99,6 +107,7 @@ void R_InterpolatePrecipMobjState(precipmobj_t *mobj, fixed_t frac, interpmobjst
 void R_CreateInterpolator_SectorPlane(thinker_t *thinker, sector_t *sector, boolean ceiling);
 void R_CreateInterpolator_SectorScroll(thinker_t *thinker, sector_t *sector, boolean ceiling);
 void R_CreateInterpolator_SideScroll(thinker_t *thinker, side_t *side);
+void R_CreateInterpolator_Polyobj(thinker_t *thinker, polyobj_t *polyobj);
 
 // Initialize level interpolators after a level change
 void R_InitializeLevelInterpolators(void);
-- 
GitLab