]> de.git.xonotic.org Git - xonotic/netradiant.git/blobdiff - tools/quake3/q3map2/tjunction.c
eol style
[xonotic/netradiant.git] / tools / quake3 / q3map2 / tjunction.c
index b3004578eca6b7e2675c8e25ba4fb8153803b654..46390dd0662daac127fb825a1e37c91d504717b2 100644 (file)
-/*\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;
+
+       edgePoint_t     chain;          // unused element of doubly linked list
+} edgeLine_t;
+
+typedef struct {
+       float           length;
+       bspDrawVert_t   *dv[2];
+} originalEdge_t;
+
+#define        MAX_ORIGINAL_EDGES      0x10000
+originalEdge_t originalEdges[MAX_ORIGINAL_EDGES];
+int                            numOriginalEdges;
+
+
+#define        MAX_EDGE_LINES          0x10000
+edgeLine_t             edgeLines[MAX_EDGE_LINES];
+int                            numEdgeLines;
+
+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 ) {
+                       if ( numOriginalEdges == MAX_ORIGINAL_EDGES ) {
+                               Error( "MAX_ORIGINAL_EDGES" );
+                       }
+                       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
+       if ( numEdgeLines >= MAX_EDGE_LINES ) {
+               Error( "MAX_EDGE_LINES" );
+       }
+
+       e = &edgeLines[ numEdgeLines ];
+       numEdgeLines++;
+
+       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                     originalVerts;
+       int                     counts[MAX_SURFACE_VERTS];
+       int                     originals[MAX_SURFACE_VERTS];
+       int                     firstVert[MAX_SURFACE_VERTS];
+       bspDrawVert_t   verts[MAX_SURFACE_VERTS], *v1, *v2;
+       int                     numVerts;
+       float           start, end, frac, c;
+       vec3_t          delta;
+       
+       
+       originalVerts = ds->numVerts;
+       
+       numVerts = 0;
+       for ( i = 0 ; i < ds->numVerts ; i++ )
+       {
+               counts[i] = 0;
+               firstVert[i] = numVerts;
+
+               // 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 )
+{
+       qboolean        valid = qtrue;
+       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++ )
+       {
+               /* don't remove points if winding is a triangle */
+               if( ds->numVerts == 3 )
+                       return valid;
+               
+               /* 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 )
+               {
+                       valid = qfalse;
+                       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--;
+               }
+       }
+       
+       /* one last check and return */
+       if( ds->numVerts < 3 )
+               valid = qfalse;
+       return valid;
+}
+
+
+
+
+
+
+
+
+
+/*
+================
+EdgeCompare
+================
+*/
+int EdgeCompare( const void *elem1, const void *elem2 ) {
+       float   d1, d2;
+
+       d1 = ((originalEdge_t *)elem1)->length;
+       d2 = ((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;
+       
+       
+       /* 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];
+               e->dv[ 0 ]->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 );
+}