#pragma once #include "gp_config.hpp" #include "gp/algorithm/min_max.hpp" #include "gp/algorithm/repeat.hpp" #include "gp/math/integer_math.hpp" #if !defined(NO_FP_MATH) # include "gp/math/fp_math.hpp" #endif #include "gp/math/q_math.hpp" namespace gp { template T lerp(T input, T low, T high) { return low + (high - low) * input; } template T lextrap(T input, T low, T high) { return (input - low) / (high - low); } template T fixed_sqrt(T value) { gp_config::assertion(value >= 0, "trying to compute square root of negative number"); if(value == 0) return 0; T ret = value / 2; T tmp; gp::repeat(fixed_passes, [&](){ tmp = ret; ret = (value / tmp + tmp) / 2; }); return ret; } template T epsilon_sqrt(T value) { gp_config::assertion(value >= 0, "trying to compute square root of negative number"); if(value == 0) return 0; T ret = value / 2; T tmp; constexpr T epsilon = gp_config::rendering::epsilon; size_t cnt = 0; while( !( (ret+epsilon)*ret > value && (ret-epsilon)*ret < value ) && cnt < cap_passes ){ tmp = ret; ret = (value / tmp + tmp) / 2; ++cnt; }; return ret; } template T stable_sqrt(T value) { gp_config::assertion(value >= 0, "trying to compute square root of negative number"); if(value == 0) return 0; T ret = value / 2; T tmp; while(ret != tmp){ tmp = ret; ret = (value / tmp + tmp) / 2; }; return ret; } template struct vec2_g { T x; T y; vec2_g() : x{} , y{} {} vec2_g( T _x, T _y ) : x{_x} , y{_y} {} vec2_g operator/(vec2_g rhs) { return { x / rhs.x, y / rhs.y }; } vec2_g operator*(vec2_g rhs) { return { x * rhs.x, y * rhs.y }; } vec2_g operator+(vec2_g oth) { return {x+oth.x, y+oth.y}; } vec2_g operator-(vec2_g oth) { return {x-oth.x, y-oth.y}; } vec2_g normalize() { T ilen = fast_isqrt(x*x+y*y); return {x*ilen, y*ilen}; } T length() { return fixed_sqrt(x*x+y*y); } }; template struct vec3_g { T x; T y; T z; T& r(){ return x; } T& g(){ return y; } T& b(){ return z; } vec3_g() : x{} , y{} , z{} {} vec3_g( T _x, T _y, T _z ) : x{_x} , y{_y} , z{_z} {} vec3_g(vec2_g left, T right) : x{left.x} , y{left.y} , z{right} {} vec3_g(T left, vec2_g right) : x{left} , y{right.x} , z{right.y} {} vec3_g operator/(vec3_g rhs) { return { x / rhs.x, y / rhs.y, z / rhs.z }; } vec3_g operator*(vec3_g rhs) { return { x * rhs.x, y * rhs.y, z * rhs.z }; } vec3_g operator+(vec3_g oth) { return {x+oth.x, y+oth.y, z+oth.z}; } vec3_g operator-(vec3_g oth) { return {x-oth.x, y-oth.y, z-oth.z}; } vec3_g normalize() { T ilen = fast_isqrt(x*x+y*y+z*z); return {x*ilen, y*ilen, z*ilen}; } T length() { return fixed_sqrt(x*x+y*y+z*z); } }; template struct vec4_g { T x; T y; T z; T w; T& r(){ return x; } T& g(){ return y; } T& b(){ return z; } T& a(){ return w; } vec4_g() : x{} , y{} , z{} , w{} {} vec4_g( T _x, T _y, T _z, T _w ) : x{_x} , y{_y} , z{_z} , w{_w} {} vec4_g(T left, vec3_g<> right) : x{left} , y{right.x} , z{right.y} , w{right.z} {} vec4_g(vec3_g<> left, T right) : x{left.x} , y{left.y} , z{left.z} , w{right} {} vec4_g operator/(vec4_g rhs) { return { x / rhs.x, y / rhs.y, z / rhs.z, w / rhs.w }; } vec4_g operator*(vec4_g rhs) { return { x * rhs.x, y * rhs.y, z * rhs.z, w * rhs.w }; } vec4_g operator+(vec4_g oth) { return {x+oth.x, y+oth.y, z+oth.z, w+oth.w}; } vec4_g operator-(vec4_g oth) { return {x-oth.x, y-oth.y, z-oth.w, z-oth.w}; } vec4_g normalize() { T ilen = fast_isqrt(x*x+y*y+z*z+w*w); return {x*ilen, y*ilen, z*ilen, w*ilen}; } T length() { return fixed_sqrt(x*x+y*y+z*z+w*w); } }; template auto sphere_sdf(vec3_g center, T radius) { return [=](vec3_g position) -> T const { auto p = position - center; return p.length() - radius; }; } template auto union_sdf(lhs _l, rhs _r) { return [=](vec3_g position) -> T const { return gp::min(_l(position), _r(position)); }; } template auto intersect_sdf(lhs _l, rhs _r) { return [=](vec3_g position) -> T const { return gp::max(_l(position), _r(position)); }; } template auto difference_sdf(lhs _l, rhs _r) { return [=](vec3_g position) -> T const { return gp::max(_l(position), -_r(position)); }; } template vec2_g operator*(vec2_g p, T v) { return {p.x*v, p.y*v}; } template vec3_g operator*(vec3_g p, T v) { return {p.x*v, p.y*v, p.z*v}; } template vec4_g operator*(vec4_g p, T v) { return {p.x*v, p.y*v, p.z*v, p.w*v}; } template vec2_g operator*(T v, vec2_g p) { return p*v; } template vec3_g operator*(T v, vec3_g p) { return p*v; } template vec4_g operator*(T v, vec4_g p) { return p*v; } } static_assert(sizeof(gp::vec3_g) == sizeof(int)*3, "vec3_g has strange alignment"); static_assert(sizeof(gp::vec4_g) == sizeof(int)*4, "vec4_g has strange alignment");