From: havoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Date: Wed, 20 Apr 2005 11:16:36 +0000 (+0000)
Subject: reimplemented rtlight portal culling (used for compiled rtlights, and can be used... 
X-Git-Tag: xonotic-v0.1.0preview~4975
X-Git-Url: https://git.rm.cloudns.org/?a=commitdiff_plain;h=a16877b21a3d5ddec652ce9ed030e7f32c3fc0e7;p=xonotic%2Fdarkplaces.git

reimplemented rtlight portal culling (used for compiled rtlights, and can be used for dlights but that is often a major speed loss)
added additional bounding box and triangle facing checks to rtlight compilation, triangles outside the box are no longer drawn


git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@5204 d7cf8633-e32d-0410-b094-e92efae38249
---

diff --git a/gl_rsurf.c b/gl_rsurf.c
index 16e50846..13b197a4 100644
--- a/gl_rsurf.c
+++ b/gl_rsurf.c
@@ -21,6 +21,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
 #include "quakedef.h"
 #include "r_shadow.h"
+#include "portals.h"
 
 #define MAX_LIGHTMAP_SIZE 256
 
@@ -1771,7 +1772,7 @@ void R_Q1BSP_RecursiveGetLightInfo(r_q1bsp_getlightinfo_t *info, mnode_t *node)
 							v[0] = info->model->brush.shadowmesh->vertex3f + e[0] * 3;
 							v[1] = info->model->brush.shadowmesh->vertex3f + e[1] * 3;
 							v[2] = info->model->brush.shadowmesh->vertex3f + e[2] * 3;
-							if (info->lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0])) && info->lightmins[0] < max(v[0][0], max(v[1][0], v[2][0])) && info->lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1])) && info->lightmins[1] < max(v[0][1], max(v[1][1], v[2][1])) && info->lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2])) && info->lightmins[2] < max(v[0][2], max(v[1][2], v[2][2])))
+							if (PointInfrontOfTriangle(info->relativelightorigin, v[0], v[1], v[2]) && info->lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0])) && info->lightmins[0] < max(v[0][0], max(v[1][0], v[2][0])) && info->lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1])) && info->lightmins[1] < max(v[0][1], max(v[1][1], v[2][1])) && info->lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2])) && info->lightmins[2] < max(v[0][2], max(v[1][2], v[2][2])))
 							{
 								SETPVSBIT(info->outsurfacepvs, surfaceindex);
 								info->outsurfacelist[info->outnumsurfaces++] = surfaceindex;
@@ -1820,25 +1821,29 @@ void R_Q1BSP_GetLightInfo(entity_render_t *ent, vec3_t relativelightorigin, floa
 	else
 		info.pvs = NULL;
 	R_UpdateAllTextureInfo(ent);
-	/*
 	if (r_shadow_compilingrtlight)
 	{
-		Portal_Visibility(info.model, info.relativelightorigin, leafmark, surfacemark, const mplane_t *frustumplanes, int numfrustumplanes, int exact, const float *boxmins, const float *boxmaxs, float *updateleafsmins, float *updateleafsmaxs)
+		// use portal recursion for exact light volume culling, and exact surface checking
+		Portal_Visibility(info.model, info.relativelightorigin, info.outleaflist, info.outleafpvs, &info.outnumleafs, info.outsurfacelist, info.outsurfacepvs, &info.outnumsurfaces, NULL, 0, true, info.lightmins, info.lightmaxs, info.outmins, info.outmaxs);
+	}
+	else if (r_shadow_realtime_dlight_portalculling.integer)
+	{
+		// use portal recursion for exact light volume culling, but not the expensive exact surface checking
+		Portal_Visibility(info.model, info.relativelightorigin, info.outleaflist, info.outleafpvs, &info.outnumleafs, info.outsurfacelist, info.outsurfacepvs, &info.outnumsurfaces, NULL, 0, r_shadow_realtime_dlight_portalculling.integer >= 2, info.lightmins, info.lightmaxs, info.outmins, info.outmaxs);
 	}
 	else
-	*/
 	{
 		// use BSP recursion as lights are often small
 		R_Q1BSP_RecursiveGetLightInfo(&info, info.model->brush.data_nodes);
 	}
 
 	// limit combined leaf box to light boundaries
-	outmins[0] = max(info.outmins[0], info.lightmins[0]);
-	outmins[1] = max(info.outmins[1], info.lightmins[1]);
-	outmins[2] = max(info.outmins[2], info.lightmins[2]);
-	outmaxs[0] = min(info.outmaxs[0], info.lightmaxs[0]);
-	outmaxs[1] = min(info.outmaxs[1], info.lightmaxs[1]);
-	outmaxs[2] = min(info.outmaxs[2], info.lightmaxs[2]);
+	outmins[0] = max(info.outmins[0] - 1, info.lightmins[0]);
+	outmins[1] = max(info.outmins[1] - 1, info.lightmins[1]);
+	outmins[2] = max(info.outmins[2] - 1, info.lightmins[2]);
+	outmaxs[0] = min(info.outmaxs[0] + 1, info.lightmaxs[0]);
+	outmaxs[1] = min(info.outmaxs[1] + 1, info.lightmaxs[1]);
+	outmaxs[2] = min(info.outmaxs[2] + 1, info.lightmaxs[2]);
 
 	*outnumleafspointer = info.outnumleafs;
 	*outnumsurfacespointer = info.outnumsurfaces;
@@ -1889,7 +1894,27 @@ void R_Q1BSP_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, vec3_t
 				// if compiling an rtlight, capture the mesh
 				t = surface->texture;
 				if ((t->basematerialflags & (MATERIALFLAG_WALL | MATERIALFLAG_TRANSPARENT)) == MATERIALFLAG_WALL)
+				{
+#if 1
+					int tri;
+					int *e;
+					float *lightmins, *lightmaxs, *v[3], *vertex3f;
+					e = surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle;
+					vertex3f = surface->groupmesh->data_vertex3f;
+					lightmins = r_shadow_compilingrtlight->cullmins;
+					lightmaxs = r_shadow_compilingrtlight->cullmaxs;
+					for (tri = 0;tri < surface->num_triangles;tri++, e += 3)
+					{
+						v[0] = vertex3f + e[0] * 3;
+						v[1] = vertex3f + e[1] * 3;
+						v[2] = vertex3f + e[2] * 3;
+						if (PointInfrontOfTriangle(relativelightorigin, v[0], v[1], v[2]) && lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0])) && lightmins[0] < max(v[0][0], max(v[1][0], v[2][0])) && lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1])) && lightmins[1] < max(v[0][1], max(v[1][1], v[2][1])) && lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2])) && lightmins[2] < max(v[0][2], max(v[1][2], v[2][2])))
+							Mod_ShadowMesh_AddMesh(r_shadow_mempool, r_shadow_compilingrtlight->static_meshchain_light, surface->texture->skin.base, surface->texture->skin.gloss, surface->texture->skin.nmap, surface->groupmesh->data_vertex3f, surface->groupmesh->data_svector3f, surface->groupmesh->data_tvector3f, surface->groupmesh->data_normal3f, surface->groupmesh->data_texcoordtexture2f, 1, e);
+					}
+#else
 					Mod_ShadowMesh_AddMesh(r_shadow_mempool, r_shadow_compilingrtlight->static_meshchain_light, surface->texture->skin.base, surface->texture->skin.gloss, surface->texture->skin.nmap, surface->groupmesh->data_vertex3f, surface->groupmesh->data_svector3f, surface->groupmesh->data_tvector3f, surface->groupmesh->data_normal3f, surface->groupmesh->data_texcoordtexture2f, surface->num_triangles, (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle));
+#endif
+				}
 			}
 			else if (ent != r_refdef.worldentity || r_worldsurfacevisible[surfacelist[surfacelistindex]])
 			{
diff --git a/portals.c b/portals.c
index 4f62b17e..d3df4481 100644
--- a/portals.c
+++ b/portals.c
@@ -325,8 +325,12 @@ typedef struct portalrecursioninfo_s
 	int numfrustumplanes;
 	vec3_t boxmins;
 	vec3_t boxmaxs;
-	qbyte *surfacemark;
-	qbyte *leafmark;
+	int numsurfaces;
+	int *surfacelist;
+	qbyte *surfacepvs;
+	int numleafs;
+	int *leaflist;
+	qbyte *leafpvs;
 	model_t *model;
 	vec3_t eye;
 	float *updateleafsmins;
@@ -337,35 +341,39 @@ portalrecursioninfo_t;
 void Portal_RecursiveFlow_ExactLeafFaces(portalrecursioninfo_t *info, int *mark, int numleafsurfaces, int firstclipplane, int numclipplanes)
 {
 	int i, j, *elements;
+	float *v[3], *vertex3f;
 	vec3_t trimins, trimaxs;
 	msurface_t *surface;
 	for (i = 0;i < numleafsurfaces;i++, mark++)
 	{
-		if (!info->surfacemark[*mark])
+		if (!CHECKPVSBIT(info->surfacepvs, *mark))
 		{
-			// FIXME?  this assumes q1bsp polygon surfaces
 			surface = info->model->brush.data_surfaces + *mark;
+			if (!BoxesOverlap(surface->mins, surface->maxs, info->boxmins, info->boxmaxs))
+				continue;
+			vertex3f = surface->groupmesh->data_vertex3f;
 			for (j = 0, elements = (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle);j < surface->num_triangles;j++, elements += 3)
 			{
-				VectorCopy((surface->groupmesh->data_vertex3f + elements[0] * 3), trianglepoints[0]);
-				VectorCopy((surface->groupmesh->data_vertex3f + elements[1] * 3), trianglepoints[1]);
-				VectorCopy((surface->groupmesh->data_vertex3f + elements[2] * 3), trianglepoints[2]);
-				if (PointInfrontOfTriangle(info->eye, trianglepoints[0], trianglepoints[1], trianglepoints[2]))
+				v[0] = vertex3f + elements[0] * 3;
+				v[1] = vertex3f + elements[1] * 3;
+				v[2] = vertex3f + elements[2] * 3;
+				if (PointInfrontOfTriangle(info->eye, v[0], v[1], v[2]))
 				{
-					trimins[0] = min(trianglepoints[0][0], min(trianglepoints[1][0], trianglepoints[2][0]));
-					trimaxs[0] = max(trianglepoints[0][0], max(trianglepoints[1][0], trianglepoints[2][0]));
-					trimins[1] = min(trianglepoints[0][1], min(trianglepoints[1][1], trianglepoints[2][1]));
-					trimaxs[1] = max(trianglepoints[0][1], max(trianglepoints[1][1], trianglepoints[2][1]));
-					trimins[2] = min(trianglepoints[0][2], min(trianglepoints[1][2], trianglepoints[2][2]));
-					trimaxs[2] = max(trianglepoints[0][2], max(trianglepoints[1][2], trianglepoints[2][2]));
+					trimins[0] = min(v[0][0], min(v[1][0], v[2][0]));
+					trimaxs[0] = max(v[0][0], max(v[1][0], v[2][0]));
+					trimins[1] = min(v[0][1], min(v[1][1], v[2][1]));
+					trimaxs[1] = max(v[0][1], max(v[1][1], v[2][1]));
+					trimins[2] = min(v[0][2], min(v[1][2], v[2][2]));
+					trimaxs[2] = max(v[0][2], max(v[1][2], v[2][2]));
 					if (BoxesOverlap(trimins, trimaxs, info->boxmins, info->boxmaxs))
-						if (Portal_PortalThroughPortalPlanes(&portalplanes[firstclipplane], numclipplanes, trianglepoints[0], 3, &portaltemppoints2[0][0], 256) >= 3)
+						if (Portal_PortalThroughPortalPlanes(&portalplanes[firstclipplane], numclipplanes, v[0], 3, &portaltemppoints2[0][0], 256) >= 3)
 							break;
 				}
 			}
 			if (j == surface->num_triangles)
 				continue;
-			info->surfacemark[*mark] = true;
+			SETPVSBIT(info->surfacepvs, *mark);
+			info->surfacelist[info->numsurfaces++] = *mark;
 		}
 	}
 }
@@ -384,17 +392,38 @@ void Portal_RecursiveFlow (portalrecursioninfo_t *info, mleaf_t *leaf, int first
 		if (info->updateleafsmaxs && info->updateleafsmaxs[i] < leaf->maxs[i]) info->updateleafsmaxs[i] = leaf->maxs[i];
 	}
 
-	if (info->leafmark)
-		info->leafmark[leaf - info->model->brush.data_leafs] = true;
+
+	if (info->leafpvs)
+	{
+		int leafindex = leaf - info->model->brush.data_leafs;
+		if (!CHECKPVSBIT(info->leafpvs, leafindex))
+		{
+			SETPVSBIT(info->leafpvs, leafindex);
+			info->leaflist[info->numleafs++] = leafindex;
+		}
+	}
 
 	// mark surfaces in leaf that can be seen through portal
-	if (leaf->numleafsurfaces && info->surfacemark)
+	if (leaf->numleafsurfaces && info->surfacepvs)
 	{
 		if (info->exact)
 			Portal_RecursiveFlow_ExactLeafFaces(info, leaf->firstleafsurface, leaf->numleafsurfaces, firstclipplane, numclipplanes);
 		else
+		{
 			for (i = 0;i < leaf->numleafsurfaces;i++)
-				info->surfacemark[leaf->firstleafsurface[i]] = true;
+			{
+				int surfaceindex = leaf->firstleafsurface[i];
+				if (!CHECKPVSBIT(info->surfacepvs, surfaceindex))
+				{
+					msurface_t *surface = info->model->brush.data_surfaces + surfaceindex;
+					if (BoxesOverlap(surface->mins, surface->maxs, info->boxmins, info->boxmaxs))
+					{
+						SETPVSBIT(info->surfacepvs, surfaceindex);
+						info->surfacelist[info->numsurfaces++] = surfaceindex;
+					}
+				}
+			}
+		}
 	}
 
 	// follow portals into other leafs
@@ -459,7 +488,7 @@ void Portal_RecursiveFindLeafForFlow(portalrecursioninfo_t *info, mnode_t *node)
 	}
 }
 
-void Portal_Visibility(model_t *model, const vec3_t eye, qbyte *leafmark, qbyte *surfacemark, const mplane_t *frustumplanes, int numfrustumplanes, int exact, const float *boxmins, const float *boxmaxs, float *updateleafsmins, float *updateleafsmaxs)
+void Portal_Visibility(model_t *model, const vec3_t eye, int *leaflist, qbyte *leafpvs, int *numleafspointer, int *surfacelist, qbyte *surfacepvs, int *numsurfacespointer, const mplane_t *frustumplanes, int numfrustumplanes, int exact, const float *boxmins, const float *boxmaxs, float *updateleafsmins, float *updateleafsmaxs)
 {
 	int i;
 	portalrecursioninfo_t info;
@@ -492,8 +521,12 @@ void Portal_Visibility(model_t *model, const vec3_t eye, qbyte *leafmark, qbyte
 	VectorCopy(boxmins, info.boxmins);
 	VectorCopy(boxmaxs, info.boxmaxs);
 	info.exact = exact;
-	info.surfacemark = surfacemark;
-	info.leafmark = leafmark;
+	info.numsurfaces = 0;
+	info.surfacelist = surfacelist;
+	info.surfacepvs = surfacepvs;
+	info.numleafs = 0;
+	info.leaflist = leaflist;
+	info.leafpvs = leafpvs;
 	info.model = model;
 	VectorCopy(eye, info.eye);
 	info.numfrustumplanes = numfrustumplanes;
@@ -506,5 +539,9 @@ void Portal_Visibility(model_t *model, const vec3_t eye, qbyte *leafmark, qbyte
 		Con_Printf("Portal_RecursiveFlow: ran out of %d plane stack when recursing through portals\n", MAXRECURSIVEPORTALPLANES);
 	if (ranoutofportals)
 		Con_Printf("Portal_RecursiveFlow: ran out of %d portal stack when recursing through portals\n", MAXRECURSIVEPORTALS);
+	if (numsurfacespointer)
+		*numsurfacespointer = info.numsurfaces;
+	if (numleafspointer)
+		*numleafspointer = info.numleafs;
 }
 
diff --git a/portals.h b/portals.h
index 6e96ce01..416e431e 100644
--- a/portals.h
+++ b/portals.h
@@ -4,7 +4,7 @@
 
 int Portal_CheckPolygon(model_t *model, vec3_t eye, float *polypoints, int numpoints);
 int Portal_CheckBox(model_t *model, vec3_t eye, vec3_t a, vec3_t b);
-void Portal_Visibility(model_t *model, const vec3_t eye, qbyte *leafmark, qbyte *surfacemark, const mplane_t *frustumplanes, int numfrustumplanes, int exact, const float *boxmins, const float *boxmaxs, float *updateleafsmins, float *updateleafsmaxs);
+void Portal_Visibility(model_t *model, const vec3_t eye, int *leaflist, qbyte *leafpvs, int *numleafspointer, int *surfacelist, qbyte *surfacepvs, int *numsurfacespointer, const mplane_t *frustumplanes, int numfrustumplanes, int exact, const float *boxmins, const float *boxmaxs, float *updateleafsmins, float *updateleafsmaxs);
 
 #endif
 
diff --git a/r_shadow.c b/r_shadow.c
index 6edd54d6..379dd078 100644
--- a/r_shadow.c
+++ b/r_shadow.c
@@ -176,6 +176,7 @@ cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1"};
 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "1000000"};
 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1"};
 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "0"};
+cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0"};
 cvar_t r_shadow_realtime_world = {CVAR_SAVE, "r_shadow_realtime_world", "0"};
 cvar_t r_shadow_realtime_world_dlightshadows = {CVAR_SAVE, "r_shadow_realtime_world_dlightshadows", "1"};
 cvar_t r_shadow_realtime_world_lightmaps = {CVAR_SAVE, "r_shadow_realtime_world_lightmaps", "0"};
@@ -560,6 +561,7 @@ void R_Shadow_Help_f(void)
 "r_shadow_projectdistance : shadow volume projection distance\n"
 "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
 "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
+"r_shadow_realtime_dlight_portalculling : work hard to reduce graphics work\n"
 "r_shadow_realtime_world : use high quality world lighting mode\n"
 "r_shadow_realtime_world_dlightshadows : cast shadows from dlights\n"
 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n"
@@ -599,6 +601,7 @@ void R_Shadow_Init(void)
 	Cvar_RegisterVariable(&r_shadow_projectdistance);
 	Cvar_RegisterVariable(&r_shadow_realtime_dlight);
 	Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
+	Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
 	Cvar_RegisterVariable(&r_shadow_realtime_world);
 	Cvar_RegisterVariable(&r_shadow_realtime_world_dlightshadows);
 	Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
diff --git a/r_shadow.h b/r_shadow.h
index 571f81d1..99417461 100644
--- a/r_shadow.h
+++ b/r_shadow.h
@@ -16,6 +16,7 @@ extern cvar_t r_shadow_portallight;
 extern cvar_t r_shadow_projectdistance;
 extern cvar_t r_shadow_realtime_dlight;
 extern cvar_t r_shadow_realtime_dlight_shadows;
+extern cvar_t r_shadow_realtime_dlight_portalculling;
 extern cvar_t r_shadow_realtime_world;
 extern cvar_t r_shadow_realtime_world_dlightshadows;
 extern cvar_t r_shadow_realtime_world_lightmaps;