Skip to content

Commit 675a427

Browse files
committed
Validate BSP vertex input
q3map2 produces garbage lightmap values on some surfaces, so do this to make sure we don't get `nan` or `inf`.
1 parent 875f89b commit 675a427

File tree

3 files changed

+79
-16
lines changed

3 files changed

+79
-16
lines changed

src/engine/renderer/GeometryOptimiser.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,11 @@ void MergeDuplicateVertices( bspSurface_t** rendererSurfaces, int numSurfaces, s
315315
srfVert_t& vert = face->verts[triangle->indexes[j]];
316316
uint32_t index = verts[vert];
317317

318+
/* There were some crashes due to bad lightmap values in .bsp vertices,
319+
do the check again here just in case some calculation earlier, like patch mesh triangulation,
320+
fucks things up again */
321+
ValidateVertex( &vert, -1, surface->shader );
322+
318323
ASSERT_LT( idx, ( uint32_t ) numIndicesIn );
319324
if ( !index ) {
320325
verts[vert] = vertIdx + 1;

src/engine/renderer/tr_bsp.cpp

Lines changed: 72 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -848,6 +848,55 @@ static void SphereFromBounds( vec3_t mins, vec3_t maxs, vec3_t origin, float* ra
848848
*radius = VectorLength( temp );
849849
}
850850

851+
static std::string VertexToString( srfVert_t* vertex ) {
852+
return Str::Format( "xyz: %f %f %f normal: %f %f %f uv: %f %f lightmap: %f %f", vertex->xyz[0], vertex->xyz[1], vertex->xyz[2],
853+
vertex->normal[0], vertex->normal[1], vertex->normal[2], vertex->st[0], vertex->st[1],
854+
vertex->lightmap[0], vertex->lightmap[1] );
855+
}
856+
857+
void ValidateVertex( srfVert_t* vertex, int vertexID, shader_t* shader ) {
858+
for ( int i = 0; i < 3; i++ ) {
859+
/* NetRadiant only allows vertices in range [-65535, 65536],
860+
but some vertices still end up outside of that range, e.g: station15 sun */
861+
if ( !Math::IsFinite( vertex->xyz[i] ) || vertex->xyz[i] < -1e9 || vertex->xyz[i] > 1e9 ) {
862+
Log::Warn( "BSP: Bad position in vertex %i: %s, %s; setting to 0.0f", vertexID,
863+
VertexToString( vertex ), shader->name);
864+
vertex->xyz[i] = 0.0f;
865+
}
866+
867+
if ( !Math::IsFinite( vertex->normal[i] ) ) {
868+
Log::Warn( "BSP: Bad vertex normal %i: %s, %s; setting to 0.0f", vertexID,
869+
VertexToString( vertex ), shader->name );
870+
vertex->normal[i] = 0.0f;
871+
872+
VectorNormalize( vertex->normal );
873+
}
874+
}
875+
876+
for ( int i = 0; i < 2; i++ ) {
877+
if ( !Math::IsFinite( vertex->st[i] ) ) {
878+
Log::Warn( "BSP: Bad uv in vertex %i: %s, %s; setting to 0.0f", vertexID,
879+
VertexToString( vertex ), shader->name );
880+
vertex->st[i] = 0.0f;
881+
}
882+
883+
// q3map2 sometimes produces garbage lightmap uv's on patch meshes and on surfaces that don't seem to use lightmaps
884+
if ( !Math::IsFinite( vertex->lightmap[i] ) || vertex->lightmap[i] < -1.0f || vertex->lightmap[i] > 1.0f ) {
885+
/* Bad lightmap uv's on surfaces that don't use lightmapping seems to be very common in q3map2,
886+
so don't spam the log with them. We still need to fix such values though */
887+
for ( const shaderStage_t* pStage = shader->stages; pStage < shader->lastStage; pStage++ ) {
888+
if ( pStage->colorRenderer == &Render_lightMapping ) {
889+
Log::Warn( "BSP: Bad lightmap in vertex %i: %s, %s; setting to 0.0f", vertexID,
890+
VertexToString( vertex ), shader->name );
891+
break;
892+
}
893+
}
894+
895+
vertex->lightmap[i] = 0.0f;
896+
}
897+
}
898+
}
899+
851900
static void ParseTriangleSurface( dsurface_t* ds, drawVert_t* verts, bspSurface_t* surf, int* indexes ) {
852901
int realLightmapNum = LittleLong( ds->lightmapNum );
853902

@@ -902,21 +951,25 @@ static void ParseTriangleSurface( dsurface_t* ds, drawVert_t* verts, bspSurface_
902951
cv->verts[ i ].normal[ j ] = LittleFloat( verts[ i ].normal[ j ] );
903952
}
904953

905-
AddPointToBounds( cv->verts[ i ].xyz, cv->bounds[ 0 ], cv->bounds[ 1 ] );
906-
907954
components[ i ].minVertex = i;
908955

909956
for ( int j = 0; j < 2; j++ ) {
910957
cv->verts[ i ].st[ j ] = LittleFloat( verts[ i ].st[ j ] );
911958
cv->verts[ i ].lightmap[ j ] = LittleFloat( verts[ i ].lightmap[ j ] );
912-
913-
components[ i ].stBounds[ 0 ][ j ] = cv->verts[ i ].st[ j ];
914-
components[ i ].stBounds[ 1 ][ j ] = cv->verts[ i ].st[ j ];
915959
}
916960

917961
cv->verts[ i ].lightmap[ 0 ] = LittleFloat( verts[ i ].lightmap[ 0 ] );
918962
cv->verts[ i ].lightmap[ 1 ] = LittleFloat( verts[ i ].lightmap[ 1 ] );
919963

964+
ValidateVertex( &cv->verts[i], ds->firstVert + i, surf->shader );
965+
966+
AddPointToBounds( cv->verts[ i ].xyz, cv->bounds[ 0 ], cv->bounds[ 1 ] );
967+
968+
for( int j = 0; j < 2; j++ ) {
969+
components[ i ].stBounds[ 0 ][ j ] = cv->verts[ i ].st[ j ];
970+
components[ i ].stBounds[ 1 ][ j ] = cv->verts[ i ].st[ j ];
971+
}
972+
920973
cv->verts[ i ].lightColor = Color::Adapt( verts[ i ].color );
921974

922975
if ( tr.overbrightBits < tr.mapOverBrightBits ) {
@@ -1065,7 +1118,6 @@ static void ParseTriSurf( dsurface_t* ds, drawVert_t* verts, bspSurface_t* surf,
10651118
static void ParseMesh( dsurface_t *ds, drawVert_t *verts, bspSurface_t *surf )
10661119
{
10671120
srfGridMesh_t *grid;
1068-
int i, j;
10691121
int width, height, numPoints;
10701122
static srfVert_t points[ MAX_PATCH_SIZE * MAX_PATCH_SIZE ];
10711123
vec3_t bounds[ 2 ];
@@ -1128,26 +1180,30 @@ static void ParseMesh( dsurface_t *ds, drawVert_t *verts, bspSurface_t *surf )
11281180
stBounds[ 1 ][ 0 ] = -99999.0f;
11291181
stBounds[ 1 ][ 1 ] = -99999.0f;
11301182

1131-
for ( i = 0; i < numPoints; i++ )
1183+
for ( int i = 0; i < numPoints; i++ )
11321184
{
1133-
for ( j = 0; j < 3; j++ )
1185+
for ( int j = 0; j < 3; j++ )
11341186
{
11351187
points[ i ].xyz[ j ] = LittleFloat( verts[ i ].xyz[ j ] );
11361188
points[ i ].normal[ j ] = LittleFloat( verts[ i ].normal[ j ] );
11371189
}
11381190

1139-
for ( j = 0; j < 2; j++ )
1191+
for ( int j = 0; j < 2; j++ )
11401192
{
11411193
points[ i ].st[ j ] = LittleFloat( verts[ i ].st[ j ] );
11421194
points[ i ].lightmap[ j ] = LittleFloat( verts[ i ].lightmap[ j ] );
1143-
1144-
stBounds[ 0 ][ j ] = std::min( stBounds[ 0 ][ j ], points[ i ].st[ j ] );
1145-
stBounds[ 1 ][ j ] = std::max( stBounds[ 1 ][ j ], points[ i ].st[ j ] );
11461195
}
11471196

11481197
points[ i ].lightmap[ 0 ] = LittleFloat( verts[ i ].lightmap[ 0 ] );
11491198
points[ i ].lightmap[ 1 ] = LittleFloat( verts[ i ].lightmap[ 1 ] );
11501199

1200+
ValidateVertex( &points[i], ds->firstVert + i, surf->shader );
1201+
1202+
for( int j = 0; j < 2; j++ ) {
1203+
stBounds[ 0 ][ j ] = std::min( stBounds[ 0 ][ j ], points[ i ].st[ j ] );
1204+
stBounds[ 1 ][ j ] = std::max( stBounds[ 1 ][ j ], points[ i ].st[ j ] );
1205+
}
1206+
11511207
points[ i ].lightColor = Color::Adapt( verts[ i ].color );
11521208

11531209
if ( tr.overbrightBits < tr.mapOverBrightBits )
@@ -1157,14 +1213,14 @@ static void ParseMesh( dsurface_t *ds, drawVert_t *verts, bspSurface_t *surf )
11571213
}
11581214

11591215
// center texture coords
1160-
for( j = 0; j < 2; j++ ) {
1216+
for( int j = 0; j < 2; j++ ) {
11611217
tcOffset[ j ] = 0.5f * (stBounds[ 1 ][ j ] + stBounds[ 0 ][ j ]);
11621218
tcOffset[ j ] = rintf( tcOffset[ j ] );
11631219
}
11641220

1165-
for ( i = 0; i < numPoints; i++ )
1221+
for ( int i = 0; i < numPoints; i++ )
11661222
{
1167-
for ( j = 0; j < 2; j++ )
1223+
for ( int j = 0; j < 2; j++ )
11681224
{
11691225
points[ i ].st[ j ] -= tcOffset[ j ];
11701226
}
@@ -1177,7 +1233,7 @@ static void ParseMesh( dsurface_t *ds, drawVert_t *verts, bspSurface_t *surf )
11771233
// copy the level of detail origin, which is the center
11781234
// of the group of all curves that must subdivide the same
11791235
// to avoid cracking
1180-
for ( i = 0; i < 3; i++ )
1236+
for ( int i = 0; i < 3; i++ )
11811237
{
11821238
bounds[ 0 ][ i ] = LittleFloat( ds->lightmapVecs[ 0 ][ i ] );
11831239
bounds[ 1 ][ i ] = LittleFloat( ds->lightmapVecs[ 1 ][ i ] );

src/engine/renderer/tr_local.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1811,6 +1811,8 @@ enum class ssaoMode {
18111811

18121812
extern void ( *rb_surfaceTable[Util::ordinal(surfaceType_t::SF_NUM_SURFACE_TYPES)] )(void * );
18131813

1814+
void ValidateVertex( srfVert_t* vertex, int vertexID, shader_t* shader );
1815+
18141816
/*
18151817
==============================================================================
18161818
BRUSH MODELS - in memory representation

0 commit comments

Comments
 (0)