// NOTE: REPLACED ALL float'S WITH vec_t'S // basic stuff #include #include #include #include #define M_PI 3.14159265358979323846f #define DEG2RAD( a ) ( ( (a) * M_PI ) / 180.0F ) typedef float vec_t; typedef vec_t vec3_t[3]; #define DotProduct(x,y) ((x)[0]*(y)[0]+(x)[1]*(y)[1]+(x)[2]*(y)[2]) #define VectorSubtract(a,b,c) ((c)[0]=(a)[0]-(b)[0],(c)[1]=(a)[1]-(b)[1],(c)[2]=(a)[2]-(b)[2]) #define VectorAdd(a,b,c) ((c)[0]=(a)[0]+(b)[0],(c)[1]=(a)[1]+(b)[1],(c)[2]=(a)[2]+(b)[2]) #define VectorCopy(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2]) #define VectorScale(v,s,o) ((o)[0]=(v)[0]*(s),(o)[1]=(v)[1]*(s),(o)[2]=(v)[2]*(s)) #define VectorMA(v,s,b,o) ((o)[0]=(v)[0]+(b)[0]*(s),(o)[1]=(v)[1]+(b)[1]*(s),(o)[2]=(v)[2]+(b)[2]*(s)) void PerpendicularVector( vec3_t dst, const vec3_t src ); void ProjectPointOnPlane( vec3_t dst, const vec3_t p, const vec3_t normal ); void MatrixMultiply(vec_t in1[3][3], vec_t in2[3][3], vec_t out[3][3]); vec_t VectorNormalize( vec3_t v ); vec_t VectorNormalize2( const vec3_t v, vec3_t out); void CrossProduct( const vec3_t v1, const vec3_t v2, vec3_t cross ); void CrossProduct( const vec3_t v1, const vec3_t v2, vec3_t cross ) { cross[0] = v1[1]*v2[2] - v1[2]*v2[1]; cross[1] = v1[2]*v2[0] - v1[0]*v2[2]; cross[2] = v1[0]*v2[1] - v1[1]*v2[0]; } vec_t VectorNormalize2( const vec3_t v, vec3_t out) { vec_t length, ilength; length = v[0]*v[0] + v[1]*v[1] + v[2]*v[2]; length = sqrt (length); if (length) { ilength = 1/length; out[0] = v[0]*ilength; out[1] = v[1]*ilength; out[2] = v[2]*ilength; } else { out[0] = 0; out[1] = 0; out[2] = 0; } return length; } vec_t VectorNormalize( vec3_t v ) { // NOTE: TTimo - Apple G4 altivec source uses double? vec_t length, ilength; length = v[0]*v[0] + v[1]*v[1] + v[2]*v[2]; length = sqrt (length); if ( length ) { ilength = 1/length; v[0] *= ilength; v[1] *= ilength; v[2] *= ilength; } return length; } void MatrixMultiply(vec_t in1[3][3], vec_t in2[3][3], vec_t out[3][3]) { out[0][0] = in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] + in1[0][2] * in2[2][0]; out[0][1] = in1[0][0] * in2[0][1] + in1[0][1] * in2[1][1] + in1[0][2] * in2[2][1]; out[0][2] = in1[0][0] * in2[0][2] + in1[0][1] * in2[1][2] + in1[0][2] * in2[2][2]; out[1][0] = in1[1][0] * in2[0][0] + in1[1][1] * in2[1][0] + in1[1][2] * in2[2][0]; out[1][1] = in1[1][0] * in2[0][1] + in1[1][1] * in2[1][1] + in1[1][2] * in2[2][1]; out[1][2] = in1[1][0] * in2[0][2] + in1[1][1] * in2[1][2] + in1[1][2] * in2[2][2]; out[2][0] = in1[2][0] * in2[0][0] + in1[2][1] * in2[1][0] + in1[2][2] * in2[2][0]; out[2][1] = in1[2][0] * in2[0][1] + in1[2][1] * in2[1][1] + in1[2][2] * in2[2][1]; out[2][2] = in1[2][0] * in2[0][2] + in1[2][1] * in2[1][2] + in1[2][2] * in2[2][2]; } void ProjectPointOnPlane( vec3_t dst, const vec3_t p, const vec3_t normal ) { vec_t d; vec3_t n; vec_t inv_denom; inv_denom = DotProduct( normal, normal ); inv_denom = 1.0f / inv_denom; d = DotProduct( normal, p ) * inv_denom; n[0] = normal[0] * inv_denom; n[1] = normal[1] * inv_denom; n[2] = normal[2] * inv_denom; dst[0] = p[0] - d * n[0]; dst[1] = p[1] - d * n[1]; dst[2] = p[2] - d * n[2]; } void PerpendicularVector( vec3_t dst, const vec3_t src ) { int pos; int i; vec_t minelem = 1.0F; vec3_t tempvec; /* ** find the smallest magnitude axially aligned vector */ for ( pos = 0, i = 0; i < 3; i++ ) { if ( fabs( src[i] ) < minelem ) { pos = i; minelem = fabs( src[i] ); } } tempvec[0] = tempvec[1] = tempvec[2] = 0.0F; tempvec[pos] = 1.0F; /* ** project the point onto the plane defined by src */ ProjectPointOnPlane( dst, tempvec, src ); /* ** normalize the result */ VectorNormalize( dst ); } /***************\ * THE FUNCTIONS * \***************/ void RPAV_QUAKE3( vec3_t dst, const vec3_t dir, const vec3_t point, vec_t degrees ) { vec_t m[3][3]; vec_t im[3][3]; vec_t zrot[3][3]; vec_t tmpmat[3][3]; vec_t rot[3][3]; int i; vec3_t vr, vup, vf; vec_t rad; vf[0] = dir[0]; vf[1] = dir[1]; vf[2] = dir[2]; PerpendicularVector( vr, dir ); CrossProduct( vr, vf, vup ); m[0][0] = vr[0]; m[1][0] = vr[1]; m[2][0] = vr[2]; m[0][1] = vup[0]; m[1][1] = vup[1]; m[2][1] = vup[2]; m[0][2] = vf[0]; m[1][2] = vf[1]; m[2][2] = vf[2]; memcpy( im, m, sizeof( im ) ); im[0][1] = m[1][0]; im[0][2] = m[2][0]; im[1][0] = m[0][1]; im[1][2] = m[2][1]; im[2][0] = m[0][2]; im[2][1] = m[1][2]; memset( zrot, 0, sizeof( zrot ) ); zrot[0][0] = zrot[1][1] = zrot[2][2] = 1.0F; rad = DEG2RAD( degrees ); zrot[0][0] = cos( rad ); zrot[0][1] = sin( rad ); zrot[1][0] = -sin( rad ); zrot[1][1] = cos( rad ); MatrixMultiply( m, zrot, tmpmat ); MatrixMultiply( tmpmat, im, rot ); for ( i = 0; i < 3; i++ ) { dst[i] = rot[i][0] * point[0] + rot[i][1] * point[1] + rot[i][2] * point[2]; } } void RPAV_TREMULOUS( vec3_t dst, const vec3_t dir, const vec3_t point, vec_t degrees ) { vec_t sin_a; vec_t cos_a; vec_t cos_ia; vec_t i_i_ia; vec_t j_j_ia; vec_t k_k_ia; vec_t i_j_ia; vec_t i_k_ia; vec_t j_k_ia; vec_t a_sin; vec_t b_sin; vec_t c_sin; vec_t rot[3][3]; cos_ia = DEG2RAD(degrees); sin_a = sin(cos_ia); cos_a = cos(cos_ia); cos_ia = 1.0F - cos_a; i_i_ia = dir[0] * dir[0] * cos_ia; j_j_ia = dir[1] * dir[1] * cos_ia; k_k_ia = dir[2] * dir[2] * cos_ia; i_j_ia = dir[0] * dir[1] * cos_ia; i_k_ia = dir[0] * dir[2] * cos_ia; j_k_ia = dir[1] * dir[2] * cos_ia; a_sin = dir[0] * sin_a; b_sin = dir[1] * sin_a; c_sin = dir[2] * sin_a; rot[0][0] = i_i_ia + cos_a; rot[0][1] = i_j_ia - c_sin; rot[0][2] = i_k_ia + b_sin; rot[1][0] = i_j_ia + c_sin; rot[1][1] = j_j_ia + cos_a; rot[1][2] = j_k_ia - a_sin; rot[2][0] = i_k_ia - b_sin; rot[2][1] = j_k_ia + a_sin; rot[2][2] = k_k_ia + cos_a; dst[0] = point[0] * rot[0][0] + point[1] * rot[0][1] + point[2] * rot[0][2]; dst[1] = point[0] * rot[1][0] + point[1] * rot[1][1] + point[2] * rot[1][2]; dst[2] = point[0] * rot[2][0] + point[1] * rot[2][1] + point[2] * rot[2][2]; } void RPAV_NEW( vec3_t dst, const vec3_t dir, const vec3_t point, vec_t degrees ) { vec_t sind, cosd, expr; vec3_t dxp; degrees = DEG2RAD( degrees ); sind = sin( degrees ); cosd = cos( degrees ); expr = ( 1 - cosd ) * DotProduct( dir, point ); CrossProduct( dir, point, dxp ); dst[0] = expr*dir[0] + cosd*point[0] + sind*dxp[0]; dst[1] = expr*dir[1] + cosd*point[1] + sind*dxp[1]; dst[2] = expr*dir[2] + cosd*point[2] + sind*dxp[2]; } /**************\ * TESTING CODE * \**************/ #define DATA_COUNT 999 #define REPEAT_COUNT 99999 vec3_t* dirs; vec3_t* points; vec_t* degs; vec3_t* work; void fillup() { int n; dirs = malloc( sizeof( vec3_t[ DATA_COUNT ] ) ); points = malloc( sizeof( vec3_t[ DATA_COUNT ] ) ); degs = malloc( sizeof( vec_t[ DATA_COUNT ] ) ); work = malloc( sizeof( vec3_t[ DATA_COUNT ] ) ); for( n = 0; n < DATA_COUNT; n++ ) { dirs[n][0] = (vec_t)rand(); dirs[n][1] = (vec_t)rand(); dirs[n][2] = (vec_t)rand(); VectorNormalize( dirs[n] ); points[n][0] = (vec_t)rand(); points[n][1] = (vec_t)rand(); points[n][2] = (vec_t)rand(); degs[n] = (vec_t)rand(); } } void test( void (*RPAV)( vec3_t, const vec3_t, const vec3_t, vec_t ), char* name, vec3_t final ) { int n, k; clock_t c1, c2; for( n = 0; n < DATA_COUNT; n++ ) { VectorCopy( points[n], work[n] ); } c1 = clock(); for( k = 0; k < REPEAT_COUNT; k++ ) { for( n = 1; n < DATA_COUNT; n++ ) { (*RPAV)( work[n], dirs[n], work[n-1], degs[n] ); } VectorCopy( work[ DATA_COUNT - 1 ], work[0] ); } c2 = clock(); printf( "%s: %imsec\n", name, c2 - c1 ); VectorCopy( work[0], final ); } int main() { int n; vec3_t final[3]; fillup(); for( n = 0; n < 6; n++ ) { vec3_t dst; RPAV_QUAKE3( dst, dirs[n], points[n], degs[n] ); printf( "RPAV_QUAKE3 : %f, %f, %f\n", dst[0], dst[1], dst[2] ); RPAV_TREMULOUS( dst, dirs[n], points[n], degs[n] ); printf( "RPAV_TREMULOUS: %f, %f, %f\n", dst[0], dst[1], dst[2] ); RPAV_NEW( dst, dirs[n], points[n], degs[n] ); printf( "RPAV_NEW : %f, %f, %f\n", dst[0], dst[1], dst[2] ); printf( "\n" ); } printf( "\nSPEED TEST (this may take a few minutes)\n\n" ); test( RPAV_QUAKE3, "RPAV_QUAKE3", final[0] ); test( RPAV_TREMULOUS, "RPAV_TREMULOUS", final[1] ); test( RPAV_NEW, "RPAV_NEW", final[2] ); printf( "\nFINAL DATA AFTER %i SEQUENTIAL ITERATIONS (LOL):\n", DATA_COUNT * REPEAT_COUNT ); printf( "RPAV_QUAKE3 : %f, %f, %f\n", final[0][0], final[0][1], final[0][2] ); printf( "RPAV_TREMULOUS: %f, %f, %f\n", final[1][0], final[1][1], final[1][2] ); printf( "RPAV_NEW : %f, %f, %f\n", final[2][0], final[2][1], final[2][2] ); return 0; }