www.pudn.com > Flash4player.rar > 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