]> git.xonotic.org Git - xonotic/netradiant.git/blobdiff - tools/quake3/q3map2/surface.c
Merge commit 'f73cc19a6166fc04269f953c980175779f81b9b0' into garux-merge
[xonotic/netradiant.git] / tools / quake3 / q3map2 / surface.c
index 061e8ab6f77e4f461b8edd5adb2265a920b79268..96f7270c8d4b37067a3dce8f9d3fb93c04e8b80f 100644 (file)
@@ -187,6 +187,7 @@ mapDrawSurface_t *MakeCelSurface( mapDrawSurface_t *src, shaderInfo_t *si ){
        /* 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;
@@ -297,7 +298,7 @@ void ClearSurface( mapDrawSurface_t *ds ){
 
 void TidyEntitySurfaces( entity_t *e ){
        int i, j, deleted;
-       mapDrawSurface_t    *out, *in;
+       mapDrawSurface_t    *out, *in = NULL;
 
 
        /* note it */
@@ -568,7 +569,7 @@ void ClassifySurfaces( int numSurfs, mapDrawSurface_t *ds ){
                                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;
@@ -589,7 +590,7 @@ void ClassifySurfaces( int numSurfs, mapDrawSurface_t *ds ){
                        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 );
                }
 
                /* -----------------------------------------------------------------
@@ -597,7 +598,7 @@ void ClassifySurfaces( int numSurfs, mapDrawSurface_t *ds ){
                   ----------------------------------------------------------------- */
 
                /* 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;
@@ -646,21 +647,29 @@ void ClassifySurfaces( int numSurfs, mapDrawSurface_t *ds ){
                        //%     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;
                }
        }
 }
@@ -772,6 +781,10 @@ byte GetShaderIndexForPoint( indexMap_t *im, vec3_t eMins, vec3_t eMaxs, vec3_t
 }
 
 
+#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
@@ -818,10 +831,10 @@ shaderInfo_t *GetIndexedShader( shaderInfo_t *parent, indexMap_t *im, int numPoi
 
        /* 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 */
@@ -917,17 +930,17 @@ mapDrawSurface_t *DrawSurfaceForSide( entity_t *e, brush_t *b, side_t *s, windin
        /* 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 );
        }
 
@@ -945,6 +958,7 @@ mapDrawSurface_t *DrawSurfaceForSide( entity_t *e, brush_t *b, side_t *s, windin
        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 ) );
@@ -1019,6 +1033,11 @@ mapDrawSurface_t *DrawSurfaceForSide( entity_t *e, brush_t *b, side_t *s, windin
        /* 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;
 }
@@ -1128,6 +1147,7 @@ mapDrawSurface_t *DrawSurfaceForMesh( entity_t *e, parseMesh_t *p, mesh_t *mesh
 
        ds->shaderInfo = si;
        ds->mapMesh = p;
+       ds->sampleSize = p->lightmapSampleSize;
        ds->lightmapScale = p->lightmapScale;   /* ydnar */
        ds->patchWidth = mesh->width;
        ds->patchHeight = mesh->height;
@@ -1148,7 +1168,7 @@ mapDrawSurface_t *DrawSurfaceForMesh( entity_t *e, parseMesh_t *p, mesh_t *mesh
 
        /* spew forth errors */
        if ( VectorLength( plane ) < 0.001f ) {
-               Sys_Printf( "BOGUS " );
+               Sys_Printf( "DrawSurfaceForMesh: bogus plane\n" );
        }
 
        /* test each vert */
@@ -1228,7 +1248,7 @@ mapDrawSurface_t *DrawSurfaceForMesh( entity_t *e, parseMesh_t *p, mesh_t *mesh
    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;
 
 
@@ -1383,7 +1403,7 @@ static void SubdivideFace_r( entity_t *e, brush_t *brush, side_t *side, winding_
                /* 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 ) {
@@ -1530,8 +1550,13 @@ 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] );
@@ -2032,6 +2057,57 @@ int FilterPointIntoTree_r( vec3_t point, mapDrawSurface_t *ds, node_t *node ){
 
 
 
+/*
+   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
@@ -2040,7 +2116,7 @@ int FilterPointIntoTree_r( vec3_t point, mapDrawSurface_t *ds, node_t *node ){
 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;
 
@@ -2053,16 +2129,33 @@ int FilterWindingIntoTree_r( winding_t *w, mapDrawSurface_t *ds, node_t *node ){
                 ( 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;
@@ -2082,7 +2175,10 @@ 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) */
+                       vec4_t reverse;
+
                        /* invert surface plane */
                        VectorSubtract( vec3_origin, plane2, reverse );
                        reverse[ 3 ] = -plane2[ 3 ];
@@ -2095,6 +2191,9 @@ int FilterWindingIntoTree_r( winding_t *w, mapDrawSurface_t *ds, node_t *node ){
                                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 ] );
@@ -2106,10 +2205,16 @@ 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 ] );
                }
@@ -2156,48 +2261,24 @@ int FilterFaceIntoTree( mapDrawSurface_t *ds, tree_t *tree ){
 #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;
 }
 
@@ -2325,9 +2406,6 @@ void EmitDrawVerts( mapDrawSurface_t *ds, bspDrawSurface_t *out ){
        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 ];
 
@@ -2442,15 +2520,13 @@ void EmitDrawIndexes( mapDrawSurface_t *ds, bspDrawSurface_t *out ){
                /* 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 ],
@@ -2528,17 +2604,22 @@ void EmitFlareSurface( mapDrawSurface_t *ds ){
    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 );
@@ -2574,7 +2655,7 @@ void EmitPatchSurface( mapDrawSurface_t *ds ){
        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;
@@ -2751,11 +2832,10 @@ static void OptimizeTriangleSurface( mapDrawSurface_t *ds ){
    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 */
@@ -2888,7 +2968,12 @@ static void EmitTriangleSurface( mapDrawSurface_t *ds ){
 
 static void EmitFaceSurface( mapDrawSurface_t *ds ){
        /* strip/fan finding was moved elsewhere */
-       StripFaceSurface( ds );
+       if ( maxAreaFaceSurface ) {
+               MaxAreaFaceSurface( ds );
+       }
+       else{
+               StripFaceSurface( ds );
+       }
        EmitTriangleSurface( ds );
 }
 
@@ -3140,7 +3225,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;
                        }
 
@@ -3206,7 +3291,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 );
+                       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;
@@ -3493,6 +3578,7 @@ void FilterDrawsurfsIntoTree( entity_t *e, tree_t *tree ){
        vec3_t origin, mins, maxs;
        int refs;
        int numSurfs, numRefs, numSkyboxSurfaces;
+       qboolean sb;
 
 
        /* note it */
@@ -3517,9 +3603,12 @@ void FilterDrawsurfsIntoTree( entity_t *e, tree_t *tree ){
                if ( ds->skybox ) {
                        refs = AddReferenceToTree_r( ds, tree->headnode, qtrue );
                        ds->skybox = qfalse;
+                       sb = qtrue;
                }
                else
                {
+                       sb = qfalse;
+
                        /* refs initially zero */
                        refs = 0;
 
@@ -3549,7 +3638,7 @@ void FilterDrawsurfsIntoTree( entity_t *e, tree_t *tree ){
                        }
 
                        /* 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;
                        }
 
@@ -3572,10 +3661,10 @@ void FilterDrawsurfsIntoTree( entity_t *e, tree_t *tree ){
                }
 
                /* 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 )
                {
@@ -3596,7 +3685,7 @@ void FilterDrawsurfsIntoTree( entity_t *e, tree_t *tree ){
                                refs = FilterPatchIntoTree( ds, tree );
                        }
                        if ( refs > 0 ) {
-                               EmitPatchSurface( ds );
+                               EmitPatchSurface( e, ds );
                        }
                        break;
 
@@ -3656,6 +3745,12 @@ void FilterDrawsurfsIntoTree( entity_t *e, tree_t *tree ){
                        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 */
@@ -3671,7 +3766,7 @@ void FilterDrawsurfsIntoTree( entity_t *e, tree_t *tree ){
                                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 );
                                }
@@ -3690,6 +3785,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++ )