diff --git a/include/fggl/math/fmath.hpp b/include/fggl/math/fmath.hpp index 35cfe88d259d7ddae3bb654a0c356b82f7ec9202..9f16a9bd890985cc754904a49a15df50d7d5ee90 100644 --- a/include/fggl/math/fmath.hpp +++ b/include/fggl/math/fmath.hpp @@ -16,28 +16,73 @@ #define FGGL_MATH_FMATH_HPP #include <cmath> +#include "fggl/math/vector.hpp" namespace fggl::math { - // wrap value in range [0, max) + /** + * A 4D floating-point vector. + */ + using vec4f = glm::vec4; + + /** + * A 3D floating-point vector. + */ + using vec3f = glm::vec3; + + /** + * A 2D floating-point vector. + */ + using vec2f = glm::vec2; + + constexpr static const math::vec2f VEC2_ZERO {0.0F, 0.0F}; + constexpr static const math::vec3f VEC3_ZERO {0.0F, 0.0F, 0.0F}; + constexpr static const math::vec3f VEC3_ONES {1.0F, 1.0F, 1.0F}; + + /** + * return the remainder (modulo) of value / maximum. + * + * This will return a value in the range [0, maximum), the result will always be positive, even if passed a negative + * input. + * + * @param value the value to wrap. + * @param max the maximum value that it can take. + * @return the wrapped value + */ inline float wrap(float value, float max) { - return fmod(max + fmod(value, max), max); + return fmodf(max + fmodf(value, max), max); } - // wrap value in range [min, max) + /** + * wrap value in range [min, max) + * + * @param value the value to be tested. + * @param min the minimum allowable value + * @param max the maximum allowable value + */ inline float wrap(float value, float min, float max) { if ( min > max ){ std::swap(min, max); }; value -= min; float rangeSize = max - min; - return value - (rangeSize* std::floor(value/rangeSize)) + min; + return value - (rangeSize * std::floor(value/rangeSize)) + min; } - // if the value is out of bounds, return that bound - inline float clamp(float value, float min, float max) { - const float t = value < min ? min : value; - return t > max ? max : t; + /** + * Ensure that value is wrapped in the range [min, max]. + * if the value is larger than max, return max. + * if the value is smaller than min, return min. + * + * @param value the value to be tested. + * @param min the minimum allowable value + * @param max the maximum allowable value + * @return value, if it is in the range [min, max], otherwise the bound that it is outside of. + */ + constexpr float clamp(float value, float min, float max) { + const float valueOrMin = value < min ? min : value; + return valueOrMin > max ? max : valueOrMin; } } // namespace fggl::math + #endif //FGGL_MATH_FMATH_HPP diff --git a/include/fggl/math/imath.hpp b/include/fggl/math/imath.hpp index e42658571f7b7e2e130d12f5f01e6b98f63acc68..7f533f87305538edef3d926f232e79bb886e9555 100644 --- a/include/fggl/math/imath.hpp +++ b/include/fggl/math/imath.hpp @@ -23,7 +23,7 @@ namespace fggl::math { // wrap value in range [0, max) inline int wrap(int value, int max) { - if ( value < 0 ) return (n-1)-(-1-value) % n; + if ( value < 0 ) return (value-1)-(-1-value) % value; if ( value >= max ) return value % max; return value; } diff --git a/include/fggl/math/types.hpp b/include/fggl/math/types.hpp index 14cc4782f477c618751e12607eba05ca434dac83..a649056fa717dd4e1d228a836090c156baff0661 100644 --- a/include/fggl/math/types.hpp +++ b/include/fggl/math/types.hpp @@ -18,13 +18,14 @@ #include <tuple> #include <iostream> -#include <glm/glm.hpp> +#include "fggl/math/vector.hpp" #include <glm/ext/matrix_transform.hpp> #include <glm/gtc/quaternion.hpp> #include <glm/gtx/transform.hpp> #include <glm/gtx/euler_angles.hpp> #include <glm/gtx/quaternion.hpp> +#include "fggl/math/fmath.hpp" #include "fggl/util/guid.hpp" #ifndef M_PI @@ -44,29 +45,72 @@ namespace fggl::math { using uint8 = std::uint8_t; // math types (aliased for ease of use) + + /** + * A 4D floating-point vector. + */ using vec4 = glm::vec4; - using vec4f = glm::vec4; + + + /** + * A 4D signed integer vector. + */ using vec4i = glm::ivec4; + + /** + * A 4D unsigned integer vector. + */ using vec4ui = glm::ivec4; + /** + * A 3D floating-point vector. + */ using vec3 = glm::vec3; + + /** + * A 3D integer vector. + */ using vec3i = glm::ivec3; - using vec3f = glm::vec3; + + /** + * A 3D unsigned integer vector. + */ using vec3ui = glm::ivec3; + /** + * A 2D floating-point vector + */ using vec2 = glm::vec2; - using vec2f = glm::vec2; + + /** + * A 2D integer vector + */ using vec2i = glm::ivec2; + + /** + * a 2D unsigned integer vector + */ using vec2ui = glm::ivec2; + /** + * A 2x2 floating-point matrix. + */ using mat2 = glm::mat2; + + /** + * A 3x3 floating-point matrix. + */ using mat3 = glm::mat3; + + /** + * A 4x4 floating-point matrix. + */ using mat4 = glm::mat4; - using quat = glm::quat; - constexpr static const math::vec2 VEC2_ZERO {0.0F, 0.0F}; - constexpr static const math::vec3 VEC3_ZERO {0.0F, 0.0F, 0.0F}; - constexpr static const math::vec3 VEC3_ONES {1.0F, 1.0F, 1.0F}; + /** + * A quaternion. + */ + using quat = glm::quat; constexpr static const math::mat4 IDENTITY_M4 {1.0F}; constexpr static const math::quat IDENTITY_Q {1.0F, 0.0, 0.0, 0.0}; @@ -81,23 +125,57 @@ namespace fggl::math { return x < xi ? xi - 1 : xi; } - inline float rescale_norm(float value, float min, float max) { + /** + * Rescale a value between [min, max] into [0, 1]. + * + * @param value the value to rescale + * @param min the minimum value of the original range + * @param max the maximum value of the original range + * @return the rescaled value, [0, 1] + */ + constexpr float rescale_norm(float value, float min, float max) { return (value - min) / (max - min); } - inline float rescale_norm(float value, float min, float max, float newMin, float newMax) { + /** + * Rescale a value between [min, max] into [newMin, newMax]. + * + * @param value the value to rescale + * @param min the minimum value of the original range + * @param max the maximum value of the original range + * @param newMin the new minimum value + * @param newMax the new maximum value + * @return the rescaled value, [newMin, newMax] + */ + constexpr float rescale_norm(float value, float min, float max, float newMin, float newMax) { return newMin + ((value - min) * (newMax - newMin)) / (max - min); } - inline float rescale_ndc(float value, float newMin, float newMax){ + /** + * Rescale a normalised device-coordinate value [-1, 1] into another range. + * + * @param value the value to rescale, [-1.0, 1.0] + * @param newMin the new minimum value + * @param newMax the new maximum value + * @return the rescaled value, [newMin, newMax] + */ + constexpr float rescale_ndc(float value, float newMin, float newMax){ return rescale_norm(value, -1, 1, newMin, newMax); } - inline float rescale_01(float value, float newMin, float newMax){ + /** + * Rescale a normalised value [0, 1] into another range. + * + * @param value the value to rescale + * @param newMin the new minimum value + * @param newMax the new maximum value + * @return the rescaled value, [newMin, newMax] + */ + constexpr float rescale_01(float value, float newMin, float newMax){ return rescale_norm(value, 0, 1, newMin, newMax); } - inline float recale_mean(float value, float avg, float max, float min) { + constexpr float recale_mean(float value, float avg, float max, float min) { return (value - avg) / (max - min); } @@ -115,6 +193,7 @@ namespace fggl::math { return modelMatrix(offset, glm::quat(eulerAngles)); } + // FIXME: we have multiple definitions of rays in the codebase! struct Ray { vec3 origin; vec3 direction; @@ -235,12 +314,4 @@ namespace fggl::math { } -// feels a bit strange to be doing this... -namespace glm { - inline bool operator<(const vec3 &lhs, const vec3 &rhs) { - return std::tie(lhs.x, lhs.y, lhs.z) - < std::tie(rhs.x, rhs.y, rhs.z); - } -} - #endif diff --git a/include/fggl/math/vector.hpp b/include/fggl/math/vector.hpp new file mode 100644 index 0000000000000000000000000000000000000000..29b117b70470a46f4973ba9cf590b0df35891842 --- /dev/null +++ b/include/fggl/math/vector.hpp @@ -0,0 +1,60 @@ +/* + * This file is part of FGGL. + * + * FGGL 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 3 of the License, or (at your option) any + * later version. + * + * FGGL 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 FGGL. + * If not, see <https://www.gnu.org/licenses/>. + */ + +// +// Created by webpigeon on 20/08/22. +// + +#ifndef FGGL_MATH_VECTOR_HPP +#define FGGL_MATH_VECTOR_HPP + +#include <ostream> + +#define GLM_FORCE_MESSAGES +#include <glm/glm.hpp> + +namespace glm { + inline bool operator<(const vec2 &lhs, const vec2 &rhs) { + return std::tie(lhs.x, lhs.y) + < std::tie(rhs.x, rhs.y); + } + + inline bool operator<(const vec3 &lhs, const vec3 &rhs) { + return std::tie(lhs.x, lhs.y, lhs.z) + < std::tie(rhs.x, rhs.y, rhs.z); + } + + inline bool operator<(const vec4 &lhs, const vec4 &rhs) { + return std::tie(lhs.x, lhs.y, lhs.z, lhs.w) + < std::tie(rhs.x, rhs.y, rhs.z, rhs.w); + } + + // output stream operators + inline std::ostream& operator<<(std::ostream& os, const vec2& v) { + os << "(" << v.x << ", " << v.y << ")"; + return os; + } + + inline std::ostream& operator<<(std::ostream& os, const vec3& v) { + os << "(" << v.x << ", " << v.y << "," << v.z << ")"; + return os; + } + + inline std::ostream& operator<<(std::ostream& os, const vec4& v) { + os << "(" << v.x << ", " << v.y << "," << v.z << "," << v.w << ")"; + return os; + } +} + +#endif //FGGL_MATH_VECTOR_HPP