Main Page | Class Hierarchy | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

tjunction.c

Go to the documentation of this file.
00001 /*
00002 ===========================================================================
00003 Copyright (C) 1999-2005 Id Software, Inc.
00004 
00005 This file is part of Quake III Arena source code.
00006 
00007 Quake III Arena source code is free software; you can redistribute it
00008 and/or modify it under the terms of the GNU General Public License as
00009 published by the Free Software Foundation; either version 2 of the License,
00010 or (at your option) any later version.
00011 
00012 Quake III Arena source code is distributed in the hope that it will be
00013 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 GNU General Public License for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Foobar; if not, write to the Free Software
00019 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00020 ===========================================================================
00021 */
00022 #include "qbsp.h"
00023 
00024 typedef struct edgePoint_s {
00025     float       intercept;
00026     vec3_t      xyz;
00027     struct edgePoint_s  *prev, *next;
00028 } edgePoint_t;
00029 
00030 typedef struct edgeLine_s {
00031     vec3_t      normal1;
00032     float       dist1;
00033     
00034     vec3_t      normal2;
00035     float       dist2;
00036     
00037     vec3_t      origin;
00038     vec3_t      dir;
00039 
00040     edgePoint_t chain;      // unused element of doubly linked list
00041 } edgeLine_t;
00042 
00043 typedef struct {
00044     float       length;
00045     drawVert_t  *dv[2];
00046 } originalEdge_t;
00047 
00048 #define MAX_ORIGINAL_EDGES  0x10000
00049 originalEdge_t  originalEdges[MAX_ORIGINAL_EDGES];
00050 int             numOriginalEdges;
00051 
00052 
00053 #define MAX_EDGE_LINES      0x10000
00054 edgeLine_t      edgeLines[MAX_EDGE_LINES];
00055 int             numEdgeLines;
00056 
00057 int             c_degenerateEdges;
00058 int             c_addedVerts;
00059 int             c_totalVerts;
00060 
00061 int             c_natural, c_rotate, c_cant;
00062 
00063 // these should be whatever epsilon we actually expect,
00064 // plus SNAP_INT_TO_FLOAT 
00065 #define LINE_POSITION_EPSILON   0.25
00066 #define POINT_ON_LINE_EPSILON   0.25
00067 
00068 /*
00069 ====================
00070 InsertPointOnEdge
00071 ====================
00072 */
00073 void InsertPointOnEdge( vec3_t v, edgeLine_t *e ) {
00074     vec3_t      delta;
00075     float       d;
00076     edgePoint_t *p, *scan;
00077 
00078     VectorSubtract( v, e->origin, delta );
00079     d = DotProduct( delta, e->dir );
00080 
00081     p = malloc( sizeof(edgePoint_t) );
00082     p->intercept = d;
00083     VectorCopy( v, p->xyz );
00084 
00085     if ( e->chain.next == &e->chain ) {
00086         e->chain.next = e->chain.prev = p;
00087         p->next = p->prev = &e->chain;
00088         return;
00089     }
00090 
00091     scan = e->chain.next;
00092     for ( ; scan != &e->chain ; scan = scan->next ) {
00093         d = p->intercept - scan->intercept;
00094         if ( d > -LINE_POSITION_EPSILON && d < LINE_POSITION_EPSILON ) {
00095             free( p );
00096             return;     // the point is already set
00097         }
00098 
00099         if ( p->intercept < scan->intercept ) {
00100             // insert here
00101             p->prev = scan->prev;
00102             p->next = scan;
00103             scan->prev->next = p;
00104             scan->prev = p;
00105             return;
00106         }
00107     }
00108 
00109     // add at the end
00110     p->prev = scan->prev;
00111     p->next = scan;
00112     scan->prev->next = p;
00113     scan->prev = p;
00114 }
00115 
00116 
00117 /*
00118 ====================
00119 AddEdge
00120 ====================
00121 */
00122 int AddEdge( vec3_t v1, vec3_t v2, qboolean createNonAxial ) {
00123     int         i;
00124     edgeLine_t  *e;
00125     float       d;
00126     vec3_t      dir;
00127 
00128     VectorSubtract( v2, v1, dir );
00129     d = VectorNormalize( dir, dir );
00130     if ( d < 0.1 ) {
00131         // if we added a 0 length vector, it would make degenerate planes
00132         c_degenerateEdges++;
00133         return -1;
00134     }
00135 
00136     if ( !createNonAxial ) {
00137         if ( fabs( dir[0] + dir[1] + dir[2] ) != 1.0 ) {
00138             if ( numOriginalEdges == MAX_ORIGINAL_EDGES ) {
00139                 Error( "MAX_ORIGINAL_EDGES" );
00140             }
00141             originalEdges[ numOriginalEdges ].dv[0] = (drawVert_t *)v1;
00142             originalEdges[ numOriginalEdges ].dv[1] = (drawVert_t *)v2;
00143             originalEdges[ numOriginalEdges ].length = d;
00144             numOriginalEdges++;
00145             return -1;
00146         }
00147     }
00148 
00149     for ( i = 0 ; i < numEdgeLines ; i++ ) {
00150         e = &edgeLines[i];
00151 
00152         d = DotProduct( v1, e->normal1 ) - e->dist1;
00153         if ( d < -POINT_ON_LINE_EPSILON || d > POINT_ON_LINE_EPSILON ) {
00154             continue;
00155         }
00156         d = DotProduct( v1, e->normal2 ) - e->dist2;
00157         if ( d < -POINT_ON_LINE_EPSILON || d > POINT_ON_LINE_EPSILON ) {
00158             continue;
00159         }
00160 
00161         d = DotProduct( v2, e->normal1 ) - e->dist1;
00162         if ( d < -POINT_ON_LINE_EPSILON || d > POINT_ON_LINE_EPSILON ) {
00163             continue;
00164         }
00165         d = DotProduct( v2, e->normal2 ) - e->dist2;
00166         if ( d < -POINT_ON_LINE_EPSILON || d > POINT_ON_LINE_EPSILON ) {
00167             continue;
00168         }
00169 
00170         // this is the edge
00171         InsertPointOnEdge( v1, e );
00172         InsertPointOnEdge( v2, e );
00173         return i;
00174     }
00175 
00176     // create a new edge
00177     if ( numEdgeLines >= MAX_EDGE_LINES ) {
00178         Error( "MAX_EDGE_LINES" );
00179     }
00180 
00181     e = &edgeLines[ numEdgeLines ];
00182     numEdgeLines++;
00183 
00184     e->chain.next = e->chain.prev = &e->chain;
00185 
00186     VectorCopy( v1, e->origin );
00187     VectorCopy( dir, e->dir );
00188 
00189     MakeNormalVectors( e->dir, e->normal1, e->normal2 );
00190     e->dist1 = DotProduct( e->origin, e->normal1 );
00191     e->dist2 = DotProduct( e->origin, e->normal2 );
00192 
00193     InsertPointOnEdge( v1, e );
00194     InsertPointOnEdge( v2, e );
00195 
00196     return numEdgeLines - 1;
00197 }
00198 
00199 /*
00200 ====================
00201 AddSurfaceEdges
00202 ====================
00203 */
00204 void AddSurfaceEdges( mapDrawSurface_t *ds ) {
00205     int     i;
00206 
00207     for ( i = 0 ; i < ds->numVerts ; i++ ) {
00208         // save the edge number in the lightmap field
00209         // so we don't need to look it up again
00210         ds->verts[i].lightmap[0] = 
00211             AddEdge( ds->verts[i].xyz, ds->verts[(i+1) % ds->numVerts].xyz, qfalse );
00212     }
00213 }
00214 
00215 /*
00216 ================
00217 ColinearEdge
00218 ================
00219 */
00220 qboolean ColinearEdge( vec3_t v1, vec3_t v2, vec3_t v3 ) {
00221     vec3_t  midpoint, dir, offset, on;
00222     float   d;
00223 
00224     VectorSubtract( v2, v1, midpoint );
00225     VectorSubtract( v3, v1, dir );
00226     d = VectorNormalize( dir, dir );
00227     if ( d == 0 ) {
00228         return qfalse;  // degenerate
00229     }
00230 
00231     d = DotProduct( midpoint, dir );
00232     VectorScale( dir, d, on );
00233     VectorSubtract( midpoint, on, offset );
00234     d = VectorLength ( offset );
00235 
00236     if ( d < 0.1 ) {
00237         return qtrue;
00238     }
00239 
00240     return qfalse;
00241 }
00242 
00243 /*
00244 ====================
00245 AddPatchEdges
00246 
00247 Add colinear border edges, which will fix some classes of patch to
00248 brush tjunctions
00249 ====================
00250 */
00251 void AddPatchEdges( mapDrawSurface_t *ds ) {
00252     int     i;
00253     float   *v1, *v2, *v3;
00254 
00255     for ( i = 0 ; i < ds->patchWidth - 2; i+=2 ) {
00256         v1 = ds->verts[ i ].xyz;
00257         v2 = ds->verts[ i + 1 ].xyz;
00258         v3 = ds->verts[ i + 2 ].xyz;
00259 
00260         // if v2 is the midpoint of v1 to v3, add an edge from v1 to v3
00261         if ( ColinearEdge( v1, v2, v3 ) ) {
00262             AddEdge( v1, v3, qfalse );
00263         }
00264 
00265         v1 = ds->verts[ ( ds->patchHeight - 1 ) * ds->patchWidth + i ].xyz;
00266         v2 = ds->verts[ ( ds->patchHeight - 1 ) * ds->patchWidth + i + 1 ].xyz;
00267         v3 = ds->verts[ ( ds->patchHeight - 1 ) * ds->patchWidth + i + 2 ].xyz;
00268 
00269         // if v2 is on the v1 to v3 line, add an edge from v1 to v3
00270         if ( ColinearEdge( v1, v2, v3 ) ) {
00271             AddEdge( v1, v3, qfalse );
00272         }
00273     }
00274 
00275     for ( i = 0 ; i < ds->patchHeight - 2 ; i+=2 ) {
00276         v1 = ds->verts[ i * ds->patchWidth ].xyz;
00277         v2 = ds->verts[ ( i + 1 ) * ds->patchWidth ].xyz;
00278         v3 = ds->verts[ ( i + 2 ) * ds->patchWidth ].xyz;
00279 
00280         // if v2 is the midpoint of v1 to v3, add an edge from v1 to v3
00281         if ( ColinearEdge( v1, v2, v3 ) ) {
00282             AddEdge( v1, v3, qfalse );
00283         }
00284 
00285         v1 = ds->verts[ ( ds->patchWidth - 1 ) + i * ds->patchWidth ].xyz;
00286         v2 = ds->verts[ ( ds->patchWidth - 1 ) + ( i + 1 ) * ds->patchWidth ].xyz;
00287         v3 = ds->verts[ ( ds->patchWidth - 1 ) + ( i + 2 ) * ds->patchWidth ].xyz;
00288 
00289         // if v2 is the midpoint of v1 to v3, add an edge from v1 to v3
00290         if ( ColinearEdge( v1, v2, v3 ) ) {
00291             AddEdge( v1, v3, qfalse );
00292         }
00293     }
00294 
00295 
00296 }
00297 
00298 
00299 /*
00300 ====================
00301 FixSurfaceJunctions
00302 ====================
00303 */
00304 #define MAX_SURFACE_VERTS   256
00305 void FixSurfaceJunctions( mapDrawSurface_t *ds ) {
00306     int         i, j, k;
00307     edgeLine_t  *e;
00308     edgePoint_t *p;
00309     int         originalVerts;
00310     int         counts[MAX_SURFACE_VERTS];
00311     int         originals[MAX_SURFACE_VERTS];
00312     int         firstVert[MAX_SURFACE_VERTS];
00313     drawVert_t  verts[MAX_SURFACE_VERTS], *v1, *v2;
00314     int         numVerts;
00315     float       start, end, frac;
00316     vec3_t      delta;
00317 
00318     originalVerts = ds->numVerts;
00319 
00320     numVerts = 0;
00321     for ( i = 0 ; i < ds->numVerts ; i++ ) {
00322         counts[i] = 0;
00323         firstVert[i] = numVerts;
00324 
00325         // copy first vert
00326         if ( numVerts == MAX_SURFACE_VERTS ) {
00327             Error( "MAX_SURFACE_VERTS" );
00328         }
00329         verts[numVerts] = ds->verts[i];
00330         originals[numVerts] = i;
00331         numVerts++;
00332 
00333         // check to see if there are any t junctions before the next vert
00334         v1 = &ds->verts[i];
00335         v2 = &ds->verts[ (i+1) % ds->numVerts ];
00336 
00337         j = (int)ds->verts[i].lightmap[0];
00338         if ( j == -1 ) {
00339             continue;       // degenerate edge
00340         }
00341         e = &edgeLines[ j ];
00342         
00343         VectorSubtract( v1->xyz, e->origin, delta );
00344         start = DotProduct( delta, e->dir );
00345 
00346         VectorSubtract( v2->xyz, e->origin, delta );
00347         end = DotProduct( delta, e->dir );
00348 
00349 
00350         if ( start < end ) {
00351             p = e->chain.next;
00352         } else {
00353             p = e->chain.prev;
00354         }
00355 
00356         for (  ; p != &e->chain ;  ) {
00357             if ( start < end ) {
00358                 if ( p->intercept > end - ON_EPSILON ) {
00359                     break;
00360                 }
00361             } else {
00362                 if ( p->intercept < end + ON_EPSILON ) {
00363                     break;
00364                 }
00365             }
00366 
00367             if ( 
00368                 ( start < end && p->intercept > start + ON_EPSILON ) ||
00369                 ( start > end && p->intercept < start - ON_EPSILON ) ) {
00370                 // insert this point
00371                 if ( numVerts == MAX_SURFACE_VERTS ) {
00372                     Error( "MAX_SURFACE_VERTS" );
00373                 }
00374 
00375                 // take the exact intercept point
00376                 VectorCopy( p->xyz, verts[ numVerts ].xyz );
00377 
00378                 // copy the normal
00379                 VectorCopy( v1->normal, verts[ numVerts ].normal );
00380 
00381                 // interpolate the texture coordinates
00382                 frac = ( p->intercept - start ) / ( end - start );
00383                 for ( j = 0 ; j < 2 ; j++ ) {
00384                     verts[ numVerts ].st[j] = v1->st[j] + 
00385                         frac * ( v2->st[j] - v1->st[j] );
00386                 }
00387                 originals[numVerts] = i;
00388                 numVerts++;
00389                 counts[i]++;
00390             }
00391 
00392             if ( start < end ) {
00393                 p = p->next;
00394             } else {
00395                 p = p->prev;
00396             }
00397         }
00398     }
00399 
00400     c_addedVerts += numVerts - ds->numVerts;
00401     c_totalVerts += numVerts;
00402 
00403 
00404     // FIXME: check to see if the entire surface degenerated
00405     // after snapping
00406 
00407     // rotate the points so that the initial vertex is between
00408     // two non-subdivided edges
00409     for ( i = 0 ; i < numVerts ; i++ ) {
00410         if ( originals[ (i+1) % numVerts ] == originals[ i ] ) {
00411             continue;
00412         }
00413         j = (i + numVerts - 1 ) % numVerts;
00414         k = (i + numVerts - 2 ) % numVerts;
00415         if ( originals[ j ] == originals[ k ] ) {
00416             continue;
00417         }
00418         break;
00419     }
00420 
00421     if ( i == 0 ) {
00422         // fine the way it is
00423         c_natural++;
00424 
00425         ds->numVerts = numVerts;
00426         ds->verts = malloc( numVerts * sizeof( *ds->verts ) );
00427         memcpy( ds->verts, verts, numVerts * sizeof( *ds->verts ) );
00428 
00429         return;
00430     }
00431     if ( i == numVerts ) {
00432         // create a vertex in the middle to start the fan
00433         c_cant++;
00434 
00435 /*
00436         memset ( &verts[numVerts], 0, sizeof( verts[numVerts] ) );
00437         for ( i = 0 ; i < numVerts ; i++ ) {
00438             for ( j = 0 ; j < 10 ; j++ ) {
00439                 verts[numVerts].xyz[j] += verts[i].xyz[j];
00440             }
00441         }
00442         for ( j = 0 ; j < 10 ; j++ ) {
00443             verts[numVerts].xyz[j] /= numVerts;
00444         }
00445 
00446         i = numVerts;
00447         numVerts++;
00448 */
00449     } else {
00450         // just rotate the vertexes
00451         c_rotate++;
00452 
00453     }
00454 
00455     ds->numVerts = numVerts;
00456     ds->verts = malloc( numVerts * sizeof( *ds->verts ) );
00457 
00458     for ( j = 0 ; j < ds->numVerts ; j++ ) {
00459         ds->verts[j] = verts[ ( j + i ) % ds->numVerts ];
00460     }
00461 }
00462 
00463 /*
00464 ================
00465 EdgeCompare
00466 ================
00467 */
00468 int EdgeCompare( const void *elem1, const void *elem2 ) {
00469     float   d1, d2;
00470 
00471     d1 = ((originalEdge_t *)elem1)->length;
00472     d2 = ((originalEdge_t *)elem2)->length;
00473 
00474     if ( d1 < d2 ) {
00475         return -1;
00476     }
00477     if ( d2 > d1 ) {
00478         return 1;
00479     }
00480     return 0;
00481 }
00482 
00483 
00484 /*
00485 ================
00486 FixTJunctions
00487 
00488 Call after the surface list has been pruned, but before lightmap allocation
00489 ================
00490 */
00491 void FixTJunctions( entity_t *ent ) {
00492     int                 i;
00493     mapDrawSurface_t    *ds;
00494     int                 axialEdgeLines;
00495     originalEdge_t      *e;
00496 
00497     qprintf("----- FixTJunctions -----\n");
00498 
00499     numEdgeLines = 0;
00500     numOriginalEdges = 0;
00501 
00502     // add all the edges
00503     // this actually creates axial edges, but it
00504     // only creates originalEdge_t structures
00505     // for non-axial edges
00506     for ( i = ent->firstDrawSurf ; i < numMapDrawSurfs ; i++ ) {
00507         ds = &mapDrawSurfs[i];
00508         if ( ds->patch ) {
00509             AddPatchEdges( ds );
00510         } else if ( ds->shaderInfo->autosprite || ds->shaderInfo->notjunc || ds->miscModel ) {
00511             // miscModels don't add tjunctions
00512         } else {
00513             AddSurfaceEdges( ds );
00514         }
00515     }
00516 
00517     axialEdgeLines = numEdgeLines;
00518 
00519     // sort the non-axial edges by length
00520     qsort( originalEdges, numOriginalEdges, sizeof(originalEdges[0]), EdgeCompare );
00521 
00522     // add the non-axial edges, longest first
00523     // this gives the most accurate edge description
00524     for ( i = 0 ; i < numOriginalEdges ; i++ ) {
00525         e = &originalEdges[i];
00526         e->dv[0]->lightmap[0] = AddEdge( e->dv[0]->xyz, e->dv[1]->xyz, qtrue );
00527     }
00528 
00529     qprintf( "%6i axial edge lines\n", axialEdgeLines );
00530     qprintf( "%6i non-axial edge lines\n", numEdgeLines - axialEdgeLines );
00531     qprintf( "%6i degenerate edges\n", c_degenerateEdges );
00532 
00533     // insert any needed vertexes
00534     for ( i = ent->firstDrawSurf ; i < numMapDrawSurfs ; i++ ) {
00535         ds = &mapDrawSurfs[i];
00536         if ( ds->patch ) {
00537             continue;
00538         }
00539         if ( ds->shaderInfo->autosprite || ds->shaderInfo->notjunc || ds->miscModel ) {
00540             continue;
00541         }
00542 
00543         FixSurfaceJunctions( ds );
00544     }
00545 
00546     qprintf( "%6i verts added for tjunctions\n", c_addedVerts );
00547     qprintf( "%6i total verts\n", c_totalVerts );
00548     qprintf( "%6i naturally ordered\n", c_natural );
00549     qprintf( "%6i rotated orders\n", c_rotate );
00550     qprintf( "%6i can't order\n", c_cant );
00551 }

Generated on Thu Aug 25 12:38:25 2005 for Quake III Arena by  doxygen 1.3.9.1