Skip to content

Commit 7160194

Browse files
committed
Merge duplicate map vertices
1 parent a78378e commit 7160194

File tree

3 files changed

+98
-43
lines changed

3 files changed

+98
-43
lines changed

src/engine/renderer/GeometryOptimiser.cpp

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -295,8 +295,50 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
295295
296296
===========================================================================
297297
*/
298+
void MergeDuplicateVertices( bspSurface_t** rendererSurfaces, int numSurfaces, srfVert_t* vertices, int numVerticesIn,
299+
glIndex_t* indices, int numIndicesIn, int& numVerticesOut, int& numIndicesOut ) {
300+
int start = Sys::Milliseconds();
298301

299-
static void ProcessMaterialSurface( MaterialSurface& surface, std::vector<MaterialSurface>& materialSurfaces,
302+
std::unordered_map<srfVert_t, uint32_t, MapVertHasher, MapVertEqual> verts;
303+
uint32_t idx = 0;
304+
uint32_t vertIdx = 0;
305+
306+
// To shut CI up since this *is* used for an assert
307+
Q_UNUSED( numIndicesIn );
308+
for ( int i = 0; i < numSurfaces; i++ ) {
309+
bspSurface_t* surface = rendererSurfaces[i];
310+
311+
srfGeneric_t* face = ( srfGeneric_t* ) surface->data;
312+
face->firstIndex = idx;
313+
for ( srfTriangle_t* triangle = face->triangles; triangle < face->triangles + face->numTriangles; triangle++ ) {
314+
for ( int j = 0; j < 3; j++ ) {
315+
srfVert_t& vert = face->verts[triangle->indexes[j]];
316+
uint32_t index = verts[vert];
317+
318+
ASSERT_LT( idx, numIndicesIn );
319+
if ( !index ) {
320+
verts[vert] = vertIdx + 1;
321+
vertices[vertIdx] = vert;
322+
indices[idx] = vertIdx;
323+
324+
ASSERT_LT( vertIdx, numVerticesIn );
325+
326+
vertIdx++;
327+
} else {
328+
indices[idx] = index - 1;
329+
}
330+
idx++;
331+
}
332+
}
333+
}
334+
335+
numVerticesOut = vertIdx;
336+
numIndicesOut = idx;
337+
338+
Log::Notice( "Merged %i vertices into %i in %i ms", numVerticesIn, numVerticesOut, Sys::Milliseconds() - start );
339+
}
340+
341+
/* static void ProcessMaterialSurface( MaterialSurface& surface, std::vector<MaterialSurface>& materialSurfaces,
300342
std::vector<MaterialSurface>& processedMaterialSurfaces,
301343
srfVert_t* verts, glIndex_t* indices ) {
302344
if ( surface.count == MAX_MATERIAL_SURFACE_TRIS ) {
@@ -312,7 +354,7 @@ static void ProcessMaterialSurface( MaterialSurface& surface, std::vector<Materi
312354
313355
processedMaterialSurfaces.push_back( srf );
314356
}
315-
}
357+
} */
316358

317359
std::vector<MaterialSurface> OptimiseMapGeometryMaterial( world_t* world, int numSurfaces ) {
318360
std::vector<MaterialSurface> materialSurfaces;
@@ -342,9 +384,5 @@ std::vector<MaterialSurface> OptimiseMapGeometryMaterial( world_t* world, int nu
342384
surfaceIndex++;
343385
}
344386

345-
while ( materialSurfaces.size() ) {
346-
ProcessMaterialSurface( materialSurfaces.front(), materialSurfaces, processedMaterialSurfaces, verts, indices );
347-
}
348-
349387
return materialSurfaces;
350388
}

src/engine/renderer/GeometryOptimiser.h

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3939
#ifndef GEOMETRY_OPTIMISER_H
4040
#define GEOMETRY_OPTIMISER_H
4141

42-
#define MAX_MATERIAL_SURFACE_TRIS 64
43-
#define MAX_MATERIAL_SURFACE_DISTANCE 256
42+
static const uint32_t MAX_MATERIAL_SURFACE_TRIS = 64;
43+
static const uint32_t MAX_MATERIAL_SURFACE_INDEXES = 3 * MAX_MATERIAL_SURFACE_TRIS;
44+
static const uint32_t MAX_MATERIAL_SURFACE_DISTANCE = 256;
4445

4546
struct TriEdge {
4647
enum State : uint32_t {
@@ -65,8 +66,46 @@ struct TriIndex {
6566
int tri2 = -1;
6667
};
6768

69+
struct MapVertHasher {
70+
size_t operator()( const srfVert_t& vert ) const {
71+
size_t hash = ~( *( ( size_t* ) &vert.xyz[0] ) << 15 );
72+
hash ^= ( *( ( size_t* ) &vert.xyz[0] ) >> 10 );
73+
hash += ( *( ( size_t* ) &vert.xyz[1] ) << 3 );
74+
hash ^= ( *( ( size_t* ) &vert.xyz[1] ) >> 6 );
75+
hash += ~( *( ( size_t* ) &vert.xyz[2] ) << 11 );
76+
hash ^= ( *( ( size_t* ) &vert.xyz[2] ) >> 16 );
77+
78+
hash ^= ( *( ( size_t* ) &vert.st[0] ) << 7 );
79+
hash += ( *( ( size_t* ) &vert.st[0] ) >> 12 );
80+
81+
hash ^= ( *( ( size_t* ) &vert.st[1] ) << 13 );
82+
hash += ( *( ( size_t* ) &vert.st[1] ) >> 8 );
83+
84+
return hash;
85+
}
86+
};
87+
88+
static bool CompareEpsilon( float lhs, float rhs ) {
89+
float diff = fabsf( lhs - rhs );
90+
return diff <= 0.000001;
91+
}
92+
93+
struct MapVertEqual {
94+
bool operator()( const srfVert_t& lhs, const srfVert_t& rhs ) const {
95+
return VectorCompare( lhs.xyz, rhs.xyz )
96+
&& CompareEpsilon( lhs.st[0], rhs.st[0] ) && CompareEpsilon( lhs.st[1], rhs.st[1] )
97+
&& CompareEpsilon( lhs.lightmap[0], rhs.lightmap[0] ) && CompareEpsilon( lhs.lightmap[1], rhs.lightmap[1] )
98+
&& VectorCompareEpsilon( lhs.normal, rhs.normal, 0.0001f )
99+
&& CompareEpsilon( lhs.qtangent[0], rhs.qtangent[0] ) && CompareEpsilon( lhs.qtangent[1], rhs.qtangent[1] )
100+
&& CompareEpsilon( lhs.qtangent[2], rhs.qtangent[2] ) && CompareEpsilon( lhs.qtangent[3], rhs.qtangent[3] )
101+
&& lhs.lightColor.ArrayBytes() == rhs.lightColor.ArrayBytes();
102+
}
103+
};
104+
68105
void OptimiseMapGeometryCore( world_t* world, bspSurface_t** rendererSurfaces, int numSurfaces );
69106
void MergeLeafSurfacesCore( world_t* world, bspSurface_t** rendererSurfaces, int numSurfaces );
107+
void MergeDuplicateVertices( bspSurface_t** rendererSurfaces, int numSurfaces, srfVert_t* vertices, int numVerticesIn,
108+
glIndex_t* indices, int numIndicesIn, int& numVerticesOut, int& numIndicesOut );
70109
std::vector<MaterialSurface> OptimiseMapGeometryMaterial( world_t* world, int numSurfaces );
71110

72111
#endif // GEOMETRY_OPTIMISER_H

src/engine/renderer/tr_bsp.cpp

Lines changed: 13 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2528,7 +2528,7 @@ R_CreateWorldVBO
25282528
static void R_CreateWorldVBO() {
25292529
int startTime = ri.Milliseconds();
25302530

2531-
int numVerts = 0;
2531+
int numVertsInitial = 0;
25322532
int numTriangles = 0;
25332533
int numSurfaces = 0;
25342534
int numPortals = 0;
@@ -2545,23 +2545,20 @@ static void R_CreateWorldVBO() {
25452545
}
25462546

25472547
if ( *surface->data == surfaceType_t::SF_FACE || *surface->data == surfaceType_t::SF_GRID
2548-
|| *surface->data == surfaceType_t::SF_TRIANGLES )
2549-
{
2548+
|| *surface->data == surfaceType_t::SF_TRIANGLES ) {
25502549
srfGeneric_t* srf = ( srfGeneric_t* ) surface->data;
25512550

2552-
numVerts += srf->numVerts;
2551+
numVertsInitial += srf->numVerts;
25532552
numTriangles += srf->numTriangles;
2554-
}
2555-
else
2556-
{
2553+
} else {
25572554
continue;
25582555
}
25592556

25602557
surface->renderable = true;
25612558
numSurfaces++;
25622559
}
25632560

2564-
if ( !numVerts || !numTriangles || !numSurfaces ) {
2561+
if ( !numVertsInitial || !numTriangles || !numSurfaces ) {
25652562
return;
25662563
}
25672564

@@ -2577,37 +2574,21 @@ static void R_CreateWorldVBO() {
25772574

25782575
OptimiseMapGeometryCore( &s_worldData, rendererSurfaces, numSurfaces );
25792576

2580-
Log::Debug( "...calculating world VBO ( %i verts %i tris )", numVerts, numTriangles );
2577+
Log::Debug( "...calculating world VBO ( %i verts %i tris )", numVertsInitial, numTriangles );
25812578

25822579
// Use srfVert_t for the temporary array used to feed R_CreateStaticVBO, despite containing
25832580
// extraneous data, so that verts can be conveniently be bulk copied from the surface.
2584-
srfVert_t* vboVerts = ( srfVert_t* ) ri.Hunk_AllocateTempMemory( numVerts * sizeof( srfVert_t ) );
2581+
srfVert_t* vboVerts = ( srfVert_t* ) ri.Hunk_AllocateTempMemory( numVertsInitial * sizeof( srfVert_t ) );
25852582
glIndex_t* vboIdxs = ( glIndex_t* ) ri.Hunk_AllocateTempMemory( 3 * numTriangles * sizeof( glIndex_t ) );
25862583

2584+
int numVerts;
2585+
int numIndices;
2586+
MergeDuplicateVertices( rendererSurfaces, numSurfaces, vboVerts, numVertsInitial, vboIdxs, 3 * numTriangles, numVerts, numIndices );
2587+
25872588
if ( glConfig2.usingMaterialSystem ) {
25882589
OptimiseMapGeometryMaterial( &s_worldData, numSurfaces );
25892590
}
25902591

2591-
// set up triangle and vertex arrays
2592-
int vboNumVerts = 0;
2593-
int vboNumIndexes = 0;
2594-
2595-
for ( int i = 0; i < numSurfaces; i++ ) {
2596-
bspSurface_t* surface = rendererSurfaces[i];
2597-
srfGeneric_t* srf = ( srfGeneric_t* ) surface->data;
2598-
2599-
srf->firstIndex = vboNumIndexes;
2600-
2601-
for ( srfTriangle_t* surfTriangle = srf->triangles; surfTriangle < srf->triangles + srf->numTriangles; surfTriangle++ ) {
2602-
vboIdxs[vboNumIndexes++] = vboNumVerts + surfTriangle->indexes[0];
2603-
vboIdxs[vboNumIndexes++] = vboNumVerts + surfTriangle->indexes[1];
2604-
vboIdxs[vboNumIndexes++] = vboNumVerts + surfTriangle->indexes[2];
2605-
}
2606-
2607-
std::copy_n( srf->verts, srf->numVerts, vboVerts + vboNumVerts );
2608-
vboNumVerts += srf->numVerts;
2609-
}
2610-
26112592
s_worldData.numPortals = numPortals;
26122593
s_worldData.portals = ( AABB* ) ri.Hunk_Alloc( numPortals * sizeof( AABB ), ha_pref::h_low );
26132594
int portal = 0;
@@ -2646,9 +2627,6 @@ static void R_CreateWorldVBO() {
26462627
}
26472628
}
26482629

2649-
ASSERT_EQ( vboNumVerts, numVerts );
2650-
ASSERT_EQ( vboNumIndexes, numTriangles * 3 );
2651-
26522630
vertexAttributeSpec_t attrs[]{
26532631
{ ATTR_INDEX_POSITION, GL_FLOAT, GL_FLOAT, &vboVerts[0].xyz, 3, sizeof( *vboVerts ), 0 },
26542632
{ ATTR_INDEX_COLOR, GL_UNSIGNED_BYTE, GL_UNSIGNED_BYTE, &vboVerts[0].lightColor, 4, sizeof( *vboVerts ), ATTR_OPTION_NORMALIZE },
@@ -2657,11 +2635,11 @@ static void R_CreateWorldVBO() {
26572635
};
26582636

26592637
if ( glConfig2.usingGeometryCache ) {
2660-
geometryCache.AddMapGeometry( vboNumVerts, vboNumIndexes, std::begin( attrs ), std::end( attrs ), vboIdxs );
2638+
geometryCache.AddMapGeometry( numVerts, numIndices, std::begin( attrs ), std::end( attrs ), vboIdxs );
26612639
}
26622640

26632641
s_worldData.vbo = R_CreateStaticVBO(
2664-
"staticWorld_VBO", std::begin( attrs ), std::end( attrs ), vboNumVerts );
2642+
"staticWorld_VBO", std::begin( attrs ), std::end( attrs ), numVerts );
26652643
s_worldData.ibo = R_CreateStaticIBO2( "staticWorld_IBO", numTriangles, vboIdxs );
26662644

26672645
ri.Hunk_FreeTempMemory( vboIdxs );

0 commit comments

Comments
 (0)