]> git.lizzy.rs Git - dragonfireclient.git/blob - src/util/numeric.h
Print --videomodes response to standard output, too
[dragonfireclient.git] / src / util / numeric.h
1 /*
2 Minetest
3 Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #ifndef UTIL_NUMERIC_HEADER
21 #define UTIL_NUMERIC_HEADER
22
23 #include "../basicmacros.h"
24 #include "../irrlichttypes.h"
25 #include "../irr_v2d.h"
26 #include "../irr_v3d.h"
27 #include "../irr_aabb3d.h"
28 #include "../threading/mutex.h"
29 #include <list>
30 #include <map>
31 #include <vector>
32
33
34 /*
35  * This class permits to cache getFacePosition call results
36  * This reduces CPU usage and vector calls
37  */
38 class FacePositionCache
39 {
40 public:
41         static std::vector<v3s16> getFacePositions(u16 d);
42 private:
43         static void generateFacePosition(u16 d);
44         static std::map<u16, std::vector<v3s16> > m_cache;
45         static Mutex m_cache_mutex;
46 };
47
48 class IndentationRaiser
49 {
50 public:
51         IndentationRaiser(u16 *indentation)
52         {
53                 m_indentation = indentation;
54                 (*m_indentation)++;
55         }
56         ~IndentationRaiser()
57         {
58                 (*m_indentation)--;
59         }
60 private:
61         u16 *m_indentation;
62 };
63
64 inline s16 getContainerPos(s16 p, s16 d)
65 {
66         return (p>=0 ? p : p-d+1) / d;
67 }
68
69 inline v2s16 getContainerPos(v2s16 p, s16 d)
70 {
71         return v2s16(
72                 getContainerPos(p.X, d),
73                 getContainerPos(p.Y, d)
74         );
75 }
76
77 inline v3s16 getContainerPos(v3s16 p, s16 d)
78 {
79         return v3s16(
80                 getContainerPos(p.X, d),
81                 getContainerPos(p.Y, d),
82                 getContainerPos(p.Z, d)
83         );
84 }
85
86 inline v2s16 getContainerPos(v2s16 p, v2s16 d)
87 {
88         return v2s16(
89                 getContainerPos(p.X, d.X),
90                 getContainerPos(p.Y, d.Y)
91         );
92 }
93
94 inline v3s16 getContainerPos(v3s16 p, v3s16 d)
95 {
96         return v3s16(
97                 getContainerPos(p.X, d.X),
98                 getContainerPos(p.Y, d.Y),
99                 getContainerPos(p.Z, d.Z)
100         );
101 }
102
103 inline void getContainerPosWithOffset(s16 p, s16 d, s16 &container, s16 &offset)
104 {
105         container = (p >= 0 ? p : p - d + 1) / d;
106         offset = p & (d - 1);
107 }
108
109 inline void getContainerPosWithOffset(const v2s16 &p, s16 d, v2s16 &container, v2s16 &offset)
110 {
111         getContainerPosWithOffset(p.X, d, container.X, offset.X);
112         getContainerPosWithOffset(p.Y, d, container.Y, offset.Y);
113 }
114
115 inline void getContainerPosWithOffset(const v3s16 &p, s16 d, v3s16 &container, v3s16 &offset)
116 {
117         getContainerPosWithOffset(p.X, d, container.X, offset.X);
118         getContainerPosWithOffset(p.Y, d, container.Y, offset.Y);
119         getContainerPosWithOffset(p.Z, d, container.Z, offset.Z);
120 }
121
122
123 inline bool isInArea(v3s16 p, s16 d)
124 {
125         return (
126                 p.X >= 0 && p.X < d &&
127                 p.Y >= 0 && p.Y < d &&
128                 p.Z >= 0 && p.Z < d
129         );
130 }
131
132 inline bool isInArea(v2s16 p, s16 d)
133 {
134         return (
135                 p.X >= 0 && p.X < d &&
136                 p.Y >= 0 && p.Y < d
137         );
138 }
139
140 inline bool isInArea(v3s16 p, v3s16 d)
141 {
142         return (
143                 p.X >= 0 && p.X < d.X &&
144                 p.Y >= 0 && p.Y < d.Y &&
145                 p.Z >= 0 && p.Z < d.Z
146         );
147 }
148
149 #define rangelim(d, min, max) ((d) < (min) ? (min) : ((d)>(max)?(max):(d)))
150 #define myfloor(x) ((x) > 0.0 ? (int)(x) : (int)(x) - 1)
151
152 inline v3s16 arealim(v3s16 p, s16 d)
153 {
154         if(p.X < 0)
155                 p.X = 0;
156         if(p.Y < 0)
157                 p.Y = 0;
158         if(p.Z < 0)
159                 p.Z = 0;
160         if(p.X > d-1)
161                 p.X = d-1;
162         if(p.Y > d-1)
163                 p.Y = d-1;
164         if(p.Z > d-1)
165                 p.Z = d-1;
166         return p;
167 }
168
169 // The naive swap performs better than the xor version
170 #define SWAP(t, x, y) do { \
171         t temp = x;            \
172         x = y;                 \
173         y = temp;              \
174 } while (0)
175
176 inline void sortBoxVerticies(v3s16 &p1, v3s16 &p2) {
177         if (p1.X > p2.X)
178                 SWAP(s16, p1.X, p2.X);
179         if (p1.Y > p2.Y)
180                 SWAP(s16, p1.Y, p2.Y);
181         if (p1.Z > p2.Z)
182                 SWAP(s16, p1.Z, p2.Z);
183 }
184
185
186 /** Returns \p f wrapped to the range [-360, 360]
187  *
188  *  See test.cpp for example cases.
189  *
190  *  \note This is also used in cases where degrees wrapped to the range [0, 360]
191  *  is innapropriate (e.g. pitch needs negative values)
192  *
193  *  \internal functionally equivalent -- although precision may vary slightly --
194  *  to fmodf((f), 360.0f) however empirical tests indicate that this approach is
195  *  faster.
196  */
197 inline float modulo360f(float f)
198 {
199         int sign;
200         int whole;
201         float fraction;
202
203         if (f < 0) {
204                 f = -f;
205                 sign = -1;
206         } else {
207                 sign = 1;
208         }
209
210         whole = f;
211
212         fraction = f - whole;
213         whole %= 360;
214
215         return sign * (whole + fraction);
216 }
217
218
219 /** Returns \p f wrapped to the range [0, 360]
220   */
221 inline float wrapDegrees_0_360(float f)
222 {
223         float value = modulo360f(f);
224         return value < 0 ? value + 360 : value;
225 }
226
227
228 /** Returns \p f wrapped to the range [-180, 180]
229   */
230 inline float wrapDegrees_180(float f)
231 {
232         float value = modulo360f(f + 180);
233         if (value < 0)
234                 value += 360;
235         return value - 180;
236 }
237
238 /*
239         Pseudo-random (VC++ rand() sucks)
240 */
241 #define MYRAND_RANGE 0xffffffff
242 u32 myrand();
243 void mysrand(unsigned int seed);
244 void myrand_bytes(void *out, size_t len);
245 int myrand_range(int min, int max);
246
247 /*
248         Miscellaneous functions
249 */
250
251 inline u32 get_bits(u32 x, u32 pos, u32 len)
252 {
253         u32 mask = (1 << len) - 1;
254         return (x >> pos) & mask;
255 }
256
257 inline void set_bits(u32 *x, u32 pos, u32 len, u32 val)
258 {
259         u32 mask = (1 << len) - 1;
260         *x &= ~(mask << pos);
261         *x |= (val & mask) << pos;
262 }
263
264 inline u32 calc_parity(u32 v)
265 {
266         v ^= v >> 16;
267         v ^= v >> 8;
268         v ^= v >> 4;
269         v &= 0xf;
270         return (0x6996 >> v) & 1;
271 }
272
273 u64 murmur_hash_64_ua(const void *key, int len, unsigned int seed);
274
275 bool isBlockInSight(v3s16 blockpos_b, v3f camera_pos, v3f camera_dir,
276                 f32 camera_fov, f32 range, f32 *distance_ptr=NULL);
277
278 /*
279         Returns nearest 32-bit integer for given floating point number.
280         <cmath> and <math.h> in VC++ don't provide round().
281 */
282 inline s32 myround(f32 f)
283 {
284         return (s32)(f < 0.f ? (f - 0.5f) : (f + 0.5f));
285 }
286
287 /*
288         Returns integer position of node in given floating point position
289 */
290 inline v3s16 floatToInt(v3f p, f32 d)
291 {
292         v3s16 p2(
293                 (p.X + (p.X>0 ? d/2 : -d/2))/d,
294                 (p.Y + (p.Y>0 ? d/2 : -d/2))/d,
295                 (p.Z + (p.Z>0 ? d/2 : -d/2))/d);
296         return p2;
297 }
298
299 /*
300         Returns floating point position of node in given integer position
301 */
302 inline v3f intToFloat(v3s16 p, f32 d)
303 {
304         v3f p2(
305                 (f32)p.X * d,
306                 (f32)p.Y * d,
307                 (f32)p.Z * d
308         );
309         return p2;
310 }
311
312 // Random helper. Usually d=BS
313 inline core::aabbox3d<f32> getNodeBox(v3s16 p, float d)
314 {
315         return core::aabbox3d<f32>(
316                 (float)p.X * d - 0.5*d,
317                 (float)p.Y * d - 0.5*d,
318                 (float)p.Z * d - 0.5*d,
319                 (float)p.X * d + 0.5*d,
320                 (float)p.Y * d + 0.5*d,
321                 (float)p.Z * d + 0.5*d
322         );
323 }
324
325 class IntervalLimiter
326 {
327 public:
328         IntervalLimiter():
329                 m_accumulator(0)
330         {
331         }
332         /*
333                 dtime: time from last call to this method
334                 wanted_interval: interval wanted
335                 return value:
336                         true: action should be skipped
337                         false: action should be done
338         */
339         bool step(float dtime, float wanted_interval)
340         {
341                 m_accumulator += dtime;
342                 if(m_accumulator < wanted_interval)
343                         return false;
344                 m_accumulator -= wanted_interval;
345                 return true;
346         }
347 protected:
348         float m_accumulator;
349 };
350
351 /*
352         Splits a list into "pages". For example, the list [1,2,3,4,5] split
353         into two pages would be [1,2,3],[4,5]. This function computes the
354         minimum and maximum indices of a single page.
355
356         length: Length of the list that should be split
357         page: Page number, 1 <= page <= pagecount
358         pagecount: The number of pages, >= 1
359         minindex: Receives the minimum index (inclusive).
360         maxindex: Receives the maximum index (exclusive).
361
362         Ensures 0 <= minindex <= maxindex <= length.
363 */
364 inline void paging(u32 length, u32 page, u32 pagecount, u32 &minindex, u32 &maxindex)
365 {
366         if(length < 1 || pagecount < 1 || page < 1 || page > pagecount)
367         {
368                 // Special cases or invalid parameters
369                 minindex = maxindex = 0;
370         }
371         else if(pagecount <= length)
372         {
373                 // Less pages than entries in the list:
374                 // Each page contains at least one entry
375                 minindex = (length * (page-1) + (pagecount-1)) / pagecount;
376                 maxindex = (length * page + (pagecount-1)) / pagecount;
377         }
378         else
379         {
380                 // More pages than entries in the list:
381                 // Make sure the empty pages are at the end
382                 if(page < length)
383                 {
384                         minindex = page-1;
385                         maxindex = page;
386                 }
387                 else
388                 {
389                         minindex = 0;
390                         maxindex = 0;
391                 }
392         }
393 }
394
395 inline float cycle_shift(float value, float by = 0, float max = 1)
396 {
397     if (value + by < 0) return max + by + value;
398     if (value + by > max) return value + by - max;
399     return value + by;
400 }
401
402 inline bool is_power_of_two(u32 n)
403 {
404         return n != 0 && (n & (n-1)) == 0;
405 }
406
407 // Compute next-higher power of 2 efficiently, e.g. for power-of-2 texture sizes.
408 // Public Domain: https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
409 inline u32 npot2(u32 orig) {
410         orig--;
411         orig |= orig >> 1;
412         orig |= orig >> 2;
413         orig |= orig >> 4;
414         orig |= orig >> 8;
415         orig |= orig >> 16;
416         return orig + 1;
417 }
418
419 #endif