X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;ds=sidebyside;f=src%2Futil%2Fnumeric.h;h=32a6f4312b04abc975a96021912fff965f8502de;hb=e16a470d59069692d654f5c1529ab313a01ded67;hp=3e82997bd98dca58bbafa715b4ddf4cb83a32159;hpb=c1b829077a3518f3a129eee11887b2358a53f20b;p=minetest.git diff --git a/src/util/numeric.h b/src/util/numeric.h index 3e82997bd..32a6f4312 100644 --- a/src/util/numeric.h +++ b/src/util/numeric.h @@ -17,38 +17,33 @@ with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#ifndef UTIL_NUMERIC_HEADER -#define UTIL_NUMERIC_HEADER - -#include "../irrlichttypes.h" -#include "../irr_v2d.h" -#include "../irr_v3d.h" -#include "../irr_aabb3d.h" -#include -#include +#pragma once + +#include "basic_macros.h" +#include "constants.h" +#include "irrlichttypes.h" +#include "irr_v2d.h" +#include "irr_v3d.h" +#include "irr_aabb3d.h" +#include "SColor.h" +#include + +#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) -// Calculate the borders of a "d-radius" cube -void getFacePositions(std::list &list, u16 d); - -class IndentationRaiser -{ -public: - IndentationRaiser(u16 *indentation) - { - m_indentation = indentation; - (*m_indentation)++; - } - ~IndentationRaiser() - { - (*m_indentation)--; - } -private: - u16 *m_indentation; -}; +// Maximum radius of a block. The magic number is +// sqrt(3.0) / 2.0 in literal form. +static constexpr const f32 BLOCK_MAX_RADIUS = 0.866025403784f * MAP_BLOCKSIZE * BS; 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) @@ -85,6 +80,26 @@ inline v3s16 getContainerPos(v3s16 p, v3s16 d) ); } +inline void getContainerPosWithOffset(s16 p, s16 d, s16 &container, s16 &offset) +{ + container = (p >= 0 ? p : p - d + 1) / d; + offset = p & (d - 1); +} + +inline void getContainerPosWithOffset(const v2s16 &p, s16 d, v2s16 &container, v2s16 &offset) +{ + getContainerPosWithOffset(p.X, d, container.X, offset.X); + getContainerPosWithOffset(p.Y, d, container.Y, offset.Y); +} + +inline void getContainerPosWithOffset(const v3s16 &p, s16 d, v3s16 &container, v3s16 &offset) +{ + getContainerPosWithOffset(p.X, d, container.X, offset.X); + getContainerPosWithOffset(p.Y, d, container.Y, offset.Y); + getContainerPosWithOffset(p.Z, d, container.Z, offset.Z); +} + + inline bool isInArea(v3s16 p, s16 d) { return ( @@ -111,42 +126,6 @@ inline bool isInArea(v3s16 p, v3s16 d) ); } -inline s16 rangelim(s16 i, s16 max) -{ - if(i < 0) - return 0; - if(i > max) - return max; - return i; -} - -#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; -} - -// 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); @@ -156,81 +135,127 @@ inline void sortBoxVerticies(v3s16 &p1, v3s16 &p2) { 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)); +} + +inline v3s16 componentwise_max(const v3s16 &a, const v3s16 &b) +{ + return v3s16(MYMAX(a.X, b.X), MYMAX(a.Y, b.Y), MYMAX(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) -{ - // 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; -} - -/* Wrap to 0...360 */ + +/** 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); +} + + +/** 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; -} - -/* Wrap to -180...180 */ + float value = modulo360f(f); + return value < 0 ? value + 360 : value; +} + + +/** Returns \p v3f wrapped to the range [0, 360] + */ +inline v3f wrapDegrees_0_360_v3f(v3f v) +{ + v3f value_v3f; + value_v3f.X = modulo360f(v.X); + value_v3f.Y = modulo360f(v.Y); + value_v3f.Z = modulo360f(v.Z); + + // Now that values are wrapped, use to get values for certain ranges + value_v3f.X = value_v3f.X < 0 ? value_v3f.X + 360 : value_v3f.X; + value_v3f.Y = value_v3f.Y < 0 ? value_v3f.Y + 360 : value_v3f.Y; + value_v3f.Z = value_v3f.Z < 0 ? value_v3f.Z + 360 : value_v3f.Z; + return value_v3f; +} + + +/** 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)) +s16 adjustDist(s16 dist, float zoom_fov); /* Returns nearest 32-bit integer for given floating point number. @@ -238,7 +263,12 @@ bool isBlockInSight(v3s16 blockpos_b, v3f camera_pos, v3f camera_dir, */ inline s32 myround(f32 f) { - return floor(f + 0.5); + return (s32)(f < 0.f ? (f - 0.5f) : (f + 0.5f)); +} + +inline constexpr f32 sqr(f32 f) +{ + return f * f; } /* @@ -246,11 +276,21 @@ inline s32 myround(f32 f) */ 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); +} + +/* + Returns integer position of node in given double precision position + */ +inline v3s16 doubleToInt(v3d p, double d) +{ + 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); } /* @@ -258,34 +298,32 @@ inline v3s16 floatToInt(v3f p, f32 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 getNodeBox(v3s16 p, float d) -{ - return core::aabbox3d( - (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 +inline aabb3f getNodeBox(v3s16 p, float 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 @@ -296,15 +334,17 @@ class IntervalLimiter 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 @@ -320,34 +360,89 @@ class IntervalLimiter */ 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; } } } -#endif +inline float cycle_shift(float value, float by = 0, float max = 1) +{ + 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; +} + +// 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; +} + +// Gradual steps towards the target value in a wrapped (circular) system +// using the shorter of both ways +template +inline void wrappedApproachShortest(T ¤t, const T target, const T stepsize, + const T maximum) +{ + T delta = target - current; + if (delta < 0) + delta += maximum; + + if (delta > stepsize && maximum - delta > stepsize) { + current += (delta < maximum / 2) ? stepsize : -stepsize; + if (current >= maximum) + current -= maximum; + } else { + current = target; + } +} + +void setPitchYawRollRad(core::matrix4 &m, const v3f &rot); + +inline void setPitchYawRoll(core::matrix4 &m, const v3f &rot) +{ + setPitchYawRollRad(m, rot * core::DEGTORAD64); +} + +v3f getPitchYawRollRad(const core::matrix4 &m); +inline v3f getPitchYawRoll(const core::matrix4 &m) +{ + return getPitchYawRollRad(m) * core::RADTODEG64; +} + +// Muliply the RGB value of a color linearly, and clamp to black/white +inline irr::video::SColor multiplyColorValue(const irr::video::SColor &color, float mod) +{ + return irr::video::SColor(color.getAlpha(), + core::clamp(color.getRed() * mod, 0, 255), + core::clamp(color.getGreen() * mod, 0, 255), + core::clamp(color.getBlue() * mod, 0, 255)); +}