Skip to content

Commit 88e7cbe

Browse files
committed
Merge duplicate map vertices
1 parent 3331c58 commit 88e7cbe

3 files changed

Lines changed: 93 additions & 37 deletions

File tree

src/engine/renderer/GeometryOptimiser.cpp

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,45 @@ 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();
301+
302+
std::unordered_map<srfVert_t, uint32_t, MapVertHasher, MapVertEqual> verts;
303+
uint32_t idx = 0;
304+
uint32_t vertIdx = 0;
305+
for ( int i = 0; i < numSurfaces; i++ ) {
306+
bspSurface_t* surface = rendererSurfaces[i];
307+
308+
srfGeneric_t* face = ( srfGeneric_t* ) surface->data;
309+
face->firstIndex = idx;
310+
for ( srfTriangle_t* triangle = face->triangles; triangle < face->triangles + face->numTriangles; triangle++ ) {
311+
for ( int j = 0; j < 3; j++ ) {
312+
srfVert_t& vert = face->verts[triangle->indexes[j]];
313+
uint32_t index = verts[vert];
314+
315+
ASSERT_LT( idx, numIndicesIn );
316+
if ( !index ) {
317+
verts[vert] = vertIdx + 1;
318+
vertices[vertIdx] = vert;
319+
indices[idx] = vertIdx;
320+
321+
ASSERT_LT( vertIdx, numVerticesIn );
322+
323+
vertIdx++;
324+
} else {
325+
indices[idx] = index - 1;
326+
}
327+
idx++;
328+
}
329+
}
330+
}
331+
332+
numVerticesOut = vertIdx;
333+
numIndicesOut = idx;
334+
335+
Log::Notice( "Merged %i vertices into %i in %i ms", numVerticesIn, numVerticesOut, Sys::Milliseconds() - start );
336+
}
298337

299338
static void ProcessMaterialSurface( MaterialSurface& surface, std::vector<MaterialSurface>& materialSurfaces,
300339
std::vector<MaterialSurface>& processedMaterialSurfaces,

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, int numTriangles );
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
srfVert_t* verts, int numVerts, glIndex_t* indices, int numIndices );
72111

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,13 +2574,17 @@ 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
srfVert_t* materialVerts = ( srfVert_t* ) ri.Hunk_AllocateTempMemory( numVerts * sizeof( srfVert_t ) );
25892590
glIndex_t* materialIdxs = ( glIndex_t* ) ri.Hunk_AllocateTempMemory( numTriangles * 3 * sizeof( glIndex_t ) );
@@ -2594,26 +2595,6 @@ static void R_CreateWorldVBO() {
25942595
ri.Hunk_FreeTempMemory( materialVerts );
25952596
}
25962597

2597-
// set up triangle and vertex arrays
2598-
int vboNumVerts = 0;
2599-
int vboNumIndexes = 0;
2600-
2601-
for ( int i = 0; i < numSurfaces; i++ ) {
2602-
bspSurface_t* surface = rendererSurfaces[i];
2603-
srfGeneric_t* srf = ( srfGeneric_t* ) surface->data;
2604-
2605-
srf->firstIndex = vboNumIndexes;
2606-
2607-
for ( srfTriangle_t* surfTriangle = srf->triangles; surfTriangle < srf->triangles + srf->numTriangles; surfTriangle++ ) {
2608-
vboIdxs[vboNumIndexes++] = vboNumVerts + surfTriangle->indexes[0];
2609-
vboIdxs[vboNumIndexes++] = vboNumVerts + surfTriangle->indexes[1];
2610-
vboIdxs[vboNumIndexes++] = vboNumVerts + surfTriangle->indexes[2];
2611-
}
2612-
2613-
std::copy_n( srf->verts, srf->numVerts, vboVerts + vboNumVerts );
2614-
vboNumVerts += srf->numVerts;
2615-
}
2616-
26172598
s_worldData.numPortals = numPortals;
26182599
s_worldData.portals = ( AABB* ) ri.Hunk_Alloc( numPortals * sizeof( AABB ), ha_pref::h_low );
26192600
int portal = 0;
@@ -2652,9 +2633,6 @@ static void R_CreateWorldVBO() {
26522633
}
26532634
}
26542635

2655-
ASSERT_EQ( vboNumVerts, numVerts );
2656-
ASSERT_EQ( vboNumIndexes, numTriangles * 3 );
2657-
26582636
vertexAttributeSpec_t attrs[]{
26592637
{ ATTR_INDEX_POSITION, GL_FLOAT, GL_FLOAT, &vboVerts[0].xyz, 3, sizeof( *vboVerts ), 0 },
26602638
{ ATTR_INDEX_COLOR, GL_UNSIGNED_BYTE, GL_UNSIGNED_BYTE, &vboVerts[0].lightColor, 4, sizeof( *vboVerts ), ATTR_OPTION_NORMALIZE },
@@ -2663,11 +2641,11 @@ static void R_CreateWorldVBO() {
26632641
};
26642642

26652643
if ( glConfig2.usingGeometryCache ) {
2666-
geometryCache.AddMapGeometry( vboNumVerts, vboNumIndexes, std::begin( attrs ), std::end( attrs ), vboIdxs );
2644+
geometryCache.AddMapGeometry( numVerts, numIndices, std::begin( attrs ), std::end( attrs ), vboIdxs );
26672645
}
26682646

26692647
s_worldData.vbo = R_CreateStaticVBO(
2670-
"staticWorld_VBO", std::begin( attrs ), std::end( attrs ), vboNumVerts );
2648+
"staticWorld_VBO", std::begin( attrs ), std::end( attrs ), numVerts );
26712649
s_worldData.ibo = R_CreateStaticIBO2( "staticWorld_IBO", numTriangles, vboIdxs );
26722650

26732651
ri.Hunk_FreeTempMemory( vboIdxs );

0 commit comments

Comments
 (0)