From fa4b49d52cb75abd06cee204a1ac0678c919afc8 Mon Sep 17 00:00:00 2001
From: fickleheart <fickle@tinted.red>
Date: Wed, 8 Jan 2020 23:19:52 -0600
Subject: [PATCH] Refactor shadow floor finding code a bit

I tried to fix ring shadows on polyobjects and got this in return:
https://media.discordapp.net/attachments/629477786943356938/664695818913185822/srb20156.png
---
 src/r_things.c | 140 ++++++++++++++++++++++++++++++++++++-------------
 src/r_things.h |   2 +
 2 files changed, 107 insertions(+), 35 deletions(-)

diff --git a/src/r_things.c b/src/r_things.c
index ca3993322a..018f5d37f4 100644
--- a/src/r_things.c
+++ b/src/r_things.c
@@ -1095,62 +1095,132 @@ static void R_SplitSprite(vissprite_t *sprite)
 	}
 }
 
-static void R_ProjectDropShadow(mobj_t *thing, vissprite_t *vis, fixed_t tx, fixed_t tz)
+//
+// R_GetShadowZ(thing, shadowslope)
+// Get the first visible floor below the object for shadows
+// shadowslope is filled with the floor's slope, if provided
+//
+fixed_t R_GetShadowZ(mobj_t *thing, pslope_t **shadowslope)
 {
-	vissprite_t *shadow;
-	patch_t *patch;
-	fixed_t xscale, yscale, shadowxscale, shadowyscale, shadowskew, x1, x2;
-	INT32 light = 0;
-	fixed_t scalemul; UINT8 trans;
-	fixed_t floordiff;
-	fixed_t floorz;
-	pslope_t *floorslope;
-
-	// Get floorz as the first floor below the object that's visible
-	floorz = (vis->heightsec != -1) ? sectors[vis->heightsec].floorheight : thing->floorz;
-	floorslope = (vis->heightsec != -1) ? NULL : thing->standingslope;
+	fixed_t z, floorz = INT32_MIN;
+	pslope_t *slope, *floorslope = NULL;
+	msecnode_t *node;
+	sector_t *sector;
+	ffloor_t *rover;
 
+	for (node = thing->touching_sectorlist; node; node = node->m_sectorlist_next)
 	{
-		boolean original = true;
-		fixed_t z;
+		sector = node->m_sector;
+
+		slope = (sector->heightsec != -1) ? NULL : sector->f_slope;
+		z = slope ? P_GetZAt(slope, thing->x, thing->y) : (
+			(sector->heightsec != -1) ? sectors[sector->heightsec].floorheight : sector->floorheight
+		);
 
-		if (vis->sector->ffloors)
+		if (z < thing->z+thing->height/2 && z > floorz)
 		{
-			ffloor_t *rover = vis->sector->ffloors;
+			floorz = z;
+			floorslope = slope;
+		}
 
-			for (; rover; rover = rover->next)
+		if (sector->ffloors)
+			for (rover = sector->ffloors; rover; rover = rover->next)
 			{
 				if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_RENDERPLANES) || (rover->alpha < 90 && !(rover->flags & FF_SWIMMABLE)))
 					continue;
 
 				z = *rover->t_slope ? P_GetZAt(*rover->t_slope, thing->x, thing->y) : *rover->topheight;
-				if (z < thing->z+thing->height/3 && z > floorz)
+				if (z < thing->z+thing->height/2 && z > floorz)
 				{
 					floorz = z;
 					floorslope = *rover->t_slope;
-					original = false;
-				}
-				else if (original && (*rover->t_slope) && z < thing->z+thing->height/3 && z > floorz - FixedMul(abs((*rover->t_slope)->zdelta), thing->radius*2))
-				{
-					// Guesstimated to be a usable floor. This is here to handle floorslope of non-grounded things, I guess.
-					floorz = z;
-					floorslope = *rover->t_slope;
-					original = false;
 				}
 			}
-		}
+	}
 
-		if (original && vis->sector->f_slope)
-		{
-			z = P_GetZAt(vis->sector->f_slope, thing->x, thing->y);
-			if (z < thing->z+thing->height/3 && z > floorz - FixedMul(abs(vis->sector->f_slope->zdelta), thing->radius*2))
+	if (thing->floorz > floorz + (!floorslope ? 0 : FixedMul(abs(floorslope->zdelta), thing->radius*3/2)))
+	{
+		floorz = thing->floorz;
+		floorslope = NULL;
+	}
+
+#if 0 // Unfortunately, this drops CEZ2 down to sub-17 FPS on my i7.
+//#ifdef POLYOBJECTS
+	// Check polyobjects and see if floorz needs to be altered, for rings only because they don't update floorz
+	if (thing->type == MT_RING)
+	{
+		INT32 xl, xh, yl, yh, bx, by;
+
+		xl = (unsigned)(thing->x - thing->radius - bmaporgx)>>MAPBLOCKSHIFT;
+		xh = (unsigned)(thing->x + thing->radius - bmaporgx)>>MAPBLOCKSHIFT;
+		yl = (unsigned)(thing->y - thing->radius - bmaporgy)>>MAPBLOCKSHIFT;
+		yh = (unsigned)(thing->y + thing->radius - bmaporgy)>>MAPBLOCKSHIFT;
+
+		BMBOUNDFIX(xl, xh, yl, yh);
+
+		validcount++;
+
+		for (by = yl; by <= yh; by++)
+			for (bx = xl; bx <= xh; bx++)
 			{
-				floorz = z;
-				floorslope = vis->sector->f_slope;
+				INT32 offset;
+				polymaplink_t *plink; // haleyjd 02/22/06
+
+				if (bx < 0 || by < 0 || bx >= bmapwidth || by >= bmapheight)
+					continue;
+
+				offset = by*bmapwidth + bx;
+
+				// haleyjd 02/22/06: consider polyobject lines
+				plink = polyblocklinks[offset];
+
+				while (plink)
+				{
+					polyobj_t *po = plink->po;
+
+					if (po->validcount != validcount) // if polyobj hasn't been checked
+					{
+						po->validcount = validcount;
+
+						if (!P_MobjInsidePolyobj(po, thing) || !(po->flags & POF_RENDERPLANES))
+						{
+							plink = (polymaplink_t *)(plink->link.next);
+							continue;
+						}
+
+						// We're inside it! Yess...
+						z = po->lines[0]->backsector->ceilingheight;
+
+						if (z < thing->z+thing->height/2 && z > floorz)
+						{
+							floorz = z;
+							floorslope = NULL;
+						}
+					}
+					plink = (polymaplink_t *)(plink->link.next);
+				}
 			}
-		}
 	}
+#endif
+
+	if (shadowslope != NULL)
+		*shadowslope = floorslope;
+
+	return floorz;
+}
+
+static void R_ProjectDropShadow(mobj_t *thing, vissprite_t *vis, fixed_t tx, fixed_t tz)
+{
+	vissprite_t *shadow;
+	patch_t *patch;
+	fixed_t xscale, yscale, shadowxscale, shadowyscale, shadowskew, x1, x2;
+	INT32 light = 0;
+	fixed_t scalemul; UINT8 trans;
+	fixed_t floordiff;
+	fixed_t floorz;
+	pslope_t *floorslope;
 
+	floorz = R_GetShadowZ(thing, &floorslope);
 
 	if (abs(floorz-viewz)/tz > 4) return; // Prevent stretchy shadows and possible crashes
 
diff --git a/src/r_things.h b/src/r_things.h
index 12f0008eb0..5649b226b8 100644
--- a/src/r_things.h
+++ b/src/r_things.h
@@ -55,6 +55,8 @@ void R_DrawFlippedMaskedColumn(column_t *column, INT32 texheight);
 //     (only sprites from namelist are added or replaced)
 void R_AddSpriteDefs(UINT16 wadnum);
 
+fixed_t R_GetShadowZ(mobj_t *thing, pslope_t **shadowslope);
+
 //SoM: 6/5/2000: Light sprites correctly!
 void R_AddSprites(sector_t *sec, INT32 lightlevel);
 void R_InitSprites(void);
-- 
GitLab