diff --git a/libs/mathlib.h b/libs/mathlib.h index 64f3f6e4..fb135b8a 100644 --- a/libs/mathlib.h +++ b/libs/mathlib.h @@ -101,7 +101,13 @@ void _CrossProduct( vec3_t v1, vec3_t v2, vec3_t cross ); // I need this define in order to test some of the regression tests from time to time. // This define affect the precision of VectorNormalize() function only. #define MATHLIB_VECTOR_NORMALIZE_PRECISION_FIX 1 -vec_t VectorNormalize( const vec3_t in, vec3_t out ); +vec_t VectorAccurateNormalize( const vec3_t in, vec3_t out ); +vec_t VectorFastNormalize( const vec3_t in, vec3_t out ); +#if MATHLIB_VECTOR_NORMALIZE_PRECISION_FIX +#define VectorNormalize VectorAccurateNormalize +#else +#define VectorNormalize VectorFastNormalize +#endif vec_t ColorNormalize( const vec3_t in, vec3_t out ); void VectorInverse( vec3_t v ); void VectorPolar( vec3_t v, float radius, float theta, float phi ); diff --git a/libs/mathlib/mathlib.c b/libs/mathlib/mathlib.c index ce6cfdc2..642f9842 100644 --- a/libs/mathlib/mathlib.c +++ b/libs/mathlib/mathlib.c @@ -153,9 +153,7 @@ void _VectorCopy( vec3_t in, vec3_t out ){ out[2] = in[2]; } -vec_t VectorNormalize( const vec3_t in, vec3_t out ) { - -#if MATHLIB_VECTOR_NORMALIZE_PRECISION_FIX +vec_t VectorAccurateNormalize( const vec3_t in, vec3_t out ) { // The sqrt() function takes double as an input and returns double as an // output according the the man pages on Debian and on FreeBSD. Therefore, @@ -179,26 +177,30 @@ vec_t VectorNormalize( const vec3_t in, vec3_t out ) { out[2] = (vec_t) ( z / length ); return (vec_t) length; +} -#else +vec_t VectorFastNormalize( const vec3_t in, vec3_t out ) { - vec_t length, ilength; + // SmileTheory: This is ioquake3's VectorNormalize2 + // for when accuracy matters less than speed + float length, ilength; - length = (vec_t)sqrt( in[0] * in[0] + in[1] * in[1] + in[2] * in[2] ); - if ( length == 0 ) { + length = in[0] * in[0] + in[1] * in[1] + in[2] * in[2]; + + if ( length ) { + /* writing it this way allows gcc to recognize that rsqrt can be used */ + ilength = 1 / (float)sqrt( length ); + /* sqrt(length) = length * (1 / sqrt(length)) */ + length *= ilength; + out[0] = in[0] * ilength; + out[1] = in[1] * ilength; + out[2] = in[2] * ilength; + } + else { VectorClear( out ); - return 0; } - ilength = 1.0f / length; - out[0] = in[0] * ilength; - out[1] = in[1] * ilength; - out[2] = in[2] * ilength; - return length; - -#endif - } vec_t ColorNormalize( const vec3_t in, vec3_t out ) { diff --git a/tools/quake3/q3map2/light.c b/tools/quake3/q3map2/light.c index ffcd832a..f03f64c7 100644 --- a/tools/quake3/q3map2/light.c +++ b/tools/quake3/q3map2/light.c @@ -720,7 +720,7 @@ float PointToPolygonFormFactor( const vec3_t point, const vec3_t normal, const w for ( i = 0; i < w->numpoints; i++ ) { VectorSubtract( w->p[ i ], point, dirs[ i ] ); - VectorNormalize( dirs[ i ], dirs[ i ] ); + VectorFastNormalize( dirs[ i ], dirs[ i ] ); } /* duplicate first vertex to avoid mod operation */ @@ -746,7 +746,7 @@ float PointToPolygonFormFactor( const vec3_t point, const vec3_t normal, const w angle = acos( dot ); CrossProduct( dirs[ i ], dirs[ j ], triVector ); - if ( VectorNormalize( triVector, triNormal ) < 0.0001f ) { + if ( VectorFastNormalize( triVector, triNormal ) < 0.0001f ) { continue; } diff --git a/tools/quake3/q3map2/light_trace.c b/tools/quake3/q3map2/light_trace.c index cb22bb44..08606f7e 100644 --- a/tools/quake3/q3map2/light_trace.c +++ b/tools/quake3/q3map2/light_trace.c @@ -1618,103 +1618,132 @@ qboolean TraceWinding( traceWinding_t *tw, trace_t *trace ){ /* TraceLine_r() returns qtrue if something is hit and tracing can stop + + SmileTheory: made half-iterative */ -static qboolean TraceLine_r( int nodeNum, vec3_t origin, vec3_t end, trace_t *trace ){ +#define TRACELINE_R_HALF_ITERATIVE 1 + +#if TRACELINE_R_HALF_ITERATIVE +static qboolean TraceLine_r( int nodeNum, const vec3_t start, const vec3_t end, trace_t *trace ) +#else +static qboolean TraceLine_r( int nodeNum, const vec3_t origin, const vec3_t end, trace_t *trace ) +#endif +{ traceNode_t *node; int side; float front, back, frac; - vec3_t mid; + vec3_t origin, mid; qboolean r; +#if TRACELINE_R_HALF_ITERATIVE + VectorCopy( start, origin ); - /* bogus node number means solid, end tracing unless testing all */ - if ( nodeNum < 0 ) { - VectorCopy( origin, trace->hit ); - trace->passSolid = qtrue; - return qtrue; - } - - /* get node */ - node = &traceNodes[ nodeNum ]; - - /* solid? */ - if ( node->type == TRACE_LEAF_SOLID ) { - VectorCopy( origin, trace->hit ); - trace->passSolid = qtrue; - return qtrue; - } - - /* leafnode? */ - if ( node->type < 0 ) { - /* note leaf and return */ - if ( node->numItems > 0 && trace->numTestNodes < MAX_TRACE_TEST_NODES ) { - trace->testNodes[ trace->numTestNodes++ ] = nodeNum; - } - return qfalse; - } - - /* ydnar 2003-09-07: don't test branches of the bsp with nothing in them when testall is enabled */ - if ( trace->testAll && node->numItems == 0 ) { - return qfalse; - } - - /* classify beginning and end points */ - switch ( node->type ) + while ( 1 ) +#endif { - case PLANE_X: - front = origin[ 0 ] - node->plane[ 3 ]; - back = end[ 0 ] - node->plane[ 3 ]; - break; + /* bogus node number means solid, end tracing unless testing all */ + if ( nodeNum < 0 ) { + VectorCopy( origin, trace->hit ); + trace->passSolid = qtrue; + return qtrue; + } - case PLANE_Y: - front = origin[ 1 ] - node->plane[ 3 ]; - back = end[ 1 ] - node->plane[ 3 ]; - break; + /* get node */ + node = &traceNodes[ nodeNum ]; - case PLANE_Z: - front = origin[ 2 ] - node->plane[ 3 ]; - back = end[ 2 ] - node->plane[ 3 ]; - break; + /* solid? */ + if ( node->type == TRACE_LEAF_SOLID ) { + VectorCopy( origin, trace->hit ); + trace->passSolid = qtrue; + return qtrue; + } - default: - front = DotProduct( origin, node->plane ) - node->plane[ 3 ]; - back = DotProduct( end, node->plane ) - node->plane[ 3 ]; - break; + /* leafnode? */ + if ( node->type < 0 ) { + /* note leaf and return */ + if ( node->numItems > 0 && trace->numTestNodes < MAX_TRACE_TEST_NODES ) { + trace->testNodes[ trace->numTestNodes++ ] = nodeNum; + } + return qfalse; + } + + /* ydnar 2003-09-07: don't test branches of the bsp with nothing in them when testall is enabled */ + if ( trace->testAll && node->numItems == 0 ) { + return qfalse; + } + + /* classify beginning and end points */ + switch ( node->type ) + { + case PLANE_X: + front = origin[ 0 ] - node->plane[ 3 ]; + back = end[ 0 ] - node->plane[ 3 ]; + break; + + case PLANE_Y: + front = origin[ 1 ] - node->plane[ 3 ]; + back = end[ 1 ] - node->plane[ 3 ]; + break; + + case PLANE_Z: + front = origin[ 2 ] - node->plane[ 3 ]; + back = end[ 2 ] - node->plane[ 3 ]; + break; + + default: + front = DotProduct( origin, node->plane ) - node->plane[ 3 ]; + back = DotProduct( end, node->plane ) - node->plane[ 3 ]; + break; + } + + /* entirely in front side? */ + if ( front >= -TRACE_ON_EPSILON && back >= -TRACE_ON_EPSILON ) { +#if TRACELINE_R_HALF_ITERATIVE + nodeNum = node->children[ 0 ]; + continue; +#else + return TraceLine_r( node->children[ 0 ], origin, end, trace ); +#endif + } + + /* entirely on back side? */ + if ( front < TRACE_ON_EPSILON && back < TRACE_ON_EPSILON ) { +#if TRACELINE_R_HALF_ITERATIVE + nodeNum = node->children[ 1 ]; + continue; +#else + return TraceLine_r( node->children[ 1 ], origin, end, trace ); +#endif + } + + /* select side */ + side = front < 0; + + /* calculate intercept point */ + frac = front / ( front - back ); + mid[ 0 ] = origin[ 0 ] + ( end[ 0 ] - origin[ 0 ] ) * frac; + mid[ 1 ] = origin[ 1 ] + ( end[ 1 ] - origin[ 1 ] ) * frac; + mid[ 2 ] = origin[ 2 ] + ( end[ 2 ] - origin[ 2 ] ) * frac; + + /* fixme: check inhibit radius, then solid nodes and ignore */ + + /* set trace hit here */ + //% VectorCopy( mid, trace->hit ); + + /* trace first side */ + if ( TraceLine_r( node->children[ side ], origin, mid, trace ) ) { + return qtrue; + } + + /* trace other side */ +#if TRACELINE_R_HALF_ITERATIVE + nodeNum = node->children[ !side ]; + VectorCopy( mid, origin ); +#else + return TraceLine_r( node->children[ !side ], mid, end, trace ); +#endif } - - /* entirely in front side? */ - if ( front >= -TRACE_ON_EPSILON && back >= -TRACE_ON_EPSILON ) { - return TraceLine_r( node->children[ 0 ], origin, end, trace ); - } - - /* entirely on back side? */ - if ( front < TRACE_ON_EPSILON && back < TRACE_ON_EPSILON ) { - return TraceLine_r( node->children[ 1 ], origin, end, trace ); - } - - /* select side */ - side = front < 0; - - /* calculate intercept point */ - frac = front / ( front - back ); - mid[ 0 ] = origin[ 0 ] + ( end[ 0 ] - origin[ 0 ] ) * frac; - mid[ 1 ] = origin[ 1 ] + ( end[ 1 ] - origin[ 1 ] ) * frac; - mid[ 2 ] = origin[ 2 ] + ( end[ 2 ] - origin[ 2 ] ) * frac; - - /* fixme: check inhibit radius, then solid nodes and ignore */ - - /* set trace hit here */ - //% VectorCopy( mid, trace->hit ); - - /* trace first side */ - r = TraceLine_r( node->children[ side ], origin, mid, trace ); - if ( r ) { - return r; - } - - /* trace other side */ - return TraceLine_r( node->children[ !side ], mid, end, trace ); } @@ -1791,7 +1820,7 @@ void TraceLine( trace_t *trace ){ float SetupTrace( trace_t *trace ){ VectorSubtract( trace->end, trace->origin, trace->displacement ); - trace->distance = VectorNormalize( trace->displacement, trace->direction ); + trace->distance = VectorFastNormalize( trace->displacement, trace->direction ); VectorCopy( trace->origin, trace->hit ); return trace->distance; }