www.pudn.com > FlashPlayer.zip > fixed.cpp
/**************************************************************************** CONFIDENTIAL AND PROPRIETARY INFORMATION. The entire contents of this file is Copyright © Macromedia, Inc. 1993-1998, All Rights Reserved. This document is an unpublished trade secret of Macromedia, Inc. and may not be viewed, copied or distributed by anyone, without the specific, written permission of Macromedia, Inc. ****************************************************************************/ #include "fixed.h" #ifdef FIXEDUSEFLOAT #include#endif SFIXED FixedNearestMultiple(SFIXED x, SFIXED factor) { SFIXED n; n = (x < 0 ? x - factor/2 : x + factor/2) / factor; return n * factor; } SFIXED FixedTan(SFIXED d) { return FixedDiv(FixedSin(d), FixedCos(d)); } #ifdef FIXEDUSEFLOAT SFIXED FixedMul(SFIXED a, SFIXED b) { return (S32)(((double)a * (double)b)*(1/65536.0)); } SFIXED FixedDiv(SFIXED a, SFIXED b) { if ( b == 0 ) return 0; return (S32)(((double)a / (double)b)*65536.0); } SFIXED FixedSin(SFIXED d) { return (S32)(sin((double)d*(3.141592654/180/65536.0))*65536.0); } SFIXED FixedCos(SFIXED d) { return (S32)(cos((double)d*(3.141592654/180/65536.0))*65536.0); } SFIXED FixedAtan2(SFIXED dy, SFIXED dx) { if ( dy == 0 && dx == 0 ) return 0; return (S32)(atan2((double)dy, (double)dx)*(180/3.141592654)*65536.0); } S32 _FPMul( S32 a, S32 b, int rshift ) { return (S32)(((double)a*(double)b)/(1L< #include // // Build precomputed sine table // void BuildSinTable( void ) { register int i, j; double theta, sintheta; double libPi2 = acos( 0 ); double fpPi2 = (double) kFPPi2 / (double) (1L << kPiPrec); double scale = libPi2 / fpPi2; FILE *fp = 0; // build sine table for ( i = 0; i < SinMaxIdx; i++ ) { // theta is in [0..128] which is a superset of [0..pi/2] theta = (double) i / (SinMaxIdx >> kPiIntBits); sintheta = sin( theta * scale ); sintheta *= (double) (1L << (SinPrec >> 1)); sintheta *= (double) (1L << (SinPrec - (SinPrec >> 1))); SinTable[ i ] = (U32) sintheta; } #ifdef FileData fp = fopen( "sintbl.dat", "w" ); #else fp = stdout; #endif if ( fp ) { // print sine table for ( i = 0; i < SinMaxIdx; i += 4 ) { fprintf( fp, "\t" ); for ( j = 0; j < 4; j++ ) fprintf( fp, "0x%08lxL, ", SinTable[ i + j ] ); fprintf( fp, "\n" ); } fprintf( fp, "\n" ); if ( fp != stdout ) fclose( fp ); } } // // Build table of coefficients for ATan approximating polynomial // void BuildATanTable( void ) { double ATanXif[ ATanN ] = // ATan table of node points used { // to approximate atan 0.0000L, 0.0001L, 0.0005L, 0.0010L, 0.0100L, 0.1000L, 0.3000L, 0.5000L, 0.7000L, 0.9000L, 1.0000L } ; register int i, j; double (*ATanCoefF)[ ATanN ] = (double (*)[ATanN]) malloc( sizeof( double ) * ATanN * ATanN ); double libPi2 = acos( 0 ); double fpPi2 = (double) kFPPi2 / (double) (1L << kPiPrec); double scale = fpPi2 / libPi2; FILE *fp = 0; // // Use Newton Divided Differences // // Compute x, and ATan( x ) for ( i = 0; i < ATanN; i++ ) { ATanXi[ i ] = (S32) (ATanXif[ i ] * (1L << ATanPrec)); ATanCoefF[ 0 ][ i ] = scale * atan( (double) ATanXi[ i ] / (1L << ATanPrec) ); } // Compute divided differences for ( i = 1; i < ATanN; i++ ) for ( j = 0; j < (ATanN - i); j++ ) ATanCoefF[ i ][ j ] = (ATanCoefF[ i - 1 ][ j + 1 ] - ATanCoefF[ i - 1 ][ j ]) / ((double) (ATanXi[ i + j ] - ATanXi[ j ]) / (1L << ATanPrec)); // Save the coefficient divided differenes as fixed point numbers for ( i = 0; i < ATanN; i++ ) ATanCoef[ i ] = (S32) (ATanCoefF[ i ][ 0 ] * (1L << ATanPrec)); free( ATanCoefF ); #ifdef FileData fp = fopen( "atantbl.dat", "w" ); #else fp = stdout; #endif if ( fp ) { // print xis for ( i = 0; i < ATanN; i++ ) fprintf( fp, "\t0x%08lxL,\n", ATanXi[ i ] ); fprintf( fp, "\n" ); // print coefficients for ( i = 0; i < ATanN; i++ ) fprintf( fp, "\t0x%08lxL,\n", ATanCoef[ i ] ); fprintf( fp, "\n" ); if ( fp != stdout ) fclose( fp ); } } // // Initialize the fixed point trig routines // void _FPInit( int fpuFlag ) { gTrigUseFPU = fpuFlag; #ifdef Test BuildSinTable(); BuildATanTable(); #endif } #endif // // Calculate the sine of a fixed point number in [0..PI/2) // // Note: outBPoint < SinPrec // SFIXED __FPSin( SFIXED x, int inBPoint, int outBPoint ) { register int i, j; U32 dx, v1, v2; // // force sine of Pi/2 to be exact // if ( (S32) x == ((S32) kFPPi2 >> (kPiPrec - inBPoint)) ) return 1L << outBPoint; // compute index to sine table j = inBPoint + kPiIntBits - SinBits; i = (j >= 0) ? (int)((U32) x >> j) : (int)((U32) x << -j); i &= SinMaxIdx - 1; // compute stored point's difference from x dx = (U32) x - ((j >= 0) ? ((U32) i << j) : ((U32) i >> -j)); // extract two points from the table v1 = SinTable[ i ]; v2 = SinTable[ i + 1 ]; // compute Legendre 1st order approximation if ( v2 >= v1 ) v1 += _FPMul( v2 - v1, dx, SinPrec - inBPoint + 1 ); else v1 -= _FPMul( v1 - v2, dx, SinPrec - inBPoint + 1 ); // return sine in appropriate precision FLASHASSERT(SinPrec>outBPoint); int shift = SinPrec - outBPoint; return (v1+(1<<(shift-1))) >> shift; // This has a problem since v1 needs to be treated as unsigned... // return( _FPRound( v1, SinPrec - outBPoint ) ); } // // Calculate the sine of a fixed point number // S32 _FPSin( S32 x, int inBPoint, int outBPoint ) { int i, sign; U32 twoPi, Pi, Pi2; S32 sinx; i = kPiPrec - inBPoint; // compute trig constants in appropriate accuracy twoPi = (S32) kFPTwoPi >> i; Pi = (S32) kFPPi >> i; Pi2 = (S32) kFPPi2 >> i; // assume positive result sign = 0; // map x to [0..2*PI) if ( x >= (S32) twoPi ) x -= ( x / twoPi) * twoPi; if ( x < 0 ) x += (-x / twoPi + 1) * twoPi; // map x to [0..PI) if ( (U32) x >= Pi ) { sign = 1; x -= Pi; } // map x to [0..PI/2) if ( (U32) x > Pi2 ) x = Pi - x; // compute sine of x sinx = __FPSin( x, inBPoint, outBPoint ); // return sine of x with appropriate sign return( sign ? -sinx : sinx ); } // // Calculate the cosine of a fixed point number // S32 _FPCos( S32 x, int inBPoint, int outBPoint ) { int i, sign; U32 twoPi, threePi2, Pi, Pi2; S32 cosx; i = kPiPrec - inBPoint; // compute trig constants in appropriate accuracy twoPi = (S32) kFPTwoPi >> i; threePi2 = (S32) kFPThreePi2 >> i; Pi = (S32) kFPPi >> i; Pi2 = (S32) kFPPi2 >> i; // assume positive result sign = 0; // map x to [0..2*PI) if ( x >= (S32) twoPi ) x -= ( x / twoPi) * twoPi; if ( x < 0 ) x += (-x / twoPi + 1) * twoPi; // map x to [0..PI/2) if ( (U32) x >= threePi2 ) x -= threePi2; else if ( (U32) x < Pi2 ) x = Pi2 - x; else { sign = 1; x -= Pi2; if ( (U32) x > Pi2 ) x = Pi - x; } // compute cosine of x cosx = __FPSin( x, inBPoint, outBPoint ); // return cosine of x with appropriate sign return( sign ? -cosx : cosx ); } // // Calculate the atan of a fixed point number in [0..1] // // Note: inBPoint < ATanPrec // outBPoint < ATanPrec // S32 __FPATan( S32 x, int inBPoint, int outBPoint ) { int i; S32 p; // normalize x to internal precision x = x << (ATanPrec - inBPoint); // compute ATanN - 1 order polynomial p = ATanCoef[ ATanN - 1 ]; for ( i = ATanN - 2; i >= 0; i-- ) p = ATanCoef[ i ] + _FPMul( p, x - ATanXi[ i ], ATanPrec ); // return atan of x in appropriate precision return( _FPRound( p, ATanPrec - outBPoint ) ); } // // Calculate the atan of a fixed point number // S32 _FPATan( S32 x, int inBPoint, int outBPoint ) { int sign = 0; S32 one = 1L << inBPoint; // if we can, use FPU //if ( gTrigUseFPU ) // return( (S32) (Rad2Deg( atan( (double) x / (1L << inBPoint) ) ) * (1L << outBPoint)) ); // map x to [0..infinity) if ( x < 0 ) { x = (x == 0x80000000L) ? 0x7fffffffL : -x; sign = 1; } // map x to [0..1] if ( x > one ) { x = _FPRound( kFPPi2, kPiPrec - outBPoint ) - __FPATan( _FPDiv( one, x, inBPoint ), inBPoint, outBPoint ); } else x = __FPATan( x, inBPoint, outBPoint ); // return atan of x with appropriate sign return( sign ? -x : x ); } // // Calculate the atan of fixed point y / fixed point x // S32 _FPATan2( S32 y, S32 x, int inBPoint, int outBPoint ) { int i; U32 Pi; S32 atanx; // if we can, use FPU //if ( gTrigUseFPU ) // return( (S32) (Rad2Deg( atan2( (double) y / (1L << inBPoint), (double) x / (1L << inBPoint) ) ) * (1L << outBPoint)) ); i = kPiPrec - outBPoint; // avoid division by zero if ( x == 0 ) { atanx = _FPRound( kFPPi2, i ); if ( y < 0 ) atanx = -atanx; } else { // compute atan y / x in appropriate accuracy atanx = _FPATan( _FPDiv( y, x, inBPoint ), inBPoint, outBPoint ); // map atanx to appropriate quadrant if ( x < 0 ) { // compute trig constants in appropriate accuracy Pi = _FPRound( kFPPi, i ); if ( y < 0 ) atanx -= Pi; else atanx += Pi; } } return( atanx ); } #endif