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