@@ -73,7 +73,19 @@ static int LeafSurfaceCompare( const void* a, const void* b ) {
7373 return 0 ;
7474}
7575
76- bspSurface_t** OptimiseMapGeometryCore ( world_t * world, int &numSurfaces ) {
76+ static void CoreResetSurfaceViewCounts ( bspSurface_t** rendererSurfaces, int numSurfaces ) {
77+ for ( int i = 0 ; i < numSurfaces; i++ ) {
78+ bspSurface_t* surface = rendererSurfaces[i];
79+
80+ surface->viewCount = -1 ;
81+ surface->lightCount = -1 ;
82+ surface->interactionBits = 0 ;
83+ }
84+ }
85+
86+ void OptimiseMapGeometryCore ( world_t * world, bspSurface_t** rendererSurfaces, int numSurfaces ) {
87+ CoreResetSurfaceViewCounts ( rendererSurfaces, numSurfaces );
88+
7789 // mark matching surfaces
7890 for ( int i = 0 ; i < world->numnodes - world->numDecisionNodes ; i++ ) {
7991 bspNode_t *leaf = world->nodes + world->numDecisionNodes + i;
@@ -85,17 +97,12 @@ bspSurface_t** OptimiseMapGeometryCore( world_t* world, int &numSurfaces ) {
8597 continue ;
8698 }
8799
88- if ( *surf1->data != surfaceType_t::SF_GRID && *surf1->data != surfaceType_t::SF_TRIANGLES
89- && *surf1->data != surfaceType_t::SF_FACE ) {
100+ if ( !surf1->renderable ) {
90101 continue ;
91102 }
92103
93104 shader_t * shader1 = surf1->shader ;
94105
95- if ( shader1->isPortal || shader1->autoSpriteMode != 0 ) {
96- continue ;
97- }
98-
99106 int fogIndex1 = surf1->fogIndex ;
100107 int lightMapNum1 = surf1->lightmapNum ;
101108 surf1->viewCount = surf1 - world->surfaces ;
@@ -110,8 +117,7 @@ bspSurface_t** OptimiseMapGeometryCore( world_t* world, int &numSurfaces ) {
110117 continue ;
111118 }
112119
113- if ( *surf2->data != surfaceType_t::SF_GRID && *surf2->data != surfaceType_t::SF_TRIANGLES
114- && *surf2->data != surfaceType_t::SF_FACE ) {
120+ if ( !surf2->renderable ) {
115121 continue ;
116122 }
117123
@@ -138,31 +144,122 @@ bspSurface_t** OptimiseMapGeometryCore( world_t* world, int &numSurfaces ) {
138144 }
139145 }
140146
141- bspSurface_t** coreSurfaces = ( bspSurface_t** ) ri.Hunk_AllocateTempMemory ( sizeof ( bspSurface_t* ) * numSurfaces );
147+ qsort ( rendererSurfaces, numSurfaces, sizeof ( bspSurface_t* ), LeafSurfaceCompare );
148+ }
149+
150+ static void SphereFromBounds ( vec3_t mins, vec3_t maxs, vec3_t origin, float * radius ) {
151+ vec3_t temp;
142152
143- numSurfaces = 0 ;
144- for ( int k = 0 ; k < world->numSurfaces ; k++ ) {
145- bspSurface_t* surface = &world->surfaces [k];
153+ VectorAdd ( mins, maxs, origin );
154+ VectorScale ( origin, 0.5 , origin );
155+ VectorSubtract ( maxs, origin, temp );
156+ *radius = VectorLength ( temp );
157+ }
158+
159+ void MergeLeafSurfacesCore ( world_t * world, bspSurface_t** rendererSurfaces, int numSurfaces ) {
160+ if ( !r_mergeLeafSurfaces->integer ) {
161+ return ;
162+ }
163+
164+ // count merged/unmerged surfaces
165+ int numUnmergedSurfaces = 0 ;
166+ int numMergedSurfaces = 0 ;
167+ int oldViewCount = -2 ;
168+
169+ for ( int i = 0 ; i < numSurfaces; i++ ) {
170+ bspSurface_t* surface = rendererSurfaces[i];
171+
172+ if ( surface->viewCount == -1 ) {
173+ numUnmergedSurfaces++;
174+ } else if ( surface->viewCount != oldViewCount ) {
175+ oldViewCount = surface->viewCount ;
176+ numMergedSurfaces++;
177+ }
178+ }
146179
147- if ( surface->shader ->isPortal ) {
148- // HACK: don't use VBO because when adding a portal we have to read back the verts CPU-side
180+ // Allocate merged surfaces
181+ world->mergedSurfaces = ( bspSurface_t* ) ri.Hunk_Alloc ( sizeof ( bspSurface_t ) * numMergedSurfaces, ha_pref::h_low );
182+
183+ // actually merge surfaces
184+ bspSurface_t* mergedSurf = world->mergedSurfaces ;
185+ oldViewCount = -2 ;
186+ for ( int i = 0 ; i < numSurfaces; i++ ) {
187+ vec3_t bounds[2 ];
188+ int surfVerts = 0 ;
189+ int surfIndexes = 0 ;
190+ srfVBOMesh_t* vboSurf;
191+ bspSurface_t* surf1 = rendererSurfaces[i];
192+
193+ // skip unmergable surfaces
194+ if ( surf1->viewCount == -1 ) {
149195 continue ;
150196 }
151197
152- if ( surface-> shader -> autoSpriteMode != 0 ) {
153- // don't use VBO because verts are rewritten each time based on view origin
198+ // skip surfaces that have already been merged
199+ if ( surf1-> viewCount == oldViewCount ) {
154200 continue ;
155201 }
156202
157- if ( *surface->data == surfaceType_t::SF_FACE || *surface->data == surfaceType_t::SF_GRID
158- || *surface->data == surfaceType_t::SF_TRIANGLES ) {
159- coreSurfaces[numSurfaces++] = surface;
203+ oldViewCount = surf1->viewCount ;
204+
205+ srfGeneric_t* srf1 = ( srfGeneric_t* ) surf1->data ;
206+ int firstIndex = srf1->firstIndex ;
207+
208+ // count verts and indexes and add bounds for the merged surface
209+ ClearBounds ( bounds[0 ], bounds[1 ] );
210+ for ( int j = i; j < numSurfaces; j++ ) {
211+ bspSurface_t* surf2 = rendererSurfaces[j];
212+
213+ // stop merging when we hit a surface that can't be merged
214+ if ( surf2->viewCount != surf1->viewCount ) {
215+ break ;
216+ }
217+
218+ srfGeneric_t* srf2 = ( srfGeneric_t* ) surf2->data ;
219+ surfIndexes += srf2->numTriangles * 3 ;
220+ surfVerts += srf2->numVerts ;
221+ BoundsAdd ( bounds[0 ], bounds[1 ], srf2->bounds [0 ], srf2->bounds [1 ] );
160222 }
161- }
162223
163- qsort ( coreSurfaces, numSurfaces, sizeof ( bspSurface_t* ), LeafSurfaceCompare );
224+ if ( !surfIndexes || !surfVerts ) {
225+ continue ;
226+ }
227+
228+ vboSurf = ( srfVBOMesh_t* ) ri.Hunk_Alloc ( sizeof ( *vboSurf ), ha_pref::h_low );
229+ *vboSurf = {};
230+ vboSurf->surfaceType = surfaceType_t::SF_VBO_MESH;
231+
232+ vboSurf->numTriangles = surfIndexes / 3 ;
233+ vboSurf->numVerts = surfVerts;
234+ vboSurf->firstIndex = firstIndex;
164235
165- return coreSurfaces;
236+ vboSurf->lightmapNum = surf1->lightmapNum ;
237+ vboSurf->vbo = world->vbo ;
238+ vboSurf->ibo = world->ibo ;
239+
240+ VectorCopy ( bounds[0 ], vboSurf->bounds [0 ] );
241+ VectorCopy ( bounds[1 ], vboSurf->bounds [1 ] );
242+ SphereFromBounds ( vboSurf->bounds [0 ], vboSurf->bounds [1 ], vboSurf->origin , &vboSurf->radius );
243+
244+ mergedSurf->data = ( surfaceType_t* ) vboSurf;
245+ mergedSurf->fogIndex = surf1->fogIndex ;
246+ mergedSurf->shader = surf1->shader ;
247+ mergedSurf->lightmapNum = surf1->lightmapNum ;
248+ mergedSurf->viewCount = -1 ;
249+
250+ // redirect view surfaces to this surf
251+ for ( int k = 0 ; k < world->numMarkSurfaces ; k++ ) {
252+ bspSurface_t** view = world->viewSurfaces + k;
253+
254+ if ( ( *view )->viewCount == surf1->viewCount ) {
255+ *view = mergedSurf;
256+ }
257+ }
258+
259+ mergedSurf++;
260+ }
261+
262+ Log::Debug ( " Processed %d surfaces into %d merged, %d unmerged" , numSurfaces, numMergedSurfaces, numUnmergedSurfaces );
166263}
167264
168265/*
@@ -224,59 +321,30 @@ std::vector<MaterialSurface> OptimiseMapGeometryMaterial( world_t* world, int nu
224321 std::vector<MaterialSurface> processedMaterialSurfaces;
225322 processedMaterialSurfaces.reserve ( numSurfaces );
226323
324+ // std::unordered_map<TriEdge, TriIndex> triEdges;
325+
227326 int surfaceIndex = 0 ;
228327 for ( int k = 0 ; k < world->numSurfaces ; k++ ) {
229328 bspSurface_t* surface = &world->surfaces [k];
230329
231- if ( surface->shader ->isPortal ) {
232- continue ;
233- }
330+ MaterialSurface srf {};
234331
235- if ( surface->shader -> autoSpriteMode ) {
236- continue ;
237- }
332+ srf. shader = surface->shader ;
333+ srf. bspSurface = true ;
334+ srf. fog = surface-> fogIndex ;
238335
239- if ( *surface->data == surfaceType_t::SF_FACE || *surface->data == surfaceType_t::SF_GRID
240- || *surface->data == surfaceType_t::SF_TRIANGLES ) {
241- MaterialSurface srf {};
242-
243- srf.shader = surface->shader ;
244- srf.bspSurface = true ;
245- srf.fog = surface->fogIndex ;
246-
247- switch ( *surface->data ) {
248- case surfaceType_t::SF_FACE:
249- srf.firstIndex = ( ( srfSurfaceFace_t* ) surface->data )->firstIndex ;
250- srf.count = ( ( srfSurfaceFace_t* ) surface->data )->numTriangles ;
251- srf.verts = ( ( srfSurfaceFace_t* ) surface->data )->verts ;
252- srf.tris = ( ( srfSurfaceFace_t* ) surface->data )->triangles ;
253- break ;
254- case surfaceType_t::SF_GRID:
255- srf.firstIndex = ( ( srfGridMesh_t* ) surface->data )->firstIndex ;
256- srf.count = ( ( srfGridMesh_t* ) surface->data )->numTriangles ;
257- srf.verts = ( ( srfGridMesh_t* ) surface->data )->verts ;
258- srf.tris = ( ( srfGridMesh_t* ) surface->data )->triangles ;
259- break ;
260- case surfaceType_t::SF_TRIANGLES:
261- srf.firstIndex = ( ( srfTriangles_t* ) surface->data )->firstIndex ;
262- srf.count = ( ( srfTriangles_t* ) surface->data )->numTriangles ;
263- srf.verts = ( ( srfTriangles_t* ) surface->data )->verts ;
264- srf.tris = ( ( srfTriangles_t* ) surface->data )->triangles ;
265- break ;
266- default :
267- break ;
268- }
336+ srf.firstIndex = ( ( srfGeneric_t* ) surface->data )->firstIndex ;
337+ srf.count = ( ( srfGeneric_t* ) surface->data )->numTriangles ;
338+ srf.verts = ( ( srfGeneric_t* ) surface->data )->verts ;
339+ srf.tris = ( ( srfGeneric_t* ) surface->data )->triangles ;
269340
270- materialSurfaces.emplace_back ( srf );
271- surfaceIndex++;
272- }
341+ materialSurfaces.emplace_back ( srf );
342+ surfaceIndex++;
273343 }
274344
275345 while ( materialSurfaces.size () ) {
276346 ProcessMaterialSurface ( materialSurfaces.front (), materialSurfaces, processedMaterialSurfaces, verts, indices );
277347 }
278348
279- // qsort( materialSurfaces, numSurfaces, sizeof( bspSurface_t* ), LeafSurfaceCompare );
280-
281349 return materialSurfaces;
282350}
0 commit comments