Quake-III-Arena

Quake III Arena GPL Source Release
Log | Files | Refs

tjunction.c (12926B)


      1 /*
      2 ===========================================================================
      3 Copyright (C) 1999-2005 Id Software, Inc.
      4 
      5 This file is part of Quake III Arena source code.
      6 
      7 Quake III Arena source code is free software; you can redistribute it
      8 and/or modify it under the terms of the GNU General Public License as
      9 published by the Free Software Foundation; either version 2 of the License,
     10 or (at your option) any later version.
     11 
     12 Quake III Arena source code is distributed in the hope that it will be
     13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 GNU General Public License for more details.
     16 
     17 You should have received a copy of the GNU General Public License
     18 along with Foobar; if not, write to the Free Software
     19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     20 ===========================================================================
     21 */
     22 #include "qbsp.h"
     23 
     24 typedef struct edgePoint_s {
     25 	float		intercept;
     26 	vec3_t		xyz;
     27 	struct edgePoint_s	*prev, *next;
     28 } edgePoint_t;
     29 
     30 typedef struct edgeLine_s {
     31 	vec3_t		normal1;
     32 	float		dist1;
     33 	
     34 	vec3_t		normal2;
     35 	float		dist2;
     36 	
     37 	vec3_t		origin;
     38 	vec3_t		dir;
     39 
     40 	edgePoint_t	chain;		// unused element of doubly linked list
     41 } edgeLine_t;
     42 
     43 typedef struct {
     44 	float		length;
     45 	drawVert_t	*dv[2];
     46 } originalEdge_t;
     47 
     48 #define	MAX_ORIGINAL_EDGES	0x10000
     49 originalEdge_t	originalEdges[MAX_ORIGINAL_EDGES];
     50 int				numOriginalEdges;
     51 
     52 
     53 #define	MAX_EDGE_LINES		0x10000
     54 edgeLine_t		edgeLines[MAX_EDGE_LINES];
     55 int				numEdgeLines;
     56 
     57 int				c_degenerateEdges;
     58 int				c_addedVerts;
     59 int				c_totalVerts;
     60 
     61 int				c_natural, c_rotate, c_cant;
     62 
     63 // these should be whatever epsilon we actually expect,
     64 // plus SNAP_INT_TO_FLOAT 
     65 #define	LINE_POSITION_EPSILON	0.25
     66 #define	POINT_ON_LINE_EPSILON	0.25
     67 
     68 /*
     69 ====================
     70 InsertPointOnEdge
     71 ====================
     72 */
     73 void InsertPointOnEdge( vec3_t v, edgeLine_t *e ) {
     74 	vec3_t		delta;
     75 	float		d;
     76 	edgePoint_t	*p, *scan;
     77 
     78 	VectorSubtract( v, e->origin, delta );
     79 	d = DotProduct( delta, e->dir );
     80 
     81 	p = malloc( sizeof(edgePoint_t) );
     82 	p->intercept = d;
     83 	VectorCopy( v, p->xyz );
     84 
     85 	if ( e->chain.next == &e->chain ) {
     86 		e->chain.next = e->chain.prev = p;
     87 		p->next = p->prev = &e->chain;
     88 		return;
     89 	}
     90 
     91 	scan = e->chain.next;
     92 	for ( ; scan != &e->chain ; scan = scan->next ) {
     93 		d = p->intercept - scan->intercept;
     94 		if ( d > -LINE_POSITION_EPSILON && d < LINE_POSITION_EPSILON ) {
     95 			free( p );
     96 			return;		// the point is already set
     97 		}
     98 
     99 		if ( p->intercept < scan->intercept ) {
    100 			// insert here
    101 			p->prev = scan->prev;
    102 			p->next = scan;
    103 			scan->prev->next = p;
    104 			scan->prev = p;
    105 			return;
    106 		}
    107 	}
    108 
    109 	// add at the end
    110 	p->prev = scan->prev;
    111 	p->next = scan;
    112 	scan->prev->next = p;
    113 	scan->prev = p;
    114 }
    115 
    116 
    117 /*
    118 ====================
    119 AddEdge
    120 ====================
    121 */
    122 int AddEdge( vec3_t v1, vec3_t v2, qboolean createNonAxial ) {
    123 	int			i;
    124 	edgeLine_t	*e;
    125 	float		d;
    126 	vec3_t		dir;
    127 
    128 	VectorSubtract( v2, v1, dir );
    129 	d = VectorNormalize( dir, dir );
    130 	if ( d < 0.1 ) {
    131 		// if we added a 0 length vector, it would make degenerate planes
    132 		c_degenerateEdges++;
    133 		return -1;
    134 	}
    135 
    136 	if ( !createNonAxial ) {
    137 		if ( fabs( dir[0] + dir[1] + dir[2] ) != 1.0 ) {
    138 			if ( numOriginalEdges == MAX_ORIGINAL_EDGES ) {
    139 				Error( "MAX_ORIGINAL_EDGES" );
    140 			}
    141 			originalEdges[ numOriginalEdges ].dv[0] = (drawVert_t *)v1;
    142 			originalEdges[ numOriginalEdges ].dv[1] = (drawVert_t *)v2;
    143 			originalEdges[ numOriginalEdges ].length = d;
    144 			numOriginalEdges++;
    145 			return -1;
    146 		}
    147 	}
    148 
    149 	for ( i = 0 ; i < numEdgeLines ; i++ ) {
    150 		e = &edgeLines[i];
    151 
    152 		d = DotProduct( v1, e->normal1 ) - e->dist1;
    153 		if ( d < -POINT_ON_LINE_EPSILON || d > POINT_ON_LINE_EPSILON ) {
    154 			continue;
    155 		}
    156 		d = DotProduct( v1, e->normal2 ) - e->dist2;
    157 		if ( d < -POINT_ON_LINE_EPSILON || d > POINT_ON_LINE_EPSILON ) {
    158 			continue;
    159 		}
    160 
    161 		d = DotProduct( v2, e->normal1 ) - e->dist1;
    162 		if ( d < -POINT_ON_LINE_EPSILON || d > POINT_ON_LINE_EPSILON ) {
    163 			continue;
    164 		}
    165 		d = DotProduct( v2, e->normal2 ) - e->dist2;
    166 		if ( d < -POINT_ON_LINE_EPSILON || d > POINT_ON_LINE_EPSILON ) {
    167 			continue;
    168 		}
    169 
    170 		// this is the edge
    171 		InsertPointOnEdge( v1, e );
    172 		InsertPointOnEdge( v2, e );
    173 		return i;
    174 	}
    175 
    176 	// create a new edge
    177 	if ( numEdgeLines >= MAX_EDGE_LINES ) {
    178 		Error( "MAX_EDGE_LINES" );
    179 	}
    180 
    181 	e = &edgeLines[ numEdgeLines ];
    182 	numEdgeLines++;
    183 
    184 	e->chain.next = e->chain.prev = &e->chain;
    185 
    186 	VectorCopy( v1, e->origin );
    187 	VectorCopy( dir, e->dir );
    188 
    189 	MakeNormalVectors( e->dir, e->normal1, e->normal2 );
    190 	e->dist1 = DotProduct( e->origin, e->normal1 );
    191 	e->dist2 = DotProduct( e->origin, e->normal2 );
    192 
    193 	InsertPointOnEdge( v1, e );
    194 	InsertPointOnEdge( v2, e );
    195 
    196 	return numEdgeLines - 1;
    197 }
    198 
    199 /*
    200 ====================
    201 AddSurfaceEdges
    202 ====================
    203 */
    204 void AddSurfaceEdges( mapDrawSurface_t *ds ) {
    205 	int		i;
    206 
    207 	for ( i = 0 ; i < ds->numVerts ; i++ ) {
    208 		// save the edge number in the lightmap field
    209 		// so we don't need to look it up again
    210 		ds->verts[i].lightmap[0] = 
    211 			AddEdge( ds->verts[i].xyz, ds->verts[(i+1) % ds->numVerts].xyz, qfalse );
    212 	}
    213 }
    214 
    215 /*
    216 ================
    217 ColinearEdge
    218 ================
    219 */
    220 qboolean ColinearEdge( vec3_t v1, vec3_t v2, vec3_t v3 ) {
    221 	vec3_t	midpoint, dir, offset, on;
    222 	float	d;
    223 
    224 	VectorSubtract( v2, v1, midpoint );
    225 	VectorSubtract( v3, v1, dir );
    226 	d = VectorNormalize( dir, dir );
    227 	if ( d == 0 ) {
    228 		return qfalse;	// degenerate
    229 	}
    230 
    231 	d = DotProduct( midpoint, dir );
    232 	VectorScale( dir, d, on );
    233 	VectorSubtract( midpoint, on, offset );
    234 	d = VectorLength ( offset );
    235 
    236 	if ( d < 0.1 ) {
    237 		return qtrue;
    238 	}
    239 
    240 	return qfalse;
    241 }
    242 
    243 /*
    244 ====================
    245 AddPatchEdges
    246 
    247 Add colinear border edges, which will fix some classes of patch to
    248 brush tjunctions
    249 ====================
    250 */
    251 void AddPatchEdges( mapDrawSurface_t *ds ) {
    252 	int		i;
    253 	float	*v1, *v2, *v3;
    254 
    255 	for ( i = 0 ; i < ds->patchWidth - 2; i+=2 ) {
    256 		v1 = ds->verts[ i ].xyz;
    257 		v2 = ds->verts[ i + 1 ].xyz;
    258 		v3 = ds->verts[ i + 2 ].xyz;
    259 
    260 		// if v2 is the midpoint of v1 to v3, add an edge from v1 to v3
    261 		if ( ColinearEdge( v1, v2, v3 ) ) {
    262 			AddEdge( v1, v3, qfalse );
    263 		}
    264 
    265 		v1 = ds->verts[ ( ds->patchHeight - 1 ) * ds->patchWidth + i ].xyz;
    266 		v2 = ds->verts[ ( ds->patchHeight - 1 ) * ds->patchWidth + i + 1 ].xyz;
    267 		v3 = ds->verts[ ( ds->patchHeight - 1 ) * ds->patchWidth + i + 2 ].xyz;
    268 
    269 		// if v2 is on the v1 to v3 line, add an edge from v1 to v3
    270 		if ( ColinearEdge( v1, v2, v3 ) ) {
    271 			AddEdge( v1, v3, qfalse );
    272 		}
    273 	}
    274 
    275 	for ( i = 0 ; i < ds->patchHeight - 2 ; i+=2 ) {
    276 		v1 = ds->verts[ i * ds->patchWidth ].xyz;
    277 		v2 = ds->verts[ ( i + 1 ) * ds->patchWidth ].xyz;
    278 		v3 = ds->verts[ ( i + 2 ) * ds->patchWidth ].xyz;
    279 
    280 		// if v2 is the midpoint of v1 to v3, add an edge from v1 to v3
    281 		if ( ColinearEdge( v1, v2, v3 ) ) {
    282 			AddEdge( v1, v3, qfalse );
    283 		}
    284 
    285 		v1 = ds->verts[ ( ds->patchWidth - 1 ) + i * ds->patchWidth ].xyz;
    286 		v2 = ds->verts[ ( ds->patchWidth - 1 ) + ( i + 1 ) * ds->patchWidth ].xyz;
    287 		v3 = ds->verts[ ( ds->patchWidth - 1 ) + ( i + 2 ) * ds->patchWidth ].xyz;
    288 
    289 		// if v2 is the midpoint of v1 to v3, add an edge from v1 to v3
    290 		if ( ColinearEdge( v1, v2, v3 ) ) {
    291 			AddEdge( v1, v3, qfalse );
    292 		}
    293 	}
    294 
    295 
    296 }
    297 
    298 
    299 /*
    300 ====================
    301 FixSurfaceJunctions
    302 ====================
    303 */
    304 #define	MAX_SURFACE_VERTS	256
    305 void FixSurfaceJunctions( mapDrawSurface_t *ds ) {
    306 	int			i, j, k;
    307 	edgeLine_t	*e;
    308 	edgePoint_t	*p;
    309 	int			originalVerts;
    310 	int			counts[MAX_SURFACE_VERTS];
    311 	int			originals[MAX_SURFACE_VERTS];
    312 	int			firstVert[MAX_SURFACE_VERTS];
    313 	drawVert_t	verts[MAX_SURFACE_VERTS], *v1, *v2;
    314 	int			numVerts;
    315 	float		start, end, frac;
    316 	vec3_t		delta;
    317 
    318 	originalVerts = ds->numVerts;
    319 
    320 	numVerts = 0;
    321 	for ( i = 0 ; i < ds->numVerts ; i++ ) {
    322 		counts[i] = 0;
    323 		firstVert[i] = numVerts;
    324 
    325 		// copy first vert
    326 		if ( numVerts == MAX_SURFACE_VERTS ) {
    327 			Error( "MAX_SURFACE_VERTS" );
    328 		}
    329 		verts[numVerts] = ds->verts[i];
    330 		originals[numVerts] = i;
    331 		numVerts++;
    332 
    333 		// check to see if there are any t junctions before the next vert
    334 		v1 = &ds->verts[i];
    335 		v2 = &ds->verts[ (i+1) % ds->numVerts ];
    336 
    337 		j = (int)ds->verts[i].lightmap[0];
    338 		if ( j == -1 ) {
    339 			continue;		// degenerate edge
    340 		}
    341 		e = &edgeLines[ j ];
    342 		
    343 		VectorSubtract( v1->xyz, e->origin, delta );
    344 		start = DotProduct( delta, e->dir );
    345 
    346 		VectorSubtract( v2->xyz, e->origin, delta );
    347 		end = DotProduct( delta, e->dir );
    348 
    349 
    350 		if ( start < end ) {
    351 			p = e->chain.next;
    352 		} else {
    353 			p = e->chain.prev;
    354 		}
    355 
    356 		for (  ; p != &e->chain ;  ) {
    357 			if ( start < end ) {
    358 				if ( p->intercept > end - ON_EPSILON ) {
    359 					break;
    360 				}
    361 			} else {
    362 				if ( p->intercept < end + ON_EPSILON ) {
    363 					break;
    364 				}
    365 			}
    366 
    367 			if ( 
    368 				( start < end && p->intercept > start + ON_EPSILON ) ||
    369 				( start > end && p->intercept < start - ON_EPSILON ) ) {
    370 				// insert this point
    371 				if ( numVerts == MAX_SURFACE_VERTS ) {
    372 					Error( "MAX_SURFACE_VERTS" );
    373 				}
    374 
    375 				// take the exact intercept point
    376 				VectorCopy( p->xyz, verts[ numVerts ].xyz );
    377 
    378 				// copy the normal
    379 				VectorCopy( v1->normal, verts[ numVerts ].normal );
    380 
    381 				// interpolate the texture coordinates
    382 				frac = ( p->intercept - start ) / ( end - start );
    383 				for ( j = 0 ; j < 2 ; j++ ) {
    384 					verts[ numVerts ].st[j] = v1->st[j] + 
    385 						frac * ( v2->st[j] - v1->st[j] );
    386 				}
    387 				originals[numVerts] = i;
    388 				numVerts++;
    389 				counts[i]++;
    390 			}
    391 
    392 			if ( start < end ) {
    393 				p = p->next;
    394 			} else {
    395 				p = p->prev;
    396 			}
    397 		}
    398 	}
    399 
    400 	c_addedVerts += numVerts - ds->numVerts;
    401 	c_totalVerts += numVerts;
    402 
    403 
    404 	// FIXME: check to see if the entire surface degenerated
    405 	// after snapping
    406 
    407 	// rotate the points so that the initial vertex is between
    408 	// two non-subdivided edges
    409 	for ( i = 0 ; i < numVerts ; i++ ) {
    410 		if ( originals[ (i+1) % numVerts ] == originals[ i ] ) {
    411 			continue;
    412 		}
    413 		j = (i + numVerts - 1 ) % numVerts;
    414 		k = (i + numVerts - 2 ) % numVerts;
    415 		if ( originals[ j ] == originals[ k ] ) {
    416 			continue;
    417 		}
    418 		break;
    419 	}
    420 
    421 	if ( i == 0 ) {
    422 		// fine the way it is
    423 		c_natural++;
    424 
    425 		ds->numVerts = numVerts;
    426 		ds->verts = malloc( numVerts * sizeof( *ds->verts ) );
    427 		memcpy( ds->verts, verts, numVerts * sizeof( *ds->verts ) );
    428 
    429 		return;
    430 	}
    431 	if ( i == numVerts ) {
    432 		// create a vertex in the middle to start the fan
    433 		c_cant++;
    434 
    435 /*
    436 		memset ( &verts[numVerts], 0, sizeof( verts[numVerts] ) );
    437 		for ( i = 0 ; i < numVerts ; i++ ) {
    438 			for ( j = 0 ; j < 10 ; j++ ) {
    439 				verts[numVerts].xyz[j] += verts[i].xyz[j];
    440 			}
    441 		}
    442 		for ( j = 0 ; j < 10 ; j++ ) {
    443 			verts[numVerts].xyz[j] /= numVerts;
    444 		}
    445 
    446 		i = numVerts;
    447 		numVerts++;
    448 */
    449 	} else {
    450 		// just rotate the vertexes
    451 		c_rotate++;
    452 
    453 	}
    454 
    455 	ds->numVerts = numVerts;
    456 	ds->verts = malloc( numVerts * sizeof( *ds->verts ) );
    457 
    458 	for ( j = 0 ; j < ds->numVerts ; j++ ) {
    459 		ds->verts[j] = verts[ ( j + i ) % ds->numVerts ];
    460 	}
    461 }
    462 
    463 /*
    464 ================
    465 EdgeCompare
    466 ================
    467 */
    468 int EdgeCompare( const void *elem1, const void *elem2 ) {
    469 	float	d1, d2;
    470 
    471 	d1 = ((originalEdge_t *)elem1)->length;
    472 	d2 = ((originalEdge_t *)elem2)->length;
    473 
    474 	if ( d1 < d2 ) {
    475 		return -1;
    476 	}
    477 	if ( d2 > d1 ) {
    478 		return 1;
    479 	}
    480 	return 0;
    481 }
    482 
    483 
    484 /*
    485 ================
    486 FixTJunctions
    487 
    488 Call after the surface list has been pruned, but before lightmap allocation
    489 ================
    490 */
    491 void FixTJunctions( entity_t *ent ) {
    492 	int					i;
    493 	mapDrawSurface_t	*ds;
    494 	int					axialEdgeLines;
    495 	originalEdge_t		*e;
    496 
    497 	qprintf("----- FixTJunctions -----\n");
    498 
    499 	numEdgeLines = 0;
    500 	numOriginalEdges = 0;
    501 
    502 	// add all the edges
    503 	// this actually creates axial edges, but it
    504 	// only creates originalEdge_t structures
    505 	// for non-axial edges
    506 	for ( i = ent->firstDrawSurf ; i < numMapDrawSurfs ; i++ ) {
    507 		ds = &mapDrawSurfs[i];
    508 		if ( ds->patch ) {
    509 			AddPatchEdges( ds );
    510 		} else if ( ds->shaderInfo->autosprite || ds->shaderInfo->notjunc || ds->miscModel ) {
    511 			// miscModels don't add tjunctions
    512 		} else {
    513 			AddSurfaceEdges( ds );
    514 		}
    515 	}
    516 
    517 	axialEdgeLines = numEdgeLines;
    518 
    519 	// sort the non-axial edges by length
    520 	qsort( originalEdges, numOriginalEdges, sizeof(originalEdges[0]), EdgeCompare );
    521 
    522 	// add the non-axial edges, longest first
    523 	// this gives the most accurate edge description
    524 	for ( i = 0 ; i < numOriginalEdges ; i++ ) {
    525 		e = &originalEdges[i];
    526 		e->dv[0]->lightmap[0] = AddEdge( e->dv[0]->xyz, e->dv[1]->xyz, qtrue );
    527 	}
    528 
    529 	qprintf( "%6i axial edge lines\n", axialEdgeLines );
    530 	qprintf( "%6i non-axial edge lines\n", numEdgeLines - axialEdgeLines );
    531 	qprintf( "%6i degenerate edges\n", c_degenerateEdges );
    532 
    533 	// insert any needed vertexes
    534 	for ( i = ent->firstDrawSurf ; i < numMapDrawSurfs ; i++ ) {
    535 		ds = &mapDrawSurfs[i];
    536 		if ( ds->patch ) {
    537 			continue;
    538 		}
    539 		if ( ds->shaderInfo->autosprite || ds->shaderInfo->notjunc || ds->miscModel ) {
    540 			continue;
    541 		}
    542 
    543 		FixSurfaceJunctions( ds );
    544 	}
    545 
    546 	qprintf( "%6i verts added for tjunctions\n", c_addedVerts );
    547 	qprintf( "%6i total verts\n", c_totalVerts );
    548 	qprintf( "%6i naturally ordered\n", c_natural );
    549 	qprintf( "%6i rotated orders\n", c_rotate );
    550 	qprintf( "%6i can't order\n", c_cant );
    551 }