/* do some fixups for celshading */
ds->planar = qfalse;
ds->planeNum = -1;
+ ds->celShader = NULL; /* don't cel shade cels :P */
/* return the surface */
return ds;
void TidyEntitySurfaces( entity_t *e ){
int i, j, deleted;
- mapDrawSurface_t *out, *in;
+ mapDrawSurface_t *out, *in = NULL;
/* note it */
if ( fabs( dist ) > PLANAR_EPSILON ) {
//% if( ds->planeNum >= 0 )
//% {
- //% Sys_Printf( "WARNING: Planar surface marked unplanar (%f > %f)\n", fabs( dist ), PLANAR_EPSILON );
+ //% Sys_FPrintf( SYS_WRN, "WARNING: Planar surface marked unplanar (%f > %f)\n", fabs( dist ), PLANAR_EPSILON );
//% ds->verts[ i ].color[ 0 ][ 0 ] = ds->verts[ i ].color[ 0 ][ 2 ] = 0;
//% }
ds->planar = qfalse;
ds->planeNum = -1;
VectorClear( ds->lightmapVecs[ 2 ] );
//% if( ds->type == SURF_META || ds->type == SURF_FACE )
- //% Sys_Printf( "WARNING: Non-planar face (%d): %s\n", ds->planeNum, ds->shaderInfo->shader );
+ //% Sys_FPrintf( SYS_WRN, "WARNING: Non-planar face (%d): %s\n", ds->planeNum, ds->shaderInfo->shader );
}
/* -----------------------------------------------------------------
----------------------------------------------------------------- */
/* vertex lit surfaces don't need this information */
- if ( si->compileFlags & C_VERTEXLIT || ds->type == SURFACE_TRIANGLES ) {
+ if ( si->compileFlags & C_VERTEXLIT || ds->type == SURFACE_TRIANGLES || nolm == qtrue ) {
VectorClear( ds->lightmapAxis );
//% VectorClear( ds->lightmapVecs[ 2 ] );
ds->sampleSize = 0;
//% Sys_Printf( "Failed to map axis %d onto patch\n", bestAxis );
}
- /* get lightmap sample size */
- if ( ds->sampleSize <= 0 ) {
- ds->sampleSize = sampleSize;
- if ( ds->shaderInfo->lightmapSampleSize ) {
- ds->sampleSize = ds->shaderInfo->lightmapSampleSize;
- }
- if ( ds->lightmapScale > 0 ) {
- ds->sampleSize *= ds->lightmapScale;
- }
- if ( ds->sampleSize <= 0 ) {
- ds->sampleSize = 1;
- }
- else if ( ds->sampleSize > 16384 ) { /* powers of 2 are preferred */
- ds->sampleSize = 16384;
- }
+ /* calculate lightmap sample size */
+ if ( ds->shaderInfo->lightmapSampleSize > 0 ) { /* shader value overrides every other */
+ ds->sampleSize = ds->shaderInfo->lightmapSampleSize;
+ }
+ else if ( ds->sampleSize <= 0 ) { /* may contain the entity asigned value */
+ ds->sampleSize = sampleSize; /* otherwise use global default */
+
+ }
+ if ( ds->lightmapScale > 0.0f ) { /* apply surface lightmap scaling factor */
+ ds->sampleSize = ds->lightmapScale * (float)ds->sampleSize;
+ ds->lightmapScale = 0; /* applied */
+ }
+
+ if ( ds->sampleSize < minSampleSize ) {
+ ds->sampleSize = minSampleSize;
+ }
+
+ if ( ds->sampleSize < 1 ) {
+ ds->sampleSize = 1;
+ }
+
+ if ( ds->sampleSize > 16384 ) { /* powers of 2 are preferred */
+ ds->sampleSize = 16384;
}
}
}
}
+#define snprintf_ignore(s, n, format, ...) do { \
+ size_t __n = snprintf(s, n, format, __VA_ARGS__); \
+ if (n >= n) {} /* truncated, ignore */ \
+} while (0)
/*
GetIndexedShader() - ydnar
/* make a shader name */
if ( minShaderIndex == maxShaderIndex ) {
- sprintf( shader, "textures/%s_%d", im->shader, maxShaderIndex );
+ snprintf_ignore( shader, sizeof shader, "textures/%s_%d", im->shader, maxShaderIndex );
}
else{
- sprintf( shader, "textures/%s_%dto%d", im->shader, minShaderIndex, maxShaderIndex );
+ snprintf_ignore( shader, sizeof shader, "textures/%s_%dto%d", im->shader, minShaderIndex, maxShaderIndex );
}
/* get the shader */
/* ydnar: sky hack/fix for GL_CLAMP borders on ati cards */
if ( skyFixHack && si->skyParmsImageBase[ 0 ] != '\0' ) {
//% Sys_FPrintf( SYS_VRB, "Enabling sky hack for shader %s using env %s\n", si->shader, si->skyParmsImageBase );
- sprintf( tempShader, "%s_lf", si->skyParmsImageBase );
+ snprintf_ignore( tempShader, sizeof tempShader, "%s_lf", si->skyParmsImageBase );
DrawSurfaceForShader( tempShader );
- sprintf( tempShader, "%s_rt", si->skyParmsImageBase );
+ snprintf_ignore( tempShader, sizeof tempShader, "%s_rt", si->skyParmsImageBase );
DrawSurfaceForShader( tempShader );
- sprintf( tempShader, "%s_ft", si->skyParmsImageBase );
+ snprintf_ignore( tempShader, sizeof tempShader, "%s_ft", si->skyParmsImageBase );
DrawSurfaceForShader( tempShader );
- sprintf( tempShader, "%s_bk", si->skyParmsImageBase );
+ snprintf_ignore( tempShader, sizeof tempShader, "%s_bk", si->skyParmsImageBase );
DrawSurfaceForShader( tempShader );
- sprintf( tempShader, "%s_up", si->skyParmsImageBase );
+ snprintf_ignore( tempShader, sizeof tempShader, "%s_up", si->skyParmsImageBase );
DrawSurfaceForShader( tempShader );
- sprintf( tempShader, "%s_dn", si->skyParmsImageBase );
+ snprintf_ignore( tempShader, sizeof tempShader, "%s_dn", si->skyParmsImageBase );
DrawSurfaceForShader( tempShader );
}
ds->mapBrush = b;
ds->sideRef = AllocSideRef( s, NULL );
ds->fogNum = -1;
+ ds->sampleSize = b->lightmapSampleSize;
ds->lightmapScale = b->lightmapScale;
ds->numVerts = w->numpoints;
ds->verts = safe_malloc( ds->numVerts * sizeof( *ds->verts ) );
/* set cel shader */
ds->celShader = b->celShader;
+ /* set shade angle */
+ if ( b->shadeAngleDegrees > 0.0f ) {
+ ds->shadeAngleDegrees = b->shadeAngleDegrees;
+ }
+
/* ydnar: gs mods: moved st biasing elsewhere */
return ds;
}
ds->shaderInfo = si;
ds->mapMesh = p;
+ ds->sampleSize = p->lightmapSampleSize;
ds->lightmapScale = p->lightmapScale; /* ydnar */
ds->patchWidth = mesh->width;
ds->patchHeight = mesh->height;
/* spew forth errors */
if ( VectorLength( plane ) < 0.001f ) {
- Sys_Printf( "BOGUS " );
+ Sys_Printf( "DrawSurfaceForMesh: bogus plane\n" );
}
/* test each vert */
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;
/* subdivide if necessary */
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 ) {
}
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] );
+/*
+ FilterPointConvexHullIntoTree_r() - ydnar
+ filters the convex hull of multiple points from a surface into the tree
+ */
+
+int FilterPointConvexHullIntoTree_r( vec3_t **points, int npoints, mapDrawSurface_t *ds, node_t *node ){
+ 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 ];
+
+ 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 += FilterPointConvexHullIntoTree_r( points, npoints, ds, node->children[ 0 ] );
+ }
+ if ( dmin <= ON_EPSILON ) {
+ refs += FilterPointConvexHullIntoTree_r( points, npoints, ds, node->children[ 1 ] );
+ }
+
+ /* return */
+ return refs;
+ }
+
+ /* add a reference */
+ return AddReferenceToLeaf( ds, node );
+}
+
+
+
/*
FilterWindingIntoTree_r() - ydnar
filters a winding from a drawsurface into the tree
int FilterWindingIntoTree_r( winding_t *w, mapDrawSurface_t *ds, node_t *node ){
int i, refs = 0;
plane_t *p1, *p2;
- vec4_t plane1, plane2, reverse;
+ vec4_t plane1, plane2;
winding_t *fat, *front, *back;
shaderInfo_t *si;
( si->mins[ 0 ] != 0.0f || si->maxs[ 0 ] != 0.0f ||
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_FPrintf( SYS_WRN, "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;
VectorCopy( p2->normal, plane2 );
plane2[ 3 ] = p2->dist;
- #if 1
+ #if 0
+ /* div0: this is the plague (inaccurate) */
+ vec4_t reverse;
+
/* invert surface plane */
VectorSubtract( vec3_origin, plane2, reverse );
reverse[ 3 ] = -plane2[ 3 ];
return FilterWindingIntoTree_r( w, ds, node->children[ 1 ] );
}
#else
+ (void) plane2;
+ /* 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 ] );
}
/* 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 ] );
}
#define FILTER_SUBDIVISION 8
static int FilterPatchIntoTree( mapDrawSurface_t *ds, tree_t *tree ){
- int i, x, y, refs;
- mesh_t src, *mesh;
- winding_t *w;
-
-
- /* 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++ )
+ for ( y = 0; y + 2 < ds->patchHeight; y += 2 )
+ for ( x = 0; x + 2 < ds->patchWidth; x += 2 )
{
- /* 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 );
+ 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 );
}
- }
- /* 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 );
return refs;
}
for ( i = 0; i < ds->numVerts; i++ )
{
/* allocate a new vert */
- if ( numBSPDrawVerts == MAX_MAP_DRAW_VERTS ) {
- Error( "MAX_MAP_DRAW_VERTS" );
- }
IncDrawVerts();
dv = &bspDrawVerts[ numBSPDrawVerts - 1 ];
/* copy new unique indexes */
for ( i = 0; i < ds->numIndexes; i++ )
{
- if ( numBSPDrawIndexes == MAX_MAP_DRAW_INDEXES ) {
- Error( "MAX_MAP_DRAW_INDEXES" );
- }
+ AUTOEXPAND_BY_REALLOC_BSP( DrawIndexes, 1024 );
bspDrawIndexes[ numBSPDrawIndexes ] = ds->indexes[ i ];
/* validate the index */
if ( ds->type != SURFACE_PATCH ) {
if ( bspDrawIndexes[ numBSPDrawIndexes ] < 0 || bspDrawIndexes[ numBSPDrawIndexes ] >= ds->numVerts ) {
- Sys_Printf( "WARNING: %d %s has invalid index %d (%d)\n",
+ Sys_FPrintf( SYS_WRN, "WARNING: %d %s has invalid index %d (%d)\n",
numBSPDrawSurfaces,
ds->shaderInfo->shader,
bspDrawIndexes[ numBSPDrawIndexes ],
emits a bsp patch drawsurface
*/
-void EmitPatchSurface( mapDrawSurface_t *ds ){
+void EmitPatchSurface( entity_t *e, mapDrawSurface_t *ds ){
int i, j;
bspDrawSurface_t *out;
int surfaceFlags, contentFlags;
+ int forcePatchMeta;
+ /* vortex: _patchMeta support */
+ forcePatchMeta = IntForKey( e, "_patchMeta" );
+ if ( !forcePatchMeta ) {
+ forcePatchMeta = IntForKey( e, "patchMeta" );
+ }
/* invert the surface if necessary */
if ( ds->backSide || ds->shaderInfo->invert ) {
bspDrawVert_t *dv1, *dv2, temp;
-
/* walk the verts, flip the normal */
for ( i = 0; i < ds->numVerts; i++ )
VectorScale( ds->verts[ i ].normal, -1.0f, ds->verts[ i ].normal );
if ( debugSurfaces ) {
out->shaderNum = EmitShader( "debugsurfaces", NULL, NULL );
}
- else if ( patchMeta ) {
+ else if ( patchMeta || forcePatchMeta ) {
/* patch meta requires that we have nodraw patches for collision */
surfaceFlags = ds->shaderInfo->surfaceFlags;
contentFlags = ds->shaderInfo->contentFlags;
creates a bsp drawsurface from arbitrary triangle surfaces
*/
-static void EmitTriangleSurface( mapDrawSurface_t *ds ){
+void EmitTriangleSurface( mapDrawSurface_t *ds ){
int i, temp;
bspDrawSurface_t *out;
-
/* invert the surface if necessary */
if ( ds->backSide || ds->shaderInfo->invert ) {
/* walk the indexes, reverse the triangle order */
static void EmitFaceSurface( mapDrawSurface_t *ds ){
/* strip/fan finding was moved elsewhere */
- StripFaceSurface( ds );
+ if ( maxAreaFaceSurface ) {
+ MaxAreaFaceSurface( ds );
+ }
+ else{
+ StripFaceSurface( ds );
+ }
EmitTriangleSurface( ds );
}
/* 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;
}
}
/* insert the model */
- InsertModel( (char *) model->model, 0, transform, NULL, ds->celShader, ds->entityNum, ds->castShadows, ds->recvShadows, 0, ds->lightmapScale );
+ InsertModel( (char *) model->model, 0, 0, transform, NULL, ds->celShader, ds->entityNum, ds->castShadows, ds->recvShadows, 0, ds->lightmapScale, 0, 0, clipDepthGlobal );
/* return to sender */
return 1;
vec3_t origin, mins, maxs;
int refs;
int numSurfs, numRefs, numSkyboxSurfaces;
+ qboolean sb;
/* note it */
if ( ds->skybox ) {
refs = AddReferenceToTree_r( ds, tree->headnode, qtrue );
ds->skybox = qfalse;
+ sb = qtrue;
}
else
{
+ sb = qfalse;
+
/* refs initially zero */
refs = 0;
}
/* ydnar: don't emit nodraw surfaces (like nodraw fog) */
- if ( si != NULL && ( si->compileFlags & C_NODRAW ) && ds->type != SURFACE_PATCH ) {
+ if ( ( si->compileFlags & C_NODRAW ) && ds->type != SURFACE_PATCH ) {
continue;
}
}
/* ydnar: remap shader */
- if ( ds->shaderInfo->remapShader && ds->shaderInfo->remapShader[ 0 ] ) {
+/* if ( ds->shaderInfo->remapShader && ds->shaderInfo->remapShader[ 0 ] ) {
ds->shaderInfo = ShaderInfoForShader( ds->shaderInfo->remapShader );
}
-
+*/
/* ydnar: gs mods: handle the various types of surfaces */
switch ( ds->type )
{
refs = FilterPatchIntoTree( ds, tree );
}
if ( refs > 0 ) {
- EmitPatchSurface( ds );
+ EmitPatchSurface( e, ds );
}
break;
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 ) {
/* tot up counts */
bspDrawSurface_t *out;
out = &bspDrawSurfaces[ numBSPDrawSurfaces - 1 ];
if ( out->numVerts == 3 && out->numIndexes > 3 ) {
- Sys_Printf( "\nWARNING: Potentially bad %s surface (%d: %d, %d)\n %s\n",
+ Sys_FPrintf( SYS_WRN, "WARNING: Potentially bad %s surface (%d: %d, %d)\n %s\n",
surfaceTypes[ ds->type ],
numBSPDrawSurfaces - 1, out->numVerts, out->numIndexes, si->shader );
}
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++ )