mirror of
https://github.com/DrBeef/ioq3quest.git
synced 2024-11-23 12:32:09 +00:00
OpenGL2: Better BSP surface merging.
This commit is contained in:
parent
918eed9295
commit
a90c17ac1b
1 changed files with 225 additions and 385 deletions
|
@ -1808,6 +1808,19 @@ static int BSPSurfaceCompare(const void *a, const void *b)
|
||||||
else if(aa->cubemapIndex > bb->cubemapIndex)
|
else if(aa->cubemapIndex > bb->cubemapIndex)
|
||||||
return 1;
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1815,31 +1828,17 @@ static int BSPSurfaceCompare(const void *a, const void *b)
|
||||||
|
|
||||||
static void CopyVert(const srfVert_t * in, srfVert_t * out)
|
static void CopyVert(const srfVert_t * in, srfVert_t * out)
|
||||||
{
|
{
|
||||||
int j;
|
VectorCopy(in->xyz, out->xyz);
|
||||||
|
|
||||||
for(j = 0; j < 3; j++)
|
|
||||||
{
|
|
||||||
out->xyz[j] = in->xyz[j];
|
|
||||||
#ifdef USE_VERT_TANGENT_SPACE
|
#ifdef USE_VERT_TANGENT_SPACE
|
||||||
out->tangent[j] = in->tangent[j];
|
VectorCopy4(in->tangent, out->tangent);
|
||||||
//out->bitangent[j] = in->bitangent[j];
|
|
||||||
#endif
|
#endif
|
||||||
out->normal[j] = in->normal[j];
|
VectorCopy(in->normal, out->normal);
|
||||||
out->lightdir[j] = in->lightdir[j];
|
VectorCopy(in->lightdir, out->lightdir);
|
||||||
}
|
|
||||||
|
|
||||||
out->tangent[3] = in->tangent[3];
|
VectorCopy2(in->st, out->st);
|
||||||
|
VectorCopy2(in->lightmap, out->lightmap);
|
||||||
|
|
||||||
for(j = 0; j < 2; j++)
|
VectorCopy4(in->vertexColors, out->vertexColors);
|
||||||
{
|
|
||||||
out->st[j] = in->st[j];
|
|
||||||
out->lightmap[j] = in->lightmap[j];
|
|
||||||
}
|
|
||||||
|
|
||||||
for(j = 0; j < 4; j++)
|
|
||||||
{
|
|
||||||
out->vertexColors[j] = in->vertexColors[j];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1866,26 +1865,74 @@ static void R_CreateWorldVBOs(void)
|
||||||
IBO_t *ibo;
|
IBO_t *ibo;
|
||||||
|
|
||||||
int maxVboSize = 4 * 1024 * 1024;
|
int maxVboSize = 4 * 1024 * 1024;
|
||||||
int maxIboSize = 4 * 1024 * 1024;
|
|
||||||
|
|
||||||
int startTime, endTime;
|
int startTime, endTime;
|
||||||
|
|
||||||
startTime = ri.Milliseconds();
|
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
|
// count surfaces
|
||||||
numSortedSurfaces = 0;
|
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;
|
srfBspSurface_t *bspSurf;
|
||||||
shader_t *shader = surface->shader;
|
shader_t *shader = surface->shader;
|
||||||
|
|
||||||
if (shader->isPortal)
|
if (shader->isPortal || shader->isSky || ShaderRequiresCPUDeforms(shader))
|
||||||
continue;
|
|
||||||
|
|
||||||
if (shader->isSky)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (ShaderRequiresCPUDeforms(shader))
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// check for this now so we can use srfBspSurface_t* universally in the rest of the function
|
// check for this now so we can use srfBspSurface_t* universally in the rest of the function
|
||||||
|
@ -1904,18 +1951,12 @@ static void R_CreateWorldVBOs(void)
|
||||||
surfacesSorted = ri.Malloc(numSortedSurfaces * sizeof(*surfacesSorted));
|
surfacesSorted = ri.Malloc(numSortedSurfaces * sizeof(*surfacesSorted));
|
||||||
|
|
||||||
j = 0;
|
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;
|
srfBspSurface_t *bspSurf;
|
||||||
shader_t *shader = surface->shader;
|
shader_t *shader = surface->shader;
|
||||||
|
|
||||||
if (shader->isPortal)
|
if (shader->isPortal || shader->isSky || ShaderRequiresCPUDeforms(shader))
|
||||||
continue;
|
|
||||||
|
|
||||||
if (shader->isSky)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (ShaderRequiresCPUDeforms(shader))
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// check for this now so we can use srfBspSurface_t* universally in the rest of the function
|
// check for this now so we can use srfBspSurface_t* universally in the rest of the function
|
||||||
|
@ -1933,37 +1974,34 @@ static void R_CreateWorldVBOs(void)
|
||||||
qsort(surfacesSorted, numSortedSurfaces, sizeof(*surfacesSorted), BSPSurfaceCompare);
|
qsort(surfacesSorted, numSortedSurfaces, sizeof(*surfacesSorted), BSPSurfaceCompare);
|
||||||
|
|
||||||
k = 0;
|
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:
|
// Find range of surfaces to place in a vbo/ibo by:
|
||||||
// - Collecting a number of surfaces which fit under maxVboSize/maxIboSize, or
|
// - Collecting a number of surfaces which fit under maxVboSize, or
|
||||||
// - All the surfaces with a single shader which go over maxVboSize/maxIboSize
|
// - All the surfaces with a single shader which go over maxVboSize
|
||||||
currVboSize = currIboSize = 0;
|
currVboSize = 0;
|
||||||
while (currVboSize < maxVboSize && currIboSize < maxIboSize && lastSurf < &surfacesSorted[numSortedSurfaces])
|
while (currVboSize < maxVboSize && lastSurf < surfacesSorted + numSortedSurfaces)
|
||||||
{
|
{
|
||||||
int addVboSize, addIboSize, currShaderIndex;
|
int addVboSize, currShaderIndex;
|
||||||
|
|
||||||
addVboSize = addIboSize = 0;
|
addVboSize = 0;
|
||||||
currShaderIndex = (*lastSurf)->shader->sortedIndex;
|
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;
|
srfBspSurface_t *bspSurf = (srfBspSurface_t *) (*currSurf)->data;
|
||||||
|
|
||||||
addVboSize += bspSurf->numVerts * sizeof(srfVert_t);
|
addVboSize += bspSurf->numVerts * sizeof(srfVert_t);
|
||||||
addIboSize += bspSurf->numIndexes * sizeof(glIndex_t);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((currVboSize != 0 && addVboSize + currVboSize > maxVboSize)
|
if (currVboSize != 0 && addVboSize + currVboSize > maxVboSize)
|
||||||
|| (currIboSize != 0 && addIboSize + currIboSize > maxIboSize))
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
lastSurf = currSurf;
|
lastSurf = currSurf;
|
||||||
|
|
||||||
currVboSize += addVboSize;
|
currVboSize += addVboSize;
|
||||||
currIboSize += addIboSize;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// count verts/indexes/surfaces
|
// count verts/indexes/surfaces
|
||||||
|
@ -2039,6 +2077,141 @@ static void R_CreateWorldVBOs(void)
|
||||||
k++;
|
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);
|
ri.Free(surfacesSorted);
|
||||||
|
|
||||||
endTime = ri.Milliseconds();
|
endTime = ri.Milliseconds();
|
||||||
|
@ -2914,335 +3087,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.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 )
|
void R_CalcVertexLightDirs( void )
|
||||||
{
|
{
|
||||||
int i, k;
|
int i, k;
|
||||||
|
@ -3569,10 +3413,6 @@ void RE_LoadWorldMap( const char *name ) {
|
||||||
|
|
||||||
// create static VBOS from the world
|
// create static VBOS from the world
|
||||||
R_CreateWorldVBOs();
|
R_CreateWorldVBOs();
|
||||||
if (r_mergeLeafSurfaces->integer)
|
|
||||||
{
|
|
||||||
R_MergeLeafSurfaces();
|
|
||||||
}
|
|
||||||
|
|
||||||
s_worldData.dataSize = (byte *)ri.Hunk_Alloc(0, h_low) - startMarker;
|
s_worldData.dataSize = (byte *)ri.Hunk_Alloc(0, h_low) - startMarker;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue