]> git.lizzy.rs Git - dragonfireclient.git/blob - src/util/numeric.h
Merge remote branch 'origin/master'
[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 "../irrlichttypes.h"
24 #include "../irr_v2d.h"
25 #include "../irr_v3d.h"
26 #include "../irr_aabb3d.h"
27 #include <irrList.h>
28
29 // Calculate the borders of a "d-radius" cube
30 void getFacePositions(core::list<v3s16> &list, u16 d);
31
32 class IndentationRaiser
33 {
34 public:
35         IndentationRaiser(u16 *indentation)
36         {
37                 m_indentation = indentation;
38                 (*m_indentation)++;
39         }
40         ~IndentationRaiser()
41         {
42                 (*m_indentation)--;
43         }
44 private:
45         u16 *m_indentation;
46 };
47
48 inline s16 getContainerPos(s16 p, s16 d)
49 {
50         return (p>=0 ? p : p-d+1) / d;
51 }
52
53 inline v2s16 getContainerPos(v2s16 p, s16 d)
54 {
55         return v2s16(
56                 getContainerPos(p.X, d),
57                 getContainerPos(p.Y, d)
58         );
59 }
60
61 inline v3s16 getContainerPos(v3s16 p, s16 d)
62 {
63         return v3s16(
64                 getContainerPos(p.X, d),
65                 getContainerPos(p.Y, d),
66                 getContainerPos(p.Z, d)
67         );
68 }
69
70 inline v2s16 getContainerPos(v2s16 p, v2s16 d)
71 {
72         return v2s16(
73                 getContainerPos(p.X, d.X),
74                 getContainerPos(p.Y, d.Y)
75         );
76 }
77
78 inline v3s16 getContainerPos(v3s16 p, v3s16 d)
79 {
80         return v3s16(
81                 getContainerPos(p.X, d.X),
82                 getContainerPos(p.Y, d.Y),
83                 getContainerPos(p.Z, d.Z)
84         );
85 }
86
87 inline bool isInArea(v3s16 p, s16 d)
88 {
89         return (
90                 p.X >= 0 && p.X < d &&
91                 p.Y >= 0 && p.Y < d &&
92                 p.Z >= 0 && p.Z < d
93         );
94 }
95
96 inline bool isInArea(v2s16 p, s16 d)
97 {
98         return (
99                 p.X >= 0 && p.X < d &&
100                 p.Y >= 0 && p.Y < d
101         );
102 }
103
104 inline bool isInArea(v3s16 p, v3s16 d)
105 {
106         return (
107                 p.X >= 0 && p.X < d.X &&
108                 p.Y >= 0 && p.Y < d.Y &&
109                 p.Z >= 0 && p.Z < d.Z
110         );
111 }
112
113 inline s16 rangelim(s16 i, s16 max)
114 {
115         if(i < 0)
116                 return 0;
117         if(i > max)
118                 return max;
119         return i;
120 }
121
122 #define rangelim(d, min, max) ((d) < (min) ? (min) : ((d)>(max)?(max):(d)))
123 #define myfloor(x) ((x) > 0.0 ? (int)(x) : (int)(x) - 1)
124
125 inline v3s16 arealim(v3s16 p, s16 d)
126 {
127         if(p.X < 0)
128                 p.X = 0;
129         if(p.Y < 0)
130                 p.Y = 0;
131         if(p.Z < 0)
132                 p.Z = 0;
133         if(p.X > d-1)
134                 p.X = d-1;
135         if(p.Y > d-1)
136                 p.Y = d-1;
137         if(p.Z > d-1)
138                 p.Z = d-1;
139         return p;
140 }
141
142
143 /*
144         See test.cpp for example cases.
145         wraps degrees to the range of -360...360
146         NOTE: Wrapping to 0...360 is not used because pitch needs negative values.
147 */
148 inline float wrapDegrees(float f)
149 {
150         // Take examples of f=10, f=720.5, f=-0.5, f=-360.5
151         // This results in
152         // 10, 720, -1, -361
153         int i = floor(f);
154         // 0, 2, 0, -1
155         int l = i / 360;
156         // NOTE: This would be used for wrapping to 0...360
157         // 0, 2, -1, -2
158         /*if(i < 0)
159                 l -= 1;*/
160         // 0, 720, 0, -360
161         int k = l * 360;
162         // 10, 0.5, -0.5, -0.5
163         f -= float(k);
164         return f;
165 }
166
167 /* Wrap to 0...360 */
168 inline float wrapDegrees_0_360(float f)
169 {
170         // Take examples of f=10, f=720.5, f=-0.5, f=-360.5
171         // This results in
172         // 10, 720, -1, -361
173         int i = floor(f);
174         // 0, 2, 0, -1
175         int l = i / 360;
176         // Wrap to 0...360
177         // 0, 2, -1, -2
178         if(i < 0)
179                 l -= 1;
180         // 0, 720, 0, -360
181         int k = l * 360;
182         // 10, 0.5, -0.5, -0.5
183         f -= float(k);
184         return f;
185 }
186
187 /* Wrap to -180...180 */
188 inline float wrapDegrees_180(float f)
189 {
190         f += 180;
191         f = wrapDegrees_0_360(f);
192         f -= 180;
193         return f;
194 }
195
196 /*
197         Pseudo-random (VC++ rand() sucks)
198 */
199 int myrand(void);
200 void mysrand(unsigned seed);
201 #define MYRAND_MAX 32767
202
203 int myrand_range(int min, int max);
204
205 /*
206         Miscellaneous functions
207 */
208
209 bool isBlockInSight(v3s16 blockpos_b, v3f camera_pos, v3f camera_dir,
210                 f32 camera_fov, f32 range, f32 *distance_ptr=NULL);
211
212 /*
213         Some helper stuff
214 */
215 #define MYMIN(a,b) ((a)<(b)?(a):(b))
216 #define MYMAX(a,b) ((a)>(b)?(a):(b))
217
218 /*
219         Returns nearest 32-bit integer for given floating point number.
220         <cmath> and <math.h> in VC++ don't provide round().
221 */
222 inline s32 myround(f32 f)
223 {
224         return floor(f + 0.5);
225 }
226
227 /*
228         Returns integer position of node in given floating point position
229 */
230 inline v3s16 floatToInt(v3f p, f32 d)
231 {
232         v3s16 p2(
233                 (p.X + (p.X>0 ? d/2 : -d/2))/d,
234                 (p.Y + (p.Y>0 ? d/2 : -d/2))/d,
235                 (p.Z + (p.Z>0 ? d/2 : -d/2))/d);
236         return p2;
237 }
238
239 /*
240         Returns floating point position of node in given integer position
241 */
242 inline v3f intToFloat(v3s16 p, f32 d)
243 {
244         v3f p2(
245                 (f32)p.X * d,
246                 (f32)p.Y * d,
247                 (f32)p.Z * d
248         );
249         return p2;
250 }
251
252 // Random helper. Usually d=BS
253 inline core::aabbox3d<f32> getNodeBox(v3s16 p, float d)
254 {
255         return core::aabbox3d<f32>(
256                 (float)p.X * d - 0.5*d,
257                 (float)p.Y * d - 0.5*d,
258                 (float)p.Z * d - 0.5*d,
259                 (float)p.X * d + 0.5*d,
260                 (float)p.Y * d + 0.5*d,
261                 (float)p.Z * d + 0.5*d
262         );
263 }
264
265 class IntervalLimiter
266 {
267 public:
268         IntervalLimiter():
269                 m_accumulator(0)
270         {
271         }
272         /*
273                 dtime: time from last call to this method
274                 wanted_interval: interval wanted
275                 return value:
276                         true: action should be skipped
277                         false: action should be done
278         */
279         bool step(float dtime, float wanted_interval)
280         {
281                 m_accumulator += dtime;
282                 if(m_accumulator < wanted_interval)
283                         return false;
284                 m_accumulator -= wanted_interval;
285                 return true;
286         }
287 protected:
288         float m_accumulator;
289 };
290
291 /*
292         Splits a list into "pages". For example, the list [1,2,3,4,5] split
293         into two pages would be [1,2,3],[4,5]. This function computes the
294         minimum and maximum indices of a single page.
295
296         length: Length of the list that should be split
297         page: Page number, 1 <= page <= pagecount
298         pagecount: The number of pages, >= 1
299         minindex: Receives the minimum index (inclusive).
300         maxindex: Receives the maximum index (exclusive).
301
302         Ensures 0 <= minindex <= maxindex <= length.
303 */
304 inline void paging(u32 length, u32 page, u32 pagecount, u32 &minindex, u32 &maxindex)
305 {
306         if(length < 1 || pagecount < 1 || page < 1 || page > pagecount)
307         {
308                 // Special cases or invalid parameters
309                 minindex = maxindex = 0;
310         }
311         else if(pagecount <= length)
312         {
313                 // Less pages than entries in the list:
314                 // Each page contains at least one entry
315                 minindex = (length * (page-1) + (pagecount-1)) / pagecount;
316                 maxindex = (length * page + (pagecount-1)) / pagecount;
317         }
318         else
319         {
320                 // More pages than entries in the list:
321                 // Make sure the empty pages are at the end
322                 if(page < length)
323                 {
324                         minindex = page-1;
325                         maxindex = page;
326                 }
327                 else
328                 {
329                         minindex = 0;
330                         maxindex = 0;
331                 }
332         }
333 }
334
335 #endif
336