From 6aa5a03c470f7a0ee54459b3a9263b771626b8c4 Mon Sep 17 00:00:00 2001
From: vortex <vortex@d7cf8633-e32d-0410-b094-e92efae38249>
Date: Wed, 13 Oct 2010 20:33:30 +0000
Subject: [PATCH] bring old R_Shadow_ScissorForBBox code (new code still there,
 commented out), since new code is broken on ATI cards, a temporary solution

git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@10527 d7cf8633-e32d-0410-b094-e92efae38249
---
 r_shadow.c | 155 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 154 insertions(+), 1 deletion(-)

diff --git a/r_shadow.c b/r_shadow.c
index fe060e00..6670fab9 100644
--- a/r_shadow.c
+++ b/r_shadow.c
@@ -2265,8 +2265,161 @@ void R_Shadow_RenderMode_End(void)
 	r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
 }
 
+int bboxedges[12][2] =
+{
+	// top
+	{0, 1}, // +X
+	{0, 2}, // +Y
+	{1, 3}, // Y, +X
+	{2, 3}, // X, +Y
+	// bottom
+	{4, 5}, // +X
+	{4, 6}, // +Y
+	{5, 7}, // Y, +X
+	{6, 7}, // X, +Y
+	// verticals
+	{0, 4}, // +Z
+	{1, 5}, // X, +Z
+	{2, 6}, // Y, +Z
+	{3, 7}, // XY, +Z
+};
+
 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
 {
+	int i, ix1, iy1, ix2, iy2;
+	float x1, y1, x2, y2;
+	vec4_t v, v2;
+	float vertex[20][3];
+	int j, k;
+	vec4_t plane4f;
+	int numvertices;
+	float corner[8][4];
+	float dist[8];
+	int sign[8];
+	float f;
+
+	r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
+	r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
+	r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
+	r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
+
+	if (!r_shadow_scissor.integer)
+		return false;
+
+	// if view is inside the light box, just say yes it's visible
+	if (BoxesOverlap(r_refdef.view.origin, r_refdef.view.origin, mins, maxs))
+		return false;
+
+	x1 = y1 = x2 = y2 = 0;
+
+	// transform all corners that are infront of the nearclip plane
+	VectorNegate(r_refdef.view.frustum[4].normal, plane4f);
+	plane4f[3] = r_refdef.view.frustum[4].dist;
+	numvertices = 0;
+	for (i = 0;i < 8;i++)
+	{
+		Vector4Set(corner[i], (i & 1) ? maxs[0] : mins[0], (i & 2) ? maxs[1] : mins[1], (i & 4) ? maxs[2] : mins[2], 1);
+		dist[i] = DotProduct4(corner[i], plane4f);
+		sign[i] = dist[i] > 0;
+		if (!sign[i])
+		{
+			VectorCopy(corner[i], vertex[numvertices]);
+			numvertices++;
+		}
+	}
+	// if some points are behind the nearclip, add clipped edge points to make
+	// sure that the scissor boundary is complete
+	if (numvertices > 0 && numvertices < 8)
+	{
+		// add clipped edge points
+		for (i = 0;i < 12;i++)
+		{
+			j = bboxedges[i][0];
+			k = bboxedges[i][1];
+			if (sign[j] != sign[k])
+			{
+				f = dist[j] / (dist[j] - dist[k]);
+				VectorLerp(corner[j], f, corner[k], vertex[numvertices]);
+				numvertices++;
+			}
+		}
+	}
+
+	// if we have no points to check, the light is behind the view plane
+	if (!numvertices)
+		return true;
+
+	// if we have some points to transform, check what screen area is covered
+	x1 = y1 = x2 = y2 = 0;
+	v[3] = 1.0f;
+	//Con_Printf("%i vertices to transform...\n", numvertices);
+	for (i = 0;i < numvertices;i++)
+	{
+		VectorCopy(vertex[i], v);
+		R_Viewport_TransformToScreen(&r_refdef.view.viewport, v, v2);
+		//Con_Printf("%.3f %.3f %.3f %.3f transformed to %.3f %.3f %.3f %.3f\n", v[0], v[1], v[2], v[3], v2[0], v2[1], v2[2], v2[3]);
+		if (i)
+		{
+			if (x1 > v2[0]) x1 = v2[0];
+			if (x2 < v2[0]) x2 = v2[0];
+			if (y1 > v2[1]) y1 = v2[1];
+			if (y2 < v2[1]) y2 = v2[1];
+		}
+		else
+		{
+			x1 = x2 = v2[0];
+			y1 = y2 = v2[1];
+		}
+	}
+
+	// now convert the scissor rectangle to integer screen coordinates
+	ix1 = (int)(x1 - 1.0f);
+	//iy1 = vid.height - (int)(y2 - 1.0f);
+	//iy1 = r_refdef.view.viewport.width + 2 * r_refdef.view.viewport.x - (int)(y2 - 1.0f);
+	iy1 = (int)(y1 - 1.0f);
+	ix2 = (int)(x2 + 1.0f);
+	//iy2 = vid.height - (int)(y1 + 1.0f);
+	//iy2 = r_refdef.view.viewport.height + 2 * r_refdef.view.viewport.y - (int)(y1 + 1.0f);
+	iy2 = (int)(y2 + 1.0f);
+	//Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
+
+	// clamp it to the screen
+	if (ix1 < r_refdef.view.viewport.x) ix1 = r_refdef.view.viewport.x;
+	if (iy1 < r_refdef.view.viewport.y) iy1 = r_refdef.view.viewport.y;
+	if (ix2 > r_refdef.view.viewport.x + r_refdef.view.viewport.width) ix2 = r_refdef.view.viewport.x + r_refdef.view.viewport.width;
+	if (iy2 > r_refdef.view.viewport.y + r_refdef.view.viewport.height) iy2 = r_refdef.view.viewport.y + r_refdef.view.viewport.height;
+
+	// if it is inside out, it's not visible
+	if (ix2 <= ix1 || iy2 <= iy1)
+		return true;
+
+	// the light area is visible, set up the scissor rectangle
+	r_shadow_lightscissor[0] = ix1;
+	r_shadow_lightscissor[1] = iy1;
+	r_shadow_lightscissor[2] = ix2 - ix1;
+	r_shadow_lightscissor[3] = iy2 - iy1;
+
+	// D3D Y coordinate is top to bottom, OpenGL is bottom to top, fix the D3D one
+	switch(vid.renderpath)
+	{
+	case RENDERPATH_D3D9:
+	case RENDERPATH_D3D10:
+	case RENDERPATH_D3D11:
+		r_shadow_lightscissor[1] = vid.height - r_shadow_lightscissor[1] - r_shadow_lightscissor[3];
+		break;
+	case RENDERPATH_GL11:
+	case RENDERPATH_GL13:
+	case RENDERPATH_GL20:
+	case RENDERPATH_CGGL:
+		break;
+	}
+
+	r_refdef.stats.lights_scissored++;
+	return false;
+
+	/*
+	VorteX: originally written by divVerent, that code is broken on ATI
+
 	if (!r_shadow_scissor.integer)
 	{
 		r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
@@ -2275,7 +2428,6 @@ qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
 		r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
 		return false;
 	}
-
 	if(R_ScissorForBBox(mins, maxs, r_shadow_lightscissor))
 	{
 		if(r_shadow_lightscissor[0] != r_refdef.view.viewport.x
@@ -2287,6 +2439,7 @@ qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
 	}
 	else
 		return true; // invisible
+	*/
 }
 
 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, const float *diffusecolor, const float *ambientcolor)
-- 
2.39.5