1 /* ScummVM - Graphic Adventure Engine
2 *
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 */
22
23 // Based on eos' math code
24
25 #ifndef COMMON_MATH_H
26 #define COMMON_MATH_H
27
28 #include "common/scummsys.h"
29 #ifdef _MSC_VER
30 // HACK:
31 // intrin.h on MSVC includes setjmp.h, which will fail compiling due to our
32 // forbidden symbol colde. Since we also can not assure that defining
33 // FORBIDDEN_SYMBOL_EXCEPTION_setjmp and FORBIDDEN_SYMBOL_EXCEPTION_longjmp
34 // will actually allow the symbols, since forbidden.h might be included
35 // earlier already we need to undefine them here...
36 #undef setjmp
37 #undef longjmp
38 #include <intrin.h>
39 // ...and redefine them here so no code can actually use it.
40 // This could be resolved by including intrin.h on MSVC in scummsys.h before
41 // the forbidden.h include. This might make sense, in case we use MSVC
42 // extensions like _BitScanReverse in more places. But for now this hack should
43 // be ok...
44 #ifndef FORBIDDEN_SYMBOL_EXCEPTION_setjmp
45 #undef setjmp
46 #define setjmp(a) FORBIDDEN_SYMBOL_REPLACEMENT
47 #endif
48
49 #ifndef FORBIDDEN_SYMBOL_EXCEPTION_longjmp
50 #undef longjmp
51 #define longjmp(a,b) FORBIDDEN_SYMBOL_REPLACEMENT
52 #endif
53 #endif
54
55 #ifndef FLT_MIN
56 #define FLT_MIN 1E-37
57 #endif
58
59 #ifndef FLT_MAX
60 #define FLT_MAX 1E+37
61 #endif
62
63 namespace Common {
64
65 /** A complex number. */
66 struct Complex {
67 float re, im;
68 };
69
70 #if GCC_ATLEAST(3, 4)
intLog2(uint32 v)71 inline int intLog2(uint32 v) {
72 // This is a slightly optimized implementation of log2 for natural numbers
73 // targeting gcc. It also saves some binary size over our fallback
74 // implementation, since it does not need any table.
75 if (v == 0)
76 return -1;
77 else
78 // This is really "sizeof(unsigned int) * CHAR_BIT - 1" but using 8
79 // instead of CHAR_BIT is sane enough and it saves us from including
80 // limits.h
81 return (sizeof(unsigned int) * 8 - 1) - __builtin_clz(v);
82 }
83 #elif defined(_MSC_VER)
intLog2(uint32 v)84 inline int intLog2(uint32 v) {
85 unsigned long result = 0;
86 unsigned char nonZero = _BitScanReverse(&result, v);
87 // _BitScanReverse stores the position of the MSB set in case its result
88 // is non zero, thus we can just return it as is.
89 return nonZero ? result : -1;
90 }
91 #else
92 // See http://graphics.stanford.edu/~seander/bithacks.html#IntegerLogLookup
93 static const char LogTable256[256] = {
94 #define LT(n) n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n
95 -1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
96 LT(4), LT(5), LT(5), LT(6), LT(6), LT(6), LT(6),
97 LT(7), LT(7), LT(7), LT(7), LT(7), LT(7), LT(7), LT(7)
98 };
99
intLog2(uint32 v)100 inline int intLog2(uint32 v) {
101 uint32 t, tt;
102
103 if ((tt = v >> 16))
104 return (t = tt >> 8) ? 24 + LogTable256[t] : 16 + LogTable256[tt];
105 else
106 return (t = v >> 8) ? 8 + LogTable256[t] : LogTable256[v];
107 }
108 #endif
109
110 // Round a number towards zero
111 // Input and Output type can be different
112 template<class InputT, class OutputT>
trunc(InputT x)113 inline OutputT trunc(InputT x) {
114 return (x > 0) ? floor(x) : ceil(x);
115 }
116
117 // Round a number towards zero
118 // Input and Output type are the same
119 template<class T>
trunc(T x)120 inline T trunc(T x) {
121 return trunc<T,T>(x);
122 }
123
124 // Convert radians to degrees
125 // Input and Output type can be different
126 // Upconvert everything to floats
127 template<class InputT, class OutputT>
rad2deg(InputT rad)128 inline OutputT rad2deg(InputT rad) {
129 return (OutputT)( (float)rad * (float)57.2957795130823); // 180.0/M_PI = 57.2957795130823
130 }
131
132 // Handle the case differently when the input type is double
133 template<class OutputT>
rad2deg(double rad)134 inline OutputT rad2deg(double rad) {
135 return (OutputT)( rad * 57.2957795130823);
136 }
137
138 // Convert radians to degrees
139 // Input and Output type are the same
140 template<class T>
rad2deg(T rad)141 inline T rad2deg(T rad) {
142 return rad2deg<T,T>(rad);
143 }
144
145 // Convert degrees to radians
146 // Input and Output type can be different
147 // Upconvert everything to floats
148 template<class InputT, class OutputT>
deg2rad(InputT deg)149 inline OutputT deg2rad(InputT deg) {
150 return (OutputT)( (float)deg * (float)0.0174532925199433); // M_PI/180.0 = 0.0174532925199433
151 }
152
153 // Handle the case differently when the input type is double
154 template<class OutputT>
deg2rad(double deg)155 inline OutputT deg2rad(double deg) {
156 return (OutputT)( deg * 0.0174532925199433);
157 }
158
159 // Convert degrees to radians
160 // Input and Output type are the same
161 template<class T>
deg2rad(T deg)162 inline T deg2rad(T deg) {
163 return deg2rad<T,T>(deg);
164 }
165
166 template<class T>
hypotenuse(T xv,T yv)167 inline T hypotenuse(T xv, T yv) {
168 return (T)sqrt((double)(xv * xv + yv * yv));
169 }
170
171 } // End of namespace Common
172
173 #endif // COMMON_MATH_H
174