/* Copyright (C) 1996-1997 Id Software, Inc. This program 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. This program 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 this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // mathlib.c -- math primitives //Dan East: //I've made many additions to this file, recreating various original functions to use //my Fixed Point Math routines. My additions all contain the acronym FPM #include #include "quakedef.h" void Sys_Error (char *error, ...); vec3_t vec3_origin = {0,0,0}; #ifdef USEFPM vec3_FPM_t vec3_originFPM = {0,0,0}; #endif int nanmask = 255<<23; /*-----------------------------------------------------------------*/ #define DEG2RAD( a ) ( a * M_PI ) / 180.0F void ProjectPointOnPlane( vec3_t dst, const vec3_t p, const vec3_t normal ) { float d; vec3_t n; float inv_denom; inv_denom = 1.0F / DotProduct( normal, normal ); 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]; } #ifdef USEFPM void ProjectPointOnPlaneFPM( vec3_FPM_t dst, const vec3_FPM_t p, const vec3_FPM_t normal ) { fixedpoint_t d; vec3_FPM_t n; fixedpoint_t inv_denom; inv_denom = /*1.0F*/0x10000 / DotProductFPM( normal, normal ); d = DotProductFPM( normal, p ) * inv_denom; n[0] = FPM_MUL(normal[0], inv_denom); n[1] = FPM_MUL(normal[1], inv_denom); n[2] = FPM_MUL(normal[2], inv_denom); dst[0] = FPM_SUB(p[0], FPM_MUL(d, n[0])); dst[1] = FPM_SUB(p[1], FPM_MUL(d, n[1])); dst[2] = FPM_SUB(p[2], FPM_MUL(d, n[2])); } #endif /* ** assumes "src" is normalized */ void PerpendicularVector( vec3_t dst, const vec3_t src ) { int pos; int i; float 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 = (float)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 ); } #ifdef USEFPM void PerpendicularVectorFPM( vec3_FPM_t dst, const vec3_FPM_t src ) { int pos; int i; fixedpoint_t minelem = 0x00010000; vec3_FPM_t tempvec; /* ** find the smallest magnitude axially aligned vector */ for ( pos = 0, i = 0; i < 3; i++ ) { if ( FPM_ABS( src[i] ) < minelem ) { pos = i; minelem = FPM_ABS( src[i] ); } } tempvec[0] = tempvec[1] = tempvec[2] = 0; tempvec[pos] = 0x10000; /* ** project the point onto the plane defined by src */ ProjectPointOnPlaneFPM( dst, tempvec, src ); /* ** normalize the result */ VectorNormalizeFPM( dst ); } #endif #ifdef _WIN32 #pragma optimize( "", off ) #endif void RotatePointAroundVector( vec3_t dst, const vec3_t dir, const vec3_t point, float degrees ) { float m[3][3]; float im[3][3]; float zrot[3][3]; float tmpmat[3][3]; float rot[3][3]; int i; vec3_t vr, vup, vf; 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]; Q_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]; Q_memset( zrot, 0, sizeof( zrot ) ); zrot[0][0] = zrot[1][1] = zrot[2][2] = 1.0F; zrot[0][0] = (float)cos( DEG2RAD( degrees ) ); zrot[0][1] = (float)sin( DEG2RAD( degrees ) ); zrot[1][0] = (float)-sin( DEG2RAD( degrees ) ); zrot[1][1] = (float)cos( DEG2RAD( degrees ) ); R_ConcatRotations( m, zrot, tmpmat ); R_ConcatRotations( 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]; } } #ifdef USEFPM void RotatePointAroundVectorFPM( vec3_FPM_t dst, const vec3_FPM_t dir, const vec3_FPM_t point, fixedpoint_t degrees ) { fixedpoint_t m[3][3]; fixedpoint_t im[3][3]; fixedpoint_t zrot[3][3]; fixedpoint_t tmpmat[3][3]; fixedpoint_t rot[3][3]; int i; vec3_FPM_t vr, vup, vf; vf[0] = dir[0]; vf[1] = dir[1]; vf[2] = dir[2]; PerpendicularVectorFPM( vr, dir ); CrossProductFPM( 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]; Q_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]; Q_memset( zrot, 0, sizeof( zrot ) ); zrot[0][0] = zrot[1][1] = zrot[2][2] = 0x10000; zrot[1][0]=-(zrot[0][0] = FPM_SIN_DEG(degrees)); zrot[1][1] = FPM_COS_DEG( degrees ); R_ConcatRotationsFPM( m, zrot, tmpmat ); R_ConcatRotationsFPM( tmpmat, im, rot ); for ( i = 0; i < 3; i++ ) { dst[i] = FPM_ADD3(FPM_MUL(rot[i][0], point[0]), FPM_MUL(rot[i][1], point[1]), FPM_MUL(rot[i][2], point[2])); } } #endif #ifdef _WIN32 #pragma optimize( "", on ) #endif /*-----------------------------------------------------------------*/ float anglemod(float a) { #if 0 if (a >= 0) a -= 360*(int)(a/360); else a += 360*( 1 + (int)(-a/360) ); #endif a = (float)((360.0/65536) * ((int)(a*(65536/360.0)) & 65535)); return a; } #ifdef USEFPM fixedpoint_t anglemodFPM(fixedpoint_t a) { #if 0 if (a >= 0) a -= 360*(int)(a/360); else a += 360*( 1 + (int)(-a/360) ); #endif //Dan: TODO: the following will overflow 16.16 signed fixedpoint. This algorithm //needs to be tweaked to work with fixedpoint without overflowing. a = FPM_FROMFLOAT((float)((360.0/65536) * ((int)(FPM_TOFLOAT(a)*(65536/360.0)) & 65535))); // a = FPM_MUL(FPM_FROMFLOAT(360.0/65536), FPM_FROMLONG((FPM_TOLONG(FPM_MUL(a,FPM_FROMFLOAT(65536/360.0))) & 65535))); return a; } #endif /* ================== BOPS_Error Split out like this for ASM to call. ================== */ void BOPS_Error (void) { Sys_Error ("BoxOnPlaneSide: Bad signbits"); } #if !id386 /* ================== BoxOnPlaneSide Returns 1, 2, or 1 + 2 ================== */ int BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, mplane_t *p) { float dist1, dist2; int sides; #if 0 // this is done by the BOX_ON_PLANE_SIDE macro before calling this // function // fast axial cases if (p->type < 3) { if (p->dist <= emins[p->type]) return 1; if (p->dist >= emaxs[p->type]) return 2; return 3; } #endif // general case switch (p->signbits) { case 0: dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2]; dist2 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2]; break; case 1: dist1 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2]; dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2]; break; case 2: dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2]; dist2 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2]; break; case 3: dist1 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2]; dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2]; break; case 4: dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2]; dist2 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2]; break; case 5: dist1 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2]; dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2]; break; case 6: dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2]; dist2 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2]; break; case 7: dist1 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2]; dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2]; break; default: dist1 = dist2 = 0; // shut up compiler BOPS_Error (); break; } #if 0 int i; vec3_t corners[2]; for (i=0 ; i<3 ; i++) { if (plane->normal[i] < 0) { corners[0][i] = emins[i]; corners[1][i] = emaxs[i]; } else { corners[1][i] = emins[i]; corners[0][i] = emaxs[i]; } } dist = DotProduct (plane->normal, corners[0]) - plane->dist; dist2 = DotProduct (plane->normal, corners[1]) - plane->dist; sides = 0; if (dist1 >= 0) sides = 1; if (dist2 < 0) sides |= 2; #endif sides = 0; if (dist1 >= p->dist) sides = 1; if (dist2 < p->dist) sides |= 2; #ifdef PARANOID if (sides == 0) Sys_Error ("BoxOnPlaneSide: sides==0"); #endif return sides; } #ifdef USEFPM int BoxOnPlaneSideFPM (vec3_FPM_t emins, vec3_FPM_t emaxs, mplane_FPM_t *p) { fixedpoint_t dist1, dist2; int sides; // general case switch (p->signbits) { case 0: dist1 = DotProductFPM(p->normal, emaxs); dist2 = DotProductFPM(p->normal, emins); break; case 1: dist1 = FPM_ADD3(FPM_MUL(p->normal[0],emins[0]),FPM_MUL(p->normal[1],emaxs[1]),FPM_MUL(p->normal[2],emaxs[2])); dist2 = FPM_ADD3(FPM_MUL(p->normal[0],emaxs[0]),FPM_MUL(p->normal[1],emins[1]),FPM_MUL(p->normal[2],emins[2])); break; case 2: dist1 = FPM_ADD3(FPM_MUL(p->normal[0],emaxs[0]),FPM_MUL(p->normal[1],emins[1]),FPM_MUL(p->normal[2],emaxs[2])); dist2 = FPM_ADD3(FPM_MUL(p->normal[0],emins[0]),FPM_MUL(p->normal[1],emaxs[1]),FPM_MUL(p->normal[2],emins[2])); break; case 3: dist1 = FPM_ADD3(FPM_MUL(p->normal[0],emins[0]),FPM_MUL(p->normal[1],emins[1]),FPM_MUL(p->normal[2],emaxs[2])); dist2 = FPM_ADD3(FPM_MUL(p->normal[0],emaxs[0]),FPM_MUL(p->normal[1],emaxs[1]),FPM_MUL(p->normal[2],emins[2])); break; case 4: dist1 = FPM_ADD3(FPM_MUL(p->normal[0],emaxs[0]),FPM_MUL(p->normal[1],emaxs[1]),FPM_MUL(p->normal[2],emins[2])); dist2 = FPM_ADD3(FPM_MUL(p->normal[0],emins[0]),FPM_MUL(p->normal[1],emins[1]),FPM_MUL(p->normal[2],emaxs[2])); break; case 5: dist1 = FPM_ADD3(FPM_MUL(p->normal[0],emins[0]),FPM_MUL(p->normal[1],emaxs[1]),FPM_MUL(p->normal[2],emins[2])); dist2 = FPM_ADD3(FPM_MUL(p->normal[0],emaxs[0]),FPM_MUL(p->normal[1],emins[1]),FPM_MUL(p->normal[2],emaxs[2])); break; case 6: dist1 = FPM_ADD3(FPM_MUL(p->normal[0],emaxs[0]),FPM_MUL(p->normal[1],emins[1]),FPM_MUL(p->normal[2],emins[2])); dist2 = FPM_ADD3(FPM_MUL(p->normal[0],emins[0]),FPM_MUL(p->normal[1],emaxs[1]),FPM_MUL(p->normal[2],emaxs[2])); break; case 7: dist1 = FPM_ADD3(FPM_MUL(p->normal[0],emins[0]),FPM_MUL(p->normal[1],emins[1]),FPM_MUL(p->normal[2],emins[2])); dist2 = FPM_ADD3(FPM_MUL(p->normal[0],emaxs[0]),FPM_MUL(p->normal[1],emaxs[1]),FPM_MUL(p->normal[2],emaxs[2])); break; default: dist1 = dist2 = 0; // shut up compiler BOPS_Error (); break; } sides = 0; if (dist1 >= p->dist) sides = 1; if (dist2 < p->dist) sides |= 2; #ifdef PARANOID if (sides == 0) Sys_Error ("BoxOnPlaneSide: sides==0"); #endif return sides; } #endif #endif void AngleVectors (vec3_t angles, vec3_t forward, vec3_t right, vec3_t up) { float angle; float sr, sp, sy, cr, cp, cy; angle = (float)(angles[YAW] * (M_PI*2 / 360)); sy = (float)sin(angle); cy = (float)cos(angle); angle = (float)(angles[PITCH] * (M_PI*2 / 360)); sp = (float)sin(angle); cp = (float)cos(angle); angle = (float)(angles[ROLL] * (M_PI*2 / 360)); sr = (float)sin(angle); cr = (float)cos(angle); forward[0] = cp*cy; forward[1] = cp*sy; forward[2] = -sp; right[0] = (-1*sr*sp*cy+-1*cr*-sy); right[1] = (-1*sr*sp*sy+-1*cr*cy); right[2] = -1*sr*cp; up[0] = (cr*sp*cy+-sr*-sy); up[1] = (cr*sp*sy+-sr*cy); up[2] = cr*cp; } #ifdef USEFPM void AngleVectorsFPM (vec3_FPM_t angles, vec3_FPM_t forward, vec3_FPM_t right, vec3_FPM_t up) { double source; double angle; // fixedpoint_t angle; // fixedpoint_t sr, sp, sy, cr, cp, cy; __int64 sr, sp, sy, cr, cp, cy; register __int64 /*conv, mul,*/ accum1, accum2, accum1b, accum2b; //Dan: ID converted all of these angles to rads for the sin, cos functions. //My Fixed Point Math routines can calc trig based on degrees. So this routine //is much more efficient than it was before source=FPM_TOFLOAT(FPM_MUL(angles[YAW], FPM_DIV(FPM_PI, FPM_FROMLONGC(180)))); angle = sin(source); sy = (__int64)(angle*(double)(2^32)); angle = cos(source); cy = (__int64)(angle*(double)(2^32)); // sy = FPM_SIN_DEG(angles[YAW]); // cy = FPM_COS_DEG(angles[YAW]); source=FPM_TOFLOAT(FPM_MUL(angles[PITCH], FPM_DIV(FPM_PI, FPM_FROMLONGC(180)))); angle = sin(source); sp = (__int64)(angle*(double)(2^32)); angle = cos(source); cp = (__int64)(angle*(double)(2^32)); // angle = angles[PITCH] * (M_PI*2 / 360); // sp = FPM_SIN_DEG(angles[PITCH]); // cp = FPM_COS_DEG(angles[PITCH]); // angle = angles[ROLL] * (M_PI*2 / 360); source=FPM_TOFLOAT(FPM_MUL(angles[ROLL], FPM_DIV(FPM_PI, FPM_FROMLONGC(180)))); angle = sin(source); sr = (__int64)(angle*(double)(2^32)); angle = cos(source); cr = (__int64)(angle*(double)(2^32)); // sr = FPM_SIN_DEG(angles[ROLL]); // cr = FPM_COS_DEG(angles[ROLL]); forward[0] = (fixedpoint_t)((cp*cy)>>32); //FPM_MUL(cp,cy); forward[1] = (fixedpoint_t)((cp*sy)>>32); //FPM_MUL(cp,sy); forward[2] = (fixedpoint_t)((-sp)>>16); accum1=-sr; accum2=-sr; accum1*=sp; accum2*=sp; accum1*=cy; accum2b=cy; accum1b=-cr; accum2b*=-cr; accum1b*=-sy; accum2*=sy; accum1+=accum1b; accum2+=accum2b; accum1>>=16; accum2>>=16; right[0]=(fixedpoint_t)accum1; right[1]=(fixedpoint_t)accum2; //right[0] = FPM_ADD(FPM_MUL(FPM_MUL(FPM_MUL(FPM_FROMLONG(-1),sr),sp),cy),FPM_MUL(FPM_MUL(FPM_FROMLONG(-1),cr),-sy)); //right[0] = (-1*sr*sp*cy+-1*cr*-sy); //right[1] = FPM_ADD(FPM_MUL(FPM_MUL(FPM_MUL(FPM_FROMLONG(-1),sr),sp),sy),FPM_MUL(FPM_MUL(FPM_FROMLONG(-1),cr),cy)); //right[1] = (-1*sr*sp*sy+-1*cr*cy); //right[2] = FPM_MUL(FPM_MUL(FPM_FROMLONG(-1),sr),cp); accum1=-sr; accum1*=cp; accum1>>=16; right[2]=(fixedpoint_t)accum1; accum1=cr; accum1*=sp; accum1*=cy; accum1b=-sr; accum1b*=-sy; accum1+=accum1b; accum1>>=16; up[0] = (fixedpoint_t)accum1; //right[2] = -1*sr*cp; //up[0] = FPM_ADD(FPM_MUL(FPM_MUL(cr,sp),cy),FPM_MUL(-sr,-sy)); //up[0] = (cr*sp*cy+-sr*-sy); accum1=cr; accum1*=sp; accum1*=sy; accum1b=-sr; accum1b*=cy; accum1+=accum1b; accum1>>=16; up[1]=(fixedpoint_t)accum1; //up[1] = FPM_ADD(FPM_MUL(FPM_MUL(cr,sp),sy),FPM_MUL(-sr,cy)); //up[1] = (cr*sp*sy+-sr*cy); accum1=cr; accum1*=cp; accum1>>=16; up[2]=(fixedpoint_t)accum1; //up[2] = FPM_MUL(cr,cp); //up[2] = cr*cp; } #endif int VectorCompare (vec3_t v1, vec3_t v2) { int i; for (i=0 ; i<3 ; i++) if (v1[i] != v2[i]) return 0; return 1; } #ifdef USEFPM int VectorCompareFPM (vec3_FPM_t v1, vec3_FPM_t v2) { int i; for (i=0 ; i<3 ; i++) if (v1[i] != v2[i]) return 0; return 1; } #endif void VectorMA (vec3_t veca, float scale, vec3_t vecb, vec3_t vecc) { vecc[0] = veca[0] + scale*vecb[0]; vecc[1] = veca[1] + scale*vecb[1]; vecc[2] = veca[2] + scale*vecb[2]; } #ifdef USEFPM void VectorMAFPM (vec3_FPM_t veca, fixedpoint_t scale, vec3_FPM_t vecb, vec3_FPM_t vecc) { vecc[0] = FPM_ADD(veca[0], FPM_MUL(scale, vecb[0])); vecc[1] = FPM_ADD(veca[1], FPM_MUL(scale, vecb[1])); vecc[2] = FPM_ADD(veca[2], FPM_MUL(scale, vecb[2])); } #endif //Dan: The following functions do not appear to be used by WinQuake /* vec_t _DotProduct (vec3_t v1, vec3_t v2) { return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2]; } void _VectorSubtract (vec3_t veca, vec3_t vecb, vec3_t out) { out[0] = veca[0]-vecb[0]; out[1] = veca[1]-vecb[1]; out[2] = veca[2]-vecb[2]; } void _VectorAdd (vec3_t veca, vec3_t vecb, vec3_t out) { out[0] = veca[0]+vecb[0]; out[1] = veca[1]+vecb[1]; out[2] = veca[2]+vecb[2]; } void _VectorCopy (vec3_t in, vec3_t out) { out[0] = in[0]; out[1] = in[1]; out[2] = in[2]; } */ void CrossProduct (vec3_t v1, 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]; } #ifdef USEFPM void CrossProductFPM (vec3_FPM_t v1, vec3_FPM_t v2, vec3_FPM_t cross) { cross[0] = FPM_SUB(FPM_MUL(v1[1], v2[2]), FPM_MUL(v1[2], v2[1])); cross[1] = FPM_SUB(FPM_MUL(v1[2], v2[0]), FPM_MUL(v1[0], v2[2])); cross[2] = FPM_SUB(FPM_MUL(v1[0], v2[1]), FPM_MUL(v1[1], v2[0])); } #endif vec_t Length(vec3_t v) { int i; float length; length = 0; for (i=0 ; i< 3 ; i++) length += v[i]*v[i]; length = (float)sqrt (length); // FIXME return length; } #ifdef USEFPM fixedpoint_t LengthFPM(vec3_FPM_t v) { int i; //Dan: squaring the vectors results in overflow, so we're hardcoding 64 bit 16.16 fixedpoint: __int64 length, tmp; // fixedpoint_t length; length = 0; for (i=0 ; i< 3 ; i++) { tmp=v[i]; length += (tmp*tmp)>>16; } return (fixedpoint_t)sqrt (length/65536.0)*65536; // FIXME (not Dan's comment) // return length; } #endif float VectorNormalize (vec3_t v) { float length, ilength; length = v[0]*v[0] + v[1]*v[1] + v[2]*v[2]; length = (float)sqrt (length); // FIXME if (length) { ilength = 1/length; v[0] *= ilength; v[1] *= ilength; v[2] *= ilength; } return length; } #ifdef USEFPM fixedpoint_t VectorNormalizeFPM (vec3_FPM_t v) { fixedpoint_t length;//, ilength; length = FPM_ADD3(FPM_MUL(v[0],v[0]),FPM_MUL(v[1],v[1]),FPM_MUL(v[2],v[2])); length = FPM_SQRT (length); // FIXME (not dan's comment) if (length) { //ilength = FPM_INV(length); v[0]=FPM_DIV(v[0], length); //FPM_MUL(v[0], ilength); v[1]=FPM_DIV(v[1], length); //FPM_MUL(v[1], ilength); v[2]=FPM_DIV(v[2], length); //FPM_MUL(v[2], ilength); } return length; } #endif void VectorInverse (vec3_t v) { v[0] = -v[0]; v[1] = -v[1]; v[2] = -v[2]; } #ifdef USEFPM void VectorInverseFPM (vec3_FPM_t v) { v[0] = -v[0]; v[1] = -v[1]; v[2] = -v[2]; } #endif void VectorScale (vec3_t in, vec_t scale, vec3_t out) { out[0] = in[0]*scale; out[1] = in[1]*scale; out[2] = in[2]*scale; } #ifdef USEFPM void VectorScaleFPM (vec3_FPM_t in, fixedpoint_t scale, vec3_FPM_t out) { out[0] = FPM_MUL(in[0], scale); out[1] = FPM_MUL(in[1], scale); out[2] = FPM_MUL(in[2], scale); } #endif int Q_log2(int val) { int answer=0; while (val>>=1) answer++; return answer; } /* ================ R_ConcatRotations ================ */ void R_ConcatRotations (float in1[3][3], float in2[3][3], float 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]; } #ifdef USEFPM void R_ConcatRotationsFPM (fixedpoint_t in1[3][3], fixedpoint_t in2[3][3], fixedpoint_t out[3][3]) { out[0][0] = FPM_ADD3(FPM_MUL(in1[0][0],in2[0][0]), FPM_MUL(in1[0][1],in2[1][0]), FPM_MUL(in1[0][2],in2[2][0])); out[0][1] = FPM_ADD3(FPM_MUL(in1[0][0],in2[0][1]), FPM_MUL(in1[0][1],in2[1][1]), FPM_MUL(in1[0][2],in2[2][1])); out[0][2] = FPM_ADD3(FPM_MUL(in1[0][0],in2[0][2]), FPM_MUL(in1[0][1],in2[1][2]), FPM_MUL(in1[0][2],in2[2][2])); out[1][0] = FPM_ADD3(FPM_MUL(in1[1][0],in2[0][0]), FPM_MUL(in1[1][1],in2[1][0]), FPM_MUL(in1[1][2],in2[2][0])); out[1][1] = FPM_ADD3(FPM_MUL(in1[1][0],in2[0][1]), FPM_MUL(in1[1][1],in2[1][1]), FPM_MUL(in1[1][2],in2[2][1])); out[1][2] = FPM_ADD3(FPM_MUL(in1[1][0],in2[0][2]), FPM_MUL(in1[1][1],in2[1][2]), FPM_MUL(in1[1][2],in2[2][2])); out[2][0] = FPM_ADD3(FPM_MUL(in1[2][0],in2[0][0]), FPM_MUL(in1[2][1],in2[1][0]), FPM_MUL(in1[2][2],in2[2][0])); out[2][1] = FPM_ADD3(FPM_MUL(in1[2][0],in2[0][1]), FPM_MUL(in1[2][1],in2[1][1]), FPM_MUL(in1[2][2],in2[2][1])); out[2][2] = FPM_ADD3(FPM_MUL(in1[2][0],in2[0][2]), FPM_MUL(in1[2][1],in2[1][2]), FPM_MUL(in1[2][2],in2[2][2])); } #endif /* ================ R_ConcatTransforms ================ */ void R_ConcatTransforms (float in1[3][4], float in2[3][4], float out[3][4]) { 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[0][3] = in1[0][0] * in2[0][3] + in1[0][1] * in2[1][3] + in1[0][2] * in2[2][3] + in1[0][3]; 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[1][3] = in1[1][0] * in2[0][3] + in1[1][1] * in2[1][3] + in1[1][2] * in2[2][3] + in1[1][3]; 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]; out[2][3] = in1[2][0] * in2[0][3] + in1[2][1] * in2[1][3] + in1[2][2] * in2[2][3] + in1[2][3]; } #ifdef USEFPM void R_ConcatTransformsFPM (fixedpoint_t in1[3][4], fixedpoint_t in2[3][4], fixedpoint_t out[3][4]) { register __int64 accum, mul; int i; for (i=0; i<3; i++) { accum=in1[i][0]; accum*=in2[0][0]; mul=in1[i][1]; mul*=in2[1][0]; accum+=mul; mul=in1[i][2]; mul*=in2[2][0]; accum+=mul; accum>>=16; out[i][0]=(fixedpoint_t)accum; accum=in1[i][0]; accum*=in2[0][1]; mul=in1[i][1]; mul*=in2[1][1]; accum+=mul; mul=in1[i][2]; mul*=in2[2][1]; accum+=mul; accum>>=16; out[i][1]=(fixedpoint_t)accum; accum=in1[i][0]; accum*=in2[0][2]; mul=in1[i][1]; mul*=in2[1][2]; accum+=mul; mul=in1[i][2]; mul*=in2[2][2]; accum+=mul; accum>>=16; out[i][2]=(fixedpoint_t)accum; accum=in1[i][0]; accum*=in2[0][3]; mul=in1[i][1]; mul*=in2[1][3]; accum+=mul; mul=in1[i][2]; mul*=in2[2][3]; accum+=mul; mul=in1[0][3]; mul<<=16; //16.16 -> 32.32 accum+=mul; accum>>=16; out[i][3]=(fixedpoint_t)accum; } } #endif /* void R_ConcatTransformsFPM (fixedpoint_t in1[3][4], fixedpoint_t in2[3][4], fixedpoint_t out[3][4]) { out[0][0] = FPM_ADD3(FPM_MUL(in1[0][0],in2[0][0]),FPM_MUL(in1[0][1],in2[1][0]), FPM_MUL(in1[0][2],in2[2][0])); out[0][1] = FPM_ADD3(FPM_MUL(in1[0][0],in2[0][1]),FPM_MUL(in1[0][1],in2[1][1]), FPM_MUL(in1[0][2],in2[2][1])); out[0][2] = FPM_ADD3(FPM_MUL(in1[0][0],in2[0][2]),FPM_MUL(in1[0][1],in2[1][2]), FPM_MUL(in1[0][2],in2[2][2])); out[0][3] = FPM_ADD(FPM_ADD3(FPM_MUL(in1[0][0],in2[0][3]),FPM_MUL(in1[0][1],in2[1][3]), FPM_MUL(in1[0][2],in2[2][3])),in1[0][3]); out[1][0] = FPM_ADD3(FPM_MUL(in1[1][0],in2[0][0]),FPM_MUL(in1[1][1],in2[1][0]), FPM_MUL(in1[1][2],in2[2][0])); out[1][1] = FPM_ADD3(FPM_MUL(in1[1][0],in2[0][1]),FPM_MUL(in1[1][1],in2[1][1]), FPM_MUL(in1[1][2],in2[2][1])); out[1][2] = FPM_ADD3(FPM_MUL(in1[1][0],in2[0][2]),FPM_MUL(in1[1][1],in2[1][2]), FPM_MUL(in1[1][2],in2[2][2])); out[1][3] = FPM_ADD(FPM_ADD3(FPM_MUL(in1[1][0],in2[0][3]),FPM_MUL(in1[1][1],in2[1][3]), FPM_MUL(in1[1][2],in2[2][3])),in1[1][3]); out[2][0] = FPM_ADD3(FPM_MUL(in1[2][0],in2[0][0]),FPM_MUL(in1[2][1],in2[1][0]), FPM_MUL(in1[2][2],in2[2][0])); out[2][1] = FPM_ADD3(FPM_MUL(in1[2][0],in2[0][1]),FPM_MUL(in1[2][1],in2[1][1]), FPM_MUL(in1[2][2],in2[2][1])); out[2][2] = FPM_ADD3(FPM_MUL(in1[2][0],in2[0][2]),FPM_MUL(in1[2][1],in2[1][2]), FPM_MUL(in1[2][2],in2[2][2])); out[2][3] = FPM_ADD(FPM_ADD3(FPM_MUL(in1[2][0],in2[0][3]),FPM_MUL(in1[2][1],in2[1][3]), FPM_MUL(in1[2][2],in2[2][3])),in1[2][3]); } */ #ifdef USEFPM void R_ConcatTransforms8_24FPM (fixedpoint_t in1[3][4], fixedpoint_t in2[3][4], fixedpoint8_24_t out[3][4]) { int i; register __int64 accum, i1, i2, i3, conv; for (i=0; i<3; i++) { accum=0; i1=in1[i][0]; i1<<=16; i2=in1[i][1]; i2<<=16; i3=in1[i][2]; i3<<=16; conv=in2[0][0]; conv<<=16; conv*=i1; accum=conv>>16; conv=in2[1][0]; conv<<=16; conv*=i2; accum+=conv>>16; conv=in2[2][0]; conv<<=16; conv*=i3; accum+=conv>>16; out[i][0] = (fixedpoint8_24_t)accum>>8; conv=in2[0][1]; conv<<=16; conv*=i1; accum=conv>>16; conv=in2[1][1]; conv<<=16; conv*=i2; accum+=conv>>16; conv=in2[2][1]; conv<<=16; conv*=i3; accum+=conv>>16; out[i][1] = (fixedpoint8_24_t)accum>>8; conv=in2[0][2]; conv<<=16; conv*=i1; accum=conv>>16; conv=in2[1][2]; conv<<=16; conv*=i2; accum+=conv>>16; conv=in2[2][2]; conv<<=16; conv*=i3; accum+=conv>>16; out[i][2] = (fixedpoint8_24_t)accum>>8; //to 8.24 conv=in2[0][3]; conv<<=16; conv*=i1; accum=conv>>16; conv=in2[1][3]; conv<<=16; conv*=i2; accum+=conv>>16; conv=in2[2][3]; conv<<=16; conv*=i3; accum+=conv>>16; conv=in1[0][3]; conv<<=16; accum+=conv; out[i][3] = (fixedpoint8_24_t)accum>>16; //to 16.16 } } #endif /* void R_ConcatTransforms8_24FPM (fixedpoint_t in1[3][4], fixedpoint_t in2[3][4], fixedpoint8_24_t out[3][4]) { out[0][0] = fpm_FromFixedPoint(FPM_ADD3(FPM_MUL(in1[0][0],in2[0][0]),FPM_MUL(in1[0][1],in2[1][0]), FPM_MUL(in1[0][2],in2[2][0]))); out[0][1] = fpm_FromFixedPoint(FPM_ADD3(FPM_MUL(in1[0][0],in2[0][1]),FPM_MUL(in1[0][1],in2[1][1]), FPM_MUL(in1[0][2],in2[2][1]))); out[0][2] = fpm_FromFixedPoint(FPM_ADD3(FPM_MUL(in1[0][0],in2[0][2]),FPM_MUL(in1[0][1],in2[1][2]), FPM_MUL(in1[0][2],in2[2][2]))); out[0][3] = (fixedpoint_t)FPM_ADD(FPM_ADD3(FPM_MUL(in1[0][0],in2[0][3]),FPM_MUL(in1[0][1],in2[1][3]), FPM_MUL(in1[0][2],in2[2][3])),in1[0][3]); out[1][0] = fpm_FromFixedPoint(FPM_ADD3(FPM_MUL(in1[1][0],in2[0][0]),FPM_MUL(in1[1][1],in2[1][0]), FPM_MUL(in1[1][2],in2[2][0]))); out[1][1] = fpm_FromFixedPoint(FPM_ADD3(FPM_MUL(in1[1][0],in2[0][1]),FPM_MUL(in1[1][1],in2[1][1]), FPM_MUL(in1[1][2],in2[2][1]))); out[1][2] = fpm_FromFixedPoint(FPM_ADD3(FPM_MUL(in1[1][0],in2[0][2]),FPM_MUL(in1[1][1],in2[1][2]), FPM_MUL(in1[1][2],in2[2][2]))); out[1][3] = (fixedpoint_t)FPM_ADD(FPM_ADD3(FPM_MUL(in1[1][0],in2[0][3]),FPM_MUL(in1[1][1],in2[1][3]), FPM_MUL(in1[1][2],in2[2][3])),in1[1][3]); out[2][0] = fpm_FromFixedPoint(FPM_ADD3(FPM_MUL(in1[2][0],in2[0][0]),FPM_MUL(in1[2][1],in2[1][0]), FPM_MUL(in1[2][2],in2[2][0]))); out[2][1] = fpm_FromFixedPoint(FPM_ADD3(FPM_MUL(in1[2][0],in2[0][1]),FPM_MUL(in1[2][1],in2[1][1]), FPM_MUL(in1[2][2],in2[2][1]))); out[2][2] = fpm_FromFixedPoint(FPM_ADD3(FPM_MUL(in1[2][0],in2[0][2]),FPM_MUL(in1[2][1],in2[1][2]), FPM_MUL(in1[2][2],in2[2][2]))); out[2][3] = (fixedpoint_t)FPM_ADD(FPM_ADD3(FPM_MUL(in1[2][0],in2[0][3]),FPM_MUL(in1[2][1],in2[1][3]), FPM_MUL(in1[2][2],in2[2][3])),in1[2][3]); } */ /* =================== FloorDivMod Returns mathematically correct (floor-based) quotient and remainder for numer and denom, both of which should contain no fractional part. The quotient must fit in 32 bits. ==================== */ void FloorDivMod (double numer, double denom, int *quotient, int *rem) { int q, r; double x; #ifndef PARANOID if (denom <= 0.0) Sys_Error ("FloorDivMod: bad denominator %d\n", denom); // if ((floor(numer) != numer) || (floor(denom) != denom)) // Sys_Error ("FloorDivMod: non-integer numer or denom %f %f\n", // numer, denom); #endif if (numer >= 0.0) { x = floor(numer / denom); q = (int)x; r = (int)floor(numer - (x * denom)); } else { // // perform operations with positive values, and fix mod to make floor-based // x = floor(-numer / denom); q = -(int)x; r = (int)floor(-numer - (x * denom)); if (r != 0) { q--; r = (int)denom - r; } } *quotient = q; *rem = r; } /* =================== GreatestCommonDivisor ==================== */ int GreatestCommonDivisor (int i1, int i2) { if (i1 > i2) { if (i2 == 0) return (i1); return GreatestCommonDivisor (i2, i1 % i2); } else { if (i1 == 0) return (i2); return GreatestCommonDivisor (i1, i2 % i1); } } #if !id386 // TODO: move to nonintel.c /* =================== Invert24To16 Inverts an 8.24 value to a 16.16 value ==================== */ fixed16_t Invert24To16(fixed16_t val) { if (val < 256) return (0xFFFFFFFF); return (fixed16_t) (((double)0x10000 * (double)0x1000000 / (double)val) + 0.5); } int ParseFloats(char *s, float *f, int *f_size) { int i, argc; if (!s || !f || !f_size) Sys_Error("ParseFloats() wrong params"); if (f_size[0] <= 0) return (f_size[0] = 0); Cmd_TokenizeString(s); // argc = min(Cmd_Argc(), f_size[0]); argc = (Cmd_Argc(), f_size[0]); for(i = 0; i < argc; i++) f[i] = Q_atof(Cmd_Argv(i)); for( ; i < f_size[0]; i++) f[i] = 0; return (f_size[0] = argc); } #endif