diff --git a/src/hardware/hw_glob.h b/src/hardware/hw_glob.h
index 94eef1d3e46e95f825f7ac89088cbb6674636225..5d1a81d4f4318826e3ce9c3b8d176a3b2baa00f5 100644
--- a/src/hardware/hw_glob.h
+++ b/src/hardware/hw_glob.h
@@ -78,6 +78,7 @@ typedef struct gr_vissprite_s
    //Hurdler: 25/04/2000: now support colormap in hardware mode
 	UINT8 *colormap;
 	INT32 dispoffset; // copy of info->dispoffset, affects ordering but not drawing
+	float z1, z2;
 } gr_vissprite_t;
 
 // --------
diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c
index 4cfbc59e9aeaba473008bbe31eafdefe9e53b3f0..92c3639435598ba39d11631e0169ef8a97d163e5 100644
--- a/src/hardware/hw_main.c
+++ b/src/hardware/hw_main.c
@@ -4229,6 +4229,7 @@ static void HWR_DrawSprite(gr_vissprite_t *spr)
 	GLPatch_t *gpatch; // sprite patch converted to hardware
 	FSurfaceInfo Surf;
 	const boolean hires = (spr->mobj && spr->mobj->skin && ((skin_t *)spr->mobj->skin)->flags & SF_HIRES);
+	//const boolean papersprite = (spr->mobj && (spr->mobj->frame & FF_PAPERSPRITE));
 	if (spr->mobj)
 		this_scale = FIXED_TO_FLOAT(spr->mobj->scale);
 	if (hires)
@@ -4272,7 +4273,8 @@ static void HWR_DrawSprite(gr_vissprite_t *spr)
 
 	// make a wall polygon (with 2 triangles), using the floor/ceiling heights,
 	// and the 2d map coords of start/end vertices
-	wallVerts[0].z = wallVerts[1].z = wallVerts[2].z = wallVerts[3].z = spr->tz;
+	wallVerts[0].z = wallVerts[3].z = spr->z1;
+	wallVerts[2].z = wallVerts[1].z = spr->z2;
 
 	// transform
 	wv = wallVerts;
@@ -5068,6 +5070,10 @@ static void HWR_ProjectSprite(mobj_t *thing)
 
 	angle_t ang;
 	INT32 heightsec, phs;
+	const boolean papersprite = (thing->frame & FF_PAPERSPRITE);
+	float offset;
+	float ang_scale = 1.0f, ang_scalez = 0.0f;
+	float z1, z2;
 
 	if (!thing)
 		return;
@@ -5082,7 +5088,7 @@ static void HWR_ProjectSprite(mobj_t *thing)
 	tz = (tr_x * gr_viewcos) + (tr_y * gr_viewsin);
 
 	// thing is behind view plane?
-	if (tz < ZCLIP_PLANE && (!cv_grmd2.value || md2_models[thing->sprite].notfound == true)) //Yellow: Only MD2's dont disappear
+	if (tz < ZCLIP_PLANE && !papersprite && (!cv_grmd2.value || md2_models[thing->sprite].notfound == true)) //Yellow: Only MD2's dont disappear
 		return;
 
 	tx = (tr_x * gr_viewsin) - (tr_y * gr_viewcos);
@@ -5120,6 +5126,27 @@ static void HWR_ProjectSprite(mobj_t *thing)
 		I_Error("sprframes NULL for sprite %d\n", thing->sprite);
 #endif
 
+	if (papersprite)
+	{
+		// Use the actual view angle, rather than the angle formed
+		// between the view point and the thing
+		// this makes sure paper sprites always appear at the right angle!
+		// Note: DO NOT do this in software mode version, it actually
+		// makes papersprites look WORSE there (I know, I've tried)
+		// Monster Iestyn - 13/05/17
+		ang = dup_viewangle - thing->angle;
+		ang_scale = FIXED_TO_FLOAT(FINESINE(ang>>ANGLETOFINESHIFT));
+		ang_scalez = FIXED_TO_FLOAT(FINECOSINE(ang>>ANGLETOFINESHIFT));
+
+		if (ang_scale < 0)
+		{
+			ang_scale = -ang_scale;
+			ang_scalez = -ang_scalez;
+		}
+	}
+	else if (sprframe->rotate != SRF_SINGLE)
+		ang = R_PointToAngle (thing->x, thing->y) - thing->angle;
+
 	if (sprframe->rotate == SRF_SINGLE)
 	{
 		// use single rotation for all views
@@ -5130,8 +5157,6 @@ static void HWR_ProjectSprite(mobj_t *thing)
 	else
 	{
 		// choose a different rotation based on player view
-		ang = R_PointToAngle (thing->x, thing->y) - thing->angle;
-
 		if ((sprframe->rotate & SRF_RIGHT) && (ang < ANGLE_180)) // See from right
 			rot = 6; // F7 slot
 		else if ((sprframe->rotate & SRF_LEFT) && (ang >= ANGLE_180)) // See from left
@@ -5149,9 +5174,12 @@ static void HWR_ProjectSprite(mobj_t *thing)
 
 	// calculate edges of the shape
 	if (flip)
-		tx -= FIXED_TO_FLOAT(spritecachedinfo[lumpoff].width - spritecachedinfo[lumpoff].offset) * this_scale;
+		offset = FIXED_TO_FLOAT(spritecachedinfo[lumpoff].width - spritecachedinfo[lumpoff].offset) * this_scale;
 	else
-		tx -= FIXED_TO_FLOAT(spritecachedinfo[lumpoff].offset) * this_scale;
+		offset = FIXED_TO_FLOAT(spritecachedinfo[lumpoff].offset) * this_scale;
+
+	z1 = tz - (offset * ang_scalez);
+	tx -= offset * ang_scale;
 
 	// project x
 	x1 = gr_windowcenterx + (tx * gr_centerx / tz);
@@ -5162,7 +5190,14 @@ static void HWR_ProjectSprite(mobj_t *thing)
 
 	x1 = tx;
 
-	tx += FIXED_TO_FLOAT(spritecachedinfo[lumpoff].width) * this_scale;
+	offset = FIXED_TO_FLOAT(spritecachedinfo[lumpoff].width) * this_scale;
+
+	z2 = z1 + (offset * ang_scalez);
+	tx += offset * ang_scale;
+
+	if (papersprite && max(z1, z2) < ZCLIP_PLANE)
+		return;
+
 	x2 = gr_windowcenterx + (tx * gr_centerx / tz);
 
 	if (vflip)
@@ -5211,6 +5246,8 @@ static void HWR_ProjectSprite(mobj_t *thing)
 	vis->patchlumpnum = sprframe->lumppat[rot];
 	vis->flip = flip;
 	vis->mobj = thing;
+	vis->z1 = z1;
+	vis->z2 = z2;
 
 	//Hurdler: 25/04/2000: now support colormap in hardware mode
 	if ((vis->mobj->flags & MF_BOSS) && (vis->mobj->flags2 & MF2_FRET) && (leveltime & 1)) // Bosses "flash"