]> git.lizzy.rs Git - dragonfireclient.git/blob - src/util/numeric.h
5ed4d0e999d1fc03e987d9dd109534a04027b944
[dragonfireclient.git] / src / util / numeric.h
1 /*
2 Minetest-c55
3 Copyright (C) 2010-2012 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
124 inline v3s16 arealim(v3s16 p, s16 d)
125 {
126         if(p.X < 0)
127                 p.X = 0;
128         if(p.Y < 0)
129                 p.Y = 0;
130         if(p.Z < 0)
131                 p.Z = 0;
132         if(p.X > d-1)
133                 p.X = d-1;
134         if(p.Y > d-1)
135                 p.Y = d-1;
136         if(p.Z > d-1)
137                 p.Z = d-1;
138         return p;
139 }
140
141
142 /*
143         See test.cpp for example cases.
144         wraps degrees to the range of -360...360
145         NOTE: Wrapping to 0...360 is not used because pitch needs negative values.
146 */
147 inline float wrapDegrees(float f)
148 {
149         // Take examples of f=10, f=720.5, f=-0.5, f=-360.5
150         // This results in
151         // 10, 720, -1, -361
152         int i = floor(f);
153         // 0, 2, 0, -1
154         int l = i / 360;
155         // NOTE: This would be used for wrapping to 0...360
156         // 0, 2, -1, -2
157         /*if(i < 0)
158                 l -= 1;*/
159         // 0, 720, 0, -360
160         int k = l * 360;
161         // 10, 0.5, -0.5, -0.5
162         f -= float(k);
163         return f;
164 }
165
166 /* Wrap to 0...360 */
167 inline float wrapDegrees_0_360(float f)
168 {
169         // Take examples of f=10, f=720.5, f=-0.5, f=-360.5
170         // This results in
171         // 10, 720, -1, -361
172         int i = floor(f);
173         // 0, 2, 0, -1
174         int l = i / 360;
175         // Wrap to 0...360
176         // 0, 2, -1, -2
177         if(i < 0)
178                 l -= 1;
179         // 0, 720, 0, -360
180         int k = l * 360;
181         // 10, 0.5, -0.5, -0.5
182         f -= float(k);
183         return f;
184 }
185
186 /* Wrap to -180...180 */
187 inline float wrapDegrees_180(float f)
188 {
189         f += 180;
190         f = wrapDegrees_0_360(f);
191         f -= 180;
192         return f;
193 }
194
195 /*
196         Pseudo-random (VC++ rand() sucks)
197 */
198 int myrand(void);
199 void mysrand(unsigned seed);
200 #define MYRAND_MAX 32767
201
202 int myrand_range(int min, int max);
203
204 /*
205         Miscellaneous functions
206 */
207
208 bool isBlockInSight(v3s16 blockpos_b, v3f camera_pos, v3f camera_dir,
209                 f32 camera_fov, f32 range, f32 *distance_ptr=NULL);
210
211 /*
212         Some helper stuff
213 */
214 #define MYMIN(a,b) ((a)<(b)?(a):(b))
215 #define MYMAX(a,b) ((a)>(b)?(a):(b))
216
217 /*
218         Returns nearest 32-bit integer for given floating point number.
219         <cmath> and <math.h> in VC++ don't provide round().
220 */
221 inline s32 myround(f32 f)
222 {
223         return floor(f + 0.5);
224 }
225
226 /*
227         Returns integer position of node in given floating point position
228 */
229 inline v3s16 floatToInt(v3f p, f32 d)
230 {
231         v3s16 p2(
232                 (p.X + (p.X>0 ? d/2 : -d/2))/d,
233                 (p.Y + (p.Y>0 ? d/2 : -d/2))/d,
234                 (p.Z + (p.Z>0 ? d/2 : -d/2))/d);
235         return p2;
236 }
237
238 /*
239         Returns floating point position of node in given integer position
240 */
241 inline v3f intToFloat(v3s16 p, f32 d)
242 {
243         v3f p2(
244                 (f32)p.X * d,
245                 (f32)p.Y * d,
246                 (f32)p.Z * d
247         );
248         return p2;
249 }
250
251 // Random helper. Usually d=BS
252 inline core::aabbox3d<f32> getNodeBox(v3s16 p, float d)
253 {
254         return core::aabbox3d<f32>(
255                 (float)p.X * d - 0.5*d,
256                 (float)p.Y * d - 0.5*d,
257                 (float)p.Z * d - 0.5*d,
258                 (float)p.X * d + 0.5*d,
259                 (float)p.Y * d + 0.5*d,
260                 (float)p.Z * d + 0.5*d
261         );
262 }
263
264 class IntervalLimiter
265 {
266 public:
267         IntervalLimiter():
268                 m_accumulator(0)
269         {
270         }
271         /*
272                 dtime: time from last call to this method
273                 wanted_interval: interval wanted
274                 return value:
275                         true: action should be skipped
276                         false: action should be done
277         */
278         bool step(float dtime, float wanted_interval)
279         {
280                 m_accumulator += dtime;
281                 if(m_accumulator < wanted_interval)
282                         return false;
283                 m_accumulator -= wanted_interval;
284                 return true;
285         }
286 protected:
287         float m_accumulator;
288 };
289
290 /*
291         Splits a list into "pages". For example, the list [1,2,3,4,5] split
292         into two pages would be [1,2,3],[4,5]. This function computes the
293         minimum and maximum indices of a single page.
294
295         length: Length of the list that should be split
296         page: Page number, 1 <= page <= pagecount
297         pagecount: The number of pages, >= 1
298         minindex: Receives the minimum index (inclusive).
299         maxindex: Receives the maximum index (exclusive).
300
301         Ensures 0 <= minindex <= maxindex <= length.
302 */
303 inline void paging(u32 length, u32 page, u32 pagecount, u32 &minindex, u32 &maxindex)
304 {
305         if(length < 1 || pagecount < 1 || page < 1 || page > pagecount)
306         {
307                 // Special cases or invalid parameters
308                 minindex = maxindex = 0;
309         }
310         else if(pagecount <= length)
311         {
312                 // Less pages than entries in the list:
313                 // Each page contains at least one entry
314                 minindex = (length * (page-1) + (pagecount-1)) / pagecount;
315                 maxindex = (length * page + (pagecount-1)) / pagecount;
316         }
317         else
318         {
319                 // More pages than entries in the list:
320                 // Make sure the empty pages are at the end
321                 if(page < length)
322                 {
323                         minindex = page-1;
324                         maxindex = page;
325                 }
326                 else
327                 {
328                         minindex = 0;
329                         maxindex = 0;
330                 }
331         }
332 }
333
334 #endif
335