[iortcw] 232/497: All: Rend2: Better BSP surface merging

Simon McVittie smcv at debian.org
Fri Sep 8 10:36:57 UTC 2017


This is an automated email from the git hooks/post-receive script.

smcv pushed a commit to annotated tag 1.42d
in repository iortcw.

commit f993d35f4ae6fb43480ce854b7511836a96c257d
Author: M4N4T4RMS at gmail.com <M4N4T4RMS at gmail.com@e65d2741-a53d-b2dc-ae96-bb75fa5e4c4a>
Date:   Wed Oct 8 23:41:14 2014 +0000

    All: Rend2: Better BSP surface merging
---
 MP/code/rend2/tr_bsp.c | 612 ++++++++++++++++++-------------------------------
 SP/code/rend2/tr_bsp.c | 611 ++++++++++++++++++------------------------------
 2 files changed, 454 insertions(+), 769 deletions(-)

diff --git a/MP/code/rend2/tr_bsp.c b/MP/code/rend2/tr_bsp.c
index fc1509c..042efdc 100644
--- a/MP/code/rend2/tr_bsp.c
+++ b/MP/code/rend2/tr_bsp.c
@@ -2040,6 +2040,20 @@ static int BSPSurfaceCompare(const void *a, const void *b)
 	else if(aa->cubemapIndex > bb->cubemapIndex)
 		return 1;
 
+	// by leaf
+	if (s_worldData.surfacesViewCount[aa - s_worldData.surfaces] < s_worldData.surfacesViewCount[bb - s_worldData.surfaces])
+		return -1;
+
+	else if (s_worldData.surfacesViewCount[aa - s_worldData.surfaces] > s_worldData.surfacesViewCount[bb - s_worldData.surfaces])
+		return 1;
+
+	// by surface number
+	if (aa < bb)
+		return -1;
+
+	else if (aa > bb)
+		return 1;
+
 
 	return 0;
 }
@@ -2047,33 +2061,20 @@ static int BSPSurfaceCompare(const void *a, const void *b)
 
 static void CopyVert(const srfVert_t * in, srfVert_t * out)
 {
-	int             j;
-
-	for(j = 0; j < 3; j++)
-	{
-		out->xyz[j]       = in->xyz[j];
+	VectorCopy(in->xyz,      out->xyz);
 #ifdef USE_VERT_TANGENT_SPACE
-		out->tangent[j]   = in->tangent[j];
-		//out->bitangent[j] = in->bitangent[j];
+	VectorCopy4(in->tangent, out->tangent);
 #endif
-		out->normal[j]    = in->normal[j];
-		out->lightdir[j]  = in->lightdir[j];
-	}
+	VectorCopy(in->normal,   out->normal);
+	VectorCopy(in->lightdir, out->lightdir);
 
-	out->tangent[3] = in->tangent[3];
-
-	for(j = 0; j < 2; j++)
-	{
-		out->st[j] = in->st[j];
-		out->lightmap[j] = in->lightmap[j];
-	}
+	VectorCopy2(in->st,       out->st);
+	VectorCopy2(in->lightmap, out->lightmap);
 
-	for(j = 0; j < 4; j++)
-	{
-		out->vertexColors[j] = in->vertexColors[j];
-	}
+	VectorCopy4(in->vertexColors, out->vertexColors);
 }
 
+
 /*
 ===============
 R_CreateWorldVBOs
@@ -2097,26 +2098,74 @@ static void R_CreateWorldVBOs(void)
 	IBO_t *ibo;
 
 	int maxVboSize = 4 * 1024 * 1024;
-	int maxIboSize = 4 * 1024 * 1024;
 
 	int             startTime, endTime;
 
 	startTime = ri.Milliseconds();
 
+	// mark surfaces with best matching leaf, using overlapping bounds
+	// using surfaceViewCount[] as leaf number, and surfacesDlightBits[] as coverage * 256
+	for (i = 0; i < s_worldData.numWorldSurfaces; i++)
+	{
+		s_worldData.surfacesViewCount[i] = -1;
+	}
+
+	for (i = 0; i < s_worldData.numWorldSurfaces; i++)
+	{
+		s_worldData.surfacesDlightBits[i] = 0;
+	}
+
+	for (i = s_worldData.numDecisionNodes; i < s_worldData.numnodes; i++)
+	{
+		mnode_t *leaf = s_worldData.nodes + i;
+
+		for (j = leaf->firstmarksurface; j < leaf->firstmarksurface + leaf->nummarksurfaces; j++)
+		{
+			int surfaceNum = s_worldData.marksurfaces[j];
+			msurface_t *surface = s_worldData.surfaces + surfaceNum;
+			float coverage = 1.0f;
+			int iCoverage;
+
+			for (k = 0; k < 3; k++)
+			{
+				float left, right;
+
+				if (leaf->mins[k] > surface->cullinfo.bounds[1][k] || surface->cullinfo.bounds[0][k] > leaf->maxs[k])
+				{
+					coverage = 0.0f;
+					break;
+				}
+
+				left  = MAX(leaf->mins[k], surface->cullinfo.bounds[0][k]);
+				right = MIN(leaf->maxs[k], surface->cullinfo.bounds[1][k]);
+
+				// nudge a bit in case this is an axis aligned wall
+				coverage *= right - left + 1.0f/256.0f;
+			}
+
+			iCoverage = coverage * 256;
+
+			if (iCoverage > s_worldData.surfacesDlightBits[surfaceNum])
+			{
+				s_worldData.surfacesDlightBits[surfaceNum] = iCoverage;
+				s_worldData.surfacesViewCount[surfaceNum] = i - s_worldData.numDecisionNodes;
+			}
+		}
+	}
+
+	for (i = 0; i < s_worldData.numWorldSurfaces; i++)
+	{
+		s_worldData.surfacesDlightBits[i] = 0;
+	}
+
 	// count surfaces
 	numSortedSurfaces = 0;
-	for(surface = &s_worldData.surfaces[0]; surface < &s_worldData.surfaces[s_worldData.numsurfaces]; surface++)
+	for(surface = s_worldData.surfaces; surface < s_worldData.surfaces + s_worldData.numWorldSurfaces; surface++)
 	{
 		srfBspSurface_t *bspSurf;
 		shader_t *shader = surface->shader;
 
-		if (shader->isPortal)
-			continue;
-
-		if (shader->isSky)
-			continue;
-
-		if (ShaderRequiresCPUDeforms(shader))
+		if (shader->isPortal || shader->isSky || ShaderRequiresCPUDeforms(shader))
 			continue;
 
 		// check for this now so we can use srfBspSurface_t* universally in the rest of the function
@@ -2135,18 +2184,12 @@ static void R_CreateWorldVBOs(void)
 	surfacesSorted = ri.Z_Malloc(numSortedSurfaces * sizeof(*surfacesSorted));
 
 	j = 0;
-	for(surface = &s_worldData.surfaces[0]; surface < &s_worldData.surfaces[s_worldData.numsurfaces]; surface++)
+	for(surface = s_worldData.surfaces; surface < s_worldData.surfaces + s_worldData.numWorldSurfaces; surface++)
 	{
 		srfBspSurface_t *bspSurf;
 		shader_t *shader = surface->shader;
 
-		if (shader->isPortal)
-			continue;
-
-		if (shader->isSky)
-			continue;
-
-		if (ShaderRequiresCPUDeforms(shader))
+		if (shader->isPortal || shader->isSky || ShaderRequiresCPUDeforms(shader))
 			continue;
 
 		// check for this now so we can use srfBspSurface_t* universally in the rest of the function
@@ -2164,37 +2207,34 @@ static void R_CreateWorldVBOs(void)
 	qsort(surfacesSorted, numSortedSurfaces, sizeof(*surfacesSorted), BSPSurfaceCompare);
 
 	k = 0;
-	for(firstSurf = lastSurf = surfacesSorted; firstSurf < &surfacesSorted[numSortedSurfaces]; firstSurf = lastSurf)
+	for(firstSurf = lastSurf = surfacesSorted; firstSurf < surfacesSorted + numSortedSurfaces; firstSurf = lastSurf)
 	{
-		int currVboSize, currIboSize;
+		int currVboSize;
 
-		// Find range of surfaces to merge by:
-		// - Collecting a number of surfaces which fit under maxVboSize/maxIboSize, or
-		// - All the surfaces with a single shader which go over maxVboSize/maxIboSize
-		currVboSize = currIboSize = 0;
-		while (currVboSize < maxVboSize && currIboSize < maxIboSize && lastSurf < &surfacesSorted[numSortedSurfaces])
+		// Find range of surfaces to place in a vbo/ibo by:
+		// - Collecting a number of surfaces which fit under maxVboSize, or
+		// - All the surfaces with a single shader which go over maxVboSize
+		currVboSize = 0;
+		while (currVboSize < maxVboSize && lastSurf < surfacesSorted + numSortedSurfaces)
 		{
-			int addVboSize, addIboSize, currShaderIndex;
+			int addVboSize, currShaderIndex;
 
-			addVboSize = addIboSize = 0;
+			addVboSize = 0;
 			currShaderIndex = (*lastSurf)->shader->sortedIndex;
 
-			for(currSurf = lastSurf; currSurf < &surfacesSorted[numSortedSurfaces] && (*currSurf)->shader->sortedIndex == currShaderIndex; currSurf++)
+			for(currSurf = lastSurf; currSurf < surfacesSorted + numSortedSurfaces && (*currSurf)->shader->sortedIndex == currShaderIndex; currSurf++)
 			{
 				srfBspSurface_t *bspSurf = (srfBspSurface_t *) (*currSurf)->data;
 
 				addVboSize += bspSurf->numVerts * sizeof(srfVert_t);
-				addIboSize += bspSurf->numIndexes * sizeof(glIndex_t);
 			}
 
-			if ((currVboSize != 0 && addVboSize + currVboSize > maxVboSize)
-			 || (currIboSize != 0 && addIboSize + currIboSize > maxIboSize))
+			if (currVboSize != 0 && addVboSize + currVboSize > maxVboSize)
 				break;
 
 			lastSurf = currSurf;
 
 			currVboSize += addVboSize;
-			currIboSize += addIboSize;
 		}
 
 		// count verts/indexes/surfaces
@@ -2270,6 +2310,141 @@ static void R_CreateWorldVBOs(void)
 		k++;
 	}
 
+	if (r_mergeLeafSurfaces->integer)
+	{
+		msurface_t *mergedSurf;
+
+		// count merged surfaces
+		int numMergedSurfaces = 0, numUnmergedSurfaces = 0;
+		for(firstSurf = lastSurf = surfacesSorted; firstSurf < surfacesSorted + numSortedSurfaces; firstSurf = lastSurf)
+		{
+			for (lastSurf++ ; lastSurf < surfacesSorted + numSortedSurfaces; lastSurf++)
+			{
+				int lastSurfLeafIndex, firstSurfLeafIndex;
+
+				if ((*lastSurf)->shader         != (*firstSurf)->shader
+				 || (*lastSurf)->fogIndex       != (*firstSurf)->fogIndex
+				 || (*lastSurf)->cubemapIndex   != (*firstSurf)->cubemapIndex)
+					break;
+
+				lastSurfLeafIndex  = s_worldData.surfacesViewCount[*lastSurf  - s_worldData.surfaces];
+				firstSurfLeafIndex = s_worldData.surfacesViewCount[*firstSurf - s_worldData.surfaces];
+
+				if (lastSurfLeafIndex != firstSurfLeafIndex)
+					break;
+			}
+
+			// don't merge single surfaces
+			if (firstSurf + 1 == lastSurf)
+			{
+				numUnmergedSurfaces++;
+				continue;
+			}
+
+			numMergedSurfaces++;
+		}
+
+		// Allocate merged surfaces
+		s_worldData.mergedSurfaces = ri.Hunk_Alloc(sizeof(*s_worldData.mergedSurfaces) * numMergedSurfaces, h_low);
+		s_worldData.mergedSurfacesViewCount = ri.Hunk_Alloc(sizeof(*s_worldData.mergedSurfacesViewCount) * numMergedSurfaces, h_low);
+		s_worldData.mergedSurfacesDlightBits = ri.Hunk_Alloc(sizeof(*s_worldData.mergedSurfacesDlightBits) * numMergedSurfaces, h_low);
+		s_worldData.mergedSurfacesPshadowBits = ri.Hunk_Alloc(sizeof(*s_worldData.mergedSurfacesPshadowBits) * numMergedSurfaces, h_low);
+		s_worldData.numMergedSurfaces = numMergedSurfaces;
+		
+		// view surfaces are like mark surfaces, except negative ones represent merged surfaces
+		// -1 represents 0, -2 represents 1, and so on
+		s_worldData.viewSurfaces = ri.Hunk_Alloc(sizeof(*s_worldData.viewSurfaces) * s_worldData.nummarksurfaces, h_low);
+
+		// copy view surfaces into mark surfaces
+		for (i = 0; i < s_worldData.nummarksurfaces; i++)
+		{
+			s_worldData.viewSurfaces[i] = s_worldData.marksurfaces[i];
+		}
+
+		// actually merge surfaces
+		mergedSurf = s_worldData.mergedSurfaces;
+		for(firstSurf = lastSurf = surfacesSorted; firstSurf < surfacesSorted + numSortedSurfaces; firstSurf = lastSurf)
+		{
+			srfBspSurface_t *bspSurf, *vboSurf;
+
+			for ( lastSurf++ ; lastSurf < surfacesSorted + numSortedSurfaces; lastSurf++)
+			{
+				int lastSurfLeafIndex, firstSurfLeafIndex;
+
+				if ((*lastSurf)->shader         != (*firstSurf)->shader
+				 || (*lastSurf)->fogIndex       != (*firstSurf)->fogIndex
+				 || (*lastSurf)->cubemapIndex   != (*firstSurf)->cubemapIndex)
+					break;
+
+				lastSurfLeafIndex  = s_worldData.surfacesViewCount[*lastSurf  - s_worldData.surfaces];
+				firstSurfLeafIndex = s_worldData.surfacesViewCount[*firstSurf - s_worldData.surfaces];
+
+				if (lastSurfLeafIndex != firstSurfLeafIndex)
+					break;
+			}
+
+			// don't merge single surfaces
+			if (firstSurf + 1 == lastSurf)
+				continue;
+
+			bspSurf = (srfBspSurface_t *)(*firstSurf)->data;
+
+			vboSurf = ri.Hunk_Alloc(sizeof(*vboSurf), h_low);
+			memset(vboSurf, 0, sizeof(*vboSurf));
+			vboSurf->surfaceType = SF_VBO_MESH;
+
+			vboSurf->vbo = bspSurf->vbo;
+			vboSurf->ibo = bspSurf->ibo;
+
+			vboSurf->firstIndex = bspSurf->firstIndex;
+			vboSurf->minIndex = bspSurf->minIndex;
+			vboSurf->maxIndex = bspSurf->maxIndex;
+
+			ClearBounds(vboSurf->cullBounds[0], vboSurf->cullBounds[1]);
+			for (currSurf = firstSurf; currSurf < lastSurf; currSurf++)
+			{
+				srfBspSurface_t *currBspSurf = (srfBspSurface_t *)(*currSurf)->data;
+
+				vboSurf->numVerts   += currBspSurf->numVerts;
+				vboSurf->numIndexes += currBspSurf->numIndexes;
+				vboSurf->minIndex = MIN(vboSurf->minIndex, currBspSurf->minIndex);
+				vboSurf->maxIndex = MAX(vboSurf->maxIndex, currBspSurf->maxIndex);
+				AddPointToBounds((*currSurf)->cullinfo.bounds[0], vboSurf->cullBounds[0], vboSurf->cullBounds[1]);
+				AddPointToBounds((*currSurf)->cullinfo.bounds[1], vboSurf->cullBounds[0], vboSurf->cullBounds[1]);
+			}
+
+			VectorCopy(vboSurf->cullBounds[0], mergedSurf->cullinfo.bounds[0]);
+			VectorCopy(vboSurf->cullBounds[1], mergedSurf->cullinfo.bounds[1]);
+
+			mergedSurf->cullinfo.type =  CULLINFO_BOX;
+			mergedSurf->data          =  (surfaceType_t *)vboSurf;
+			mergedSurf->fogIndex      =  (*firstSurf)->fogIndex;
+			mergedSurf->cubemapIndex  =  (*firstSurf)->cubemapIndex;
+			mergedSurf->shader        =  (*firstSurf)->shader;
+
+			// redirect view surfaces to this surf
+			for (currSurf = firstSurf; currSurf < lastSurf; currSurf++)
+				s_worldData.surfacesViewCount[*currSurf - s_worldData.surfaces] = -2;
+
+			for (k = 0; k < s_worldData.nummarksurfaces; k++)
+			{
+				if (s_worldData.surfacesViewCount[s_worldData.marksurfaces[k]] == -2)
+					s_worldData.viewSurfaces[k] = -((int)(mergedSurf - s_worldData.mergedSurfaces) + 1);
+			}
+
+			for (currSurf = firstSurf; currSurf < lastSurf; currSurf++)
+				s_worldData.surfacesViewCount[*currSurf - s_worldData.surfaces] = -1;
+
+			mergedSurf++;
+		}
+
+		ri.Printf(PRINT_ALL, "Processed %d mergeable surfaces into %d merged, %d unmerged\n", 
+			numSortedSurfaces, numMergedSurfaces, numUnmergedSurfaces);
+	}
+
+	for (i = 0; i < s_worldData.numWorldSurfaces; i++)
+		s_worldData.surfacesViewCount[i] = -1;
+
 	ri.Free(surfacesSorted);
 
 	endTime = ri.Milliseconds();
@@ -3266,335 +3441,6 @@ void R_RenderAllCubemaps(void)
 }
 
 
-/*
-=================
-R_MergeLeafSurfaces
-
-Merges surfaces that share a common leaf
-=================
-*/
-void R_MergeLeafSurfaces(void)
-{
-	int i, j, k;
-	int numWorldSurfaces;
-	int mergedSurfIndex;
-	int numMergedSurfaces;
-	int numUnmergedSurfaces;
-	VBO_t *vbo;
-	IBO_t *ibo;
-
-	msurface_t *mergedSurf;
-
-	glIndex_t *iboIndexes, *outIboIndexes;
-	int numIboIndexes;
-
-	int startTime, endTime;
-
-	startTime = ri.Milliseconds();
-
-	numWorldSurfaces = s_worldData.numWorldSurfaces;
-
-	// use viewcount to keep track of mergers
-	for (i = 0; i < numWorldSurfaces; i++)
-	{
-		s_worldData.surfacesViewCount[i] = -1;
-	}
-
-	// mark matching surfaces
-	for (i = 0; i < s_worldData.numnodes - s_worldData.numDecisionNodes; i++)
-	{
-		mnode_t *leaf = s_worldData.nodes + s_worldData.numDecisionNodes + i;
-
-		for (j = 0; j < leaf->nummarksurfaces; j++)
-		{
-			msurface_t *surf1;
-			shader_t *shader1;
-			int fogIndex1;
-			int cubemapIndex1;
-			int surfNum1;
-
-			surfNum1 = *(s_worldData.marksurfaces + leaf->firstmarksurface + j);
-
-			if (s_worldData.surfacesViewCount[surfNum1] != -1)
-				continue;
-
-			surf1 = s_worldData.surfaces + surfNum1;
-
-			if ((*surf1->data != SF_GRID) && (*surf1->data != SF_TRIANGLES) && (*surf1->data != SF_FACE))
-				continue;
-
-			shader1 = surf1->shader;
-
-			if(shader1->isSky)
-				continue;
-
-			if(shader1->isPortal)
-				continue;
-
-			if(ShaderRequiresCPUDeforms(shader1))
-				continue;
-
-			fogIndex1 = surf1->fogIndex;
-			cubemapIndex1 = surf1->cubemapIndex;
-
-			s_worldData.surfacesViewCount[surfNum1] = surfNum1;
-
-			for (k = j + 1; k < leaf->nummarksurfaces; k++)
-			{
-				msurface_t *surf2;
-				shader_t *shader2;
-				int fogIndex2;
-				int cubemapIndex2;
-				int surfNum2;
-
-				surfNum2 = *(s_worldData.marksurfaces + leaf->firstmarksurface + k);
-
-				if (s_worldData.surfacesViewCount[surfNum2] != -1)
-					continue;
-				
-				surf2 = s_worldData.surfaces + surfNum2;
-
-				if ((*surf2->data != SF_GRID) && (*surf2->data != SF_TRIANGLES) && (*surf2->data != SF_FACE))
-					continue;
-
-				shader2 = surf2->shader;
-
-				if (shader1 != shader2)
-					continue;
-
-				fogIndex2 = surf2->fogIndex;
-
-				if (fogIndex1 != fogIndex2)
-					continue;
-
-				cubemapIndex2 = surf2->cubemapIndex;
-
-				if (cubemapIndex1 != cubemapIndex2)
-					continue;
-
-				s_worldData.surfacesViewCount[surfNum2] = surfNum1;
-			}
-		}
-	}
-
-	// don't add surfaces that don't merge to any others to the merged list
-	for (i = 0; i < numWorldSurfaces; i++)
-	{
-		qboolean merges = qfalse;
-
-		if (s_worldData.surfacesViewCount[i] != i)
-			continue;
-
-		for (j = 0; j < numWorldSurfaces; j++)
-		{
-			if (j == i)
-				continue;
-
-			if (s_worldData.surfacesViewCount[j] == i)
-			{
-				merges = qtrue;
-				break;
-			}
-		}
-
-		if (!merges)
-			s_worldData.surfacesViewCount[i] = -1;
-	}	
-
-	// count merged/unmerged surfaces
-	numMergedSurfaces = 0;
-	numUnmergedSurfaces = 0;
-	for (i = 0; i < numWorldSurfaces; i++)
-	{
-		if (s_worldData.surfacesViewCount[i] == i)
-		{
-			numMergedSurfaces++;
-		}
-		else if (s_worldData.surfacesViewCount[i] == -1)
-		{
-			numUnmergedSurfaces++;
-		}
-	}
-
-	// Allocate merged surfaces
-	s_worldData.mergedSurfaces = ri.Hunk_Alloc(sizeof(*s_worldData.mergedSurfaces) * numMergedSurfaces, h_low);
-	s_worldData.mergedSurfacesViewCount = ri.Hunk_Alloc(sizeof(*s_worldData.mergedSurfacesViewCount) * numMergedSurfaces, h_low);
-	s_worldData.mergedSurfacesDlightBits = ri.Hunk_Alloc(sizeof(*s_worldData.mergedSurfacesDlightBits) * numMergedSurfaces, h_low);
-	s_worldData.mergedSurfacesPshadowBits = ri.Hunk_Alloc(sizeof(*s_worldData.mergedSurfacesPshadowBits) * numMergedSurfaces, h_low);
-	s_worldData.numMergedSurfaces = numMergedSurfaces;
-	
-	// view surfaces are like mark surfaces, except negative ones represent merged surfaces
-	// -1 represents 0, -2 represents 1, and so on
-	s_worldData.viewSurfaces = ri.Hunk_Alloc(sizeof(*s_worldData.viewSurfaces) * s_worldData.nummarksurfaces, h_low);
-
-	// copy view surfaces into mark surfaces
-	for (i = 0; i < s_worldData.nummarksurfaces; i++)
-	{
-		s_worldData.viewSurfaces[i] = s_worldData.marksurfaces[i];
-	}
-
-	// need to be synched here
-	R_IssuePendingRenderCommands();
-
-	// actually merge surfaces
-	mergedSurfIndex = 0;
-	mergedSurf = s_worldData.mergedSurfaces;
-	for (i = 0; i < numWorldSurfaces; i++)
-	{
-		msurface_t *surf1;
-
-		vec3_t bounds[2];
-
-		int numSurfsToMerge;
-		int numIndexes;
-		int numVerts;
-		int firstIndex;
-
-		srfBspSurface_t *vboSurf;
-
-		if (s_worldData.surfacesViewCount[i] != i)
-			continue;
-
-		surf1 = s_worldData.surfaces + i;
-
-		// retrieve vbo
-		vbo = ((srfBspSurface_t *)(surf1->data))->vbo;
-
-		// count verts, indexes, and surfaces
-		numSurfsToMerge = 0;
-		numIndexes = 0;
-		numVerts = 0;
-		for (j = i; j < numWorldSurfaces; j++)
-		{
-			msurface_t *surf2;
-			srfBspSurface_t *bspSurf;
-
-			if (s_worldData.surfacesViewCount[j] != i)
-				continue;
-
-			surf2 = s_worldData.surfaces + j;
-
-			bspSurf = (srfBspSurface_t *) surf2->data;
-
-			numIndexes += bspSurf->numIndexes;
-			numVerts += bspSurf->numVerts;
-			numSurfsToMerge++;
-		}
-
-		if (numVerts == 0 || numIndexes == 0 || numSurfsToMerge < 2)
-		{
-			continue;
-		}
-
-		// create ibo
-		ibo = tr.ibos[tr.numIBOs] = ri.Hunk_Alloc(sizeof(*ibo), h_low);
-		memset(ibo, 0, sizeof(*ibo));
-		Q_strncpyz(ibo->name, va("staticWorldMesh_IBO_mergedSurfs%i", tr.numIBOs++), sizeof(ibo->name));
-		numIboIndexes = 0;
-
-		// allocate indexes
-		iboIndexes = outIboIndexes = ri.Z_Malloc(numIndexes * sizeof(*outIboIndexes));
-
-		// Merge surfaces (indexes) and calculate bounds
-		ClearBounds(bounds[0], bounds[1]);
-		firstIndex = numIboIndexes;
-		for (j = i; j < numWorldSurfaces; j++)
-		{
-			msurface_t *surf2;
-			srfBspSurface_t *bspSurf;
-
-			if (s_worldData.surfacesViewCount[j] != i)
-				continue;
-
-			surf2 = s_worldData.surfaces + j;
-
-			AddPointToBounds(surf2->cullinfo.bounds[0], bounds[0], bounds[1]);
-			AddPointToBounds(surf2->cullinfo.bounds[1], bounds[0], bounds[1]);
-
-			bspSurf = (srfBspSurface_t *) surf2->data;
-			for (k = 0; k < bspSurf->numIndexes; k++)
-			{
-				*outIboIndexes++ = bspSurf->indexes[k] + bspSurf->firstVert;
-				numIboIndexes++;
-			}
-			break;
-		}
-
-		vboSurf = ri.Hunk_Alloc(sizeof(*vboSurf), h_low);
-		memset(vboSurf, 0, sizeof(*vboSurf));
-		vboSurf->surfaceType = SF_VBO_MESH;
-
-		vboSurf->vbo = vbo;
-		vboSurf->ibo = ibo;
-
-		vboSurf->numIndexes = numIndexes;
-		vboSurf->numVerts = numVerts;
-		vboSurf->firstIndex = firstIndex;
-
-		vboSurf->minIndex = *(iboIndexes + firstIndex);
-		vboSurf->maxIndex = *(iboIndexes + firstIndex);
-
-		for (j = 0; j < numIndexes; j++)
-		{
-			vboSurf->minIndex = MIN(vboSurf->minIndex, *(iboIndexes + firstIndex + j));
-			vboSurf->maxIndex = MAX(vboSurf->maxIndex, *(iboIndexes + firstIndex + j));
-		}
-
-		VectorCopy(bounds[0], vboSurf->cullBounds[0]);
-		VectorCopy(bounds[1], vboSurf->cullBounds[1]);
-
-		VectorCopy(bounds[0], mergedSurf->cullinfo.bounds[0]);
-		VectorCopy(bounds[1], mergedSurf->cullinfo.bounds[1]);
-
-		mergedSurf->cullinfo.type = CULLINFO_BOX;
-		mergedSurf->data          = (surfaceType_t *)vboSurf;
-		mergedSurf->fogIndex      = surf1->fogIndex;
-		mergedSurf->cubemapIndex  = surf1->cubemapIndex;
-		mergedSurf->shader        = surf1->shader;
-
-		// finish up the ibo
-		qglGenBuffersARB(1, &ibo->indexesVBO);
-
-		R_BindIBO(ibo);
-		qglBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, numIboIndexes * sizeof(*iboIndexes), iboIndexes, GL_STATIC_DRAW_ARB);
-		R_BindNullIBO();
-
-		GL_CheckErrors();
-
-		ri.Free(iboIndexes);
-
-		// redirect view surfaces to this surf
-		for (j = 0; j < numWorldSurfaces; j++)
-		{
-			if (s_worldData.surfacesViewCount[j] != i)
-				continue;
-
-			for (k = 0; k < s_worldData.nummarksurfaces; k++)
-			{
-				int *mark = s_worldData.marksurfaces + k;
-				int *view = s_worldData.viewSurfaces + k;
-
-				if (*mark == j)
-					*view = -(mergedSurfIndex + 1);
-			}
-		}
-
-		mergedSurfIndex++;
-		mergedSurf++;
-	}
-
-	endTime = ri.Milliseconds();
-
-	ri.Printf(PRINT_ALL, "Processed %d surfaces into %d merged, %d unmerged in %5.2f seconds\n", 
-		numWorldSurfaces, numMergedSurfaces, numUnmergedSurfaces, (endTime - startTime) / 1000.0f);
-
-	// reset viewcounts
-	for (i = 0; i < numWorldSurfaces; i++)
-	{
-		s_worldData.surfacesViewCount[i] = -1;
-	}
-}
-
 void R_CalcVertexLightDirs( void )
 {
 	int i, k;
@@ -3945,10 +3791,6 @@ void RE_LoadWorldMap( const char *name ) {
 
 	// create static VBOS from the world
 	R_CreateWorldVBOs();
-	if (r_mergeLeafSurfaces->integer)
-	{
-		R_MergeLeafSurfaces();
-	}
 
 	s_worldData.dataSize = (byte *)ri.Hunk_Alloc( 0, h_low ) - startMarker;
 
diff --git a/SP/code/rend2/tr_bsp.c b/SP/code/rend2/tr_bsp.c
index 1b9365d..4b616df 100644
--- a/SP/code/rend2/tr_bsp.c
+++ b/SP/code/rend2/tr_bsp.c
@@ -2029,39 +2029,40 @@ static int BSPSurfaceCompare(const void *a, const void *b)
 	else if(aa->fogIndex > bb->fogIndex)
 		return 1;
 
+	// by leaf
+	if (s_worldData.surfacesViewCount[aa - s_worldData.surfaces] < s_worldData.surfacesViewCount[bb - s_worldData.surfaces])
+		return -1;
+
+	else if (s_worldData.surfacesViewCount[aa - s_worldData.surfaces] > s_worldData.surfacesViewCount[bb - s_worldData.surfaces])
+		return 1;
+
+	// by surface number
+	if (aa < bb)
+		return -1;
+
+	else if (aa > bb)
+		return 1;
+
 	return 0;
 }
 
 
 static void CopyVert(const srfVert_t * in, srfVert_t * out)
 {
-	int             j;
-
-	for(j = 0; j < 3; j++)
-	{
-		out->xyz[j]       = in->xyz[j];
+	VectorCopy(in->xyz,      out->xyz);
 #ifdef USE_VERT_TANGENT_SPACE
-		out->tangent[j]   = in->tangent[j];
-		//out->bitangent[j] = in->bitangent[j];
+	VectorCopy4(in->tangent, out->tangent);
 #endif
-		out->normal[j]    = in->normal[j];
-		out->lightdir[j]  = in->lightdir[j];
-	}
+	VectorCopy(in->normal,   out->normal);
+	VectorCopy(in->lightdir, out->lightdir);
 
-	out->tangent[3] = in->tangent[3];
-
-	for(j = 0; j < 2; j++)
-	{
-		out->st[j] = in->st[j];
-		out->lightmap[j] = in->lightmap[j];
-	}
+	VectorCopy2(in->st,       out->st);
+	VectorCopy2(in->lightmap, out->lightmap);
 
-	for(j = 0; j < 4; j++)
-	{
-		out->vertexColors[j] = in->vertexColors[j];
-	}
+	VectorCopy4(in->vertexColors, out->vertexColors);
 }
 
+
 /*
 ===============
 R_CreateWorldVBOs
@@ -2085,26 +2086,74 @@ static void R_CreateWorldVBOs(void)
 	IBO_t *ibo;
 
 	int maxVboSize = 4 * 1024 * 1024;
-	int maxIboSize = 4 * 1024 * 1024;
 
 	int             startTime, endTime;
 
 	startTime = ri.Milliseconds();
 
+	// mark surfaces with best matching leaf, using overlapping bounds
+	// using surfaceViewCount[] as leaf number, and surfacesDlightBits[] as coverage * 256
+	for (i = 0; i < s_worldData.numWorldSurfaces; i++)
+	{
+		s_worldData.surfacesViewCount[i] = -1;
+	}
+
+	for (i = 0; i < s_worldData.numWorldSurfaces; i++)
+	{
+		s_worldData.surfacesDlightBits[i] = 0;
+	}
+
+	for (i = s_worldData.numDecisionNodes; i < s_worldData.numnodes; i++)
+	{
+		mnode_t *leaf = s_worldData.nodes + i;
+
+		for (j = leaf->firstmarksurface; j < leaf->firstmarksurface + leaf->nummarksurfaces; j++)
+		{
+			int surfaceNum = s_worldData.marksurfaces[j];
+			msurface_t *surface = s_worldData.surfaces + surfaceNum;
+			float coverage = 1.0f;
+			int iCoverage;
+
+			for (k = 0; k < 3; k++)
+			{
+				float left, right;
+
+				if (leaf->mins[k] > surface->cullinfo.bounds[1][k] || surface->cullinfo.bounds[0][k] > leaf->maxs[k])
+				{
+					coverage = 0.0f;
+					break;
+				}
+
+				left  = MAX(leaf->mins[k], surface->cullinfo.bounds[0][k]);
+				right = MIN(leaf->maxs[k], surface->cullinfo.bounds[1][k]);
+
+				// nudge a bit in case this is an axis aligned wall
+				coverage *= right - left + 1.0f/256.0f;
+			}
+
+			iCoverage = coverage * 256;
+
+			if (iCoverage > s_worldData.surfacesDlightBits[surfaceNum])
+			{
+				s_worldData.surfacesDlightBits[surfaceNum] = iCoverage;
+				s_worldData.surfacesViewCount[surfaceNum] = i - s_worldData.numDecisionNodes;
+			}
+		}
+	}
+
+	for (i = 0; i < s_worldData.numWorldSurfaces; i++)
+	{
+		s_worldData.surfacesDlightBits[i] = 0;
+	}
+
 	// count surfaces
 	numSortedSurfaces = 0;
-	for(surface = &s_worldData.surfaces[0]; surface < &s_worldData.surfaces[s_worldData.numsurfaces]; surface++)
+	for(surface = s_worldData.surfaces; surface < s_worldData.surfaces + s_worldData.numWorldSurfaces; surface++)
 	{
 		srfBspSurface_t *bspSurf;
 		shader_t *shader = surface->shader;
 
-		if (shader->isPortal)
-			continue;
-
-		if (shader->isSky)
-			continue;
-
-		if (ShaderRequiresCPUDeforms(shader))
+		if (shader->isPortal || shader->isSky || ShaderRequiresCPUDeforms(shader))
 			continue;
 
 		// check for this now so we can use srfBspSurface_t* universally in the rest of the function
@@ -2123,18 +2172,12 @@ static void R_CreateWorldVBOs(void)
 	surfacesSorted = ri.Z_Malloc(numSortedSurfaces * sizeof(*surfacesSorted));
 
 	j = 0;
-	for(surface = &s_worldData.surfaces[0]; surface < &s_worldData.surfaces[s_worldData.numsurfaces]; surface++)
+	for(surface = s_worldData.surfaces; surface < s_worldData.surfaces + s_worldData.numWorldSurfaces; surface++)
 	{
 		srfBspSurface_t *bspSurf;
 		shader_t *shader = surface->shader;
 
-		if (shader->isPortal)
-			continue;
-
-		if (shader->isSky)
-			continue;
-
-		if (ShaderRequiresCPUDeforms(shader))
+		if (shader->isPortal || shader->isSky || ShaderRequiresCPUDeforms(shader))
 			continue;
 
 		// check for this now so we can use srfBspSurface_t* universally in the rest of the function
@@ -2152,37 +2195,34 @@ static void R_CreateWorldVBOs(void)
 	qsort(surfacesSorted, numSortedSurfaces, sizeof(*surfacesSorted), BSPSurfaceCompare);
 
 	k = 0;
-	for(firstSurf = lastSurf = surfacesSorted; firstSurf < &surfacesSorted[numSortedSurfaces]; firstSurf = lastSurf)
+	for(firstSurf = lastSurf = surfacesSorted; firstSurf < surfacesSorted + numSortedSurfaces; firstSurf = lastSurf)
 	{
-		int currVboSize, currIboSize;
+		int currVboSize;
 
-		// Find range of surfaces to merge by:
-		// - Collecting a number of surfaces which fit under maxVboSize/maxIboSize, or
-		// - All the surfaces with a single shader which go over maxVboSize/maxIboSize
-		currVboSize = currIboSize = 0;
-		while (currVboSize < maxVboSize && currIboSize < maxIboSize && lastSurf < &surfacesSorted[numSortedSurfaces])
+		// Find range of surfaces to place in a vbo/ibo by:
+		// - Collecting a number of surfaces which fit under maxVboSize, or
+		// - All the surfaces with a single shader which go over maxVboSize
+		currVboSize = 0;
+		while (currVboSize < maxVboSize && lastSurf < surfacesSorted + numSortedSurfaces)
 		{
-			int addVboSize, addIboSize, currShaderIndex;
+			int addVboSize, currShaderIndex;
 
-			addVboSize = addIboSize = 0;
+			addVboSize = 0;
 			currShaderIndex = (*lastSurf)->shader->sortedIndex;
 
-			for(currSurf = lastSurf; currSurf < &surfacesSorted[numSortedSurfaces] && (*currSurf)->shader->sortedIndex == currShaderIndex; currSurf++)
+			for(currSurf = lastSurf; currSurf < surfacesSorted + numSortedSurfaces && (*currSurf)->shader->sortedIndex == currShaderIndex; currSurf++)
 			{
 				srfBspSurface_t *bspSurf = (srfBspSurface_t *) (*currSurf)->data;
 
 				addVboSize += bspSurf->numVerts * sizeof(srfVert_t);
-				addIboSize += bspSurf->numIndexes * sizeof(glIndex_t);
 			}
 
-			if ((currVboSize != 0 && addVboSize + currVboSize > maxVboSize)
-			 || (currIboSize != 0 && addIboSize + currIboSize > maxIboSize))
+			if (currVboSize != 0 && addVboSize + currVboSize > maxVboSize)
 				break;
 
 			lastSurf = currSurf;
 
 			currVboSize += addVboSize;
-			currIboSize += addIboSize;
 		}
 
 		// count verts/indexes/surfaces
@@ -2258,6 +2298,141 @@ static void R_CreateWorldVBOs(void)
 		k++;
 	}
 
+	if (r_mergeLeafSurfaces->integer)
+	{
+		msurface_t *mergedSurf;
+
+		// count merged surfaces
+		int numMergedSurfaces = 0, numUnmergedSurfaces = 0;
+		for(firstSurf = lastSurf = surfacesSorted; firstSurf < surfacesSorted + numSortedSurfaces; firstSurf = lastSurf)
+		{
+			for (lastSurf++ ; lastSurf < surfacesSorted + numSortedSurfaces; lastSurf++)
+			{
+				int lastSurfLeafIndex, firstSurfLeafIndex;
+
+				if ((*lastSurf)->shader         != (*firstSurf)->shader
+				 || (*lastSurf)->fogIndex       != (*firstSurf)->fogIndex
+				 || (*lastSurf)->cubemapIndex   != (*firstSurf)->cubemapIndex)
+					break;
+
+				lastSurfLeafIndex  = s_worldData.surfacesViewCount[*lastSurf  - s_worldData.surfaces];
+				firstSurfLeafIndex = s_worldData.surfacesViewCount[*firstSurf - s_worldData.surfaces];
+
+				if (lastSurfLeafIndex != firstSurfLeafIndex)
+					break;
+			}
+
+			// don't merge single surfaces
+			if (firstSurf + 1 == lastSurf)
+			{
+				numUnmergedSurfaces++;
+				continue;
+			}
+
+			numMergedSurfaces++;
+		}
+
+		// Allocate merged surfaces
+		s_worldData.mergedSurfaces = ri.Hunk_Alloc(sizeof(*s_worldData.mergedSurfaces) * numMergedSurfaces, h_low);
+		s_worldData.mergedSurfacesViewCount = ri.Hunk_Alloc(sizeof(*s_worldData.mergedSurfacesViewCount) * numMergedSurfaces, h_low);
+		s_worldData.mergedSurfacesDlightBits = ri.Hunk_Alloc(sizeof(*s_worldData.mergedSurfacesDlightBits) * numMergedSurfaces, h_low);
+		s_worldData.mergedSurfacesPshadowBits = ri.Hunk_Alloc(sizeof(*s_worldData.mergedSurfacesPshadowBits) * numMergedSurfaces, h_low);
+		s_worldData.numMergedSurfaces = numMergedSurfaces;
+		
+		// view surfaces are like mark surfaces, except negative ones represent merged surfaces
+		// -1 represents 0, -2 represents 1, and so on
+		s_worldData.viewSurfaces = ri.Hunk_Alloc(sizeof(*s_worldData.viewSurfaces) * s_worldData.nummarksurfaces, h_low);
+
+		// copy view surfaces into mark surfaces
+		for (i = 0; i < s_worldData.nummarksurfaces; i++)
+		{
+			s_worldData.viewSurfaces[i] = s_worldData.marksurfaces[i];
+		}
+
+		// actually merge surfaces
+		mergedSurf = s_worldData.mergedSurfaces;
+		for(firstSurf = lastSurf = surfacesSorted; firstSurf < surfacesSorted + numSortedSurfaces; firstSurf = lastSurf)
+		{
+			srfBspSurface_t *bspSurf, *vboSurf;
+
+			for ( lastSurf++ ; lastSurf < surfacesSorted + numSortedSurfaces; lastSurf++)
+			{
+				int lastSurfLeafIndex, firstSurfLeafIndex;
+
+				if ((*lastSurf)->shader         != (*firstSurf)->shader
+				 || (*lastSurf)->fogIndex       != (*firstSurf)->fogIndex
+				 || (*lastSurf)->cubemapIndex   != (*firstSurf)->cubemapIndex)
+					break;
+
+				lastSurfLeafIndex  = s_worldData.surfacesViewCount[*lastSurf  - s_worldData.surfaces];
+				firstSurfLeafIndex = s_worldData.surfacesViewCount[*firstSurf - s_worldData.surfaces];
+
+				if (lastSurfLeafIndex != firstSurfLeafIndex)
+					break;
+			}
+
+			// don't merge single surfaces
+			if (firstSurf + 1 == lastSurf)
+				continue;
+
+			bspSurf = (srfBspSurface_t *)(*firstSurf)->data;
+
+			vboSurf = ri.Hunk_Alloc(sizeof(*vboSurf), h_low);
+			memset(vboSurf, 0, sizeof(*vboSurf));
+			vboSurf->surfaceType = SF_VBO_MESH;
+
+			vboSurf->vbo = bspSurf->vbo;
+			vboSurf->ibo = bspSurf->ibo;
+
+			vboSurf->firstIndex = bspSurf->firstIndex;
+			vboSurf->minIndex = bspSurf->minIndex;
+			vboSurf->maxIndex = bspSurf->maxIndex;
+
+			ClearBounds(vboSurf->cullBounds[0], vboSurf->cullBounds[1]);
+			for (currSurf = firstSurf; currSurf < lastSurf; currSurf++)
+			{
+				srfBspSurface_t *currBspSurf = (srfBspSurface_t *)(*currSurf)->data;
+
+				vboSurf->numVerts   += currBspSurf->numVerts;
+				vboSurf->numIndexes += currBspSurf->numIndexes;
+				vboSurf->minIndex = MIN(vboSurf->minIndex, currBspSurf->minIndex);
+				vboSurf->maxIndex = MAX(vboSurf->maxIndex, currBspSurf->maxIndex);
+				AddPointToBounds((*currSurf)->cullinfo.bounds[0], vboSurf->cullBounds[0], vboSurf->cullBounds[1]);
+				AddPointToBounds((*currSurf)->cullinfo.bounds[1], vboSurf->cullBounds[0], vboSurf->cullBounds[1]);
+			}
+
+			VectorCopy(vboSurf->cullBounds[0], mergedSurf->cullinfo.bounds[0]);
+			VectorCopy(vboSurf->cullBounds[1], mergedSurf->cullinfo.bounds[1]);
+
+			mergedSurf->cullinfo.type =  CULLINFO_BOX;
+			mergedSurf->data          =  (surfaceType_t *)vboSurf;
+			mergedSurf->fogIndex      =  (*firstSurf)->fogIndex;
+			mergedSurf->cubemapIndex  =  (*firstSurf)->cubemapIndex;
+			mergedSurf->shader        =  (*firstSurf)->shader;
+
+			// redirect view surfaces to this surf
+			for (currSurf = firstSurf; currSurf < lastSurf; currSurf++)
+				s_worldData.surfacesViewCount[*currSurf - s_worldData.surfaces] = -2;
+
+			for (k = 0; k < s_worldData.nummarksurfaces; k++)
+			{
+				if (s_worldData.surfacesViewCount[s_worldData.marksurfaces[k]] == -2)
+					s_worldData.viewSurfaces[k] = -((int)(mergedSurf - s_worldData.mergedSurfaces) + 1);
+			}
+
+			for (currSurf = firstSurf; currSurf < lastSurf; currSurf++)
+				s_worldData.surfacesViewCount[*currSurf - s_worldData.surfaces] = -1;
+
+			mergedSurf++;
+		}
+
+		ri.Printf(PRINT_ALL, "Processed %d mergeable surfaces into %d merged, %d unmerged\n", 
+			numSortedSurfaces, numMergedSurfaces, numUnmergedSurfaces);
+	}
+
+	for (i = 0; i < s_worldData.numWorldSurfaces; i++)
+		s_worldData.surfacesViewCount[i] = -1;
+
 	ri.Free(surfacesSorted);
 
 	endTime = ri.Milliseconds();
@@ -3252,334 +3427,6 @@ void R_RenderAllCubemaps(void)
 }
 
 
-/*
-=================
-R_MergeLeafSurfaces
-
-Merges surfaces that share a common leaf
-=================
-*/
-void R_MergeLeafSurfaces(void)
-{
-	int i, j, k;
-	int numWorldSurfaces;
-	int mergedSurfIndex;
-	int numMergedSurfaces;
-	int numUnmergedSurfaces;
-	VBO_t *vbo;
-	IBO_t *ibo;
-
-	msurface_t *mergedSurf;
-
-	glIndex_t *iboIndexes, *outIboIndexes;
-	int numIboIndexes;
-
-	int startTime, endTime;
-
-	startTime = ri.Milliseconds();
-
-	numWorldSurfaces = s_worldData.numWorldSurfaces;
-
-	// use viewcount to keep track of mergers
-	for (i = 0; i < numWorldSurfaces; i++)
-	{
-		s_worldData.surfacesViewCount[i] = -1;
-	}
-
-	// mark matching surfaces
-	for (i = 0; i < s_worldData.numnodes - s_worldData.numDecisionNodes; i++)
-	{
-		mnode_t *leaf = s_worldData.nodes + s_worldData.numDecisionNodes + i;
-
-		for (j = 0; j < leaf->nummarksurfaces; j++)
-		{
-			msurface_t *surf1;
-			shader_t *shader1;
-			int fogIndex1;
-			int cubemapIndex1;
-			int surfNum1;
-
-			surfNum1 = *(s_worldData.marksurfaces + leaf->firstmarksurface + j);
-
-			if (s_worldData.surfacesViewCount[surfNum1] != -1)
-				continue;
-
-			surf1 = s_worldData.surfaces + surfNum1;
-
-			if ((*surf1->data != SF_GRID) && (*surf1->data != SF_TRIANGLES) && (*surf1->data != SF_FACE))
-				continue;
-
-			shader1 = surf1->shader;
-
-			if(shader1->isSky)
-				continue;
-
-			if(shader1->isPortal)
-				continue;
-
-			if(ShaderRequiresCPUDeforms(shader1))
-				continue;
-
-			fogIndex1 = surf1->fogIndex;
-			cubemapIndex1 = surf1->cubemapIndex;
-
-			s_worldData.surfacesViewCount[surfNum1] = surfNum1;
-
-			for (k = j + 1; k < leaf->nummarksurfaces; k++)
-			{
-				msurface_t *surf2;
-				shader_t *shader2;
-				int fogIndex2;
-				int cubemapIndex2;
-				int surfNum2;
-
-				surfNum2 = *(s_worldData.marksurfaces + leaf->firstmarksurface + k);
-
-				if (s_worldData.surfacesViewCount[surfNum2] != -1)
-					continue;
-				
-				surf2 = s_worldData.surfaces + surfNum2;
-
-				if ((*surf2->data != SF_GRID) && (*surf2->data != SF_TRIANGLES) && (*surf2->data != SF_FACE))
-					continue;
-
-				shader2 = surf2->shader;
-
-				if (shader1 != shader2)
-					continue;
-
-				fogIndex2 = surf2->fogIndex;
-
-				if (fogIndex1 != fogIndex2)
-					continue;
-
-				cubemapIndex2 = surf2->cubemapIndex;
-
-				if (cubemapIndex1 != cubemapIndex2)
-					continue;
-
-				s_worldData.surfacesViewCount[surfNum2] = surfNum1;
-			}
-		}
-	}
-
-	// don't add surfaces that don't merge to any others to the merged list
-	for (i = 0; i < numWorldSurfaces; i++)
-	{
-		qboolean merges = qfalse;
-
-		if (s_worldData.surfacesViewCount[i] != i)
-			continue;
-
-		for (j = 0; j < numWorldSurfaces; j++)
-		{
-			if (j == i)
-				continue;
-
-			if (s_worldData.surfacesViewCount[j] == i)
-			{
-				merges = qtrue;
-				break;
-			}
-		}
-
-		if (!merges)
-			s_worldData.surfacesViewCount[i] = -1;
-	}	
-
-	// count merged/unmerged surfaces
-	numMergedSurfaces = 0;
-	numUnmergedSurfaces = 0;
-	for (i = 0; i < numWorldSurfaces; i++)
-	{
-		if (s_worldData.surfacesViewCount[i] == i)
-		{
-			numMergedSurfaces++;
-		}
-		else if (s_worldData.surfacesViewCount[i] == -1)
-		{
-			numUnmergedSurfaces++;
-		}
-	}
-
-	// Allocate merged surfaces
-	s_worldData.mergedSurfaces = ri.Hunk_Alloc(sizeof(*s_worldData.mergedSurfaces) * numMergedSurfaces, h_low);
-	s_worldData.mergedSurfacesViewCount = ri.Hunk_Alloc(sizeof(*s_worldData.mergedSurfacesViewCount) * numMergedSurfaces, h_low);
-	s_worldData.mergedSurfacesDlightBits = ri.Hunk_Alloc(sizeof(*s_worldData.mergedSurfacesDlightBits) * numMergedSurfaces, h_low);
-	s_worldData.mergedSurfacesPshadowBits = ri.Hunk_Alloc(sizeof(*s_worldData.mergedSurfacesPshadowBits) * numMergedSurfaces, h_low);
-	s_worldData.numMergedSurfaces = numMergedSurfaces;
-	
-	// view surfaces are like mark surfaces, except negative ones represent merged surfaces
-	// -1 represents 0, -2 represents 1, and so on
-	s_worldData.viewSurfaces = ri.Hunk_Alloc(sizeof(*s_worldData.viewSurfaces) * s_worldData.nummarksurfaces, h_low);
-
-	// copy view surfaces into mark surfaces
-	for (i = 0; i < s_worldData.nummarksurfaces; i++)
-	{
-		s_worldData.viewSurfaces[i] = s_worldData.marksurfaces[i];
-	}
-
-	// need to be synched here
-	R_IssuePendingRenderCommands();
-
-	// actually merge surfaces
-	mergedSurfIndex = 0;
-	mergedSurf = s_worldData.mergedSurfaces;
-	for (i = 0; i < numWorldSurfaces; i++)
-	{
-		msurface_t *surf1;
-
-		vec3_t bounds[2];
-
-		int numSurfsToMerge;
-		int numIndexes;
-		int numVerts;
-		int firstIndex;
-
-		srfBspSurface_t *vboSurf;
-
-		if (s_worldData.surfacesViewCount[i] != i)
-			continue;
-
-		surf1 = s_worldData.surfaces + i;
-
-		// retrieve vbo
-		vbo = ((srfBspSurface_t *)(surf1->data))->vbo;
-
-		// count verts, indexes, and surfaces
-		numSurfsToMerge = 0;
-		numIndexes = 0;
-		numVerts = 0;
-		for (j = i; j < numWorldSurfaces; j++)
-		{
-			msurface_t *surf2;
-			srfBspSurface_t *bspSurf;
-
-			if (s_worldData.surfacesViewCount[j] != i)
-				continue;
-
-			surf2 = s_worldData.surfaces + j;
-
-			bspSurf = (srfBspSurface_t *) surf2->data;
-			numIndexes += bspSurf->numIndexes;
-			numVerts += bspSurf->numVerts;
-			numSurfsToMerge++;
-		}
-
-		if (numVerts == 0 || numIndexes == 0 || numSurfsToMerge < 2)
-		{
-			continue;
-		}
-
-		// create ibo
-		ibo = tr.ibos[tr.numIBOs] = ri.Hunk_Alloc(sizeof(*ibo), h_low);
-		memset(ibo, 0, sizeof(*ibo));
-		Q_strncpyz(ibo->name, va("staticWorldMesh_IBO_mergedSurfs%i", tr.numIBOs++), sizeof(ibo->name));
-		numIboIndexes = 0;
-
-		// allocate indexes
-		iboIndexes = outIboIndexes = ri.Z_Malloc(numIndexes * sizeof(*outIboIndexes));
-
-		// Merge surfaces (indexes) and calculate bounds
-		ClearBounds(bounds[0], bounds[1]);
-		firstIndex = numIboIndexes;
-		for (j = i; j < numWorldSurfaces; j++)
-		{
-			msurface_t *surf2;
-			srfBspSurface_t *bspSurf;
-
-			if (s_worldData.surfacesViewCount[j] != i)
-				continue;
-
-			surf2 = s_worldData.surfaces + j;
-
-			AddPointToBounds(surf2->cullinfo.bounds[0], bounds[0], bounds[1]);
-			AddPointToBounds(surf2->cullinfo.bounds[1], bounds[0], bounds[1]);
-
-			bspSurf = (srfBspSurface_t *) surf2->data;
-			for (k = 0; k < bspSurf->numIndexes; k++)
-			{
-				*outIboIndexes++ = bspSurf->indexes[k] + bspSurf->firstVert;
-				numIboIndexes++;
-			}
-			break;
-		}
-
-		vboSurf = ri.Hunk_Alloc(sizeof(*vboSurf), h_low);
-		memset(vboSurf, 0, sizeof(*vboSurf));
-		vboSurf->surfaceType = SF_VBO_MESH;
-
-		vboSurf->vbo = vbo;
-		vboSurf->ibo = ibo;
-
-		vboSurf->numIndexes = numIndexes;
-		vboSurf->numVerts = numVerts;
-		vboSurf->firstIndex = firstIndex;
-
-		vboSurf->minIndex = *(iboIndexes + firstIndex);
-		vboSurf->maxIndex = *(iboIndexes + firstIndex);
-
-		for (j = 0; j < numIndexes; j++)
-		{
-			vboSurf->minIndex = MIN(vboSurf->minIndex, *(iboIndexes + firstIndex + j));
-			vboSurf->maxIndex = MAX(vboSurf->maxIndex, *(iboIndexes + firstIndex + j));
-		}
-
-		VectorCopy(bounds[0], vboSurf->cullBounds[0]);
-		VectorCopy(bounds[1], vboSurf->cullBounds[1]);
-
-		VectorCopy(bounds[0], mergedSurf->cullinfo.bounds[0]);
-		VectorCopy(bounds[1], mergedSurf->cullinfo.bounds[1]);
-
-		mergedSurf->cullinfo.type = CULLINFO_BOX;
-		mergedSurf->data          = (surfaceType_t *)vboSurf;
-		mergedSurf->fogIndex      = surf1->fogIndex;
-		mergedSurf->cubemapIndex  = surf1->cubemapIndex;
-		mergedSurf->shader        = surf1->shader;
-
-		// finish up the ibo
-		qglGenBuffersARB(1, &ibo->indexesVBO);
-
-		R_BindIBO(ibo);
-		qglBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, numIboIndexes * sizeof(*iboIndexes), iboIndexes, GL_STATIC_DRAW_ARB);
-		R_BindNullIBO();
-
-		GL_CheckErrors();
-
-		ri.Free(iboIndexes);
-
-		// redirect view surfaces to this surf
-		for (j = 0; j < numWorldSurfaces; j++)
-		{
-			if (s_worldData.surfacesViewCount[j] != i)
-				continue;
-
-			for (k = 0; k < s_worldData.nummarksurfaces; k++)
-			{
-				int *mark = s_worldData.marksurfaces + k;
-				int *view = s_worldData.viewSurfaces + k;
-
-				if (*mark == j)
-					*view = -(mergedSurfIndex + 1);
-			}
-		}
-
-		mergedSurfIndex++;
-		mergedSurf++;
-	}
-
-	endTime = ri.Milliseconds();
-
-	ri.Printf(PRINT_ALL, "Processed %d surfaces into %d merged, %d unmerged in %5.2f seconds\n", 
-		numWorldSurfaces, numMergedSurfaces, numUnmergedSurfaces, (endTime - startTime) / 1000.0f);
-
-	// reset viewcounts
-	for (i = 0; i < numWorldSurfaces; i++)
-	{
-		s_worldData.surfacesViewCount[i] = -1;
-	}
-}
-
 void R_CalcVertexLightDirs( void )
 {
 	int i, k;
@@ -3932,10 +3779,6 @@ void RE_LoadWorldMap( const char *name ) {
 
 	// create static VBOS from the world
 	R_CreateWorldVBOs();
-	if (r_mergeLeafSurfaces->integer)
-	{
-		R_MergeLeafSurfaces();
-	}
 
 	s_worldData.dataSize = (byte *)ri.Hunk_Alloc( 0, h_low ) - startMarker;
 

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-games/iortcw.git



More information about the Pkg-games-commits mailing list