From 3420855dc075bd8ba8bcfe364db71944075de4b4 Mon Sep 17 00:00:00 2001 From: Flatmush Date: Mon, 14 Feb 2011 20:59:41 +0000 Subject: Initial commit. Since its use in fgl and the Dingoo SDK the functions have been separated into more descriptive files/modules. --- libfixmath/Makefile | 48 ++++++++++++++++ libfixmath/fix16.c | 99 +++++++++++++++++++++++++++++++++ libfixmath/fix16.h | 118 ++++++++++++++++++++++++++++++++++++++++ libfixmath/fix16_sqrt.c | 35 ++++++++++++ libfixmath/fix16_trig.c | 115 +++++++++++++++++++++++++++++++++++++++ libfixmath/fixmath.h | 22 ++++++++ libfixmath/fract32.c | 25 +++++++++ libfixmath/fract32.h | 36 ++++++++++++ libfixmath/libfixmath.a | Bin 0 -> 27896 bytes libfixmath/libfixmath.cbp | 47 ++++++++++++++++ libfixmath/obj/dbg/fix16.o | Bin 0 -> 7087 bytes libfixmath/obj/dbg/fix16_sqrt.o | Bin 0 -> 4294 bytes libfixmath/obj/dbg/fix16_trig.o | Bin 0 -> 7719 bytes libfixmath/obj/dbg/fract32.o | Bin 0 -> 4201 bytes libfixmath/obj/dbg/uint32.o | Bin 0 -> 3553 bytes libfixmath/uint32.c | 15 +++++ libfixmath/uint32.h | 19 +++++++ 17 files changed, 579 insertions(+) create mode 100644 libfixmath/Makefile create mode 100644 libfixmath/fix16.c create mode 100644 libfixmath/fix16.h create mode 100644 libfixmath/fix16_sqrt.c create mode 100644 libfixmath/fix16_trig.c create mode 100644 libfixmath/fixmath.h create mode 100644 libfixmath/fract32.c create mode 100644 libfixmath/fract32.h create mode 100644 libfixmath/libfixmath.a create mode 100644 libfixmath/libfixmath.cbp create mode 100644 libfixmath/obj/dbg/fix16.o create mode 100644 libfixmath/obj/dbg/fix16_sqrt.o create mode 100644 libfixmath/obj/dbg/fix16_trig.o create mode 100644 libfixmath/obj/dbg/fract32.o create mode 100644 libfixmath/obj/dbg/uint32.o create mode 100644 libfixmath/uint32.c create mode 100644 libfixmath/uint32.h diff --git a/libfixmath/Makefile b/libfixmath/Makefile new file mode 100644 index 0000000..b284590 --- /dev/null +++ b/libfixmath/Makefile @@ -0,0 +1,48 @@ +#Project settings +PROJECT = libfixmath +LIB = +SRC = . +INC = + +#Compiler settings +CPP = gcc +CC = gcc +AS = gcc +LD = gcc +AR = ar +CPP_FLAGS = -O2 $(INC) -Wall -Wextra -c +CC_FLAGS = -O2 $(INC) -Wall -Wextra -c +AS_FLAGS = $(CC_FLAGS) -D_ASSEMBLER_ +LD_FLAGS = -Wall + +# Find all source files +SRC_CPP = $(foreach dir, $(SRC), $(wildcard $(dir)/*.cpp)) +SRC_C = $(foreach dir, $(SRC), $(wildcard $(dir)/*.c)) +SRC_S = $(foreach dir, $(SRC), $(wildcard $(dir)/*.S)) +OBJ_CPP = $(patsubst %.cpp, %.o, $(SRC_CPP)) +OBJ_C = $(patsubst %.c, %.o, $(SRC_C)) +OBJ_S = $(patsubst %.S, %.o, $(SRC_S)) +OBJ = $(OBJ_CPP) $(OBJ_C) $(OBJ_S) + +# Compile rules. +.PHONY : all +all: $(PROJECT).a + +$(PROJECT).a: $(OBJ) + $(AR) rcs $(PROJECT).a $(OBJ) + +$(OBJ_CPP) : %.o : %.cpp + $(CPP) $(CPP_FLAGS) -o $@ $< + +$(OBJ_C) : %.o : %.c + $(CC) $(CC_FLAGS) -o $@ $< + +$(OBJ_S) : %.o : %.S + $(AS) $(AS_FLAGS) -o $@ $< + + + +# Clean rules +.PHONY : clean +clean: + rm -f $(PROJECT).a $(OBJ) diff --git a/libfixmath/fix16.c b/libfixmath/fix16.c new file mode 100644 index 0000000..f564202 --- /dev/null +++ b/libfixmath/fix16.c @@ -0,0 +1,99 @@ +#include "fix16.h" + + + +const fix16_t fix16_pi = 205887; +const fix16_t fix16_e = 178145; +const fix16_t fix16_one = 0x00010000; + + + +double fix16_to_dbl(const fix16_t inVal) { + return ((double)inVal / 65536.0); +} + +fix16_t fix16_from_dbl(const double inVal) { + return (fix16_t)(inVal * 65536.0); +} + +float fix16_to_float(const fix16_t inVal) { + return ((float)inVal / 65536.0f); +} + +fix16_t fix16_from_float(const float inVal) { + return (fix16_t)(inVal * 65536.0f); +} + +int32_t fix16_to_int(const fix16_t inVal) { + return ((inVal + 0x00008000) >> 16); +} + +fix16_t fix16_from_int(const int32_t inVal) { + return (inVal << 16); +} + + + +fix16_t fix16_sadd(fix16_t inArg0, fix16_t inArg1) { + fix16_t tempResult = (inArg0 + inArg1); + if((tempResult > 0) && (inArg0 < 0) && (inArg1 < 0)) + return 0x80000000; + if((tempResult < 0) && (inArg0 > 0) && (inArg1 > 0)) + return 0x7FFFFFFF; + return tempResult; +} + + + +fix16_t fix16_mul(fix16_t inArg0, fix16_t inArg1) { + int64_t tempResult = ((int64_t)inArg0 * (int64_t)inArg1) + 0x00008000; + tempResult >>= 16; + return tempResult; +} + +fix16_t fix16_smul(fix16_t inArg0, fix16_t inArg1) { + int64_t tempResult = ((int64_t)inArg0 * (int64_t)inArg1) + 0x00008000; + tempResult >>= 16; + if(tempResult < fix16_MIN) + return fix16_MIN; + if(tempResult > fix16_MAX) + return fix16_MAX; + return tempResult; +} + + + +fix16_t fix16_div(fix16_t inArg0, fix16_t inArg1) { + int64_t tempResult = inArg0; + tempResult <<= 16; + tempResult += (inArg1 >> 1); + tempResult /= inArg1; + return tempResult; +} + +fix16_t fix16_sdiv(fix16_t inArg0, fix16_t inArg1) { + if(inArg1 == 0) { + if(inArg0 < 0) + return fix16_MIN; + return fix16_MAX; + } + int64_t tempResult = inArg0; + tempResult <<= 16; + tempResult += (inArg1 >> 1); + tempResult /= inArg1; + if(tempResult < fix16_MIN) + return fix16_MIN; + if(tempResult > fix16_MAX) + return fix16_MAX; + return tempResult; +} + + + +fix16_t fix16_lerp16(fix16_t inArg0, fix16_t inArg1, uint16_t inFract) { + int64_t tempOut; + tempOut = ((int64_t)inArg0 * (fix16_one - inFract)); + tempOut += ((int64_t)inArg1 * inFract); + tempOut >>= 16; + return (fix16_t)tempOut; +} diff --git a/libfixmath/fix16.h b/libfixmath/fix16.h new file mode 100644 index 0000000..05e4bc3 --- /dev/null +++ b/libfixmath/fix16.h @@ -0,0 +1,118 @@ +#ifndef __libfixmath_fix16_h__ +#define __libfixmath_fix16_h__ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include + +#define fix16_MAX (fix16_t)0x7FFFFFFF /*!< the maximum value of fix16_t */ +#define fix16_MIN (fix16_t)0x80000000 /*!< the minimum value of fix16_t */ + +typedef int32_t fix16_t; + +extern const fix16_t fix16_pi; /*!< fix16_t value of pi */ +extern const fix16_t fix16_e; /*!< fix16_t value of e */ +extern const fix16_t fix16_one; /*!< fix16_t value of 1 */ + +/*! Coverts a fix16_t to a double and returns the result. +*/ +extern double fix16_to_dbl(const fix16_t inVal); + +/*! Converts a double to a fix16_t and returns the result. +*/ +extern fix16_t fix16_from_dbl(const double inVal); + +/*! Converts a fix16_t to a float and returns the result. +*/ +extern float fix16_to_float(const fix16_t inVal); + +/*! Converts a float to a fix16_t and returns the result. +*/ +extern fix16_t fix16_from_float(const float inVal); + +/*! Converts a fix16_t to a signed integer and returns the result. +*/ +extern int32_t fix16_to_int(const fix16_t inVal); + +/*! Converts a signed integer to a fix16_t and returns the result. +*/ +extern fix16_t fix16_from_int(const int32_t inVal); + + + +/*! Performs a saturated addition (overflow-protected) of the two given fix16_t's and returns the result. +*/ +extern fix16_t fix16_sadd(fix16_t inArg0, fix16_t inArg1); + + + +/*! Multiplies the two given fix16_t's and returns the result. +*/ +extern fix16_t fix16_mul(fix16_t inArg0, fix16_t inArg1); + +/*! Performs a saturated multiplication (overflow-protected) of the two given fix16_t's and returns the result. +*/ +extern fix16_t fix16_smul(fix16_t inArg0, fix16_t inArg1); + + + +/*! Divides the first given fix16_t by the second and returns the result. +*/ +extern fix16_t fix16_div(fix16_t inArg0, fix16_t inArg1); + +/*! Performs a saturated division (overflow-protected) of the first fix16_t by the second and returns the result. +*/ +extern fix16_t fix16_sdiv(fix16_t inArg0, fix16_t inArg1); + + + +/*! Returns the linear interpolation: (inArg0 * (1 - inFract)) + (inArg1 * inFract) +*/ +extern fix16_t fix16_lerp16(fix16_t inArg0, fix16_t inArg1, uint16_t inFract); + + + +/*! Returns the sine of the given fix16_t. +*/ +extern fix16_t fix16_sin(fix16_t inAngle); + +/*! Returns the cosine of the given fix16_t. +*/ +extern fix16_t fix16_cos(fix16_t inAngle); + +/*! Returns the tangent of the given fix16_t. +*/ +extern fix16_t fix16_tan(fix16_t inAngle); + +/*! Returns the arcsine of the given fix16_t. +*/ +extern fix16_t fix16_asin(fix16_t inValue); + +/*! Returns the arccosine of the given fix16_t. +*/ +extern fix16_t fix16_acos(fix16_t inValue); + +/*! Returns the arctangent of the given fix16_t. +*/ +extern fix16_t fix16_atan(fix16_t inValue); + +/*! Returns the arctangent of inY/inX. +*/ +extern fix16_t fix16_atan2(fix16_t inY, fix16_t inX); + + + +/*! Returns the square root of the given fix16_t. +*/ +extern fix16_t fix16_sqrt(fix16_t inValue); + + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libfixmath/fix16_sqrt.c b/libfixmath/fix16_sqrt.c new file mode 100644 index 0000000..f913a62 --- /dev/null +++ b/libfixmath/fix16_sqrt.c @@ -0,0 +1,35 @@ +#include "fix16.h" + + + +fix16_t _fix16_sqrt_cache_index[4096] = { 0 }; +fix16_t _fix16_sqrt_cache_value[4096] = { 0 }; + + + +fix16_t fix16_sqrt(fix16_t inValue) { + fix16_t tempIndex = (((inValue >> 16) ^ (inValue >> 4)) & 0x00000FFF); + if(_fix16_sqrt_cache_index[tempIndex] == inValue) + return _fix16_sqrt_cache_value[tempIndex]; + + int64_t tempOp = inValue; tempOp <<= 16; + int64_t tempOut = 0; + int64_t tempOne = 0x4000000000000000ULL; + + while(tempOne > tempOp) + tempOne >>= 2; + + while(tempOne != 0) { + if (tempOp >= tempOut + tempOne) { + tempOp -= tempOut + tempOne; + tempOut += tempOne << 1; + } + tempOut >>= 1; + tempOne >>= 2; + } + + _fix16_sqrt_cache_index[tempIndex] = inValue; + _fix16_sqrt_cache_value[tempIndex] = tempOut; + + return tempOut; +} diff --git a/libfixmath/fix16_trig.c b/libfixmath/fix16_trig.c new file mode 100644 index 0000000..9d5046b --- /dev/null +++ b/libfixmath/fix16_trig.c @@ -0,0 +1,115 @@ +#include "fix16.h" + + + +fix16_t _fix16_sin_cache_index[4096] = { 0 }; +fix16_t _fix16_sin_cache_value[4096] = { 0 }; +fix16_t _fix16_atan_cache_index[4096] = { 0 }; +fix16_t _fix16_atan_cache_value[4096] = { 0 }; + + + +fix16_t fix16_sin(fix16_t inAngle) { + fix16_t tempAngle = inAngle % (fix16_pi << 1); + if(tempAngle > fix16_pi) + tempAngle -= (fix16_pi << 1); + else if(tempAngle < -fix16_pi) + tempAngle += (fix16_pi << 1); + + fix16_t tempIndex = ((inAngle >> 5) & 0x00000FFF); + if(_fix16_sin_cache_index[tempIndex] == inAngle) + return _fix16_sin_cache_value[tempIndex]; + + fix16_t tempAngleSq = fix16_mul(tempAngle, tempAngle); + + fix16_t tempOut = tempAngle; + tempAngle = fix16_mul(tempAngle, tempAngleSq); + tempOut -= (tempAngle / 6); + tempAngle = fix16_mul(tempAngle, tempAngleSq); + tempOut += (tempAngle / 120); + tempAngle = fix16_mul(tempAngle, tempAngleSq); + tempOut -= (tempAngle / 5040); + tempAngle = fix16_mul(tempAngle, tempAngleSq); + tempOut += (tempAngle / 362880); + tempAngle = fix16_mul(tempAngle, tempAngleSq); + tempOut -= (tempAngle / 39916800); + + _fix16_sin_cache_index[tempIndex] = inAngle; + _fix16_sin_cache_value[tempIndex] = tempOut; + + return tempOut; +} + +fix16_t fix16_cos(fix16_t inAngle) { + return fix16_sin(inAngle + (fix16_pi >> 1)); +} + +fix16_t fix16_tan(fix16_t inAngle) { + return fix16_div(fix16_sin(inAngle), fix16_cos(inAngle)); +} + +fix16_t fix16_asin(fix16_t inValue) { + if((inValue > 1) || (inValue < -1)) + return 0; + fix16_t tempOut; + tempOut = (1 - fix16_mul(inValue, inValue)); + tempOut = (inValue / fix16_sqrt(tempOut)); + tempOut = fix16_atan(tempOut); + return tempOut; +} + +fix16_t fix16_acos(fix16_t inValue) { + return ((fix16_pi >> 1) - fix16_asin(inValue)); +} + +fix16_t _fix16_atan(fix16_t inValue) { + fix16_t tempOut; + if(inValue > 29736) { + tempOut = (1 + fix16_mul(inValue, inValue)); + tempOut = (1 + fix16_sqrt(tempOut)); + tempOut = (inValue / tempOut); + tempOut = _fix16_atan(tempOut); + return (tempOut << 1); + } + + fix16_t tempValue = inValue; + fix16_t tempValSq = fix16_mul(inValue, inValue); + tempOut = inValue; + tempValue = fix16_mul(tempValue, tempValSq); + tempOut += (tempValue / 3); + tempValue = fix16_mul(tempValue, tempValSq); + tempOut += (tempValue / 5); + tempValue = fix16_mul(tempValue, tempValSq); + tempOut += (tempValue / 7); + tempValue = fix16_mul(tempValue, tempValSq); + tempOut += (tempValue / 9); + tempValue = fix16_mul(tempValue, tempValSq); + tempOut += (tempValue / 11); + + return tempOut; +} + +fix16_t fix16_atan(fix16_t inValue) { + fix16_t tempIndex = (((inValue >> 16) ^ (inValue >> 4)) & 0x00000FFF); + if(_fix16_atan_cache_index[tempIndex] == inValue) + return _fix16_atan_cache_value[tempIndex]; + fix16_t tempOut = _fix16_atan(inValue); + _fix16_atan_cache_index[tempIndex] = inValue; + _fix16_atan_cache_value[tempIndex] = tempOut; + return tempOut; +} + +fix16_t fix16_atan2(fix16_t inY, fix16_t inX) { + if(inX == 0) { + if(inY == 0) + return 0; + if(inY > 0) + return (fix16_pi >> 1); + return -(fix16_pi >> 1); + } + if(inY > 0) + return fix16_atan(fix16_div(inY, inX)); + if(inY >= 0) + return (fix16_pi + fix16_atan(fix16_div(inY, inX))); + return (-fix16_pi + fix16_atan(fix16_div(inY, inX))); +} diff --git a/libfixmath/fixmath.h b/libfixmath/fixmath.h new file mode 100644 index 0000000..ed35f7d --- /dev/null +++ b/libfixmath/fixmath.h @@ -0,0 +1,22 @@ +#ifndef __libfixmath_fixmath_h__ +#define __libfixmath_fixmath_h__ + +#ifdef __cplusplus +extern "C" +{ +#endif + +/*! + \file fixmath.h + \brief Functions to perform fast accurate fixed-point math operations. +*/ + +#include "uint32.h" +#include "fract32.h" +#include "fix16.h" + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libfixmath/fract32.c b/libfixmath/fract32.c new file mode 100644 index 0000000..c351258 --- /dev/null +++ b/libfixmath/fract32.c @@ -0,0 +1,25 @@ +#include "fract32.h" + + + +fract32_t fract32_create(uint32_t inNumerator, uint32_t inDenominator) { + if(inDenominator <= inNumerator) + return 0xFFFFFFFF; + uint32_t tempMod = (inNumerator % inDenominator); + uint32_t tempDiv = (0xFFFFFFFF / (inDenominator - 1)); + return (tempMod * tempDiv); +} + +fract32_t fract32_invert(fract32_t inFract) { + return (0xFFFFFFFF - inFract); +} + +uint32_t fract32_usmul(uint32_t inVal, fract32_t inFract) { + return (uint32_t)(((uint64_t)inVal * (uint64_t)inFract) >> 32); +} + +int32_t fract32_smul(int32_t inVal, fract32_t inFract) { + if(inVal < 0) + return -fract32_usmul(-inVal, inFract); + return fract32_usmul(inVal, inFract); +} diff --git a/libfixmath/fract32.h b/libfixmath/fract32.h new file mode 100644 index 0000000..8b6df05 --- /dev/null +++ b/libfixmath/fract32.h @@ -0,0 +1,36 @@ +#ifndef __libfixmath_fract32_h__ +#define __libfixmath_fract32_h__ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include + +typedef uint32_t fract32_t; + +/*! Creates a fraction using unsigned integers. + \param inNumerator the unsigned integer numerator + \param inDenominator the unsigned integer denominator + \return a fraction using the given numerator and denominator +*/ +extern fract32_t fract32_create(uint32_t inNumerator, uint32_t inDenominator); + +/*! Inverts the given fraction, swapping the numerator and the denominator. +*/ +extern fract32_t fract32_invert(fract32_t inFract); + +/*! Performs unsigned saturated (overflow-protected) multiplication with the two given fractions and returns the result as an unsigned integer. +*/ +extern uint32_t fract32_usmul(uint32_t inVal, fract32_t inFract); + +/*! Performs saturated (overflow-protected) multiplication with the two given fractions and returns the result as a signed integer. +*/ +extern int32_t fract32_smul(int32_t inVal, fract32_t inFract); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libfixmath/libfixmath.a b/libfixmath/libfixmath.a new file mode 100644 index 0000000..e77751c Binary files /dev/null and b/libfixmath/libfixmath.a differ diff --git a/libfixmath/libfixmath.cbp b/libfixmath/libfixmath.cbp new file mode 100644 index 0000000..07c4618 --- /dev/null +++ b/libfixmath/libfixmath.cbp @@ -0,0 +1,47 @@ + + + + + + diff --git a/libfixmath/obj/dbg/fix16.o b/libfixmath/obj/dbg/fix16.o new file mode 100644 index 0000000..797ff43 Binary files /dev/null and b/libfixmath/obj/dbg/fix16.o differ diff --git a/libfixmath/obj/dbg/fix16_sqrt.o b/libfixmath/obj/dbg/fix16_sqrt.o new file mode 100644 index 0000000..8e338c1 Binary files /dev/null and b/libfixmath/obj/dbg/fix16_sqrt.o differ diff --git a/libfixmath/obj/dbg/fix16_trig.o b/libfixmath/obj/dbg/fix16_trig.o new file mode 100644 index 0000000..d7e48b2 Binary files /dev/null and b/libfixmath/obj/dbg/fix16_trig.o differ diff --git a/libfixmath/obj/dbg/fract32.o b/libfixmath/obj/dbg/fract32.o new file mode 100644 index 0000000..862085a Binary files /dev/null and b/libfixmath/obj/dbg/fract32.o differ diff --git a/libfixmath/obj/dbg/uint32.o b/libfixmath/obj/dbg/uint32.o new file mode 100644 index 0000000..f9c6f15 Binary files /dev/null and b/libfixmath/obj/dbg/uint32.o differ diff --git a/libfixmath/uint32.c b/libfixmath/uint32.c new file mode 100644 index 0000000..2980ab9 --- /dev/null +++ b/libfixmath/uint32.c @@ -0,0 +1,15 @@ +#include "uint32.h" + + + +uint32_t uint32_log2(uint32_t inVal) { + if(inVal == 0) + return 0; + uint32_t tempOut = 0; + if(inVal >= (1 << 16)) { inVal >>= 16; tempOut += 16; } + if(inVal >= (1 << 8)) { inVal >>= 8; tempOut += 8; } + if(inVal >= (1 << 4)) { inVal >>= 4; tempOut += 4; } + if(inVal >= (1 << 2)) { inVal >>= 2; tempOut += 2; } + if(inVal >= (1 << 1)) { tempOut += 1; } + return tempOut; +} diff --git a/libfixmath/uint32.h b/libfixmath/uint32.h new file mode 100644 index 0000000..1303338 --- /dev/null +++ b/libfixmath/uint32.h @@ -0,0 +1,19 @@ +#ifndef __libfixmath_uint32_h__ +#define __libfixmath_uint32_h__ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include + +/*! Performs an unsigned log-base2 on the specified unsigned integer and returns the result. +*/ +extern uint32_t uint32_log2(uint32_t inVal); + +#ifdef __cplusplus +} +#endif + +#endif -- cgit v1.2.3