forked from Mirrors/openclonk
C4Real: Split into multiple implementations
Each implementation gets their own header and class to separate them. The class is wrapped by C4Real, a template class with the requested implementation as template argument. This is to ensure a fixed interface regardless of the underlying implementation. C4Real expects its template class to mostly have the same interface as a standard C++ float; differences are handled by template specialization.floating-point
parent
59f5ee646c
commit
fa59c32429
|
@ -348,6 +348,9 @@ set(OC_CLONK_SOURCES
|
|||
src/lib/C4Random.h
|
||||
src/lib/C4Real.cpp
|
||||
src/lib/C4Real.h
|
||||
src/lib/C4RealImpl_Fixed.cpp
|
||||
src/lib/C4RealImpl_Fixed.h
|
||||
src/lib/C4RealImpl_FPU.h
|
||||
src/lib/C4Rect.cpp
|
||||
src/lib/C4Rect.h
|
||||
src/lib/C4RTF.cpp
|
||||
|
|
|
@ -99,6 +99,9 @@ src/lib/C4Random.cpp \
|
|||
src/lib/C4Random.h \
|
||||
src/lib/C4Real.cpp \
|
||||
src/lib/C4Real.h \
|
||||
src/lib/C4RealImpl_Fixed.cpp \
|
||||
src/lib/C4RealImpl_Fixed.h \
|
||||
src/lib/C4RealImpl_FPU.h \
|
||||
src/lib/C4Rect.cpp \
|
||||
src/lib/C4Rect.h \
|
||||
src/lib/C4RTF.cpp \
|
||||
|
|
|
@ -3533,6 +3533,7 @@ public:
|
|||
virtual void Byte(uint8_t &rByte) { if (haveCompleteMatch()) if (!iEntryNr--) { int32_t i=rByte; ProcessInt(i); rByte =i; } }
|
||||
virtual void Boolean(bool &rBool) { if (haveCompleteMatch()) if (!iEntryNr--) ProcessBool(rBool); }
|
||||
virtual void Character(char &rChar) { if (haveCompleteMatch()) if (!iEntryNr--) ProcessChar(rChar); }
|
||||
virtual void Float(float &flt) { assert(!"Can't compile/decompile float from structure"); }
|
||||
|
||||
// The C4ID-Adaptor will set RCT_ID for it's strings (see C4Id.h), so we don't have to guess the type.
|
||||
virtual void String(char *szString, size_t iMaxLength, RawCompileType eType)
|
||||
|
|
9045
src/lib/C4Real.cpp
9045
src/lib/C4Real.cpp
File diff suppressed because it is too large
Load Diff
386
src/lib/C4Real.h
386
src/lib/C4Real.h
|
@ -5,6 +5,7 @@
|
|||
* Copyright (c) 2002, 2005 Sven Eberhardt
|
||||
* Copyright (c) 2002, 2004-2005, 2007 Peter Wortmann
|
||||
* Copyright (c) 2005, 2007 Günther Brammer
|
||||
* Copyright (c) 2010 Nicolas Hake
|
||||
* Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de
|
||||
*
|
||||
* Portions might be copyrighted by other authors who have contributed
|
||||
|
@ -28,7 +29,7 @@
|
|||
because floating point calculations are not guaranteed to be network
|
||||
safe...however, it can be solved as a data type with operator
|
||||
overloading, automatic type conversions, etc now - Sven2 */
|
||||
/* After some time with synchronous float use, C4Fixed is used again to
|
||||
/* After some time with synchronous float use, C4Real is used again to
|
||||
work around the problem that different compilers produce different
|
||||
floating point code, leading to desyncs between linux and windows
|
||||
engines. */
|
||||
|
@ -36,308 +37,133 @@
|
|||
#ifndef INC_C4Real
|
||||
#define INC_C4Real
|
||||
|
||||
#include <math.h>
|
||||
// C4RealBase modes:
|
||||
// C4REAL_MODE_SOFTWARE: fixpoint math, all operations emulated by
|
||||
// software
|
||||
// C4REAL_MODE_SOFT_FLOAT: floating-point math, all operations emulated by
|
||||
// software
|
||||
// C4REAL_MODE_FPU_FLOAT: floating-point math, all operations run on FPU
|
||||
// C4REAL_MODE_SSE_FLOAT: floating-point math, all operations run on SSE
|
||||
// unit (which is usually the FPU as well, but w/o
|
||||
// extended precision)
|
||||
#define C4REAL_MODE_SOFTWARE 1
|
||||
//#define C4REAL_MODE_SOFT_FLOAT 2
|
||||
#define C4REAL_MODE_FPU_FLOAT 3
|
||||
//#define C4REAL_MODE_SSE_FLOAT 4
|
||||
|
||||
// activate to switch to classic fixed-point math
|
||||
#define C4REAL_USE_FIXNUM 1
|
||||
#define inline ALWAYS_INLINE
|
||||
#define FIXED_EMULATE_64BIT
|
||||
|
||||
// note: C4Fixed has to be defined even though it isn't used
|
||||
// any more. It is used to convert old-format fixed values
|
||||
// to the new-format float ones.
|
||||
|
||||
#ifdef C4REAL_USE_FIXNUM
|
||||
extern long SineTable[9001]; // external table of sine values
|
||||
#ifndef C4REAL_MODE
|
||||
#define C4REAL_MODE C4REAL_MODE_SOFTWARE
|
||||
#endif
|
||||
|
||||
// fixpoint shift (check 64 bit emulation before changing!)
|
||||
#define FIXED_SHIFT 16
|
||||
// fixpoint factor
|
||||
#define FIXED_FPF int32_t(1 << FIXED_SHIFT)
|
||||
|
||||
class C4Fixed
|
||||
template<class C4RealImpl>
|
||||
class C4RealBase
|
||||
{
|
||||
#ifdef C4REAL_USE_FIXNUM
|
||||
friend int fixtoi(const C4Fixed &x);
|
||||
friend int fixtoi(const C4Fixed &x, int32_t prec);
|
||||
friend C4Fixed itofix(int32_t x);
|
||||
friend C4Fixed itofix(int32_t x, int32_t prec);
|
||||
friend float fixtof(const C4Fixed &x);
|
||||
friend C4Fixed ftofix(float x);
|
||||
#else
|
||||
friend void FIXED_TO_FLOAT(float *pVal);
|
||||
#endif
|
||||
friend void CompileFunc(C4Fixed &rValue, StdCompiler *pComp);
|
||||
C4RealImpl value;
|
||||
|
||||
friend C4RealBase Sin(const C4RealBase &);
|
||||
friend C4RealBase Cos(const C4RealBase &);
|
||||
public:
|
||||
int32_t val; // internal value
|
||||
inline C4RealBase(int32_t val = 0) : value(val) { }
|
||||
inline C4RealBase(float val) : value(val) {}
|
||||
inline C4RealBase(int32_t val, int32_t prec) : value(val) { operator/=(C4RealBase(prec)); }
|
||||
// Conversion between different implementations of C4RealBase
|
||||
template<class T>
|
||||
inline C4RealBase(const C4RealBase<T> &val) : value(static_cast<float>(val)) { }
|
||||
|
||||
public:
|
||||
// constructors
|
||||
inline C4Fixed () { /*val=0;*/ } // why initialize?
|
||||
inline C4Fixed (const C4Fixed &rCpy): val(rCpy.val) { }
|
||||
|
||||
// Conversion must be done by the conversion routines itofix, fixtoi, ftofix and fixtof
|
||||
// in order to be backward compatible, so everything is private.
|
||||
private:
|
||||
explicit inline C4Fixed(int32_t iVal)
|
||||
: val (iVal * FIXED_FPF)
|
||||
{ }
|
||||
explicit inline C4Fixed(int32_t iVal, int32_t iPrec)
|
||||
: val( iPrec < FIXED_FPF
|
||||
? iVal * (FIXED_FPF / iPrec) + (iVal * (FIXED_FPF % iPrec)) / iPrec
|
||||
: int32_t( int64_t(iVal) * FIXED_FPF / iPrec )
|
||||
)
|
||||
{ }
|
||||
explicit inline C4Fixed(float fVal)
|
||||
: val(static_cast<int32_t>(fVal * float(FIXED_FPF)))
|
||||
{ }
|
||||
|
||||
// round to int
|
||||
int32_t to_int() const
|
||||
{
|
||||
int32_t r = val;
|
||||
// be careful not to overflow
|
||||
r += (val <= 0x7fffffff - FIXED_FPF / 2) * FIXED_FPF / 2;
|
||||
// ensure that -x.50 is rounded to -(x+1)
|
||||
r -= (val < 0);
|
||||
r >>= FIXED_SHIFT;
|
||||
// round 32767.5 to 32768 (not that anybody cares)
|
||||
r += (val > 0x7fffffff - FIXED_FPF / 2);
|
||||
return r;
|
||||
}
|
||||
int32_t to_int(int32_t prec) const
|
||||
{
|
||||
int64_t r = val;
|
||||
r *= prec;
|
||||
r += FIXED_FPF / 2;
|
||||
r -= (val < 0);
|
||||
r >>= FIXED_SHIFT;
|
||||
return int32_t(r);
|
||||
}
|
||||
// convert to floating point value
|
||||
float to_float() const
|
||||
{
|
||||
return float(val) / float(FIXED_FPF);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
// set integer (allowed for historic reasons)
|
||||
inline C4Fixed &operator = (int32_t x) { return *this = C4Fixed(x); }
|
||||
|
||||
// test value
|
||||
inline operator bool () const { return !! val; }
|
||||
inline bool operator ! () const { return ! val; }
|
||||
// Copy ctor and assignment
|
||||
inline C4RealBase(const C4RealBase &rhs) : value(rhs.value) {}
|
||||
inline C4RealBase &operator = (const C4RealBase &rhs) { value = rhs.value; return *this; }
|
||||
inline C4RealBase &operator = (float rhs) { value = C4RealImpl(rhs); return *this; }
|
||||
inline C4RealBase &operator = (int rhs) { value = C4RealImpl(rhs); return *this; }
|
||||
|
||||
// arithmetic operations
|
||||
inline C4Fixed &operator += (const C4Fixed &fVal2)
|
||||
{
|
||||
val += fVal2.val;
|
||||
return *this;
|
||||
}
|
||||
inline C4Fixed &operator -= (const C4Fixed &fVal2)
|
||||
{
|
||||
val -= fVal2.val;
|
||||
return *this;
|
||||
}
|
||||
inline C4Fixed &operator *= (const C4Fixed &fVal2)
|
||||
{
|
||||
#ifndef FIXED_EMULATE_64BIT
|
||||
val = int32_t( (int64_t(val) * fVal2.val) / FIXED_FPF );
|
||||
#else
|
||||
int32_t x0 = val & (FIXED_FPF - 1),
|
||||
x1 = val >> FIXED_SHIFT;
|
||||
int32_t y0 = fVal2.val & (FIXED_FPF - 1),
|
||||
y1 = fVal2.val >> FIXED_SHIFT;
|
||||
val = x0*y0/FIXED_FPF + x0*y1 + x1*y0 + x1*y1*FIXED_FPF;
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
inline C4Fixed &operator *= (int32_t iVal2)
|
||||
{
|
||||
val *= iVal2;
|
||||
return *this;
|
||||
}
|
||||
inline C4Fixed &operator /= (const C4Fixed &fVal2)
|
||||
{
|
||||
val = int32_t( (int64_t(val) * FIXED_FPF) / fVal2.val );
|
||||
return *this;
|
||||
}
|
||||
inline C4Fixed &operator /= (int32_t iVal2)
|
||||
{
|
||||
val /= iVal2;
|
||||
return *this;
|
||||
}
|
||||
inline C4Fixed operator - () const
|
||||
{
|
||||
C4Fixed fr; fr.val=-val; return fr;
|
||||
}
|
||||
inline C4Fixed operator + () const
|
||||
{
|
||||
return *this;
|
||||
#define C4REAL_ARITHMETIC_OPERATOR(op) \
|
||||
/* combined arithmetic and assignment ops */ \
|
||||
inline C4RealBase &operator op##= (const C4RealBase &rhs) { value op##= rhs.value; return *this; } \
|
||||
inline C4RealBase &operator op##= (float rhs) { return *this op##= C4RealBase(rhs); } \
|
||||
inline C4RealBase &operator op##= (int rhs) { return *this op##= C4RealBase(rhs); } \
|
||||
/* arithmetic operations on copies */ \
|
||||
inline C4RealBase operator op (const C4RealBase &rhs) const { C4RealBase nrv(*this); nrv op##= rhs; return nrv; } \
|
||||
inline C4RealBase operator op (float rhs) const { C4RealBase nrv(*this); nrv op##= rhs; return nrv; } \
|
||||
inline C4RealBase operator op (int rhs) const { C4RealBase nrv(*this); nrv op##= rhs; return nrv; } \
|
||||
/* arithmetic operations on copies, right-hand C4Real */ \
|
||||
/* friends defined in the class are implicitly inline */ \
|
||||
friend C4RealBase operator op (float lhs, const C4RealBase &rhs) { C4RealBase nrv(lhs); nrv op##= rhs; return nrv; } \
|
||||
friend C4RealBase operator op (int lhs, const C4RealBase &rhs) { C4RealBase nrv(lhs); nrv op##= rhs; return nrv; }
|
||||
|
||||
C4REAL_ARITHMETIC_OPERATOR(+)
|
||||
C4REAL_ARITHMETIC_OPERATOR(-)
|
||||
C4REAL_ARITHMETIC_OPERATOR(*)
|
||||
C4REAL_ARITHMETIC_OPERATOR(/)
|
||||
#undef C4REAL_ARITHMETIC_OPERATOR
|
||||
|
||||
inline C4RealBase operator + () const { return *this; }
|
||||
inline C4RealBase operator - () const
|
||||
{
|
||||
C4RealBase nrv(*this);
|
||||
nrv.value = -nrv.value;
|
||||
return nrv;
|
||||
}
|
||||
|
||||
inline bool operator == (const C4Fixed &fVal2) const { return val==fVal2.val; }
|
||||
inline bool operator < (const C4Fixed &fVal2) const { return val<fVal2.val; }
|
||||
inline bool operator > (const C4Fixed &fVal2) const { return val>fVal2.val; }
|
||||
inline bool operator <= (const C4Fixed &fVal2) const { return val<=fVal2.val; }
|
||||
inline bool operator >= (const C4Fixed &fVal2) const { return val>=fVal2.val; }
|
||||
inline bool operator != (const C4Fixed &fVal2) const { return val!=fVal2.val; }
|
||||
#define C4REAL_COMPARISON_OPERATOR(op) \
|
||||
inline bool operator op (const C4RealBase &rhs) const { return value op rhs.value; } \
|
||||
inline bool operator op (float rhs) const { return *this op C4RealBase(rhs); } \
|
||||
inline bool operator op (int rhs) const { return *this op C4RealBase(rhs); }
|
||||
C4REAL_COMPARISON_OPERATOR(<)
|
||||
C4REAL_COMPARISON_OPERATOR(<=)
|
||||
C4REAL_COMPARISON_OPERATOR(==)
|
||||
C4REAL_COMPARISON_OPERATOR(>=)
|
||||
C4REAL_COMPARISON_OPERATOR(>)
|
||||
C4REAL_COMPARISON_OPERATOR(!=)
|
||||
#undef C4REAL_COMPARISON_OPERATOR
|
||||
|
||||
// and wrappers
|
||||
inline C4Fixed &operator += (int32_t iVal2) { return operator += (C4Fixed(iVal2)); }
|
||||
inline C4Fixed &operator -= (int32_t iVal2) { return operator -= (C4Fixed(iVal2)); }
|
||||
|
||||
inline C4Fixed operator + (const C4Fixed &fVal2) const { return C4Fixed(*this) += fVal2; }
|
||||
inline C4Fixed operator - (const C4Fixed &fVal2) const { return C4Fixed(*this) -= fVal2; }
|
||||
inline C4Fixed operator * (const C4Fixed &fVal2) const { return C4Fixed(*this) *= fVal2; }
|
||||
inline C4Fixed operator / (const C4Fixed &fVal2) const { return C4Fixed(*this) /= fVal2; }
|
||||
|
||||
inline C4Fixed operator + (int32_t iVal2) const { return C4Fixed(*this) += iVal2; }
|
||||
inline C4Fixed operator - (int32_t iVal2) const { return C4Fixed(*this) -= iVal2; }
|
||||
inline C4Fixed operator * (int32_t iVal2) const { return C4Fixed(*this) *= iVal2; }
|
||||
inline C4Fixed operator / (int32_t iVal2) const { return C4Fixed(*this) /= iVal2; }
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER <= 1200
|
||||
inline C4Fixed operator + (int iVal2) const { return operator + (int32_t(iVal2)); }
|
||||
inline C4Fixed operator - (int iVal2) const { return operator - (int32_t(iVal2)); }
|
||||
inline C4Fixed operator * (int iVal2) const { return operator * (int32_t(iVal2)); }
|
||||
inline C4Fixed operator / (int iVal2) const { return operator / (int32_t(iVal2)); }
|
||||
#endif
|
||||
|
||||
inline bool operator == (int32_t iVal2) const { return operator == (C4Fixed(iVal2)); }
|
||||
inline bool operator < (int32_t iVal2) const { return operator < (C4Fixed(iVal2)); }
|
||||
inline bool operator > (int32_t iVal2) const { return operator > (C4Fixed(iVal2)); }
|
||||
inline bool operator <= (int32_t iVal2) const { return operator <= (C4Fixed(iVal2)); }
|
||||
inline bool operator >= (int32_t iVal2) const { return operator >= (C4Fixed(iVal2)); }
|
||||
inline bool operator != (int32_t iVal2) const { return operator != (C4Fixed(iVal2)); }
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER <= 1200
|
||||
inline bool operator == (int iVal2) const { return operator == (C4Fixed(int32_t(iVal2))); }
|
||||
inline bool operator < (int iVal2) const { return operator < (C4Fixed(int32_t(iVal2))); }
|
||||
inline bool operator > (int iVal2) const { return operator > (C4Fixed(int32_t(iVal2))); }
|
||||
inline bool operator <= (int iVal2) const { return operator <= (C4Fixed(int32_t(iVal2))); }
|
||||
inline bool operator >= (int iVal2) const { return operator >= (C4Fixed(int32_t(iVal2))); }
|
||||
inline bool operator != (int iVal2) const { return operator != (C4Fixed(int32_t(iVal2))); }
|
||||
#endif
|
||||
|
||||
#ifdef C4REAL_USE_FIXNUM
|
||||
C4Fixed sin_deg() const
|
||||
{
|
||||
// adjust angle
|
||||
int32_t v=int32_t((int64_t(val)*100)/FIXED_FPF); if (v<0) v=18000-v; v%=36000;
|
||||
// get sine
|
||||
C4Fixed fr;
|
||||
switch (v/9000)
|
||||
{
|
||||
case 0: fr.val=+SineTable[v]; break;
|
||||
case 1: fr.val=+SineTable[18000-v]; break;
|
||||
case 2: fr.val=-SineTable[v-18000]; break;
|
||||
case 3: fr.val=-SineTable[36000-v]; break;
|
||||
}
|
||||
return fr;
|
||||
}
|
||||
C4Fixed cos_deg() const
|
||||
{
|
||||
// adjust angle
|
||||
int32_t v=int32_t((int64_t(val)*100)/FIXED_FPF); if (v<0) v=-v; v%=36000;
|
||||
// get cosine
|
||||
C4Fixed fr;
|
||||
switch (v/9000)
|
||||
{
|
||||
case 0: fr.val=+SineTable[9000-v]; break;
|
||||
case 1: fr.val=-SineTable[v-9000]; break;
|
||||
case 2: fr.val=-SineTable[27000-v]; break;
|
||||
case 3: fr.val=+SineTable[v-27000]; break;
|
||||
}
|
||||
return fr;
|
||||
}
|
||||
#endif
|
||||
// Conversion
|
||||
inline operator int() const { return value; }
|
||||
inline operator float() const { return value; }
|
||||
|
||||
// Boolean operators
|
||||
// Not using safe-bool-idiom here, because we already define conversions
|
||||
// to integer, which is why we don't need to worry about unwanted con-
|
||||
// versions via operator bool
|
||||
inline operator bool() const { return static_cast<bool>(value); }
|
||||
inline bool operator !() const { return !operator bool(); }
|
||||
};
|
||||
|
||||
#ifdef C4REAL_USE_FIXNUM
|
||||
typedef C4RealBase<class C4RealImpl_Fixed> C4Real_Fixed;
|
||||
typedef C4RealBase<float> C4Real_FPU_Float;
|
||||
|
||||
typedef C4Fixed C4Real;
|
||||
#include "C4RealImpl_Fixed.h"
|
||||
#include "C4RealImpl_FPU.h"
|
||||
|
||||
// *** wrap C4Real to requested C4RealBase instantiation
|
||||
|
||||
#if C4REAL_MODE == C4REAL_MODE_SOFTWARE
|
||||
typedef C4Real_Fixed C4Real;
|
||||
#elif C4REAL_MODE == C4REAL_MODE_FPU_FLOAT
|
||||
typedef C4Real_FPU_Float C4Real;
|
||||
#endif
|
||||
|
||||
// Instantiate other C4RealBases as well
|
||||
template class C4RealBase<C4RealImpl_Fixed>;
|
||||
template class C4RealBase<float>;
|
||||
|
||||
// conversion
|
||||
inline float fixtof(const C4Fixed &x) { return x.to_float(); }
|
||||
inline C4Fixed ftofix(float x) { return C4Fixed(x); }
|
||||
inline int fixtoi(const C4Fixed &x) { return x.to_int(); }
|
||||
inline int fixtoi(const C4Fixed &x, int32_t prec) { return x.to_int(prec); }
|
||||
inline C4Fixed itofix(int32_t x) { return C4Fixed(x); }
|
||||
inline C4Fixed itofix(int32_t x, int32_t prec) { return C4Fixed(x, prec); }
|
||||
inline float fixtof(const C4Real &x) { return static_cast<float>(x); }
|
||||
inline C4Real ftofix(float x) { return C4Real(x); }
|
||||
inline int fixtoi(const C4Real &x) { return static_cast<int>(x); }
|
||||
inline int fixtoi(const C4Real &x, int32_t prec) { return static_cast<int>(x * prec); }
|
||||
inline C4Real itofix(int32_t x) { return C4Real(x); }
|
||||
inline C4Real itofix(int32_t x, int32_t prec) { return C4Real(x, prec); }
|
||||
|
||||
// additional functions
|
||||
inline C4Real Sin(const C4Real &fAngle) { return fAngle.sin_deg(); }
|
||||
inline C4Real Cos(const C4Real &fAngle) { return fAngle.cos_deg(); }
|
||||
inline C4Real C4REAL100(int x) { return itofix(x, 100); }
|
||||
//inline C4Real C4REAL256(int x) { return itofix(x, 256); }
|
||||
inline C4Real C4REAL256(int x) { C4Fixed r; r.val = x * FIXED_FPF / 256; return r; }
|
||||
inline C4Real C4REAL10(int x) { return itofix(x, 10); }
|
||||
inline C4Real C4REAL100(int x) { C4Real nrv(x); nrv /= 100; return nrv; }
|
||||
inline C4Real C4REAL256(int x) { C4Real nrv(x); nrv /= 256; return nrv; }
|
||||
inline C4Real C4REAL10(int x) { C4Real nrv(x); nrv /= 10; return nrv; }
|
||||
|
||||
#else
|
||||
|
||||
// *** wrap C4Real to float
|
||||
|
||||
typedef float C4Real;
|
||||
|
||||
// fixtoi: use asm fistp, round up
|
||||
inline int fixtoi(C4Real x)
|
||||
{
|
||||
int e;
|
||||
#ifdef _MSC_VER
|
||||
float y = x;
|
||||
_asm
|
||||
{
|
||||
or y,1;
|
||||
fld y;
|
||||
fistp e;
|
||||
}
|
||||
#else
|
||||
asm ("or $1, %0" : "+rom" (x));
|
||||
asm ("fistp%z0 %0" : "=om" (e) : "t" (x) : "st");
|
||||
#endif
|
||||
return e;
|
||||
}
|
||||
|
||||
// conversion
|
||||
inline int fixtoi(const C4Real &x, int32_t prec) { return fixtoi(x*prec); }
|
||||
inline C4Real itofix(int x) { return static_cast<C4Real>(x); }
|
||||
inline C4Real itofix(int x, int prec) { return static_cast<C4Real>(x) / prec; }
|
||||
inline float fixtof(const C4Real &x) { return x; }
|
||||
inline C4Real ftofix(float x) { return x; }
|
||||
|
||||
// additional functions
|
||||
inline C4Real Sin(C4Real x) { return float(sin(x * 3.141592f / 180)); }
|
||||
inline C4Real Cos(C4Real x) { return float(cos(x * 3.141592f / 180)); }
|
||||
inline C4Real C4REAL100(int x) { return float(x) / 100; }
|
||||
inline C4Real C4REAL256(int x) { return float(x) / 256; }
|
||||
inline C4Real C4REAL10(int x) { return float(x) / 10; }
|
||||
|
||||
#endif
|
||||
// define 0
|
||||
const C4Real Fix0 = itofix(0);
|
||||
|
||||
// conversion...
|
||||
// note: keep out! really dirty casts!
|
||||
#ifdef C4REAL_USE_FIXNUM
|
||||
inline void FLOAT_TO_FIXED(C4Real *pVal)
|
||||
{
|
||||
*pVal = ftofix (*reinterpret_cast<float *>(pVal));
|
||||
}
|
||||
#else
|
||||
inline void FIXED_TO_FLOAT(C4Real *pVal)
|
||||
{
|
||||
*pVal = reinterpret_cast<C4Fixed *>(pVal)->to_float();
|
||||
}
|
||||
#endif
|
||||
|
||||
#undef inline
|
||||
const C4Real Fix0 = C4Real(0);
|
||||
|
||||
// CompileFunc for C4Real
|
||||
void CompileFunc(C4Real &rValue, StdCompiler *pComp);
|
||||
|
||||
#endif //FIXED_H_INC
|
||||
#endif //C4REAL_H_INC
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* OpenClonk, http://www.openclonk.org
|
||||
*
|
||||
* Copyright (c) 2010 Nicolas Hake
|
||||
*
|
||||
* Portions might be copyrighted by other authors who have contributed
|
||||
* to OpenClonk.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
* See isc_license.txt for full license and disclaimer.
|
||||
*
|
||||
* "Clonk" is a registered trademark of Matthes Bender.
|
||||
* See clonk_trademark_license.txt for full license.
|
||||
*/
|
||||
|
||||
/* Fixed point math extracted from ALLEGRO by Shawn Hargreaves */
|
||||
|
||||
#ifndef INC_RealImpl_FPU
|
||||
#define INC_RealImpl_FPU
|
||||
|
||||
#ifndef INC_C4Real
|
||||
#error C4RealImpl_FPU.h must not be included by itself; include C4Real.h instead
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# define _USE_MATH_DEFINES
|
||||
#endif
|
||||
#include <cmath>
|
||||
|
||||
inline C4Real_FPU_Float Sin(const C4Real_FPU_Float &real)
|
||||
{
|
||||
return C4Real_FPU_Float(std::sin(real.value * static_cast<float>(M_PI) / 180.0f));
|
||||
}
|
||||
inline C4Real_FPU_Float Cos(const C4Real_FPU_Float &real)
|
||||
{
|
||||
return C4Real_FPU_Float(std::cos(real.value * static_cast<float>(M_PI) / 180.0f));
|
||||
}
|
||||
|
||||
// Overload to avoid conversion warning
|
||||
template<>
|
||||
inline C4Real_FPU_Float::operator bool () const
|
||||
{
|
||||
return value != 0.0f;
|
||||
}
|
||||
|
||||
// C4Real_Fixed rounds up. Why?
|
||||
#ifdef _M_X64
|
||||
#include <xmmintrin.h>
|
||||
#endif
|
||||
template<>
|
||||
inline C4Real_FPU_Float::operator int () const
|
||||
{
|
||||
float y = value;
|
||||
#if defined _M_X64
|
||||
*reinterpret_cast<int*>(&y) |= 1;
|
||||
return _mm_cvtss_si32(_mm_load_ss(&y));
|
||||
#elif defined _MSC_VER
|
||||
int e;
|
||||
_asm
|
||||
{
|
||||
or y,1;
|
||||
fld y;
|
||||
fistp e;
|
||||
}
|
||||
return e;
|
||||
#elif defined __GNUC__
|
||||
int e;
|
||||
asm ("or $1, %0" : "+rom" (y));
|
||||
asm ("fistp%z0 %0" : "=om" (e) : "t" (y) : "st");
|
||||
return e;
|
||||
#else
|
||||
#error Unknown processor; implement rounding here
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,185 @@
|
|||
/*
|
||||
* OpenClonk, http://www.openclonk.org
|
||||
*
|
||||
* Copyright (c) 1998-2000 Matthes Bender
|
||||
* Copyright (c) 2002, 2005 Sven Eberhardt
|
||||
* Copyright (c) 2002, 2004-2005, 2007 Peter Wortmann
|
||||
* Copyright (c) 2005, 2007 Günther Brammer
|
||||
* Copyright (c) 2010 Nicolas Hake
|
||||
* Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de
|
||||
*
|
||||
* Portions might be copyrighted by other authors who have contributed
|
||||
* to OpenClonk.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
* See isc_license.txt for full license and disclaimer.
|
||||
*
|
||||
* "Clonk" is a registered trademark of Matthes Bender.
|
||||
* See clonk_trademark_license.txt for full license.
|
||||
*/
|
||||
|
||||
/* Fixed point math extracted from ALLEGRO by Shawn Hargreaves */
|
||||
|
||||
#ifndef INC_RealImpl_Fixed
|
||||
#define INC_RealImpl_Fixed
|
||||
|
||||
#ifndef INC_C4Real
|
||||
#error C4RealImpl_Fixed.h must not be included by itself; include C4Real.h instead
|
||||
#endif
|
||||
|
||||
#define FIXED_EMULATE_64BIT
|
||||
|
||||
#include <boost/operators.hpp>
|
||||
class C4RealImpl_Fixed
|
||||
: boost::totally_ordered<C4RealImpl_Fixed,
|
||||
boost::equivalent<C4RealImpl_Fixed
|
||||
> >
|
||||
{
|
||||
// fixpoint shift (check 64 bit emulation before changing!)
|
||||
static const int32_t FIXED_SHIFT = 16;
|
||||
static const int32_t FIXED_FPF = 1 << FIXED_SHIFT;
|
||||
|
||||
int32_t val; // Internal value
|
||||
static long SineTable[9001]; // external table of sine values
|
||||
|
||||
public:
|
||||
inline C4RealImpl_Fixed() : val(0) {}
|
||||
inline C4RealImpl_Fixed(const C4RealImpl_Fixed &rhs) : val(rhs.val) {}
|
||||
explicit inline C4RealImpl_Fixed(int32_t iVal) : val (iVal * FIXED_FPF) { }
|
||||
explicit inline C4RealImpl_Fixed(int32_t iVal, int32_t iPrec)
|
||||
: val( iPrec < FIXED_FPF
|
||||
? iVal * (FIXED_FPF / iPrec) + (iVal * (FIXED_FPF % iPrec)) / iPrec
|
||||
: int32_t( int64_t(iVal) * FIXED_FPF / iPrec )
|
||||
)
|
||||
{ }
|
||||
explicit inline C4RealImpl_Fixed(float fVal)
|
||||
: val(static_cast<int32_t>(fVal * float(FIXED_FPF)))
|
||||
{ }
|
||||
|
||||
int32_t to_int() const
|
||||
{
|
||||
int32_t r = val;
|
||||
// be careful not to overflow
|
||||
r += (val <= 0x7fffffff - FIXED_FPF / 2) * FIXED_FPF / 2;
|
||||
// ensure that -x.50 is rounded to -(x+1)
|
||||
r -= (val < 0);
|
||||
r >>= FIXED_SHIFT;
|
||||
// round 32767.5 to 32768 (not that anybody cares)
|
||||
r += (val > 0x7fffffff - FIXED_FPF / 2);
|
||||
return r;
|
||||
}
|
||||
int32_t to_int(int32_t prec) const
|
||||
{
|
||||
int64_t r = val;
|
||||
r *= prec;
|
||||
r += FIXED_FPF / 2;
|
||||
r -= (val < 0);
|
||||
r >>= FIXED_SHIFT;
|
||||
return int32_t(r);
|
||||
}
|
||||
|
||||
// convert to floating point value
|
||||
float to_float() const
|
||||
{
|
||||
return float(val) / float(FIXED_FPF);
|
||||
}
|
||||
|
||||
// Arithmetics.
|
||||
C4RealImpl_Fixed &operator += (const C4RealImpl_Fixed &rhs)
|
||||
{
|
||||
val += rhs.val;
|
||||
return *this;
|
||||
}
|
||||
C4RealImpl_Fixed &operator -= (const C4RealImpl_Fixed &rhs)
|
||||
{
|
||||
val -= rhs.val;
|
||||
return *this;
|
||||
}
|
||||
C4RealImpl_Fixed &operator *= (const C4RealImpl_Fixed &rhs)
|
||||
{
|
||||
#ifndef FIXED_EMULATE_64BIT
|
||||
val = int32_t( (int64_t(val) * rhs.val) / FIXED_FPF );
|
||||
#else
|
||||
int32_t x0 = val & (FIXED_FPF - 1),
|
||||
x1 = val >> FIXED_SHIFT;
|
||||
int32_t y0 = rhs.val & (FIXED_FPF - 1),
|
||||
y1 = rhs.val >> FIXED_SHIFT;
|
||||
val = x0*y0/FIXED_FPF + x0*y1 + x1*y0 + x1*y1*FIXED_FPF;
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
C4RealImpl_Fixed &operator /= (const C4RealImpl_Fixed &rhs)
|
||||
{
|
||||
val = int32_t( (int64_t(val) * FIXED_FPF) / rhs.val );
|
||||
return *this;
|
||||
}
|
||||
C4RealImpl_Fixed operator - ()
|
||||
{
|
||||
C4RealImpl_Fixed nrv(*this);
|
||||
nrv.val = -nrv.val;
|
||||
return nrv;
|
||||
}
|
||||
|
||||
C4RealImpl_Fixed sin_deg() const
|
||||
{
|
||||
// adjust angle
|
||||
int32_t v=int32_t((int64_t(val)*100)/FIXED_FPF); if (v<0) v=18000-v; v%=36000;
|
||||
// get sine
|
||||
C4RealImpl_Fixed fr;
|
||||
switch (v/9000)
|
||||
{
|
||||
case 0: fr.val=+SineTable[v]; break;
|
||||
case 1: fr.val=+SineTable[18000-v]; break;
|
||||
case 2: fr.val=-SineTable[v-18000]; break;
|
||||
case 3: fr.val=-SineTable[36000-v]; break;
|
||||
}
|
||||
return fr;
|
||||
}
|
||||
C4RealImpl_Fixed cos_deg() const
|
||||
{
|
||||
// adjust angle
|
||||
int32_t v=int32_t((int64_t(val)*100)/FIXED_FPF); if (v<0) v=-v; v%=36000;
|
||||
// get cosine
|
||||
C4RealImpl_Fixed fr;
|
||||
switch (v/9000)
|
||||
{
|
||||
case 0: fr.val=+SineTable[9000-v]; break;
|
||||
case 1: fr.val=-SineTable[v-9000]; break;
|
||||
case 2: fr.val=-SineTable[27000-v]; break;
|
||||
case 3: fr.val=+SineTable[v-27000]; break;
|
||||
}
|
||||
return fr;
|
||||
}
|
||||
|
||||
// Comparison
|
||||
bool operator < (const C4RealImpl_Fixed &rhs) const { return val < rhs.val; }
|
||||
|
||||
operator bool () const { return val != 0; }
|
||||
|
||||
// Conversion
|
||||
operator float () const { return to_float(); }
|
||||
operator int () const { return to_int(); }
|
||||
};
|
||||
|
||||
// Avoid overflowing
|
||||
template<>
|
||||
inline C4RealBase<C4RealImpl_Fixed>::C4RealBase(int32_t val, int32_t prec)
|
||||
: value(val, prec)
|
||||
{}
|
||||
|
||||
inline C4Real_Fixed Sin(const C4Real_Fixed &real)
|
||||
{
|
||||
C4Real_Fixed nrv;
|
||||
nrv.value = real.value.sin_deg();
|
||||
return nrv;
|
||||
}
|
||||
inline C4Real_Fixed Cos(const C4Real_Fixed &real)
|
||||
{
|
||||
C4Real_Fixed nrv;
|
||||
nrv.value = real.value.cos_deg();
|
||||
return nrv;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -70,6 +70,7 @@ void StdCompilerBinWrite::Byte(int8_t &rByte) { WriteValue(rByte); }
|
|||
void StdCompilerBinWrite::Byte(uint8_t &rByte) { WriteValue(rByte); }
|
||||
void StdCompilerBinWrite::Boolean(bool &rBool) { WriteValue(rBool); }
|
||||
void StdCompilerBinWrite::Character(char &rChar) { WriteValue(rChar); }
|
||||
void StdCompilerBinWrite::Float(float &val) { WriteValue(val); }
|
||||
void StdCompilerBinWrite::String(char *szString, size_t iMaxLength, RawCompileType eType)
|
||||
{
|
||||
WriteData(szString, strlen(szString) + 1);
|
||||
|
@ -128,6 +129,7 @@ void StdCompilerBinRead::Byte(int8_t &rByte) { ReadValue(rByte); }
|
|||
void StdCompilerBinRead::Byte(uint8_t &rByte) { ReadValue(rByte); }
|
||||
void StdCompilerBinRead::Boolean(bool &rBool) { ReadValue(rBool); }
|
||||
void StdCompilerBinRead::Character(char &rChar) { ReadValue(rChar); }
|
||||
void StdCompilerBinRead::Float(float &val) { ReadValue(val); }
|
||||
void StdCompilerBinRead::String(char *szString, size_t iMaxLength, RawCompileType eType)
|
||||
{
|
||||
// At least one byte data needed
|
||||
|
@ -281,6 +283,12 @@ void StdCompilerINIWrite::Character(char &rChar)
|
|||
PrepareForValue();
|
||||
Buf.AppendFormat("%c", rChar);
|
||||
}
|
||||
void StdCompilerINIWrite::Float(float &val)
|
||||
{
|
||||
PrepareForValue();
|
||||
Buf.AppendFormat("%f", val);
|
||||
}
|
||||
|
||||
|
||||
void StdCompilerINIWrite::String(char *szString, size_t iMaxLength, RawCompileType eType)
|
||||
{
|
||||
|
@ -613,6 +621,31 @@ void StdCompilerINIRead::Character(char &rChar)
|
|||
{ notFound("Character"); return; }
|
||||
rChar = *pPos++;
|
||||
}
|
||||
void StdCompilerINIRead::Float(float &val)
|
||||
{
|
||||
if (!pPos)
|
||||
{ notFound("Float"); return; }
|
||||
// Skip whitespace
|
||||
SkipWhitespace();
|
||||
// Read number.
|
||||
const char *pnPos = pPos;
|
||||
double num = strtod(pPos, const_cast<char **>(&pnPos));
|
||||
// Could not read?
|
||||
if (!num && pnPos == pPos)
|
||||
{ notFound("Float"); return; }
|
||||
if (num < std::numeric_limits<float>::min() || num > std::numeric_limits<float>::max())
|
||||
{
|
||||
Warn("number out of range (%f to %f): %f ",
|
||||
static_cast<double>(std::numeric_limits<float>::min()),
|
||||
static_cast<double>(std::numeric_limits<float>::max()),
|
||||
num);
|
||||
if (num < std::numeric_limits<float>::min()) num = std::numeric_limits<float>::min();
|
||||
else if (num > std::numeric_limits<float>::max()) num = std::numeric_limits<float>::max();
|
||||
}
|
||||
// Get over it
|
||||
pPos = pnPos;
|
||||
val = num;
|
||||
}
|
||||
void StdCompilerINIRead::String(char *szString, size_t iMaxLength, RawCompileType eType)
|
||||
{
|
||||
// Read data
|
||||
|
|
|
@ -139,6 +139,7 @@ public:
|
|||
virtual void Byte(uint8_t &rByte) = 0; // Needs separator!
|
||||
virtual void Boolean(bool &rBool) = 0;
|
||||
virtual void Character(char &rChar) = 0; // Alphanumerical only!
|
||||
virtual void Float(float &val) = 0;
|
||||
|
||||
|
||||
// Compile raw data (strings)
|
||||
|
@ -177,6 +178,7 @@ public:
|
|||
void Value(int8_t &rInt) { Byte(rInt); }
|
||||
void Value(uint8_t &rInt) { Byte(rInt); }
|
||||
void Value(bool &rBool) { Boolean(rBool); }
|
||||
void Value(float &val) { Float(val); }
|
||||
|
||||
// Compiling/Decompiling (may throw a data format exception!)
|
||||
template <class T> inline void Compile(T RREF rStruct)
|
||||
|
@ -434,6 +436,7 @@ public:
|
|||
virtual void Byte(uint8_t &rByte) { }
|
||||
virtual void Boolean(bool &rBool) { }
|
||||
virtual void Character(char &rChar) { }
|
||||
virtual void Float(float &val) { }
|
||||
virtual void String(char *szString, size_t iMaxLength, RawCompileType eType = RCT_Escaped) { }
|
||||
virtual void String(char **pszString, RawCompileType eType = RCT_Escaped) { }
|
||||
virtual void Raw(void *pData, size_t iSize, RawCompileType eType = RCT_Escaped) { }
|
||||
|
@ -466,6 +469,7 @@ public:
|
|||
virtual void Byte(uint8_t &rByte);
|
||||
virtual void Boolean(bool &rBool);
|
||||
virtual void Character(char &rChar);
|
||||
virtual void Float(float &val);
|
||||
virtual void String(char *szString, size_t iMaxLength, RawCompileType eType = RCT_Escaped);
|
||||
virtual void String(char **pszString, RawCompileType eType = RCT_Escaped);
|
||||
virtual void Raw(void *pData, size_t iSize, RawCompileType eType = RCT_Escaped);
|
||||
|
@ -506,6 +510,7 @@ public:
|
|||
virtual void Byte(uint8_t &rByte);
|
||||
virtual void Boolean(bool &rBool);
|
||||
virtual void Character(char &rChar);
|
||||
virtual void Float(float &val);
|
||||
virtual void String(char *szString, size_t iMaxLength, RawCompileType eType = RCT_Escaped);
|
||||
virtual void String(char **pszString, RawCompileType eType = RCT_Escaped);
|
||||
virtual void Raw(void *pData, size_t iSize, RawCompileType eType = RCT_Escaped);
|
||||
|
@ -584,6 +589,7 @@ public:
|
|||
virtual void Byte(uint8_t &rByte);
|
||||
virtual void Boolean(bool &rBool);
|
||||
virtual void Character(char &rChar);
|
||||
virtual void Float(float &val);
|
||||
virtual void String(char *szString, size_t iMaxLength, RawCompileType eType = RCT_Escaped);
|
||||
virtual void String(char **pszString, RawCompileType eType = RCT_Escaped);
|
||||
virtual void Raw(void *pData, size_t iSize, RawCompileType eType = RCT_Escaped);
|
||||
|
@ -655,6 +661,7 @@ public:
|
|||
virtual void Byte(uint8_t &rByte);
|
||||
virtual void Boolean(bool &rBool);
|
||||
virtual void Character(char &rChar);
|
||||
virtual void Float(float &val);
|
||||
virtual void String(char *szString, size_t iMaxLength, RawCompileType eType = RCT_Escaped);
|
||||
virtual void String(char **pszString, RawCompileType eType = RCT_Escaped);
|
||||
virtual void Raw(void *pData, size_t iSize, RawCompileType eType = RCT_Escaped);
|
||||
|
|
|
@ -516,6 +516,11 @@ void StdCompilerConfigWrite::Raw(void *pData, size_t iSize, RawCompileType eType
|
|||
excCorrupt("Raw values aren't supported for registry compilers!");
|
||||
}
|
||||
|
||||
void StdCompilerConfigWrite::Float(float &val)
|
||||
{
|
||||
excCorrupt(0, "Float values aren't supported for registry compilers!");
|
||||
}
|
||||
|
||||
void StdCompilerConfigWrite::Begin()
|
||||
{
|
||||
assert(!iDepth);
|
||||
|
@ -699,6 +704,11 @@ void StdCompilerConfigRead::Raw(void *pData, size_t iSize, RawCompileType eType)
|
|||
excCorrupt(0, "Raw values aren't supported for registry compilers!");
|
||||
}
|
||||
|
||||
void StdCompilerConfigRead::Float(float &val)
|
||||
{
|
||||
excCorrupt(0, "Float values aren't supported for registry compilers!");
|
||||
}
|
||||
|
||||
void StdCompilerConfigRead::Begin()
|
||||
{
|
||||
assert(!iDepth);
|
||||
|
|
|
@ -106,6 +106,7 @@ public:
|
|||
virtual void Byte(uint8_t &rByte);
|
||||
virtual void Boolean(bool &rBool);
|
||||
virtual void Character(char &rChar);
|
||||
virtual void Float(float &val);
|
||||
virtual void String(char *szString, size_t iMaxLength, RawCompileType eType = RCT_Escaped);
|
||||
virtual void String(char **pszString, RawCompileType eType = RCT_Escaped);
|
||||
virtual void Raw(void *pData, size_t iSize, RawCompileType eType = RCT_Escaped);
|
||||
|
@ -162,6 +163,7 @@ public:
|
|||
virtual void Byte(uint8_t &rByte);
|
||||
virtual void Boolean(bool &rBool);
|
||||
virtual void Character(char &rChar);
|
||||
virtual void Float(float &val);
|
||||
virtual void String(char *szString, size_t iMaxLength, RawCompileType eType = RCT_Escaped);
|
||||
virtual void String(char **pszString, RawCompileType eType = RCT_Escaped);
|
||||
virtual void Raw(void *pData, size_t iSize, RawCompileType eType = RCT_Escaped);
|
||||
|
|
Loading…
Reference in New Issue