-/*\r
-Copyright (C) 1999-2007 id Software, Inc. and contributors.\r
-For a list of contributors, see the accompanying CONTRIBUTORS file.\r
-\r
-This file is part of GtkRadiant.\r
-\r
-GtkRadiant is free software; you can redistribute it and/or modify\r
-it under the terms of the GNU General Public License as published by\r
-the Free Software Foundation; either version 2 of the License, or\r
-(at your option) any later version.\r
-\r
-GtkRadiant is distributed in the hope that it will be useful,\r
-but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
-GNU General Public License for more details.\r
-\r
-You should have received a copy of the GNU General Public License\r
-along with GtkRadiant; if not, write to the Free Software\r
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\r
-\r
-----------------------------------------------------------------------------------\r
-\r
-This code has been altered significantly from its original form, to support\r
-several games based on the Quake III Arena engine, in the form of "Q3Map2."\r
-\r
-------------------------------------------------------------------------------- */\r
-\r
-\r
-\r
-/* marker */\r
-#define TJUNCTION_C\r
-\r
-\r
-\r
-/* dependencies */\r
-#include "q3map2.h"\r
-\r
-\r
-\r
-\r
-typedef struct edgePoint_s {\r
- float intercept;\r
- vec3_t xyz;\r
- struct edgePoint_s *prev, *next;\r
-} edgePoint_t;\r
-\r
-typedef struct edgeLine_s {\r
- vec3_t normal1;\r
- float dist1;\r
- \r
- vec3_t normal2;\r
- float dist2;\r
- \r
- vec3_t origin;\r
- vec3_t dir;\r
-\r
- edgePoint_t chain; // unused element of doubly linked list\r
-} edgeLine_t;\r
-\r
-typedef struct {\r
- float length;\r
- bspDrawVert_t *dv[2];\r
-} originalEdge_t;\r
-\r
-#define MAX_ORIGINAL_EDGES 0x10000\r
-originalEdge_t originalEdges[MAX_ORIGINAL_EDGES];\r
-int numOriginalEdges;\r
-\r
-\r
-#define MAX_EDGE_LINES 0x10000\r
-edgeLine_t edgeLines[MAX_EDGE_LINES];\r
-int numEdgeLines;\r
-\r
-int c_degenerateEdges;\r
-int c_addedVerts;\r
-int c_totalVerts;\r
-\r
-int c_natural, c_rotate, c_cant;\r
-\r
-// these should be whatever epsilon we actually expect,\r
-// plus SNAP_INT_TO_FLOAT \r
-#define LINE_POSITION_EPSILON 0.25\r
-#define POINT_ON_LINE_EPSILON 0.25\r
-\r
-/*\r
-====================\r
-InsertPointOnEdge\r
-====================\r
-*/\r
-void InsertPointOnEdge( vec3_t v, edgeLine_t *e ) {\r
- vec3_t delta;\r
- float d;\r
- edgePoint_t *p, *scan;\r
-\r
- VectorSubtract( v, e->origin, delta );\r
- d = DotProduct( delta, e->dir );\r
-\r
- p = safe_malloc( sizeof(edgePoint_t) );\r
- p->intercept = d;\r
- VectorCopy( v, p->xyz );\r
-\r
- if ( e->chain.next == &e->chain ) {\r
- e->chain.next = e->chain.prev = p;\r
- p->next = p->prev = &e->chain;\r
- return;\r
- }\r
-\r
- scan = e->chain.next;\r
- for ( ; scan != &e->chain ; scan = scan->next ) {\r
- d = p->intercept - scan->intercept;\r
- if ( d > -LINE_POSITION_EPSILON && d < LINE_POSITION_EPSILON ) {\r
- free( p );\r
- return; // the point is already set\r
- }\r
-\r
- if ( p->intercept < scan->intercept ) {\r
- // insert here\r
- p->prev = scan->prev;\r
- p->next = scan;\r
- scan->prev->next = p;\r
- scan->prev = p;\r
- return;\r
- }\r
- }\r
-\r
- // add at the end\r
- p->prev = scan->prev;\r
- p->next = scan;\r
- scan->prev->next = p;\r
- scan->prev = p;\r
-}\r
-\r
-\r
-/*\r
-====================\r
-AddEdge\r
-====================\r
-*/\r
-int AddEdge( vec3_t v1, vec3_t v2, qboolean createNonAxial ) {\r
- int i;\r
- edgeLine_t *e;\r
- float d;\r
- vec3_t dir;\r
-\r
- VectorSubtract( v2, v1, dir );\r
- d = VectorNormalize( dir, dir );\r
- if ( d < 0.1 ) {\r
- // if we added a 0 length vector, it would make degenerate planes\r
- c_degenerateEdges++;\r
- return -1;\r
- }\r
-\r
- if ( !createNonAxial ) {\r
- if ( fabs( dir[0] + dir[1] + dir[2] ) != 1.0 ) {\r
- if ( numOriginalEdges == MAX_ORIGINAL_EDGES ) {\r
- Error( "MAX_ORIGINAL_EDGES" );\r
- }\r
- originalEdges[ numOriginalEdges ].dv[0] = (bspDrawVert_t *)v1;\r
- originalEdges[ numOriginalEdges ].dv[1] = (bspDrawVert_t *)v2;\r
- originalEdges[ numOriginalEdges ].length = d;\r
- numOriginalEdges++;\r
- return -1;\r
- }\r
- }\r
-\r
- for ( i = 0 ; i < numEdgeLines ; i++ ) {\r
- e = &edgeLines[i];\r
-\r
- d = DotProduct( v1, e->normal1 ) - e->dist1;\r
- if ( d < -POINT_ON_LINE_EPSILON || d > POINT_ON_LINE_EPSILON ) {\r
- continue;\r
- }\r
- d = DotProduct( v1, e->normal2 ) - e->dist2;\r
- if ( d < -POINT_ON_LINE_EPSILON || d > POINT_ON_LINE_EPSILON ) {\r
- continue;\r
- }\r
-\r
- d = DotProduct( v2, e->normal1 ) - e->dist1;\r
- if ( d < -POINT_ON_LINE_EPSILON || d > POINT_ON_LINE_EPSILON ) {\r
- continue;\r
- }\r
- d = DotProduct( v2, e->normal2 ) - e->dist2;\r
- if ( d < -POINT_ON_LINE_EPSILON || d > POINT_ON_LINE_EPSILON ) {\r
- continue;\r
- }\r
-\r
- // this is the edge\r
- InsertPointOnEdge( v1, e );\r
- InsertPointOnEdge( v2, e );\r
- return i;\r
- }\r
-\r
- // create a new edge\r
- if ( numEdgeLines >= MAX_EDGE_LINES ) {\r
- Error( "MAX_EDGE_LINES" );\r
- }\r
-\r
- e = &edgeLines[ numEdgeLines ];\r
- numEdgeLines++;\r
-\r
- e->chain.next = e->chain.prev = &e->chain;\r
-\r
- VectorCopy( v1, e->origin );\r
- VectorCopy( dir, e->dir );\r
-\r
- MakeNormalVectors( e->dir, e->normal1, e->normal2 );\r
- e->dist1 = DotProduct( e->origin, e->normal1 );\r
- e->dist2 = DotProduct( e->origin, e->normal2 );\r
-\r
- InsertPointOnEdge( v1, e );\r
- InsertPointOnEdge( v2, e );\r
-\r
- return numEdgeLines - 1;\r
-}\r
-\r
-\r
-\r
-/*\r
-AddSurfaceEdges()\r
-adds a surface's edges\r
-*/\r
-\r
-void AddSurfaceEdges( mapDrawSurface_t *ds )\r
-{\r
- int i;\r
- \r
-\r
- for( i = 0; i < ds->numVerts; i++ )\r
- {\r
- /* save the edge number in the lightmap field so we don't need to look it up again */\r
- ds->verts[i].lightmap[ 0 ][ 0 ] = \r
- AddEdge( ds->verts[ i ].xyz, ds->verts[ (i + 1) % ds->numVerts ].xyz, qfalse );\r
- }\r
-}\r
-\r
-\r
-\r
-/*\r
-ColinearEdge()\r
-determines if an edge is colinear\r
-*/\r
-\r
-qboolean ColinearEdge( vec3_t v1, vec3_t v2, vec3_t v3 )\r
-{\r
- vec3_t midpoint, dir, offset, on;\r
- float d;\r
-\r
- VectorSubtract( v2, v1, midpoint );\r
- VectorSubtract( v3, v1, dir );\r
- d = VectorNormalize( dir, dir );\r
- if ( d == 0 ) {\r
- return qfalse; // degenerate\r
- }\r
-\r
- d = DotProduct( midpoint, dir );\r
- VectorScale( dir, d, on );\r
- VectorSubtract( midpoint, on, offset );\r
- d = VectorLength ( offset );\r
-\r
- if ( d < 0.1 ) {\r
- return qtrue;\r
- }\r
-\r
- return qfalse;\r
-}\r
-\r
-\r
-\r
-/*\r
-====================\r
-AddPatchEdges\r
-\r
-Add colinear border edges, which will fix some classes of patch to\r
-brush tjunctions\r
-====================\r
-*/\r
-void AddPatchEdges( mapDrawSurface_t *ds ) {\r
- int i;\r
- float *v1, *v2, *v3;\r
-\r
- for ( i = 0 ; i < ds->patchWidth - 2; i+=2 ) {\r
- v1 = ds->verts[ i ].xyz;\r
- v2 = ds->verts[ i + 1 ].xyz;\r
- v3 = ds->verts[ i + 2 ].xyz;\r
-\r
- // if v2 is the midpoint of v1 to v3, add an edge from v1 to v3\r
- if ( ColinearEdge( v1, v2, v3 ) ) {\r
- AddEdge( v1, v3, qfalse );\r
- }\r
-\r
- v1 = ds->verts[ ( ds->patchHeight - 1 ) * ds->patchWidth + i ].xyz;\r
- v2 = ds->verts[ ( ds->patchHeight - 1 ) * ds->patchWidth + i + 1 ].xyz;\r
- v3 = ds->verts[ ( ds->patchHeight - 1 ) * ds->patchWidth + i + 2 ].xyz;\r
-\r
- // if v2 is on the v1 to v3 line, add an edge from v1 to v3\r
- if ( ColinearEdge( v1, v2, v3 ) ) {\r
- AddEdge( v1, v3, qfalse );\r
- }\r
- }\r
-\r
- for ( i = 0 ; i < ds->patchHeight - 2 ; i+=2 ) {\r
- v1 = ds->verts[ i * ds->patchWidth ].xyz;\r
- v2 = ds->verts[ ( i + 1 ) * ds->patchWidth ].xyz;\r
- v3 = ds->verts[ ( i + 2 ) * ds->patchWidth ].xyz;\r
-\r
- // if v2 is the midpoint of v1 to v3, add an edge from v1 to v3\r
- if ( ColinearEdge( v1, v2, v3 ) ) {\r
- AddEdge( v1, v3, qfalse );\r
- }\r
-\r
- v1 = ds->verts[ ( ds->patchWidth - 1 ) + i * ds->patchWidth ].xyz;\r
- v2 = ds->verts[ ( ds->patchWidth - 1 ) + ( i + 1 ) * ds->patchWidth ].xyz;\r
- v3 = ds->verts[ ( ds->patchWidth - 1 ) + ( i + 2 ) * ds->patchWidth ].xyz;\r
-\r
- // if v2 is the midpoint of v1 to v3, add an edge from v1 to v3\r
- if ( ColinearEdge( v1, v2, v3 ) ) {\r
- AddEdge( v1, v3, qfalse );\r
- }\r
- }\r
-\r
-\r
-}\r
-\r
-\r
-/*\r
-====================\r
-FixSurfaceJunctions\r
-====================\r
-*/\r
-#define MAX_SURFACE_VERTS 256\r
-void FixSurfaceJunctions( mapDrawSurface_t *ds ) {\r
- int i, j, k;\r
- edgeLine_t *e;\r
- edgePoint_t *p;\r
- int originalVerts;\r
- int counts[MAX_SURFACE_VERTS];\r
- int originals[MAX_SURFACE_VERTS];\r
- int firstVert[MAX_SURFACE_VERTS];\r
- bspDrawVert_t verts[MAX_SURFACE_VERTS], *v1, *v2;\r
- int numVerts;\r
- float start, end, frac, c;\r
- vec3_t delta;\r
- \r
- \r
- originalVerts = ds->numVerts;\r
- \r
- numVerts = 0;\r
- for ( i = 0 ; i < ds->numVerts ; i++ )\r
- {\r
- counts[i] = 0;\r
- firstVert[i] = numVerts;\r
-\r
- // copy first vert\r
- if ( numVerts == MAX_SURFACE_VERTS ) {\r
- Error( "MAX_SURFACE_VERTS" );\r
- }\r
- verts[numVerts] = ds->verts[i];\r
- originals[numVerts] = i;\r
- numVerts++;\r
-\r
- // check to see if there are any t junctions before the next vert\r
- v1 = &ds->verts[i];\r
- v2 = &ds->verts[ (i+1) % ds->numVerts ];\r
-\r
- j = (int)ds->verts[i].lightmap[ 0 ][ 0 ];\r
- if ( j == -1 ) {\r
- continue; // degenerate edge\r
- }\r
- e = &edgeLines[ j ];\r
- \r
- VectorSubtract( v1->xyz, e->origin, delta );\r
- start = DotProduct( delta, e->dir );\r
-\r
- VectorSubtract( v2->xyz, e->origin, delta );\r
- end = DotProduct( delta, e->dir );\r
-\r
-\r
- if ( start < end ) {\r
- p = e->chain.next;\r
- } else {\r
- p = e->chain.prev;\r
- }\r
-\r
- for ( ; p != &e->chain ; ) {\r
- if ( start < end ) {\r
- if ( p->intercept > end - ON_EPSILON ) {\r
- break;\r
- }\r
- } else {\r
- if ( p->intercept < end + ON_EPSILON ) {\r
- break;\r
- }\r
- }\r
-\r
- if ( \r
- ( start < end && p->intercept > start + ON_EPSILON ) ||\r
- ( start > end && p->intercept < start - ON_EPSILON ) ) {\r
- // insert this point\r
- if ( numVerts == MAX_SURFACE_VERTS ) {\r
- Error( "MAX_SURFACE_VERTS" );\r
- }\r
- \r
- /* take the exact intercept point */\r
- VectorCopy( p->xyz, verts[ numVerts ].xyz );\r
- \r
- /* interpolate the texture coordinates */\r
- frac = ( p->intercept - start ) / ( end - start );\r
- for ( j = 0 ; j < 2 ; j++ ) {\r
- verts[ numVerts ].st[j] = v1->st[j] + \r
- frac * ( v2->st[j] - v1->st[j] );\r
- }\r
- \r
- /* copy the normal (FIXME: what about nonplanar surfaces? */\r
- VectorCopy( v1->normal, verts[ numVerts ].normal );\r
- \r
- /* ydnar: interpolate the color */\r
- for( k = 0; k < MAX_LIGHTMAPS; k++ )\r
- {\r
- for( j = 0; j < 4; j++ )\r
- {\r
- c = (float) v1->color[ k ][ j ] + frac * ((float) v2->color[ k ][ j ] - (float) v1->color[ k ][ j ]);\r
- verts[ numVerts ].color[ k ][ j ] = (byte) (c < 255.0f ? c : 255);\r
- }\r
- }\r
- \r
- /* next... */\r
- originals[ numVerts ] = i;\r
- numVerts++;\r
- counts[ i ]++;\r
- }\r
-\r
- if ( start < end ) {\r
- p = p->next;\r
- } else {\r
- p = p->prev;\r
- }\r
- }\r
- }\r
-\r
- c_addedVerts += numVerts - ds->numVerts;\r
- c_totalVerts += numVerts;\r
-\r
-\r
- // FIXME: check to see if the entire surface degenerated\r
- // after snapping\r
-\r
- // rotate the points so that the initial vertex is between\r
- // two non-subdivided edges\r
- for ( i = 0 ; i < numVerts ; i++ ) {\r
- if ( originals[ (i+1) % numVerts ] == originals[ i ] ) {\r
- continue;\r
- }\r
- j = (i + numVerts - 1 ) % numVerts;\r
- k = (i + numVerts - 2 ) % numVerts;\r
- if ( originals[ j ] == originals[ k ] ) {\r
- continue;\r
- }\r
- break;\r
- }\r
-\r
- if ( i == 0 ) {\r
- // fine the way it is\r
- c_natural++;\r
-\r
- ds->numVerts = numVerts;\r
- ds->verts = safe_malloc( numVerts * sizeof( *ds->verts ) );\r
- memcpy( ds->verts, verts, numVerts * sizeof( *ds->verts ) );\r
-\r
- return;\r
- }\r
- if ( i == numVerts ) {\r
- // create a vertex in the middle to start the fan\r
- c_cant++;\r
-\r
-/*\r
- memset ( &verts[numVerts], 0, sizeof( verts[numVerts] ) );\r
- for ( i = 0 ; i < numVerts ; i++ ) {\r
- for ( j = 0 ; j < 10 ; j++ ) {\r
- verts[numVerts].xyz[j] += verts[i].xyz[j];\r
- }\r
- }\r
- for ( j = 0 ; j < 10 ; j++ ) {\r
- verts[numVerts].xyz[j] /= numVerts;\r
- }\r
-\r
- i = numVerts;\r
- numVerts++;\r
-*/\r
- } else {\r
- // just rotate the vertexes\r
- c_rotate++;\r
-\r
- }\r
-\r
- ds->numVerts = numVerts;\r
- ds->verts = safe_malloc( numVerts * sizeof( *ds->verts ) );\r
-\r
- for ( j = 0 ; j < ds->numVerts ; j++ ) {\r
- ds->verts[j] = verts[ ( j + i ) % ds->numVerts ];\r
- }\r
-}\r
-\r
-\r
-\r
-\r
-\r
-/*\r
-FixBrokenSurface() - ydnar\r
-removes nearly coincident verts from a planar winding surface\r
-returns qfalse if the surface is broken\r
-*/\r
-\r
-extern void SnapWeldVector( vec3_t a, vec3_t b, vec3_t out );\r
-\r
-#define DEGENERATE_EPSILON 0.1\r
-\r
-int c_broken = 0;\r
-\r
-qboolean FixBrokenSurface( mapDrawSurface_t *ds )\r
-{\r
- qboolean valid = qtrue;\r
- bspDrawVert_t *dv1, *dv2, avg;\r
- int i, j, k;\r
- float dist;\r
- \r
- \r
- /* dummy check */\r
- if( ds == NULL )\r
- return qfalse;\r
- if( ds->type != SURFACE_FACE )\r
- return qfalse;\r
- \r
- /* check all verts */\r
- for( i = 0; i < ds->numVerts; i++ )\r
- {\r
- /* don't remove points if winding is a triangle */\r
- if( ds->numVerts == 3 )\r
- return valid;\r
- \r
- /* get verts */\r
- dv1 = &ds->verts[ i ];\r
- dv2 = &ds->verts[ (i + 1) % ds->numVerts ];\r
- \r
- /* degenerate edge? */\r
- VectorSubtract( dv1->xyz, dv2->xyz, avg.xyz );\r
- dist = VectorLength( avg.xyz );\r
- if( dist < DEGENERATE_EPSILON )\r
- {\r
- valid = qfalse;\r
- Sys_FPrintf( SYS_VRB, "WARNING: Degenerate T-junction edge found, fixing...\n" );\r
-\r
- /* create an average drawvert */\r
- /* ydnar 2002-01-26: added nearest-integer welding preference */\r
- SnapWeldVector( dv1->xyz, dv2->xyz, avg.xyz );\r
- VectorAdd( dv1->normal, dv2->normal, avg.normal );\r
- VectorNormalize( avg.normal, avg.normal );\r
- avg.st[ 0 ] = (dv1->st[ 0 ] + dv2->st[ 0 ]) * 0.5f;\r
- avg.st[ 1 ] = (dv1->st[ 1 ] + dv2->st[ 1 ]) * 0.5f;\r
- \r
- /* lightmap st/colors */\r
- for( k = 0; k < MAX_LIGHTMAPS; k++ )\r
- {\r
- avg.lightmap[ k ][ 0 ] = (dv1->lightmap[ k ][ 0 ] + dv2->lightmap[ k ][ 0 ]) * 0.5f;\r
- avg.lightmap[ k ][ 1 ] = (dv1->lightmap[ k ][ 1 ] + dv2->lightmap[ k ][ 1 ]) * 0.5f;\r
- for( j = 0; j < 4; j++ )\r
- avg.color[ k ][ j ] = (int) (dv1->color[ k ][ j ] + dv2->color[ k ][ j ]) >> 1;\r
- }\r
- \r
- /* ydnar: der... */\r
- memcpy( dv1, &avg, sizeof( avg ) );\r
- \r
- /* move the remaining verts */\r
- for( k = i + 2; k < ds->numVerts; k++ )\r
- {\r
- /* get verts */\r
- dv1 = &ds->verts[ k ];\r
- dv2 = &ds->verts[ k - 1 ];\r
- \r
- /* copy */\r
- memcpy( dv2, dv1, sizeof( bspDrawVert_t ) );\r
- }\r
- ds->numVerts--;\r
- }\r
- }\r
- \r
- /* one last check and return */\r
- if( ds->numVerts < 3 )\r
- valid = qfalse;\r
- return valid;\r
-}\r
-\r
-\r
-\r
-\r
-\r
-\r
-\r
-\r
-\r
-/*\r
-================\r
-EdgeCompare\r
-================\r
-*/\r
-int EdgeCompare( const void *elem1, const void *elem2 ) {\r
- float d1, d2;\r
-\r
- d1 = ((originalEdge_t *)elem1)->length;\r
- d2 = ((originalEdge_t *)elem2)->length;\r
-\r
- if ( d1 < d2 ) {\r
- return -1;\r
- }\r
- if ( d2 > d1 ) {\r
- return 1;\r
- }\r
- return 0;\r
-}\r
-\r
-\r
-\r
-/*\r
-FixTJunctions\r
-call after the surface list has been pruned\r
-*/\r
-\r
-void FixTJunctions( entity_t *ent )\r
-{\r
- int i;\r
- mapDrawSurface_t *ds;\r
- shaderInfo_t *si;\r
- int axialEdgeLines;\r
- originalEdge_t *e;\r
- \r
- \r
- /* meta mode has its own t-junction code (currently not as good as this code) */\r
- //% if( meta )\r
- //% return; \r
- \r
- /* note it */\r
- Sys_FPrintf( SYS_VRB, "--- FixTJunctions ---\n" );\r
- numEdgeLines = 0;\r
- numOriginalEdges = 0;\r
- \r
- // add all the edges\r
- // this actually creates axial edges, but it\r
- // only creates originalEdge_t structures\r
- // for non-axial edges\r
- for ( i = ent->firstDrawSurf ; i < numMapDrawSurfs ; i++ )\r
- {\r
- /* get surface and early out if possible */\r
- ds = &mapDrawSurfs[ i ];\r
- si = ds->shaderInfo;\r
- if( (si->compileFlags & C_NODRAW) || si->autosprite || si->notjunc || ds->numVerts == 0 )\r
- continue;\r
- \r
- /* ydnar: gs mods: handle the various types of surfaces */\r
- switch( ds->type )\r
- {\r
- /* handle brush faces */\r
- case SURFACE_FACE:\r
- AddSurfaceEdges( ds );\r
- break;\r
- \r
- /* handle patches */\r
- case SURFACE_PATCH:\r
- AddPatchEdges( ds );\r
- break;\r
- \r
- /* fixme: make triangle surfaces t-junction */\r
- default:\r
- break;\r
- }\r
- }\r
-\r
- axialEdgeLines = numEdgeLines;\r
-\r
- // sort the non-axial edges by length\r
- qsort( originalEdges, numOriginalEdges, sizeof(originalEdges[0]), EdgeCompare );\r
-\r
- // add the non-axial edges, longest first\r
- // this gives the most accurate edge description\r
- for ( i = 0 ; i < numOriginalEdges ; i++ ) {\r
- e = &originalEdges[i];\r
- e->dv[ 0 ]->lightmap[ 0 ][ 0 ] = AddEdge( e->dv[ 0 ]->xyz, e->dv[ 1 ]->xyz, qtrue );\r
- }\r
-\r
- Sys_FPrintf( SYS_VRB, "%9d axial edge lines\n", axialEdgeLines );\r
- Sys_FPrintf( SYS_VRB, "%9d non-axial edge lines\n", numEdgeLines - axialEdgeLines );\r
- Sys_FPrintf( SYS_VRB, "%9d degenerate edges\n", c_degenerateEdges );\r
-\r
- // insert any needed vertexes\r
- for( i = ent->firstDrawSurf; i < numMapDrawSurfs ; i++ )\r
- {\r
- /* get surface and early out if possible */\r
- ds = &mapDrawSurfs[ i ];\r
- si = ds->shaderInfo;\r
- if( (si->compileFlags & C_NODRAW) || si->autosprite || si->notjunc || ds->numVerts == 0 || ds->type != SURFACE_FACE )\r
- continue;\r
- \r
- /* ydnar: gs mods: handle the various types of surfaces */\r
- switch( ds->type )\r
- {\r
- /* handle brush faces */\r
- case SURFACE_FACE:\r
- FixSurfaceJunctions( ds );\r
- if( FixBrokenSurface( ds ) == qfalse )\r
- {\r
- c_broken++;\r
- ClearSurface( ds );\r
- }\r
- break;\r
- \r
- /* fixme: t-junction triangle models and patches */\r
- default:\r
- break;\r
- }\r
- }\r
- \r
- /* emit some statistics */\r
- Sys_FPrintf( SYS_VRB, "%9d verts added for T-junctions\n", c_addedVerts );\r
- Sys_FPrintf( SYS_VRB, "%9d total verts\n", c_totalVerts );\r
- Sys_FPrintf( SYS_VRB, "%9d naturally ordered\n", c_natural );\r
- Sys_FPrintf( SYS_VRB, "%9d rotated orders\n", c_rotate );\r
- Sys_FPrintf( SYS_VRB, "%9d can't order\n", c_cant );\r
- Sys_FPrintf( SYS_VRB, "%9d broken (degenerate) surfaces removed\n", c_broken );\r
-}\r
+/* -------------------------------------------------------------------------------
+
+ Copyright (C) 1999-2007 id Software, Inc. and contributors.
+ For a list of contributors, see the accompanying CONTRIBUTORS file.
+
+ This file is part of GtkRadiant.
+
+ GtkRadiant is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ GtkRadiant is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GtkRadiant; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ ----------------------------------------------------------------------------------
+
+ This code has been altered significantly from its original form, to support
+ several games based on the Quake III Arena engine, in the form of "Q3Map2."
+
+ ------------------------------------------------------------------------------- */
+
+
+
+/* marker */
+#define TJUNCTION_C
+
+
+
+/* dependencies */
+#include "q3map2.h"
+
+
+
+
+typedef struct edgePoint_s {
+ float intercept;
+ vec3_t xyz;
+ struct edgePoint_s *prev, *next;
+} edgePoint_t;
+
+typedef struct edgeLine_s {
+ vec3_t normal1;
+ float dist1;
+
+ vec3_t normal2;
+ float dist2;
+
+ vec3_t origin;
+ vec3_t dir;
+
+ // unused element of doubly linked list
+ edgePoint_t *chain;
+} edgeLine_t;
+
+typedef struct {
+ float length;
+ bspDrawVert_t *dv[2];
+} originalEdge_t;
+
+originalEdge_t *originalEdges = NULL;
+int numOriginalEdges;
+int allocatedOriginalEdges = 0;
+
+edgeLine_t *edgeLines = NULL;
+int numEdgeLines;
+int allocatedEdgeLines = 0;
+
+int c_degenerateEdges;
+int c_addedVerts;
+int c_totalVerts;
+
+int c_natural, c_rotate, c_cant;
+
+// these should be whatever epsilon we actually expect,
+// plus SNAP_INT_TO_FLOAT
+#define LINE_POSITION_EPSILON 0.25
+#define POINT_ON_LINE_EPSILON 0.25
+
+/*
+ ====================
+ InsertPointOnEdge
+ ====================
+ */
+void InsertPointOnEdge( vec3_t v, edgeLine_t *e ) {
+ vec3_t delta;
+ float d;
+ edgePoint_t *p, *scan;
+
+ VectorSubtract( v, e->origin, delta );
+ d = DotProduct( delta, e->dir );
+
+ p = safe_malloc( sizeof( edgePoint_t ) );
+ p->intercept = d;
+ VectorCopy( v, p->xyz );
+
+ if ( e->chain->next == e->chain ) {
+ e->chain->next = e->chain->prev = p;
+ p->next = p->prev = e->chain;
+ return;
+ }
+
+ scan = e->chain->next;
+ for ( ; scan != e->chain ; scan = scan->next ) {
+ d = p->intercept - scan->intercept;
+ if ( d > -LINE_POSITION_EPSILON && d < LINE_POSITION_EPSILON ) {
+ free( p );
+ return; // the point is already set
+ }
+
+ if ( p->intercept < scan->intercept ) {
+ // insert here
+ p->prev = scan->prev;
+ p->next = scan;
+ scan->prev->next = p;
+ scan->prev = p;
+ return;
+ }
+ }
+
+ // add at the end
+ p->prev = scan->prev;
+ p->next = scan;
+ scan->prev->next = p;
+ scan->prev = p;
+}
+
+
+/*
+ ====================
+ AddEdge
+ ====================
+ */
+int AddEdge( vec3_t v1, vec3_t v2, qboolean createNonAxial ) {
+ int i;
+ edgeLine_t *e;
+ float d;
+ vec3_t dir;
+
+ VectorSubtract( v2, v1, dir );
+ d = VectorNormalize( dir, dir );
+ if ( d < 0.1 ) {
+ // if we added a 0 length vector, it would make degenerate planes
+ c_degenerateEdges++;
+ return -1;
+ }
+
+ if ( !createNonAxial ) {
+ if ( fabs( dir[0] + dir[1] + dir[2] ) != 1.0 ) {
+ AUTOEXPAND_BY_REALLOC( originalEdges, numOriginalEdges, allocatedOriginalEdges, 1024 );
+ originalEdges[ numOriginalEdges ].dv[0] = (bspDrawVert_t *)v1;
+ originalEdges[ numOriginalEdges ].dv[1] = (bspDrawVert_t *)v2;
+ originalEdges[ numOriginalEdges ].length = d;
+ numOriginalEdges++;
+ return -1;
+ }
+ }
+
+ for ( i = 0 ; i < numEdgeLines ; i++ ) {
+ e = &edgeLines[i];
+
+ d = DotProduct( v1, e->normal1 ) - e->dist1;
+ if ( d < -POINT_ON_LINE_EPSILON || d > POINT_ON_LINE_EPSILON ) {
+ continue;
+ }
+ d = DotProduct( v1, e->normal2 ) - e->dist2;
+ if ( d < -POINT_ON_LINE_EPSILON || d > POINT_ON_LINE_EPSILON ) {
+ continue;
+ }
+
+ d = DotProduct( v2, e->normal1 ) - e->dist1;
+ if ( d < -POINT_ON_LINE_EPSILON || d > POINT_ON_LINE_EPSILON ) {
+ continue;
+ }
+ d = DotProduct( v2, e->normal2 ) - e->dist2;
+ if ( d < -POINT_ON_LINE_EPSILON || d > POINT_ON_LINE_EPSILON ) {
+ continue;
+ }
+
+ // this is the edge
+ InsertPointOnEdge( v1, e );
+ InsertPointOnEdge( v2, e );
+ return i;
+ }
+
+ // create a new edge
+ AUTOEXPAND_BY_REALLOC( edgeLines, numEdgeLines, allocatedEdgeLines, 1024 );
+
+ e = &edgeLines[ numEdgeLines ];
+ numEdgeLines++;
+
+ e->chain = safe_malloc( sizeof( edgePoint_t ) );
+ e->chain->next = e->chain->prev = e->chain;
+
+ VectorCopy( v1, e->origin );
+ VectorCopy( dir, e->dir );
+
+ MakeNormalVectors( e->dir, e->normal1, e->normal2 );
+ e->dist1 = DotProduct( e->origin, e->normal1 );
+ e->dist2 = DotProduct( e->origin, e->normal2 );
+
+ InsertPointOnEdge( v1, e );
+ InsertPointOnEdge( v2, e );
+
+ return numEdgeLines - 1;
+}
+
+
+
+/*
+ AddSurfaceEdges()
+ adds a surface's edges
+ */
+
+void AddSurfaceEdges( mapDrawSurface_t *ds ){
+ int i;
+
+
+ for ( i = 0; i < ds->numVerts; i++ )
+ {
+ /* save the edge number in the lightmap field so we don't need to look it up again */
+ ds->verts[i].lightmap[ 0 ][ 0 ] =
+ AddEdge( ds->verts[ i ].xyz, ds->verts[ ( i + 1 ) % ds->numVerts ].xyz, qfalse );
+ }
+}
+
+
+
+/*
+ ColinearEdge()
+ determines if an edge is colinear
+ */
+
+qboolean ColinearEdge( vec3_t v1, vec3_t v2, vec3_t v3 ){
+ vec3_t midpoint, dir, offset, on;
+ float d;
+
+ VectorSubtract( v2, v1, midpoint );
+ VectorSubtract( v3, v1, dir );
+ d = VectorNormalize( dir, dir );
+ if ( d == 0 ) {
+ return qfalse; // degenerate
+ }
+
+ d = DotProduct( midpoint, dir );
+ VectorScale( dir, d, on );
+ VectorSubtract( midpoint, on, offset );
+ d = VectorLength( offset );
+
+ if ( d < 0.1 ) {
+ return qtrue;
+ }
+
+ return qfalse;
+}
+
+
+
+/*
+ ====================
+ AddPatchEdges
+
+ Add colinear border edges, which will fix some classes of patch to
+ brush tjunctions
+ ====================
+ */
+void AddPatchEdges( mapDrawSurface_t *ds ) {
+ int i;
+ float *v1, *v2, *v3;
+
+ for ( i = 0 ; i < ds->patchWidth - 2; i += 2 ) {
+ v1 = ds->verts[ i ].xyz;
+ v2 = ds->verts[ i + 1 ].xyz;
+ v3 = ds->verts[ i + 2 ].xyz;
+
+ // if v2 is the midpoint of v1 to v3, add an edge from v1 to v3
+ if ( ColinearEdge( v1, v2, v3 ) ) {
+ AddEdge( v1, v3, qfalse );
+ }
+
+ v1 = ds->verts[ ( ds->patchHeight - 1 ) * ds->patchWidth + i ].xyz;
+ v2 = ds->verts[ ( ds->patchHeight - 1 ) * ds->patchWidth + i + 1 ].xyz;
+ v3 = ds->verts[ ( ds->patchHeight - 1 ) * ds->patchWidth + i + 2 ].xyz;
+
+ // if v2 is on the v1 to v3 line, add an edge from v1 to v3
+ if ( ColinearEdge( v1, v2, v3 ) ) {
+ AddEdge( v1, v3, qfalse );
+ }
+ }
+
+ for ( i = 0 ; i < ds->patchHeight - 2 ; i += 2 ) {
+ v1 = ds->verts[ i * ds->patchWidth ].xyz;
+ v2 = ds->verts[ ( i + 1 ) * ds->patchWidth ].xyz;
+ v3 = ds->verts[ ( i + 2 ) * ds->patchWidth ].xyz;
+
+ // if v2 is the midpoint of v1 to v3, add an edge from v1 to v3
+ if ( ColinearEdge( v1, v2, v3 ) ) {
+ AddEdge( v1, v3, qfalse );
+ }
+
+ v1 = ds->verts[ ( ds->patchWidth - 1 ) + i * ds->patchWidth ].xyz;
+ v2 = ds->verts[ ( ds->patchWidth - 1 ) + ( i + 1 ) * ds->patchWidth ].xyz;
+ v3 = ds->verts[ ( ds->patchWidth - 1 ) + ( i + 2 ) * ds->patchWidth ].xyz;
+
+ // if v2 is the midpoint of v1 to v3, add an edge from v1 to v3
+ if ( ColinearEdge( v1, v2, v3 ) ) {
+ AddEdge( v1, v3, qfalse );
+ }
+ }
+
+
+}
+
+
+/*
+ ====================
+ FixSurfaceJunctions
+ ====================
+ */
+#define MAX_SURFACE_VERTS 256
+void FixSurfaceJunctions( mapDrawSurface_t *ds ) {
+ int i, j, k;
+ edgeLine_t *e;
+ edgePoint_t *p;
+ int counts[MAX_SURFACE_VERTS];
+ int originals[MAX_SURFACE_VERTS];
+ bspDrawVert_t verts[MAX_SURFACE_VERTS], *v1, *v2;
+ int numVerts;
+ float start, end, frac, c;
+ vec3_t delta;
+
+ // zero the verts array, verts are tested to not be null in FindMetaVertex()
+ memset( verts, 0, sizeof( verts ) );
+
+ numVerts = 0;
+ for ( i = 0 ; i < ds->numVerts ; i++ )
+ {
+ counts[i] = 0;
+
+ // copy first vert
+ if ( numVerts == MAX_SURFACE_VERTS ) {
+ Error( "MAX_SURFACE_VERTS" );
+ }
+ verts[numVerts] = ds->verts[i];
+ originals[numVerts] = i;
+ numVerts++;
+
+ // check to see if there are any t junctions before the next vert
+ v1 = &ds->verts[i];
+ v2 = &ds->verts[ ( i + 1 ) % ds->numVerts ];
+
+ j = (int)ds->verts[i].lightmap[ 0 ][ 0 ];
+ if ( j == -1 ) {
+ continue; // degenerate edge
+ }
+ e = &edgeLines[ j ];
+
+ VectorSubtract( v1->xyz, e->origin, delta );
+ start = DotProduct( delta, e->dir );
+
+ VectorSubtract( v2->xyz, e->origin, delta );
+ end = DotProduct( delta, e->dir );
+
+
+ if ( start < end ) {
+ p = e->chain->next;
+ }
+ else {
+ p = e->chain->prev;
+ }
+
+ for ( ; p != e->chain ; ) {
+ if ( start < end ) {
+ if ( p->intercept > end - ON_EPSILON ) {
+ break;
+ }
+ }
+ else {
+ if ( p->intercept < end + ON_EPSILON ) {
+ break;
+ }
+ }
+
+ if (
+ ( start < end && p->intercept > start + ON_EPSILON ) ||
+ ( start > end && p->intercept < start - ON_EPSILON ) ) {
+ // insert this point
+ if ( numVerts == MAX_SURFACE_VERTS ) {
+ Error( "MAX_SURFACE_VERTS" );
+ }
+
+ /* take the exact intercept point */
+ VectorCopy( p->xyz, verts[ numVerts ].xyz );
+
+ /* interpolate the texture coordinates */
+ frac = ( p->intercept - start ) / ( end - start );
+ for ( j = 0 ; j < 2 ; j++ ) {
+ verts[ numVerts ].st[j] = v1->st[j] +
+ frac * ( v2->st[j] - v1->st[j] );
+ }
+
+ /* copy the normal (FIXME: what about nonplanar surfaces? */
+ VectorCopy( v1->normal, verts[ numVerts ].normal );
+
+ /* ydnar: interpolate the color */
+ for ( k = 0; k < MAX_LIGHTMAPS; k++ )
+ {
+ for ( j = 0; j < 4; j++ )
+ {
+ c = (float) v1->color[ k ][ j ] + frac * ( (float) v2->color[ k ][ j ] - (float) v1->color[ k ][ j ] );
+ verts[ numVerts ].color[ k ][ j ] = (byte) ( c < 255.0f ? c : 255 );
+ }
+ }
+
+ /* next... */
+ originals[ numVerts ] = i;
+ numVerts++;
+ counts[ i ]++;
+ }
+
+ if ( start < end ) {
+ p = p->next;
+ }
+ else {
+ p = p->prev;
+ }
+ }
+ }
+
+ c_addedVerts += numVerts - ds->numVerts;
+ c_totalVerts += numVerts;
+
+
+ // FIXME: check to see if the entire surface degenerated
+ // after snapping
+
+ // rotate the points so that the initial vertex is between
+ // two non-subdivided edges
+ for ( i = 0 ; i < numVerts ; i++ ) {
+ if ( originals[ ( i + 1 ) % numVerts ] == originals[ i ] ) {
+ continue;
+ }
+ j = ( i + numVerts - 1 ) % numVerts;
+ k = ( i + numVerts - 2 ) % numVerts;
+ if ( originals[ j ] == originals[ k ] ) {
+ continue;
+ }
+ break;
+ }
+
+ if ( i == 0 ) {
+ // fine the way it is
+ c_natural++;
+
+ ds->numVerts = numVerts;
+ ds->verts = safe_malloc( numVerts * sizeof( *ds->verts ) );
+ memcpy( ds->verts, verts, numVerts * sizeof( *ds->verts ) );
+
+ return;
+ }
+ if ( i == numVerts ) {
+ // create a vertex in the middle to start the fan
+ c_cant++;
+
+/*
+ memset ( &verts[numVerts], 0, sizeof( verts[numVerts] ) );
+ for ( i = 0 ; i < numVerts ; i++ ) {
+ for ( j = 0 ; j < 10 ; j++ ) {
+ verts[numVerts].xyz[j] += verts[i].xyz[j];
+ }
+ }
+ for ( j = 0 ; j < 10 ; j++ ) {
+ verts[numVerts].xyz[j] /= numVerts;
+ }
+
+ i = numVerts;
+ numVerts++;
+ */
+ }
+ else {
+ // just rotate the vertexes
+ c_rotate++;
+
+ }
+
+ ds->numVerts = numVerts;
+ ds->verts = safe_malloc( numVerts * sizeof( *ds->verts ) );
+
+ for ( j = 0 ; j < ds->numVerts ; j++ ) {
+ ds->verts[j] = verts[ ( j + i ) % ds->numVerts ];
+ }
+}
+
+
+
+
+
+/*
+ FixBrokenSurface() - ydnar
+ removes nearly coincident verts from a planar winding surface
+ returns qfalse if the surface is broken
+ */
+
+extern void SnapWeldVector( vec3_t a, vec3_t b, vec3_t out );
+
+#define DEGENERATE_EPSILON 0.1
+
+int c_broken = 0;
+
+qboolean FixBrokenSurface( mapDrawSurface_t *ds ){
+ bspDrawVert_t *dv1, *dv2, avg;
+ int i, j, k;
+ float dist;
+
+
+ /* dummy check */
+ if ( ds == NULL ) {
+ return qfalse;
+ }
+ if ( ds->type != SURFACE_FACE ) {
+ return qfalse;
+ }
+
+ /* check all verts */
+ for ( i = 0; i < ds->numVerts; i++ )
+ {
+ /* get verts */
+ dv1 = &ds->verts[ i ];
+ dv2 = &ds->verts[ ( i + 1 ) % ds->numVerts ];
+
+ /* degenerate edge? */
+ VectorSubtract( dv1->xyz, dv2->xyz, avg.xyz );
+ dist = VectorLength( avg.xyz );
+ if ( dist < DEGENERATE_EPSILON ) {
+ Sys_FPrintf( SYS_VRB, "WARNING: Degenerate T-junction edge found, fixing...\n" );
+
+ /* create an average drawvert */
+ /* ydnar 2002-01-26: added nearest-integer welding preference */
+ SnapWeldVector( dv1->xyz, dv2->xyz, avg.xyz );
+ VectorAdd( dv1->normal, dv2->normal, avg.normal );
+ VectorNormalize( avg.normal, avg.normal );
+ avg.st[ 0 ] = ( dv1->st[ 0 ] + dv2->st[ 0 ] ) * 0.5f;
+ avg.st[ 1 ] = ( dv1->st[ 1 ] + dv2->st[ 1 ] ) * 0.5f;
+
+ /* lightmap st/colors */
+ for ( k = 0; k < MAX_LIGHTMAPS; k++ )
+ {
+ avg.lightmap[ k ][ 0 ] = ( dv1->lightmap[ k ][ 0 ] + dv2->lightmap[ k ][ 0 ] ) * 0.5f;
+ avg.lightmap[ k ][ 1 ] = ( dv1->lightmap[ k ][ 1 ] + dv2->lightmap[ k ][ 1 ] ) * 0.5f;
+ for ( j = 0; j < 4; j++ )
+ avg.color[ k ][ j ] = (int) ( dv1->color[ k ][ j ] + dv2->color[ k ][ j ] ) >> 1;
+ }
+
+ /* ydnar: der... */
+ memcpy( dv1, &avg, sizeof( avg ) );
+
+ /* move the remaining verts */
+ for ( k = i + 2; k < ds->numVerts; k++ )
+ {
+ /* get verts */
+ dv1 = &ds->verts[ k ];
+ dv2 = &ds->verts[ k - 1 ];
+
+ /* copy */
+ memcpy( dv2, dv1, sizeof( bspDrawVert_t ) );
+ }
+ ds->numVerts--;
+
+ /* after welding, we have to consider the same vertex again, as it now has a new neighbor dv2 */
+ --i;
+
+ /* should ds->numVerts have become 0, then i is now -1. In the next iteration, the loop will abort. */
+ }
+ }
+
+ /* one last check and return */
+ return ds->numVerts >= 3;
+}
+
+
+
+
+
+
+
+
+
+/*
+ ================
+ EdgeCompare
+ ================
+ */
+int EdgeCompare( const void *elem1, const void *elem2 ) {
+ float d1, d2;
+
+ d1 = ( (const originalEdge_t *)elem1 )->length;
+ d2 = ( (const originalEdge_t *)elem2 )->length;
+
+ if ( d1 < d2 ) {
+ return -1;
+ }
+ if ( d2 > d1 ) {
+ return 1;
+ }
+ return 0;
+}
+
+
+
+/*
+ FixTJunctions
+ call after the surface list has been pruned
+ */
+
+void FixTJunctions( entity_t *ent ){
+ int i;
+ mapDrawSurface_t *ds;
+ shaderInfo_t *si;
+ int axialEdgeLines;
+ originalEdge_t *e;
+ bspDrawVert_t *dv;
+
+ /* meta mode has its own t-junction code (currently not as good as this code) */
+ //% if( meta )
+ //% return;
+
+ /* note it */
+ Sys_FPrintf( SYS_VRB, "--- FixTJunctions ---\n" );
+ numEdgeLines = 0;
+ numOriginalEdges = 0;
+
+ // add all the edges
+ // this actually creates axial edges, but it
+ // only creates originalEdge_t structures
+ // for non-axial edges
+ for ( i = ent->firstDrawSurf ; i < numMapDrawSurfs ; i++ )
+ {
+ /* get surface and early out if possible */
+ ds = &mapDrawSurfs[ i ];
+ si = ds->shaderInfo;
+ if ( ( si->compileFlags & C_NODRAW ) || si->autosprite || si->notjunc || ds->numVerts == 0 ) {
+ continue;
+ }
+
+ /* ydnar: gs mods: handle the various types of surfaces */
+ switch ( ds->type )
+ {
+ /* handle brush faces */
+ case SURFACE_FACE:
+ AddSurfaceEdges( ds );
+ break;
+
+ /* handle patches */
+ case SURFACE_PATCH:
+ AddPatchEdges( ds );
+ break;
+
+ /* fixme: make triangle surfaces t-junction */
+ default:
+ break;
+ }
+ }
+
+ axialEdgeLines = numEdgeLines;
+
+ // sort the non-axial edges by length
+ qsort( originalEdges, numOriginalEdges, sizeof( originalEdges[0] ), EdgeCompare );
+
+ // add the non-axial edges, longest first
+ // this gives the most accurate edge description
+ for ( i = 0 ; i < numOriginalEdges ; i++ ) {
+ e = &originalEdges[i];
+ dv = e->dv[0]; // e might change during AddEdge
+ dv->lightmap[ 0 ][ 0 ] = AddEdge( e->dv[ 0 ]->xyz, e->dv[ 1 ]->xyz, qtrue );
+ }
+
+ Sys_FPrintf( SYS_VRB, "%9d axial edge lines\n", axialEdgeLines );
+ Sys_FPrintf( SYS_VRB, "%9d non-axial edge lines\n", numEdgeLines - axialEdgeLines );
+ Sys_FPrintf( SYS_VRB, "%9d degenerate edges\n", c_degenerateEdges );
+
+ // insert any needed vertexes
+ for ( i = ent->firstDrawSurf; i < numMapDrawSurfs ; i++ )
+ {
+ /* get surface and early out if possible */
+ ds = &mapDrawSurfs[ i ];
+ si = ds->shaderInfo;
+ if ( ( si->compileFlags & C_NODRAW ) || si->autosprite || si->notjunc || ds->numVerts == 0 || ds->type != SURFACE_FACE ) {
+ continue;
+ }
+
+ /* ydnar: gs mods: handle the various types of surfaces */
+ switch ( ds->type )
+ {
+ /* handle brush faces */
+ case SURFACE_FACE:
+ FixSurfaceJunctions( ds );
+ if ( FixBrokenSurface( ds ) == qfalse ) {
+ c_broken++;
+ ClearSurface( ds );
+ }
+ break;
+
+ /* fixme: t-junction triangle models and patches */
+ default:
+ break;
+ }
+ }
+
+ /* emit some statistics */
+ Sys_FPrintf( SYS_VRB, "%9d verts added for T-junctions\n", c_addedVerts );
+ Sys_FPrintf( SYS_VRB, "%9d total verts\n", c_totalVerts );
+ Sys_FPrintf( SYS_VRB, "%9d naturally ordered\n", c_natural );
+ Sys_FPrintf( SYS_VRB, "%9d rotated orders\n", c_rotate );
+ Sys_FPrintf( SYS_VRB, "%9d can't order\n", c_cant );
+ Sys_FPrintf( SYS_VRB, "%9d broken (degenerate) surfaces removed\n", c_broken );
+}