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