OpenClonk
C4Real.h
Go to the documentation of this file.
1 /*
2  * OpenClonk, http://www.openclonk.org
3  *
4  * Copyright (c) 1998-2000, Matthes Bender
5  * Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de/
6  * Copyright (c) 2009-2016, The OpenClonk Team and contributors
7  *
8  * Distributed under the terms of the ISC license; see accompanying file
9  * "COPYING" for details.
10  *
11  * "Clonk" is a registered trademark of Matthes Bender, used with permission.
12  * See accompanying file "TRADEMARK" for details.
13  *
14  * To redistribute this file separately, substitute the full license texts
15  * for the above references.
16  */
17 
18 /* Fixed point math extracted from ALLEGRO by Shawn Hargreaves */
19 
20 /* The Clonk engine uses fixed point math for exact object positions.
21  This is rather silly. Nowadays we should simply use floats. However,
22  I never dared changing the whole thing. */
23 /* 01-17-2002: I think the whole, ugly fixed-thing has to be revived,
24  because floating point calculations are not guaranteed to be network
25  safe...however, it can be solved as a data type with operator
26  overloading, automatic type conversions, etc now - Sven2 */
27 /* After some time with synchronous float use, C4Fixed is used again to
28  work around the problem that different compilers produce different
29  floating point code, leading to desyncs between linux and windows
30  engines. */
31 
32 #ifndef INC_C4Real
33 #define INC_C4Real
34 
35 // activate to switch to classic fixed-point math
36 #define C4REAL_USE_FIXNUM 1
37 #define inline ALWAYS_INLINE
38 
39 // gcc 4.6 generates better code for FIXED_EMULATE_64BIT disablen for both
40 // 32 and 64 bit. It properly recognizes that the 32,32->64 multiplication
41 // instruction of the x86 is the right choice for the job whereas the more
42 // complicated FIXED_EMULATE_64BIT version requires multiple multiplications
43 //#define FIXED_EMULATE_64BIT
44 
45 // note: C4Fixed has to be defined even though it isn't used
46 // any more. It is used to convert old-format fixed values
47 // to the new-format float ones.
48 
49 #ifdef C4REAL_USE_FIXNUM
50 extern long SineTable[9001]; // external table of sine values
51 #endif
52 
53 // fixpoint shift (check 64 bit emulation before changing!)
54 #define FIXED_SHIFT 16
55 // fixpoint factor
56 #define FIXED_FPF int32_t(1 << FIXED_SHIFT)
57 
58 class C4Fixed
59 {
60 #ifdef C4REAL_USE_FIXNUM
61  friend int fixtoi(const C4Fixed &x);
62  friend int fixtoi(const C4Fixed &x, int32_t prec);
63  friend C4Fixed itofix(int32_t x);
64  friend C4Fixed itofix(int32_t x, int32_t prec);
65  friend float fixtof(const C4Fixed &x);
66  friend C4Fixed ftofix(float x);
67 #else
68  friend void FIXED_TO_FLOAT(float *pVal);
69 #endif
70  friend void CompileFunc(C4Fixed &rValue, StdCompiler *pComp);
71 
72 public:
73  int32_t val; // internal value
74 
75 public:
76  // constructors
77  inline C4Fixed () = default;
78  inline C4Fixed (const C4Fixed &) = default;
79 
80  // Conversion must be done by the conversion routines itofix, fixtoi, ftofix and fixtof
81  // in order to be backward compatible, so everything is private.
82 private:
83  explicit inline C4Fixed(int32_t iVal)
84  : val (iVal * FIXED_FPF)
85  { }
86  explicit inline C4Fixed(int32_t iVal, int32_t iPrec)
87  : val( iPrec < FIXED_FPF
88  ? iVal * (FIXED_FPF / iPrec) + (iVal * (FIXED_FPF % iPrec)) / iPrec
89  : int32_t( int64_t(iVal) * FIXED_FPF / iPrec )
90  )
91  { }
92  explicit inline C4Fixed(float fVal)
93  : val(static_cast<int32_t>(fVal * float(FIXED_FPF)))
94  { }
95 
96  // round to int
97  int32_t to_int() const
98  {
99  int32_t r = val;
100  // round towards positive infinity
101  r >>= (FIXED_SHIFT - 1);
102  r += 1;
103  r >>= 1;
104  return r;
105  }
106  int32_t to_int(int32_t prec) const
107  {
108  int64_t r = val;
109  r *= prec;
110  r += FIXED_FPF / 2;
111  r >>= FIXED_SHIFT;
112  return int32_t(r);
113  }
114  // convert to floating point value
115  float to_float() const
116  {
117  return float(val) / float(FIXED_FPF);
118  }
119 
120 public:
121 
122  // set integer (allowed for historic reasons)
123  inline C4Fixed &operator = (int32_t x) { return *this = C4Fixed(x); }
124 
125  // test value
126  explicit operator bool () const { return val != 0; }
127  inline bool operator ! () const { return ! val; }
128 
129  // arithmetic operations
130  inline C4Fixed &operator += (const C4Fixed &fVal2)
131  {
132  val += fVal2.val;
133  return *this;
134  }
135  inline C4Fixed &operator -= (const C4Fixed &fVal2)
136  {
137  val -= fVal2.val;
138  return *this;
139  }
140  inline C4Fixed &operator *= (const C4Fixed &fVal2)
141  {
142 #ifndef FIXED_EMULATE_64BIT
143  val = int32_t( (int64_t(val) * fVal2.val) / FIXED_FPF );
144 #else
145  uint32_t x0 = val & (FIXED_FPF - 1);
146  int32_t x1 = val >> FIXED_SHIFT;
147  uint32_t y0 = fVal2.val & (FIXED_FPF - 1);
148  int32_t y1 = fVal2.val >> FIXED_SHIFT;
149  val = int32_t(x0*y0/FIXED_FPF) + int32_t(x0)*y1 + x1*int32_t(y0) + x1*y1*FIXED_FPF;
150 #endif
151  return *this;
152  }
153  inline C4Fixed &operator *= (int32_t iVal2)
154  {
155  val *= iVal2;
156  return *this;
157  }
158  inline C4Fixed &operator /= (const C4Fixed &fVal2)
159  {
160  val = int32_t( (int64_t(val) * FIXED_FPF) / fVal2.val );
161  return *this;
162  }
163  inline C4Fixed &operator /= (int32_t iVal2)
164  {
165  val /= iVal2;
166  return *this;
167  }
168  inline C4Fixed operator - () const
169  {
170  C4Fixed fr; fr.val=-val; return fr;
171  }
172  inline C4Fixed operator + () const
173  {
174  return *this;
175  }
176 
177  inline bool operator == (const C4Fixed &fVal2) const { return val==fVal2.val; }
178  inline bool operator < (const C4Fixed &fVal2) const { return val<fVal2.val; }
179  inline bool operator > (const C4Fixed &fVal2) const { return val>fVal2.val; }
180  inline bool operator <= (const C4Fixed &fVal2) const { return val<=fVal2.val; }
181  inline bool operator >= (const C4Fixed &fVal2) const { return val>=fVal2.val; }
182  inline bool operator != (const C4Fixed &fVal2) const { return val!=fVal2.val; }
183 
184  // and wrappers
185  inline C4Fixed &operator += (int32_t iVal2) { return operator += (C4Fixed(iVal2)); }
186  inline C4Fixed &operator -= (int32_t iVal2) { return operator -= (C4Fixed(iVal2)); }
187 
188  inline C4Fixed operator + (const C4Fixed &fVal2) const { return C4Fixed(*this) += fVal2; }
189  inline C4Fixed operator - (const C4Fixed &fVal2) const { return C4Fixed(*this) -= fVal2; }
190  inline C4Fixed operator * (const C4Fixed &fVal2) const { return C4Fixed(*this) *= fVal2; }
191  inline C4Fixed operator / (const C4Fixed &fVal2) const { return C4Fixed(*this) /= fVal2; }
192 
193  inline C4Fixed operator + (int32_t iVal2) const { return C4Fixed(*this) += iVal2; }
194  inline C4Fixed operator - (int32_t iVal2) const { return C4Fixed(*this) -= iVal2; }
195  inline C4Fixed operator * (int32_t iVal2) const { return C4Fixed(*this) *= iVal2; }
196  inline C4Fixed operator / (int32_t iVal2) const { return C4Fixed(*this) /= iVal2; }
197 
198  inline C4Fixed operator + (float iVal2) const { return C4Fixed(*this) += iVal2; }
199  inline C4Fixed operator - (float iVal2) const { return C4Fixed(*this) -= iVal2; }
200  inline C4Fixed operator * (float iVal2) const { return C4Fixed(*this) *= iVal2; }
201  inline C4Fixed operator / (float iVal2) const { return C4Fixed(*this) /= iVal2; }
202 
203  inline bool operator == (int32_t iVal2) const { return operator == (C4Fixed(iVal2)); }
204  inline bool operator < (int32_t iVal2) const { return operator < (C4Fixed(iVal2)); }
205  inline bool operator > (int32_t iVal2) const { return operator > (C4Fixed(iVal2)); }
206  inline bool operator <= (int32_t iVal2) const { return operator <= (C4Fixed(iVal2)); }
207  inline bool operator >= (int32_t iVal2) const { return operator >= (C4Fixed(iVal2)); }
208  inline bool operator != (int32_t iVal2) const { return operator != (C4Fixed(iVal2)); }
209 
210  inline bool operator == (float iVal2) const { return operator == (C4Fixed(iVal2)); }
211  inline bool operator < (float iVal2) const { return operator < (C4Fixed(iVal2)); }
212  inline bool operator > (float iVal2) const { return operator > (C4Fixed(iVal2)); }
213  inline bool operator <= (float iVal2) const { return operator <= (C4Fixed(iVal2)); }
214  inline bool operator >= (float iVal2) const { return operator >= (C4Fixed(iVal2)); }
215  inline bool operator != (float iVal2) const { return operator != (C4Fixed(iVal2)); }
216 
217 #ifdef C4REAL_USE_FIXNUM
218  C4Fixed sin_deg() const
219  {
220  // adjust angle
221  int32_t v=int32_t((int64_t(val)*100)/FIXED_FPF); if (v<0) v=18000-v; v%=36000;
222  // get sine
223  C4Fixed fr;
224  switch (v/9000)
225  {
226  case 0: fr.val=+SineTable[v]; break;
227  case 1: fr.val=+SineTable[18000-v]; break;
228  case 2: fr.val=-SineTable[v-18000]; break;
229  case 3: fr.val=-SineTable[36000-v]; break;
230  }
231  return fr;
232  }
233  C4Fixed cos_deg() const
234  {
235  // adjust angle
236  int32_t v=int32_t((int64_t(val)*100)/FIXED_FPF); if (v<0) v=-v; v%=36000;
237  // get cosine
238  C4Fixed fr;
239  switch (v/9000)
240  {
241  case 0: fr.val=+SineTable[9000-v]; break;
242  case 1: fr.val=-SineTable[v-9000]; break;
243  case 2: fr.val=-SineTable[27000-v]; break;
244  case 3: fr.val=+SineTable[v-27000]; break;
245  }
246  return fr;
247  }
248 #endif
249 
250 };
251 
252 #ifdef C4REAL_USE_FIXNUM
253 
254 typedef C4Fixed C4Real;
255 
256 // conversion
257 inline float fixtof(const C4Fixed &x) { return x.to_float(); }
258 inline C4Fixed ftofix(float x) { return C4Fixed(x); }
259 inline int fixtoi(const C4Fixed &x) { return x.to_int(); }
260 inline int fixtoi(const C4Fixed &x, int32_t prec) { return x.to_int(prec); }
261 inline C4Fixed itofix(int32_t x) { return C4Fixed(x); }
262 inline C4Fixed itofix(int32_t x, int32_t prec) { return C4Fixed(x, prec); }
263 
264 // additional functions
265 inline C4Real Sin(const C4Real &fAngle) { return fAngle.sin_deg(); }
266 inline C4Real Cos(const C4Real &fAngle) { return fAngle.cos_deg(); }
267 inline C4Real C4REAL100(int x) { return itofix(x, 100); }
268 inline C4Real C4REAL256(int x) { C4Fixed r; r.val = x * FIXED_FPF / 256; return r; }
269 inline C4Real C4REAL10(int x) { return itofix(x, 10); }
270 
271 #else
272 
273 // *** wrap C4Real to float
274 
275 typedef float C4Real;
276 
277 // fixtoi: use asm fistp, round up
278 inline int fixtoi(C4Real x)
279 {
280  int e;
281 #ifdef _MSC_VER
282  float y = x;
283  _asm
284  {
285  or y,1;
286  fld y;
287  fistp e;
288  }
289 #else
290 asm ("or $1, %0" : "+rom" (x));
291 asm ("fistp%z0 %0" : "=om" (e) : "t" (x) : "st");
292 #endif
293  return e;
294 }
295 
296 // conversion
297 inline int fixtoi(const C4Real &x, int32_t prec) { return fixtoi(x*prec); }
298 inline C4Real itofix(int x) { return static_cast<C4Real>(x); }
299 inline C4Real itofix(int x, int prec) { return static_cast<C4Real>(x) / prec; }
300 inline float fixtof(const C4Real &x) { return x; }
301 inline C4Real ftofix(float x) { return x; }
302 
303 // additional functions
304 inline C4Real Sin(C4Real x) { return float(sin(x * 3.141592f / 180)); }
305 inline C4Real Cos(C4Real x) { return float(cos(x * 3.141592f / 180)); }
306 inline C4Real C4REAL100(int x) { return float(x) / 100; }
307 inline C4Real C4REAL256(int x) { return float(x) / 256; }
308 inline C4Real C4REAL10(int x) { return float(x) / 10; }
309 
310 #endif
311 // define 0
312 const C4Real Fix0 = itofix(0);
313 const C4Real Fix1 = itofix(1);
314 
315 // conversion...
316 // note: keep out! really dirty casts!
317 #ifdef C4REAL_USE_FIXNUM
318 inline void FLOAT_TO_FIXED(C4Real *pVal)
319 {
320  *pVal = ftofix (*reinterpret_cast<float *>(pVal));
321 }
322 #else
323 inline void FIXED_TO_FLOAT(C4Real *pVal)
324 {
325  *pVal = reinterpret_cast<C4Fixed *>(pVal)->to_float();
326 }
327 #endif
328 
329 #undef inline
330 
331 // CompileFunc for C4Real
332 void CompileFunc(C4Real &rValue, StdCompiler *pComp);
333 
334 #endif //FIXED_H_INC
#define FIXED_FPF
Definition: C4Real.h:56
float fixtof(const C4Fixed &x)
Definition: C4Real.h:257
C4Fixed itofix(int32_t x)
Definition: C4Real.h:261
C4Real Cos(const C4Real &fAngle)
Definition: C4Real.h:266
int fixtoi(const C4Fixed &x)
Definition: C4Real.h:259
C4Fixed ftofix(float x)
Definition: C4Real.h:258
const C4Real Fix0
Definition: C4Real.h:312
void FLOAT_TO_FIXED(C4Real *pVal)
Definition: C4Real.h:318
C4Real C4REAL100(int x)
Definition: C4Real.h:267
void CompileFunc(C4Real &rValue, StdCompiler *pComp)
Definition: C4Real.cpp:9033
C4Real C4REAL10(int x)
Definition: C4Real.h:269
long SineTable[9001]
#define FIXED_SHIFT
Definition: C4Real.h:54
C4Fixed C4Real
Definition: C4Real.h:254
C4Real Sin(const C4Real &fAngle)
Definition: C4Real.h:265
C4Real C4REAL256(int x)
Definition: C4Real.h:268
const C4Real Fix1
Definition: C4Real.h:313
Definition: C4Real.h:59
bool operator>(const C4Fixed &fVal2) const
Definition: C4Real.h:179
int32_t val
Definition: C4Real.h:73
C4Fixed & operator*=(const C4Fixed &fVal2)
Definition: C4Real.h:140
bool operator<(const C4Fixed &fVal2) const
Definition: C4Real.h:178
C4Fixed & operator/=(const C4Fixed &fVal2)
Definition: C4Real.h:158
bool operator>=(const C4Fixed &fVal2) const
Definition: C4Real.h:181
C4Fixed operator*(const C4Fixed &fVal2) const
Definition: C4Real.h:190
C4Fixed(const C4Fixed &)=default
friend float fixtof(const C4Fixed &x)
Definition: C4Real.h:257
C4Fixed & operator+=(const C4Fixed &fVal2)
Definition: C4Real.h:130
friend C4Fixed itofix(int32_t x)
Definition: C4Real.h:261
C4Fixed operator-() const
Definition: C4Real.h:168
friend int fixtoi(const C4Fixed &x)
Definition: C4Real.h:259
friend C4Fixed ftofix(float x)
Definition: C4Real.h:258
bool operator!() const
Definition: C4Real.h:127
C4Fixed operator/(const C4Fixed &fVal2) const
Definition: C4Real.h:191
friend void CompileFunc(C4Fixed &rValue, StdCompiler *pComp)
Definition: C4Real.cpp:9033
C4Fixed & operator=(int32_t x)
Definition: C4Real.h:123
C4Fixed sin_deg() const
Definition: C4Real.h:218
C4Fixed()=default
C4Fixed cos_deg() const
Definition: C4Real.h:233
C4Fixed & operator-=(const C4Fixed &fVal2)
Definition: C4Real.h:135
bool operator==(const C4Fixed &fVal2) const
Definition: C4Real.h:177
C4Fixed operator+() const
Definition: C4Real.h:172
bool operator!=(const C4Fixed &fVal2) const
Definition: C4Real.h:182
bool operator<=(const C4Fixed &fVal2) const
Definition: C4Real.h:180