/* * Minetest * Copyright (C) 2010-2014 celeron55, Perttu Ahola * Copyright (C) 2010-2014 kwolekr, Ryan Kwolek * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include "noise.h" #include #include // memset #include "debug.h" #include "util/numeric.h" #include "util/string.h" #include "exceptions.h" #define NOISE_MAGIC_X 1619 #define NOISE_MAGIC_Y 31337 #define NOISE_MAGIC_Z 52591 #define NOISE_MAGIC_SEED 1013 typedef float (*Interp2dFxn)( float v00, float v10, float v01, float v11, float x, float y); typedef float (*Interp3dFxn)( float v000, float v100, float v010, float v110, float v001, float v101, float v011, float v111, float x, float y, float z); float cos_lookup[16] = { 1.0, 0.9238, 0.7071, 0.3826, 0, -0.3826, -0.7071, -0.9238, 1.0, -0.9238, -0.7071, -0.3826, 0, 0.3826, 0.7071, 0.9238 }; FlagDesc flagdesc_noiseparams[] = { {"defaults", NOISE_FLAG_DEFAULTS}, {"eased", NOISE_FLAG_EASED}, {"absvalue", NOISE_FLAG_ABSVALUE}, {"pointbuffer", NOISE_FLAG_POINTBUFFER}, {"simplex", NOISE_FLAG_SIMPLEX}, {NULL, 0} }; /////////////////////////////////////////////////////////////////////////////// PcgRandom::PcgRandom(u64 state, u64 seq) { seed(state, seq); } void PcgRandom::seed(u64 state, u64 seq) { m_state = 0U; m_inc = (seq << 1u) | 1u; next(); m_state += state; next(); } u32 PcgRandom::next() { u64 oldstate = m_state; m_state = oldstate * 6364136223846793005ULL + m_inc; u32 xorshifted = ((oldstate >> 18u) ^ oldstate) >> 27u; u32 rot = oldstate >> 59u; return (xorshifted >> rot) | (xorshifted << ((-rot) & 31)); } u32 PcgRandom::range(u32 bound) { /* If the bound is not a multiple of the RNG's range, it may cause bias, e.g. a RNG has a range from 0 to 3 and we take want a number 0 to 2. Using rand() % 3, the number 0 would be twice as likely to appear. With a very large RNG range, the effect becomes less prevalent but still present. This can be solved by modifying the range of the RNG to become a multiple of bound by dropping values above the a threshhold. In our example, threshhold == 4 - 3 = 1 % 3 == 1, so reject 0, thus making the range 3 with no bias. This loop looks dangerous, but will always terminate due to the RNG's property of uniformity. */ u32 threshhold = -bound % bound; u32 r; while ((r = next()) < threshhold) ; return r % bound; } s32 PcgRandom::range(s32 min, s32 max) { if (max < min) throw PrngException("Invalid range (max < min)"); u32 bound = max - min + 1; return range(bound) + min; } void PcgRandom::bytes(void *out, size_t len) { u8 *outb = (u8 *)out; int bytes_left = 0; u32 r; while (len--) { if (bytes_left == 0) { bytes_left = sizeof(u32); r = next(); } *outb = r & 0xFF; outb++; bytes_left--; r >>= 8; } } s32 PcgRandom::randNormalDist(s32 min, s32 max, int num_trials) { s32 accum = 0; for (int i = 0; i != num_trials; i++) accum += range(min, max); return myround((float)accum / num_trials); } /////////////////////////////////////////////////////////////////////////////// float noise2d(int x, int y, int seed) { int n = (NOISE_MAGIC_X * x + NOISE_MAGIC_Y * y + NOISE_MAGIC_SEED * seed) & 0x7fffffff; n = (n >> 13) ^ n; n = (n * (n * n * 60493 + 19990303) + 1376312589) & 0x7fffffff; return 1.f - (float)n / 0x40000000; } float noise3d(int x, int y, int z, int seed) { int n = (NOISE_MAGIC_X * x + NOISE_MAGIC_Y * y + NOISE_MAGIC_Z * z + NOISE_MAGIC_SEED * seed) & 0x7fffffff; n = (n >> 13) ^ n; n = (n * (n * n * 60493 + 19990303) + 1376312589) & 0x7fffffff; return 1.f - (float)n / 0x40000000; } inline float dotProduct(float vx, float vy, float wx, float wy) { return vx * wx + vy * wy; } inline float linearInterpolation(float v0, float v1, float t) { return v0 + (v1 - v0) * t; } inline float biLinearInterpolation( float v00, float v10, float v01, float v11, float x, float y) { float tx = easeCurve(x); float ty = easeCurve(y); #if 0 return ( v00 * (1 - tx) * (1 - ty) + v10 * tx * (1 - ty) + v01 * (1 - tx) * ty + v11 * tx * ty ); #endif float u = linearInterpolation(v00, v10, tx); float v = linearInterpolation(v01, v11, tx); return linearInterpolation(u, v, ty); } inline float biLinearInterpolationNoEase( float v00, float v10, float v01, float v11, float x, float y) { float u = linearInterpolation(v00, v10, x); float v = linearInterpolation(v01, v11, x); return linearInterpolation(u, v, y); } float triLinearInterpolation( float v000, float v100, float v010, float v110, float v001, float v101, float v011, float v111, float x, float y, float z) { float tx = easeCurve(x); float ty = easeCurve(y); float tz = easeCurve(z); #if 0 return ( v000 * (1 - tx) * (1 - ty) * (1 - tz) + v100 * tx * (1 - ty) * (1 - tz) + v010 * (1 - tx) * ty * (1 - tz) + v110 * tx * ty * (1 - tz) + v001 * (1 - tx) * (1 - ty) * tz + v101 * tx * (1 - ty) * tz + v011 * (1 - tx) * ty * tz + v111 * tx * ty * tz ); #endif float u = biLinearInterpolationNoEase(v000, v100, v010, v110, tx, ty); float v = biLinearInterpolationNoEase(v001, v101, v011, v111, tx, ty); return linearInterpolation(u, v, tz); } float triLinearInterpolationNoEase( float v000, float v100, float v010, float v110, float v001, float v101, float v011, float v111, float x, float y, float z) { float u = biLinearInterpolationNoEase(v000, v100, v010, v110, x, y); float v = biLinearInterpolationNoEase(v001, v101, v011, v111, x, y); return linearInterpolation(u, v, z); } #if 0 float noise2d_gradient(float x, float y, int seed) { // Calculate the integer coordinates int x0 = (x > 0.0 ? (int)x : (int)x - 1); int y0 = (y > 0.0 ? (int)y : (int)y - 1); // Calculate the remaining part of the coordinates float xl = x - (float)x0; float yl = y - (float)y0; // Calculate random cosine lookup table indices for the integer corners. // They are looked up as unit vector gradients from the lookup table. int n00 = (int)((noise2d(x0, y0, seed)+1)*8); int n10 = (int)((noise2d(x0+1, y0, seed)+1)*8); int n01 = (int)((noise2d(x0, y0+1, seed)+1)*8); int n11 = (int)((noise2d(x0+1, y0+1, seed)+1)*8); // Make a dot product for the gradients and the positions, to get the values float s = dotProduct(cos_lookup[n00], cos_lookup[(n00+12)%16], xl, yl); float u = dotProduct(-cos_lookup[n10], cos_lookup[(n10+12)%16], 1.-xl, yl); float v = dotProduct(cos_lookup[n01], -cos_lookup[(n01+12)%16], xl, 1.-yl); float w = dotProduct(-cos_lookup[n11], -cos_lookup[(n11+12)%16], 1.-xl, 1.-yl); // Interpolate between the values return biLinearInterpolation(s,u,v,w,xl,yl); } #endif float noise2d_gradient(float x, float y, int seed, bool eased) { // Calculate the integer coordinates int x0 = myfloor(x); int y0 = myfloor(y); // Calculate the remaining part of the coordinates float xl = x - (float)x0; float yl = y - (float)y0; // Get values for corners of square float v00 = noise2d(x0, y0, seed); float v10 = noise2d(x0+1, y0, seed); float v01 = noise2d(x0, y0+1, seed); float v11 = noise2d(x0+1, y0+1, seed); // Interpolate if (eased) return biLinearInterpolation(v00, v10, v01, v11, xl, yl); else return biLinearInterpolationNoEase(v00, v10, v01, v11, xl, yl); } float noise3d_gradient(float x, float y Minetest Copyright (C) 2016 est31, <MTest31@outlook.com> This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #pragma once #include "irrlichttypes_extrabloated.h" #include "keys.h" #include <bitset> #include <vector> enum JoystickAxis { JA_SIDEWARD_MOVE, JA_FORWARD_MOVE, JA_FRUSTUM_HORIZONTAL, JA_FRUSTUM_VERTICAL, // To know the count of enum values JA_COUNT, }; struct JoystickAxisLayout { u16 axis_id; // -1 if to invert, 1 if to keep it. int invert; }; struct JoystickCombination { virtual bool isTriggered(const irr::SEvent::SJoystickEvent &ev) const=0; GameKeyType key; }; struct JoystickButtonCmb : public JoystickCombination { JoystickButtonCmb() = default; JoystickButtonCmb(GameKeyType key, u32 filter_mask, u32 compare_mask) : filter_mask(filter_mask), compare_mask(compare_mask) { this->key = key; } virtual ~JoystickButtonCmb() = default; virtual bool isTriggered(const irr::SEvent::SJoystickEvent &ev) const; u32 filter_mask; u32 compare_mask; }; struct JoystickAxisCmb : public JoystickCombination { JoystickAxisCmb() = default; JoystickAxisCmb(GameKeyType key, u16 axis_to_compare, int direction, s16 thresh) : axis_to_compare(axis_to_compare), direction(direction), thresh(thresh) { this->key = key; } virtual ~JoystickAxisCmb() = default; bool isTriggered(const irr::SEvent::SJoystickEvent &ev) const override; u16 axis_to_compare; // if -1, thresh must be smaller than the axis value in order to trigger // if 1, thresh must be bigger than the axis value in order to trigger int direction; s16 thresh; }; struct JoystickLayout { std::vector<JoystickButtonCmb> button_keys; std::vector<JoystickAxisCmb> axis_keys; JoystickAxisLayout axes[JA_COUNT]; s16 axes_dead_border; }; class JoystickController { public: JoystickController(); void onJoystickConnect(const std::vector<irr::SJoystickInfo> &joystick_infos); bool handleEvent(const irr::SEvent::SJoystickEvent &ev); void clear(); bool wasKeyDown(GameKeyType b) { bool r = m_past_pressed_keys[b]; m_past_pressed_keys[b] = false; return r; } bool getWasKeyDown(GameKeyType b) { return m_past_pressed_keys[b]; } void clearWasKeyDown(GameKeyType b) { m_past_pressed_keys[b] = false; } bool wasKeyReleased(GameKeyType b) { bool r = m_past_released_keys[b]; m_past_released_keys[b] = false; return r; } bool getWasKeyReleased(GameKeyType b) { return m_past_pressed_keys[b]; } void clearWasKeyReleased(GameKeyType b) { m_past_pressed_keys[b] = false; } bool isKeyDown(GameKeyType b) { return m_pressed_keys[b]; } s16 getAxis(JoystickAxis axis) { return m_axes_vals[axis]; } s16 getAxisWithoutDead(JoystickAxis axis); f32 doubling_dtime; private: void setLayoutFromControllerName(