From 14a0567343a3160944963471eb45cff78e4dbb46 Mon Sep 17 00:00:00 2001
From: Christoph Oelckers <c.oelckers@zdoom.fake>
Date: Thu, 3 Mar 2016 11:58:04 +0100
Subject: [PATCH] - optimized the portal translation functions by
 precalculating the rotation angle, sine and cosine.

---
 src/p_map.cpp    | 31 +++++++++-----------
 src/p_maputl.cpp | 11 ++++---
 src/portal.cpp   | 76 +++++++++++++++++++++++-------------------------
 src/portal.h     | 11 ++++---
 src/r_main.cpp   |  6 ++--
 5 files changed, 66 insertions(+), 69 deletions(-)

diff --git a/src/p_map.cpp b/src/p_map.cpp
index 0fe73229cb..0151d48039 100644
--- a/src/p_map.cpp
+++ b/src/p_map.cpp
@@ -1041,8 +1041,8 @@ static bool PIT_CheckPortal(FMultiBlockLinesIterator &mit, FMultiBlockLinesItera
 	line_t *lp = cres.line->getPortalDestination();
 	fixed_t zofs = 0;
 
-	P_TranslatePortalXY(cres.line, lp, cres.position.x, cres.position.y);
-	P_TranslatePortalZ(cres.line, lp, zofs);
+	P_TranslatePortalXY(cres.line, cres.position.x, cres.position.y);
+	P_TranslatePortalZ(cres.line, zofs);
 
 	// fudge a bit with the portal line so that this gets included in the checks that normally only get run on two-sided lines
 	sector_t *sec = lp->backsector;
@@ -2325,14 +2325,13 @@ bool P_TryMove(AActor *thing, fixed_t x, fixed_t y,
 			}
 			else if (!portalcrossed)
 			{
-				line_t *out = port->mDestination;
 				fixedvec3 pos = { tm.x, tm.y, thing->Z() };
 				fixedvec3 oldthingpos = thing->Pos();
 				fixedvec2 thingpos = oldthingpos;
 				
-				P_TranslatePortalXY(ld, out, pos.x, pos.y);
-				P_TranslatePortalXY(ld, out, thingpos.x, thingpos.y);
-				P_TranslatePortalZ(ld, out, pos.z);
+				P_TranslatePortalXY(ld, pos.x, pos.y);
+				P_TranslatePortalXY(ld, thingpos.x, thingpos.y);
+				P_TranslatePortalZ(ld, pos.z);
 				thing->SetXYZ(thingpos.x, thingpos.y, pos.z);
 				if (!P_CheckPosition(thing, pos.x, pos.y, true))	// check if some actor blocks us on the other side. (No line checks, because of the mess that'd create.)
 				{
@@ -2342,8 +2341,8 @@ bool P_TryMove(AActor *thing, fixed_t x, fixed_t y,
 				}
 				thing->UnlinkFromWorld();
 				thing->SetXYZ(pos);
-				P_TranslatePortalVXVY(ld, out, thing->velx, thing->vely);
-				P_TranslatePortalAngle(ld, out, thing->angle);
+				P_TranslatePortalVXVY(ld, thing->velx, thing->vely);
+				P_TranslatePortalAngle(ld, thing->angle);
 				thing->LinkToWorld();
 				P_FindFloorCeiling(thing);
 				thing->ClearInterpolation();
@@ -2355,7 +2354,6 @@ bool P_TryMove(AActor *thing, fixed_t x, fixed_t y,
 			{
 				divline_t dl1 = { besthit.oldrefpos.x,besthit. oldrefpos.y, besthit.refpos.x - besthit.oldrefpos.x, besthit.refpos.y - besthit.oldrefpos.y };
 				fixedvec3a hit = { dl1.x + FixedMul(dl1.dx, bestfrac), dl1.y + FixedMul(dl1.dy, bestfrac), 0, 0 };
-				line_t *out = port->mDestination;
 
 				R_AddInterpolationPoint(hit);
 				if (port->mType == PORTT_LINKED)
@@ -2365,10 +2363,10 @@ bool P_TryMove(AActor *thing, fixed_t x, fixed_t y,
 				}
 				else
 				{
-					P_TranslatePortalXY(ld, out, hit.x, hit.y);
-					P_TranslatePortalZ(ld, out, hit.z);
+					P_TranslatePortalXY(ld, hit.x, hit.y);
+					P_TranslatePortalZ(ld, hit.z);
 					players[consoleplayer].viewz += hit.z;	// needs to be done here because otherwise the renderer will not catch the change.
-					P_TranslatePortalAngle(ld, out, hit.angle);
+					P_TranslatePortalAngle(ld, hit.angle);
 				}
 				R_AddInterpolationPoint(hit);
 			}
@@ -3700,7 +3698,6 @@ struct aim_t
 		aim_t newtrace = Clone();
 
 		FLinePortal *port = li->getPortal();
-		line_t *dest = port->mDestination;
 
 		newtrace.toppitch = toppitch;
 		newtrace.bottompitch = bottompitch;
@@ -3708,9 +3705,9 @@ struct aim_t
 		newtrace.unlinked = (port->mType != PORTT_LINKED);
 		newtrace.startpos = startpos;
 		newtrace.aimtrace = aimtrace;
-		P_TranslatePortalXY(li, dest, newtrace.startpos.x, newtrace.startpos.y);
-		P_TranslatePortalZ(li, dest, newtrace.startpos.z);
-		P_TranslatePortalVXVY(li, dest, newtrace.aimtrace.x, newtrace.aimtrace.y);
+		P_TranslatePortalXY(li, newtrace.startpos.x, newtrace.startpos.y);
+		P_TranslatePortalZ(li, newtrace.startpos.z);
+		P_TranslatePortalVXVY(li, newtrace.aimtrace.x, newtrace.aimtrace.y);
 
 		newtrace.startfrac = frac + FixedDiv(FRACUNIT, attackrange);	// this is to skip the transition line to the portal which would produce a bogus opening
 
@@ -3718,7 +3715,7 @@ struct aim_t
 		fixed_t y = newtrace.startpos.y + FixedMul(newtrace.aimtrace.y, newtrace.startfrac);
 
 		newtrace.lastsector = P_PointInSector(x, y);
-		P_TranslatePortalZ(li, dest, limitz);
+		P_TranslatePortalZ(li, limitz);
 		Printf("-----Entering line portal from sector %d to sector %d\n", lastsector->sectornum, newtrace.lastsector->sectornum);
 		newtrace.AimTraverse();
 		SetResult(linetarget, newtrace.linetarget);
diff --git a/src/p_maputl.cpp b/src/p_maputl.cpp
index 2a8c0efda1..c6453285eb 100644
--- a/src/p_maputl.cpp
+++ b/src/p_maputl.cpp
@@ -1660,14 +1660,13 @@ int FPathTraverse::PortalRelocate(intercept_t *in, int flags, fixedvec3 *optpos)
 	fixed_t hity = trace.y;
 	fixed_t endx = trace.x + trace.dx;
 	fixed_t endy = trace.y + trace.dy;
-	line_t *out = in->d.line->getPortalDestination();
-
-	P_TranslatePortalXY(in->d.line, out, hitx, hity);
-	P_TranslatePortalXY(in->d.line, out, endx, endy);
+	
+	P_TranslatePortalXY(in->d.line, hitx, hity);
+	P_TranslatePortalXY(in->d.line, endx, endy);
 	if (optpos != NULL)
 	{
-		P_TranslatePortalXY(in->d.line, out, optpos->x, optpos->y);
-		P_TranslatePortalZ(in->d.line, out, optpos->z);
+		P_TranslatePortalXY(in->d.line, optpos->x, optpos->y);
+		P_TranslatePortalZ(in->d.line, optpos->z);
 	}
 	intercepts.Resize(intercept_index);
 	init(hitx, hity, endx, endy, flags, in->frac);
diff --git a/src/portal.cpp b/src/portal.cpp
index 01afb0bc48..f9c3cec2a6 100644
--- a/src/portal.cpp
+++ b/src/portal.cpp
@@ -265,9 +265,17 @@ void P_SpawnLinePortal(line_t* line)
 		if (port->mDestination != NULL)
 		{
 			port->mDefFlags = port->mType == PORTT_VISUAL ? PORTF_VISIBLE : port->mType == PORTT_TELEPORT ? PORTF_TYPETELEPORT : PORTF_TYPEINTERACTIVE;
-
-
 		}
+
+		// Get the angle between the two linedefs, for rotating
+		// orientation and velocity. Rotate 180 degrees, and flip
+		// the position across the exit linedef, if reversed.
+
+		double angle = atan2(dst->dy, dst->dx) - atan2(line->dy, line->dx) + M_PI;
+		port->mSinRot = FLOAT2FIXED(sin(angle));
+		port->mCosRot = FLOAT2FIXED(cos(angle));
+		port->mAngleDiff = RAD2ANGLE(angle);
+
 	}
 	else if (line->args[2] == PORTT_LINKEDEE && line->args[0] == 0)
 	{
@@ -546,30 +554,22 @@ bool P_ClipLineToPortal(line_t* line, line_t* portal, fixed_t viewx, fixed_t vie
 //
 //============================================================================
 
-void P_TranslatePortalXY(line_t* src, line_t* dst, fixed_t& x, fixed_t& y)
+void P_TranslatePortalXY(line_t* src, fixed_t& x, fixed_t& y)
 {
-	if (!src || !dst)
-		return;
+	if (!src) return;
+	FLinePortal *port = src->getPortal();
+	if (!port) return;
 
-	fixed_t nposx, nposy;	// offsets from line
-
-	// Get the angle between the two linedefs, for rotating
-	// orientation and velocity. Rotate 180 degrees, and flip
-	// the position across the exit linedef, if reversed.
-
-	double angle = atan2(dst->dy, dst->dx) - atan2(src->dy, src->dx) + M_PI;
-	fixed_t s = FLOAT2FIXED(sin(angle));
-	fixed_t c = FLOAT2FIXED(cos(angle));
-
-	nposx = x - src->v1->x;
-	nposy = y - src->v1->y;
+	// offsets from line
+	fixed_t nposx = x - src->v1->x;
+	fixed_t nposy = y - src->v1->y;
 
 	// Rotate position along normal to match exit linedef
-	fixed_t tx = FixedMul(nposx, c) - FixedMul(nposy, s);
-	fixed_t ty = FixedMul(nposy, c) + FixedMul(nposx, s);
+	fixed_t tx = FixedMul(nposx, port->mCosRot) - FixedMul(nposy, port->mSinRot);
+	fixed_t ty = FixedMul(nposy, port->mCosRot) + FixedMul(nposx, port->mSinRot);
 
-	tx += dst->v2->x;
-	ty += dst->v2->y;
+	tx += port->mDestination->v2->x;
+	ty += port->mDestination->v2->y;
 
 	x = tx;
 	y = ty;
@@ -581,16 +581,16 @@ void P_TranslatePortalXY(line_t* src, line_t* dst, fixed_t& x, fixed_t& y)
 //
 //============================================================================
 
-void P_TranslatePortalVXVY(line_t* src, line_t* dst, fixed_t& vx, fixed_t& vy)
+void P_TranslatePortalVXVY(line_t* src, fixed_t& vx, fixed_t& vy)
 {
-	double angle = atan2(dst->dy, dst->dx) - atan2(src->dy, src->dx) + M_PI;
-	fixed_t s = FLOAT2FIXED(sin(angle));
-	fixed_t c = FLOAT2FIXED(cos(angle));
+	if (!src) return;
+	FLinePortal *port = src->getPortal();
+	if (!port) return;
 
 	fixed_t orig_velx = vx;
 	fixed_t orig_vely = vy;
-	vx = FixedMul(orig_velx, c) - FixedMul(orig_vely, s);
-	vy = FixedMul(orig_vely, c) + FixedMul(orig_velx, s);
+	vx = FixedMul(orig_velx, port->mCosRot) - FixedMul(orig_vely, port->mSinRot);
+	vy = FixedMul(orig_vely, port->mCosRot) + FixedMul(orig_velx, port->mSinRot);
 }
 
 //============================================================================
@@ -599,15 +599,12 @@ void P_TranslatePortalVXVY(line_t* src, line_t* dst, fixed_t& vx, fixed_t& vy)
 //
 //============================================================================
 
-void P_TranslatePortalAngle(line_t* src, line_t* dst, angle_t& angle)
+void P_TranslatePortalAngle(line_t* src, angle_t& angle)
 {
-	if (!src || !dst)
-		return;
-
-	// Get the angle between the two linedefs, for rotating
-	// orientation and velocity. Rotate 180 degrees, and flip
-	// the position across the exit linedef, if reversed.
-	angle += RAD2ANGLE(atan2(dst->dy, dst->dx) - atan2(src->dy, src->dx)) + ANGLE_180;
+	if (!src) return;
+	FLinePortal *port = src->getPortal();
+	if (!port) return;
+	angle += port->mAngleDiff;
 }
 
 //============================================================================
@@ -616,12 +613,14 @@ void P_TranslatePortalAngle(line_t* src, line_t* dst, angle_t& angle)
 //
 //============================================================================
 
-void P_TranslatePortalZ(line_t* src, line_t* dst, fixed_t& z)
+void P_TranslatePortalZ(line_t* src, fixed_t& z)
 {
 	// args[2] = 0 - no adjustment
 	// args[2] = 1 - adjust by floor difference
 	// args[2] = 2 - adjust by ceiling difference
 
+	// This cannot be precalculated because heights may change.
+	line_t *dst = src->getPortalDestination();
 	switch (src->getPortalAlignment())
 	{
 	case PORG_FLOOR:
@@ -704,7 +703,6 @@ fixedvec2 P_GetOffsetPosition(fixed_t x, fixed_t y, fixed_t dx, fixed_t dy)
 				// hit a portal line.
 				line_t *line = in->d.line;
 				FLinePortal *port = line->getPortal();
-				line_t* out = port->mDestination;
 
 				// Teleport portals are intentionally ignored since skipping this stuff is their entire reason for existence.
 				if (port->mFlags & PORTF_INTERACTIVE)
@@ -723,8 +721,8 @@ fixedvec2 P_GetOffsetPosition(fixed_t x, fixed_t y, fixed_t dx, fixed_t dy)
 					{
 						// interactive ones are more complex because the vector may be rotated.
 						// Note: There is no z-translation here, there's just too much code in the engine that wouldn't be able to handle interactive portals with a height difference.
-						P_TranslatePortalXY(line, out, hit.x, hit.y);
-						P_TranslatePortalXY(line, out, dest.x, dest.y);
+						P_TranslatePortalXY(line, hit.x, hit.y);
+						P_TranslatePortalXY(line, dest.x, dest.y);
 					}
 					// update the fields, end this trace and restart from the new position
 					dx = dest.x - hit.x;
diff --git a/src/portal.h b/src/portal.h
index 127a9ec3ba..b8a5d3ba38 100644
--- a/src/portal.h
+++ b/src/portal.h
@@ -173,6 +173,9 @@ struct FLinePortal
 	BYTE mFlags;
 	BYTE mDefFlags;
 	BYTE mAlign;
+	angle_t mAngleDiff;
+	fixed_t mSinRot;
+	fixed_t mCosRot;
 };
 
 extern TArray<FLinePortal> linePortals;
@@ -192,10 +195,10 @@ inline int P_NumPortalGroups()
 
 /* code ported from prototype */
 bool P_ClipLineToPortal(line_t* line, line_t* portal, fixed_t viewx, fixed_t viewy, bool partial = true, bool samebehind = true);
-void P_TranslatePortalXY(line_t* src, line_t* dst, fixed_t& x, fixed_t& y);
-void P_TranslatePortalVXVY(line_t* src, line_t* dst, fixed_t& vx, fixed_t& vy);
-void P_TranslatePortalAngle(line_t* src, line_t* dst, angle_t& angle);
-void P_TranslatePortalZ(line_t* src, line_t* dst, fixed_t& z);
+void P_TranslatePortalXY(line_t* src, fixed_t& x, fixed_t& y);
+void P_TranslatePortalVXVY(line_t* src, fixed_t& vx, fixed_t& vy);
+void P_TranslatePortalAngle(line_t* src, angle_t& angle);
+void P_TranslatePortalZ(line_t* src, fixed_t& z);
 void P_NormalizeVXVY(fixed_t& vx, fixed_t& vy);
 fixed_t P_PointLineDistance(line_t* line, fixed_t x, fixed_t y);
 fixedvec2 P_GetOffsetPosition(fixed_t x, fixed_t y, fixed_t dx, fixed_t dy);
diff --git a/src/r_main.cpp b/src/r_main.cpp
index 12dd3916bd..c445787a07 100644
--- a/src/r_main.cpp
+++ b/src/r_main.cpp
@@ -732,9 +732,9 @@ void R_EnterPortal (PortalDrawseg* pds, int depth)
 	}
 	else
 	{
-		P_TranslatePortalXY(pds->src, pds->dst, viewx, viewy);
-		P_TranslatePortalZ(pds->src, pds->dst, viewz);
-		P_TranslatePortalAngle(pds->src, pds->dst, viewangle);
+		P_TranslatePortalXY(pds->src, viewx, viewy);
+		P_TranslatePortalZ(pds->src, viewz);
+		P_TranslatePortalAngle(pds->src, viewangle);
 	}
 
 	viewsin = finesine[viewangle>>ANGLETOFINESHIFT];