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
Nicolas Hake 2010-05-19 07:25:01 +02:00
parent 59f5ee646c
commit fa59c32429
12 changed files with 9462 additions and 9318 deletions

View File

@ -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

View File

@ -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 \

View File

@ -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)

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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);