51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-#ifndef UTIL_NUMERIC_HEADER
-#define UTIL_NUMERIC_HEADER
+#pragma once
+#include "basic_macros.h"
#include "../irrlichttypes.h"
#include "../irr_v2d.h"
#include "../irr_v3d.h"
#include "../irr_aabb3d.h"
-#include <list>
-#include <algorithm>
-// Calculate the borders of a "d-radius" cube
-void getFacePositions(std::list<v3s16> &list, u16 d);
+#define rangelim(d, min, max) ((d) < (min) ? (min) : ((d) > (max) ? (max) : (d)))
+#define myfloor(x) ((x) < 0.0 ? (int)(x) - 1 : (int)(x))
+// The naive swap performs better than the xor version
+#define SWAP(t, x, y) do { \
+ t temp = x; \
+ x = y; \
+ y = temp; \
+} while (0)
-class IndentationRaiser
-{
-public:
- IndentationRaiser(u16 *indentation)
- {
- m_indentation = indentation;
- (*m_indentation)++;
- }
- ~IndentationRaiser()
- {
- (*m_indentation)--;
- }
-private:
- u16 *m_indentation;
-};
inline s16 getContainerPos(s16 p, s16 d)
{
- return (p>=0 ? p : p-d+1) / d;
+ return (p >= 0 ? p : p - d + 1) / d;
}
inline v2s16 getContainerPos(v2s16 p, s16 d)
);
}
-#define rangelim(d, min, max) ((d) < (min) ? (min) : ((d)>(max)?(max):(d)))
-#define myfloor(x) ((x) > 0.0 ? (int)(x) : (int)(x) - 1)
-
-inline v3s16 arealim(v3s16 p, s16 d)
-{
- if(p.X < 0)
- p.X = 0;
- if(p.Y < 0)
- p.Y = 0;
- if(p.Z < 0)
- p.Z = 0;
- if(p.X > d-1)
- p.X = d-1;
- if(p.Y > d-1)
- p.Y = d-1;
- if(p.Z > d-1)
- p.Z = d-1;
- return p;
-}
-
-#define ARRLEN(x) (sizeof(x) / sizeof((x)[0]))
-#define CONTAINS(c, v) (std::find((c).begin(), (c).end(), (v)) != (c).end())
-
-// The naive swap performs better than the xor version
-#define SWAP(t, x, y) do { \
- t temp = x; \
- x = y; \
- y = temp; \
-} while (0)
-
inline void sortBoxVerticies(v3s16 &p1, v3s16 &p2) {
if (p1.X > p2.X)
SWAP(s16, p1.X, p2.X);
SWAP(s16, p1.Z, p2.Z);
}
+inline v3s16 componentwise_min(const v3s16 &a, const v3s16 &b)
+{
+ return v3s16(MYMIN(a.X, b.X), MYMIN(a.Y, b.Y), MYMIN(a.Z, b.Z));
+}
-/*
- See test.cpp for example cases.
- wraps degrees to the range of -360...360
- NOTE: Wrapping to 0...360 is not used because pitch needs negative values.
-*/
-inline float wrapDegrees(float f)
+inline v3s16 componentwise_max(const v3s16 &a, const v3s16 &b)
{
- // Take examples of f=10, f=720.5, f=-0.5, f=-360.5
- // This results in
- // 10, 720, -1, -361
- int i = floor(f);
- // 0, 2, 0, -1
- int l = i / 360;
- // NOTE: This would be used for wrapping to 0...360
- // 0, 2, -1, -2
- /*if(i < 0)
- l -= 1;*/
- // 0, 720, 0, -360
- int k = l * 360;
- // 10, 0.5, -0.5, -0.5
- f -= float(k);
- return f;
+ return v3s16(MYMAX(a.X, b.X), MYMAX(a.Y, b.Y), MYMAX(a.Z, b.Z));
+}
+
+
+/** Returns \p f wrapped to the range [-360, 360]
+ *
+ * See test.cpp for example cases.
+ *
+ * \note This is also used in cases where degrees wrapped to the range [0, 360]
+ * is innapropriate (e.g. pitch needs negative values)
+ *
+ * \internal functionally equivalent -- although precision may vary slightly --
+ * to fmodf((f), 360.0f) however empirical tests indicate that this approach is
+ * faster.
+ */
+inline float modulo360f(float f)
+{
+ int sign;
+ int whole;
+ float fraction;
+
+ if (f < 0) {
+ f = -f;
+ sign = -1;
+ } else {
+ sign = 1;
+ }
+
+ whole = f;
+
+ fraction = f - whole;
+ whole %= 360;
+
+ return sign * (whole + fraction);
}
-/* Wrap to 0...360 */
+
+/** Returns \p f wrapped to the range [0, 360]
+ */
inline float wrapDegrees_0_360(float f)
{
- // Take examples of f=10, f=720.5, f=-0.5, f=-360.5
- // This results in
- // 10, 720, -1, -361
- int i = floor(f);
- // 0, 2, 0, -1
- int l = i / 360;
- // Wrap to 0...360
- // 0, 2, -1, -2
- if(i < 0)
- l -= 1;
- // 0, 720, 0, -360
- int k = l * 360;
- // 10, 0.5, -0.5, -0.5
- f -= float(k);
- return f;
+ float value = modulo360f(f);
+ return value < 0 ? value + 360 : value;
}
-/* Wrap to -180...180 */
+
+/** Returns \p f wrapped to the range [-180, 180]
+ */
inline float wrapDegrees_180(float f)
{
- f += 180;
- f = wrapDegrees_0_360(f);
- f -= 180;
- return f;
+ float value = modulo360f(f + 180);
+ if (value < 0)
+ value += 360;
+ return value - 180;
}
/*
Pseudo-random (VC++ rand() sucks)
*/
-int myrand(void);
-void mysrand(unsigned seed);
-#define MYRAND_MAX 32767
-
+#define MYRAND_RANGE 0xffffffff
+u32 myrand();
+void mysrand(unsigned int seed);
+void myrand_bytes(void *out, size_t len);
int myrand_range(int min, int max);
/*
Miscellaneous functions
*/
+inline u32 get_bits(u32 x, u32 pos, u32 len)
+{
+ u32 mask = (1 << len) - 1;
+ return (x >> pos) & mask;
+}
+
+inline void set_bits(u32 *x, u32 pos, u32 len, u32 val)
+{
+ u32 mask = (1 << len) - 1;
+ *x &= ~(mask << pos);
+ *x |= (val & mask) << pos;
+}
+
+inline u32 calc_parity(u32 v)
+{
+ v ^= v >> 16;
+ v ^= v >> 8;
+ v ^= v >> 4;
+ v &= 0xf;
+ return (0x6996 >> v) & 1;
+}
+
u64 murmur_hash_64_ua(const void *key, int len, unsigned int seed);
bool isBlockInSight(v3s16 blockpos_b, v3f camera_pos, v3f camera_dir,
f32 camera_fov, f32 range, f32 *distance_ptr=NULL);
-/*
- Some helper stuff
-*/
-#define MYMIN(a,b) ((a)<(b)?(a):(b))
-#define MYMAX(a,b) ((a)>(b)?(a):(b))
-
/*
Returns nearest 32-bit integer for given floating point number.
<cmath> and <math.h> in VC++ don't provide round().
*/
inline s32 myround(f32 f)
{
- return floor(f + 0.5);
+ return (s32)(f < 0.f ? (f - 0.5f) : (f + 0.5f));
}
/*
*/
inline v3s16 floatToInt(v3f p, f32 d)
{
- v3s16 p2(
- (p.X + (p.X>0 ? d/2 : -d/2))/d,
- (p.Y + (p.Y>0 ? d/2 : -d/2))/d,
- (p.Z + (p.Z>0 ? d/2 : -d/2))/d);
- return p2;
+ return v3s16(
+ (p.X + (p.X > 0 ? d / 2 : -d / 2)) / d,
+ (p.Y + (p.Y > 0 ? d / 2 : -d / 2)) / d,
+ (p.Z + (p.Z > 0 ? d / 2 : -d / 2)) / d);
}
/*
*/
inline v3f intToFloat(v3s16 p, f32 d)
{
- v3f p2(
+ return v3f(
(f32)p.X * d,
(f32)p.Y * d,
(f32)p.Z * d
);
- return p2;
}
// Random helper. Usually d=BS
-inline core::aabbox3d<f32> getNodeBox(v3s16 p, float d)
+inline aabb3f getNodeBox(v3s16 p, float d)
{
- return core::aabbox3d<f32>(
- (float)p.X * d - 0.5*d,
- (float)p.Y * d - 0.5*d,
- (float)p.Z * d - 0.5*d,
- (float)p.X * d + 0.5*d,
- (float)p.Y * d + 0.5*d,
- (float)p.Z * d + 0.5*d
+ return aabb3f(
+ (float)p.X * d - 0.5f * d,
+ (float)p.Y * d - 0.5f * d,
+ (float)p.Z * d - 0.5f * d,
+ (float)p.X * d + 0.5f * d,
+ (float)p.Y * d + 0.5f * d,
+ (float)p.Z * d + 0.5f * d
);
}
+
class IntervalLimiter
{
public:
- IntervalLimiter():
- m_accumulator(0)
- {
- }
+ IntervalLimiter() = default;
+
/*
dtime: time from last call to this method
wanted_interval: interval wanted
bool step(float dtime, float wanted_interval)
{
m_accumulator += dtime;
- if(m_accumulator < wanted_interval)
+ if (m_accumulator < wanted_interval)
return false;
m_accumulator -= wanted_interval;
return true;
}
-protected:
- float m_accumulator;
+
+private:
+ float m_accumulator = 0.0f;
};
+
/*
Splits a list into "pages". For example, the list [1,2,3,4,5] split
into two pages would be [1,2,3],[4,5]. This function computes the
*/
inline void paging(u32 length, u32 page, u32 pagecount, u32 &minindex, u32 &maxindex)
{
- if(length < 1 || pagecount < 1 || page < 1 || page > pagecount)
- {
+ if (length < 1 || pagecount < 1 || page < 1 || page > pagecount) {
// Special cases or invalid parameters
minindex = maxindex = 0;
- }
- else if(pagecount <= length)
- {
+ } else if(pagecount <= length) {
// Less pages than entries in the list:
// Each page contains at least one entry
minindex = (length * (page-1) + (pagecount-1)) / pagecount;
maxindex = (length * page + (pagecount-1)) / pagecount;
- }
- else
- {
+ } else {
// More pages than entries in the list:
// Make sure the empty pages are at the end
- if(page < length)
- {
+ if (page < length) {
minindex = page-1;
maxindex = page;
- }
- else
- {
+ } else {
minindex = 0;
maxindex = 0;
}
inline float cycle_shift(float value, float by = 0, float max = 1)
{
- if (value + by < 0) return max + by + value;
+ if (value + by < 0) return value + by + max;
if (value + by > max) return value + by - max;
return value + by;
}
inline bool is_power_of_two(u32 n)
{
- return n != 0 && (n & (n-1)) == 0;
+ return n != 0 && (n & (n - 1)) == 0;
}
-#endif
-
+// Compute next-higher power of 2 efficiently, e.g. for power-of-2 texture sizes.
+// Public Domain: https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
+inline u32 npot2(u32 orig) {
+ orig--;
+ orig |= orig >> 1;
+ orig |= orig >> 2;
+ orig |= orig >> 4;
+ orig |= orig >> 8;
+ orig |= orig >> 16;
+ return orig + 1;
+}