X-Git-Url: https://de.git.xonotic.org/?a=blobdiff_plain;f=tools%2Fquake3%2Fq3map2%2Fsurface.c;h=e2ec89093b9155fd5946a38e1dc80e2987887e39;hb=76dd045925622ea3b35204df18f7fbd179b2ec51;hp=6a49c791f3eb5e33f34a1abff0815cf8a54f1565;hpb=f92c4fa25685862cc7916d67a3b23edeaf1ad47f;p=xonotic%2Fnetradiant.git diff --git a/tools/quake3/q3map2/surface.c b/tools/quake3/q3map2/surface.c index 6a49c791..e2ec8909 100644 --- a/tools/quake3/q3map2/surface.c +++ b/tools/quake3/q3map2/surface.c @@ -291,7 +291,7 @@ deletes all empty or bad surfaces from the surface list void TidyEntitySurfaces( entity_t *e ) { int i, j, deleted; - mapDrawSurface_t *out, *in; + mapDrawSurface_t *out, *in = NULL; /* note it */ @@ -1207,7 +1207,7 @@ DrawSurfaceForFlare() - ydnar creates a flare draw surface */ -mapDrawSurface_t *DrawSurfaceForFlare( int entNum, vec3_t origin, vec3_t normal, vec3_t color, char *flareShader, int lightStyle ) +mapDrawSurface_t *DrawSurfaceForFlare( int entNum, vec3_t origin, vec3_t normal, vec3_t color, const char *flareShader, int lightStyle ) { mapDrawSurface_t *ds; @@ -1356,7 +1356,7 @@ static void SubdivideFace_r( entity_t *e, brush_t *brush, side_t *side, winding_ if( (subCeil - subFloor) > subdivisions ) { /* clip the winding */ - ClipWindingEpsilon( w, planeNormal, d, epsilon, &frontWinding, &backWinding ); + ClipWindingEpsilon( w, planeNormal, d, epsilon, &frontWinding, &backWinding ); /* not strict; we assume we always keep a winding */ /* the clip may not produce two polygons if it was epsilon close */ if( frontWinding == NULL ) @@ -1498,8 +1498,14 @@ void ClipSideIntoTree_r( winding_t *w, side_t *side, node_t *node ) } plane = &mapplanes[ node->planenum ]; - ClipWindingEpsilon ( w, plane->normal, plane->dist, - ON_EPSILON, &front, &back ); + ClipWindingEpsilonStrict ( w, plane->normal, plane->dist, + ON_EPSILON, &front, &back ); /* strict, we handle the "winding disappeared" case */ + if(!front && !back) + { + /* in doubt, register it in both nodes */ + front = CopyWinding(w); + back = CopyWinding(w); + } FreeWinding( w ); ClipSideIntoTree_r( front, side, node->children[0] ); @@ -1966,35 +1972,42 @@ int FilterPointIntoTree_r( vec3_t point, mapDrawSurface_t *ds, node_t *node ) } /* -FilterBoxIntoTree_r() - ydnar -filters a box from a surface into the tree +FilterPointConvexHullIntoTree_r() - ydnar +filters the convex hull of multiple points from a surface into the tree */ -int FilterBoxIntoTree_r( vec3_t mins, vec3_t maxs, mapDrawSurface_t *ds, node_t *node ) +int FilterPointConvexHullIntoTree_r( vec3_t **points, int npoints, mapDrawSurface_t *ds, node_t *node ) { - float d, d0, d1, d2, dmin, dmax; + float d, dmin, dmax; plane_t *plane; int refs = 0; - + int i; + + if(!points) + return 0; /* is this a decision node? */ if( node->planenum != PLANENUM_LEAF ) { /* classify the point in relation to the plane */ plane = &mapplanes[ node->planenum ]; - d = DotProduct( mins, plane->normal ) - plane->dist; - d0 = (maxs[0] - mins[0]) * plane->normal[0]; - d1 = (maxs[1] - mins[1]) * plane->normal[1]; - d2 = (maxs[2] - mins[2]) * plane->normal[2]; - dmax = d + (d0>0 ? d0 : 0) + (d1>0 ? d1 : 0) + (d2>0 ? d2 : 0); - dmin = d + (d0<0 ? d0 : 0) + (d1<0 ? d1 : 0) + (d2<0 ? d2 : 0); + + dmin = dmax = DotProduct( *(points[0]), plane->normal ) - plane->dist; + for(i = 1; i < npoints; ++i) + { + d = DotProduct( *(points[i]), plane->normal ) - plane->dist; + if(d > dmax) + dmax = d; + if(d < dmin) + dmin = d; + } /* filter by this plane */ refs = 0; if( dmax >= -ON_EPSILON ) - refs += FilterBoxIntoTree_r( mins, maxs, ds, node->children[ 0 ] ); + refs += FilterPointConvexHullIntoTree_r( points, npoints, ds, node->children[ 0 ] ); if( dmin <= ON_EPSILON ) - refs += FilterBoxIntoTree_r( mins, maxs, ds, node->children[ 1 ] ); + refs += FilterPointConvexHullIntoTree_r( points, npoints, ds, node->children[ 1 ] ); /* return */ return refs; @@ -2028,16 +2041,34 @@ int FilterWindingIntoTree_r( winding_t *w, mapDrawSurface_t *ds, node_t *node ) si->mins[ 1 ] != 0.0f || si->maxs[ 1 ] != 0.0f || si->mins[ 2 ] != 0.0f || si->maxs[ 2 ] != 0.0f) ) { + static qboolean warned = qfalse; + if(!warned) + { + Sys_Printf( "WARNING: this map uses the deformVertexes move hack\n" ); + warned = qtrue; + } + /* 'fatten' the winding by the shader mins/maxs (parsed from vertexDeform move) */ /* note this winding is completely invalid (concave, nonplanar, etc) */ - fat = AllocWinding( w->numpoints * 3 ); - fat->numpoints = w->numpoints * 3; + fat = AllocWinding( w->numpoints * 3 + 3 ); + fat->numpoints = w->numpoints * 3 + 3; for( i = 0; i < w->numpoints; i++ ) { VectorCopy( w->p[ i ], fat->p[ i ] ); - VectorAdd( w->p[ i ], si->mins, fat->p[ i * 2 ] ); - VectorAdd( w->p[ i ], si->maxs, fat->p[ i * 3 ] ); + VectorAdd( w->p[ i ], si->mins, fat->p[ i + (w->numpoints+1) ] ); + VectorAdd( w->p[ i ], si->maxs, fat->p[ i + (w->numpoints+1) * 2 ] ); } + VectorCopy( w->p[ 0 ], fat->p[ i ] ); + VectorAdd( w->p[ 0 ], si->mins, fat->p[ i + w->numpoints ] ); + VectorAdd( w->p[ 0 ], si->maxs, fat->p[ i + w->numpoints * 2 ] ); + + /* + * note: this winding is STILL not suitable for ClipWindingEpsilon, and + * also does not really fulfill the intention as it only contains + * origin, +mins, +maxs, but thanks to the "closing" points I just + * added to the three sub-windings, the fattening at least doesn't make + * it worse + */ FreeWinding( w ); w = fat; @@ -2059,7 +2090,9 @@ int FilterWindingIntoTree_r( winding_t *w, mapDrawSurface_t *ds, node_t *node ) VectorCopy( p2->normal, plane2 ); plane2[ 3 ] = p2->dist; - #if 1 + #if 0 + /* div0: this is the plague (inaccurate) */ + /* invert surface plane */ VectorSubtract( vec3_origin, plane2, reverse ); reverse[ 3 ] = -plane2[ 3 ]; @@ -2070,6 +2103,8 @@ int FilterWindingIntoTree_r( winding_t *w, mapDrawSurface_t *ds, node_t *node ) if( DotProduct( plane1, reverse ) > 0.999f && fabs( plane1[ 3 ] - reverse[ 3 ] ) < 0.001f ) return FilterWindingIntoTree_r( w, ds, node->children[ 1 ] ); #else + /* div0: this is the cholera (doesn't hit enough) */ + /* the drawsurf might have an associated plane, if so, force a filter here */ if( ds->planeNum == node->planenum ) return FilterWindingIntoTree_r( w, ds, node->children[ 0 ] ); @@ -2079,10 +2114,17 @@ int FilterWindingIntoTree_r( winding_t *w, mapDrawSurface_t *ds, node_t *node ) } /* clip the winding by this plane */ - ClipWindingEpsilon( w, plane1, plane1[ 3 ], ON_EPSILON, &front, &back ); + ClipWindingEpsilonStrict( w, plane1, plane1[ 3 ], ON_EPSILON, &front, &back ); /* strict; we handle the "winding disappeared" case */ /* filter by this plane */ refs = 0; + if( front == NULL && back == NULL ) + { + /* same plane, this is an ugly hack */ + /* but better too many than too few refs */ + refs += FilterWindingIntoTree_r( CopyWinding(w), ds, node->children[ 0 ] ); + refs += FilterWindingIntoTree_r( CopyWinding(w), ds, node->children[ 1 ] ); + } if( front != NULL ) refs += FilterWindingIntoTree_r( front, ds, node->children[ 0 ] ); if( back != NULL ) @@ -2129,65 +2171,23 @@ subdivides a patch into an approximate curve and filters it into the tree static int FilterPatchIntoTree( mapDrawSurface_t *ds, tree_t *tree ) { - int i, x, y, refs; - mesh_t src, *mesh; - winding_t *w; - -#if 0 - /* subdivide the surface */ - src.width = ds->patchWidth; - src.height = ds->patchHeight; - src.verts = ds->verts; - mesh = SubdivideMesh( src, FILTER_SUBDIVISION, 32 ); + int x, y, refs = 0; - /* filter each quad into the tree (fixme: use new patch x-triangulation code?) */ - refs = 0; - for( y = 0; y < (mesh->height - 1); y++ ) - { - for( x = 0; x < (mesh->width - 1); x++ ) - { - /* triangle 1 */ - w = AllocWinding( 3 ); - w->numpoints = 3; - VectorCopy( mesh->verts[ y * mesh->width + x ].xyz, w->p[ 0 ] ); - VectorCopy( mesh->verts[ y * mesh->width + x + 1 ].xyz, w->p[ 1 ] ); - VectorCopy( mesh->verts[ (y + 1) * mesh->width + x ].xyz, w->p[ 2 ] ); - refs += FilterWindingIntoTree_r( w, ds, tree->headnode ); - - /* triangle 2 */ - w = AllocWinding( 3 ); - w->numpoints = 3; - VectorCopy( mesh->verts[ y * mesh->width + x + 1 ].xyz, w->p[ 0 ] ); - VectorCopy( mesh->verts[ (y + 1 ) * mesh->width + x + 1 ].xyz, w->p[ 1 ] ); - VectorCopy( mesh->verts[ (y + 1 ) * mesh->width + x ].xyz, w->p[ 2 ] ); - refs += FilterWindingIntoTree_r( w, ds, tree->headnode ); - } - } - - /* use point filtering as well */ - for( i = 0; i < (mesh->width * mesh->height); i++ ) - refs += FilterPointIntoTree_r( mesh->verts[ i ].xyz, ds, tree->headnode ); - - /* free the subdivided mesh and return */ - FreeMesh( mesh ); -#else for(y = 0; y + 2 < ds->patchHeight; y += 2) for(x = 0; x + 2 < ds->patchWidth; x += 2) { - vec3_t mins, maxs; - ClearBounds(mins, maxs); - AddPointToBounds(ds->verts[(y+0) * ds->patchWidth + (x+0)].xyz, mins, maxs); - AddPointToBounds(ds->verts[(y+0) * ds->patchWidth + (x+1)].xyz, mins, maxs); - AddPointToBounds(ds->verts[(y+0) * ds->patchWidth + (x+2)].xyz, mins, maxs); - AddPointToBounds(ds->verts[(y+1) * ds->patchWidth + (x+0)].xyz, mins, maxs); - AddPointToBounds(ds->verts[(y+1) * ds->patchWidth + (x+1)].xyz, mins, maxs); - AddPointToBounds(ds->verts[(y+1) * ds->patchWidth + (x+2)].xyz, mins, maxs); - AddPointToBounds(ds->verts[(y+2) * ds->patchWidth + (x+0)].xyz, mins, maxs); - AddPointToBounds(ds->verts[(y+2) * ds->patchWidth + (x+1)].xyz, mins, maxs); - AddPointToBounds(ds->verts[(y+2) * ds->patchWidth + (x+2)].xyz, mins, maxs); - refs += FilterBoxIntoTree_r(mins, maxs, ds, tree->headnode); + vec3_t *points[9]; + points[0] = &ds->verts[(y+0) * ds->patchWidth + (x+0)].xyz; + points[1] = &ds->verts[(y+0) * ds->patchWidth + (x+1)].xyz; + points[2] = &ds->verts[(y+0) * ds->patchWidth + (x+2)].xyz; + points[3] = &ds->verts[(y+1) * ds->patchWidth + (x+0)].xyz; + points[4] = &ds->verts[(y+1) * ds->patchWidth + (x+1)].xyz; + points[5] = &ds->verts[(y+1) * ds->patchWidth + (x+2)].xyz; + points[6] = &ds->verts[(y+2) * ds->patchWidth + (x+0)].xyz; + points[7] = &ds->verts[(y+2) * ds->patchWidth + (x+1)].xyz; + points[8] = &ds->verts[(y+2) * ds->patchWidth + (x+2)].xyz; + refs += FilterPointConvexHullIntoTree_r(points, 9, ds, tree->headnode); } -#endif return refs; } @@ -2874,7 +2874,10 @@ emits a bsp planar winding (brush face) drawsurface static void EmitFaceSurface(mapDrawSurface_t *ds ) { /* strip/fan finding was moved elsewhere */ - StripFaceSurface( ds ); + if(maxAreaFaceSurface) + MaxAreaFaceSurface( ds ); + else + StripFaceSurface( ds ); EmitTriangleSurface(ds); } @@ -3129,7 +3132,7 @@ int AddSurfaceModelsToTriangle_r( mapDrawSurface_t *ds, surfaceModel_t *model, b /* roll the dice (model's odds scaled by vertex alpha) */ odds = model->odds * (tri[ 0 ]->color[ 0 ][ 3 ] + tri[ 0 ]->color[ 0 ][ 3 ] + tri[ 0 ]->color[ 0 ][ 3 ]) / 765.0f; r = Random(); - if( r > model->odds ) + if( r > odds ) return 0; /* calculate scale */ @@ -3194,7 +3197,7 @@ int AddSurfaceModelsToTriangle_r( mapDrawSurface_t *ds, surfaceModel_t *model, b } /* insert the model */ - InsertModel( (char *) model->model, 0, transform, NULL, ds->celShader, ds->entityNum, ds->castShadows, ds->recvShadows, 0, ds->lightmapScale, 0, 0 ); + InsertModel( (char *) model->model, 0, 0, transform, NULL, ds->celShader, ds->entityNum, ds->castShadows, ds->recvShadows, 0, ds->lightmapScale, 0, 0 ); /* return to sender */ return 1; @@ -3472,6 +3475,7 @@ void FilterDrawsurfsIntoTree( entity_t *e, tree_t *tree ) vec3_t origin, mins, maxs; int refs; int numSurfs, numRefs, numSkyboxSurfaces; + qboolean sb; /* note it */ @@ -3490,15 +3494,18 @@ void FilterDrawsurfsIntoTree( entity_t *e, tree_t *tree ) /* get shader */ si = ds->shaderInfo; - + /* ydnar: skybox surfaces are special */ if( ds->skybox ) { refs = AddReferenceToTree_r( ds, tree->headnode, qtrue ); ds->skybox = qfalse; + sb = qtrue; } else { + sb = qfalse; + /* refs initially zero */ refs = 0; @@ -3618,6 +3625,11 @@ void FilterDrawsurfsIntoTree( entity_t *e, tree_t *tree ) refs = 0; break; } + + /* maybe surface got marked as skybox again */ + /* if we keep that flag, it will get scaled up AGAIN */ + if(sb) + ds->skybox = qfalse; /* tot up the references */ if( refs > 0 ) @@ -3656,6 +3668,7 @@ void FilterDrawsurfsIntoTree( entity_t *e, tree_t *tree ) Sys_FPrintf( SYS_VRB, "%9d (%d) emitted drawsurfs\n", numSurfs, numBSPDrawSurfaces ); Sys_FPrintf( SYS_VRB, "%9d stripped face surfaces\n", numStripSurfaces ); Sys_FPrintf( SYS_VRB, "%9d fanned face surfaces\n", numFanSurfaces ); + Sys_FPrintf( SYS_VRB, "%9d maxarea'd face surfaces\n", numMaxAreaSurfaces ); Sys_FPrintf( SYS_VRB, "%9d surface models generated\n", numSurfaceModels ); Sys_FPrintf( SYS_VRB, "%9d skybox surfaces generated\n", numSkyboxSurfaces ); for( i = 0; i < NUM_SURFACE_TYPES; i++ )