/* This file is part of Darling. Copyright (C) 2012-2013 Lubos Dolezel Darling 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 3 of the License, or (at your option) any later version. Darling 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 Darling. If not, see . */ #include "FixMath.h" #include #include namespace Darling { static const int32_t InfPlus = std::numeric_limits::max(); static const int32_t InfMinus = std::numeric_limits::min(); static const int32_t FixedRatio = 0x10000; static const int32_t FractRatio = 0x40000000; template int32_t checkNumberBounds(T t) { if (t < -0x1p31f) return InfMinus; else if (t > 0x1p31f) return InfPlus; else return int32_t(t); } } float FixedToFloat(Fixed f) { return float(f) / Darling::FixedRatio; } Fixed FloatToFixed(float f) { return Darling::checkNumberBounds(f * Darling::FixedRatio); } Fract FloatToFract(float f) { return Darling::checkNumberBounds(f * Darling::FractRatio); } float FractToFloat(Fract f) { return float(f) / Darling::FractRatio; } Fixed FixRatio(short n, short denominator) { float f = float(n) / float(denominator); return FloatToFixed(f); } Fixed FixMul(Fixed a, Fixed b) { float f = FixedToFloat(a) * FixedToFloat(b); return FloatToFixed(f); } short FixRound(Fixed f) { return f >> 16; } Fract Fix2Frac(Fixed f) { return f << 14; } int32_t Fix2Long(Fixed f) { return f >> 16; } Fixed Long2Fix(int32_t v) { return Darling::checkNumberBounds(int64_t(v) * Darling::FixedRatio); } Fixed Frac2Fix(Fract f) { return Darling::checkNumberBounds(f * 0x4000); } Fract FracMul(Fract x, Fract y) { return FloatToFract(FractToFloat(x) * FractToFloat(y)); } Fixed FixDiv(Fixed x, Fixed y) { return FloatToFixed(FixedToFloat(x) / FixedToFloat(y)); } Fract FracDiv(Fract x, Fract y) { return FloatToFract(FractToFloat(x) / FractToFloat(y)); } Fract FracSqrt(Fract x) { return FloatToFract(sqrtf(FractToFloat(x))); } Fract FracSin(Fixed x) { return FloatToFract(sinf(FractToFloat(x))); } Fract FracCos(Fixed x) { return FloatToFract(cosf(FractToFloat(x))); } Fixed FixATan2(int32_t x, int32_t y) { float f = atan2f(x, y); return FloatToFixed(f); } double Frac2X(Fract f) { return double(f) / Darling::FractRatio; } double Fix2X(Fract f) { return double(f) / Darling::FixedRatio; } Fixed X2Fix(double d) { return Darling::checkNumberBounds(d * Darling::FixedRatio); } Fract X2Frac(double d) { return Darling::checkNumberBounds(d * Darling::FractRatio); } short WideCompare(const wide* a, const wide* b) { if (*reinterpret_cast(a) > *reinterpret_cast(b)) return 1; else if (*reinterpret_cast(a) < *reinterpret_cast(b)) return -1; else return 0; } wide* WideAdd(wide* dst, const wide* val) { *reinterpret_cast(dst) += *reinterpret_cast(val); return dst; } wide* WideSubtract(wide* dst, const wide* val) { *reinterpret_cast(dst) -= *reinterpret_cast(val); return dst; } wide* WideNegate(wide* val) { *reinterpret_cast(val) = -*reinterpret_cast(val); return val; } wide* WideShift(wide* dst, int32_t shift) // rounds upwards { int64_t result, mask; bool round; if (shift >= 0) { result = *(reinterpret_cast(dst)) >> shift; mask = result << shift; } else { result = *(reinterpret_cast(dst)) << (-shift); mask = result >> (-shift); } round = ((*reinterpret_cast(dst)) & ~mask) != 0; if (round) result++; *reinterpret_cast(dst) = result; return dst; } uint32_t WideSquareRoot(const wide* val) { return (uint32_t) sqrt(*reinterpret_cast(val)); } wide* WideMultiply(int32_t a, int32_t b, wide* dst) { *reinterpret_cast(dst) = int64_t(a) * int64_t(b); return dst; } int32_t WideDivide(const wide* divd, int32_t divs, int32_t* remainder) { if (remainder) *remainder = *reinterpret_cast(divd) % divs; return int32_t(*reinterpret_cast(divd) / divs); } wide* WideWideDivide(wide* divd, int32_t divs, int32_t* remainder) { if (remainder) *remainder = *reinterpret_cast(divd) % divs; *reinterpret_cast(divd) /= divs; return divd; } wide* WideBitShift(wide* dst, int32_t shift) { // positive -> right // negative -> left if (shift >= 0) *reinterpret_cast(dst) >>= shift; else *reinterpret_cast(dst) <<= (-shift); return dst; } UnsignedFixed UnsignedFixedMulDiv(UnsignedFixed a, UnsignedFixed mul, UnsignedFixed div) { // Is this correct? return uint64_t(a) * uint64_t(mul) / uint64_t(div); }