diff --git a/core/math/linalg/glsl/linalg_glsl.odin b/core/math/linalg/glsl/linalg_glsl.odin new file mode 100644 index 000000000..9cce68149 --- /dev/null +++ b/core/math/linalg/glsl/linalg_glsl.odin @@ -0,0 +1,1786 @@ +// core:math/linalg/glsl implements a GLSL-like mathematics library plus numerous other utility procedures +package math_linalg_glsl + +import "core:builtin" + +TAU :: 6.28318530717958647692528676655900576 +PI :: 3.14159265358979323846264338327950288 +E :: 2.71828182845904523536 +τ :: TAU +π :: PI +e :: E + +SQRT_TWO :: 1.41421356237309504880168872420969808 +SQRT_THREE :: 1.73205080756887729352744634150587236 +SQRT_FIVE :: 2.23606797749978969640917366873127623 + +LN2 :: 0.693147180559945309417232121458176568 +LN10 :: 2.30258509299404568401799145468436421 + +F32_EPSILON :: 1e-7 +F64_EPSILON :: 1e-15 + +// Odin matrices are stored internally as Column-Major, which matches OpenGL/GLSL by default +mat2 :: distinct matrix[2, 2]f32 +mat3 :: distinct matrix[3, 3]f32 +mat4 :: distinct matrix[4, 4]f32 +mat2x2 :: mat2 +mat3x3 :: mat3 +mat4x4 :: mat4 + +// IMPORTANT NOTE: These data types are "backwards" in normal mathematical terms +// but they match how GLSL and OpenGL defines them in name +// Odin: matrix[R, C]f32 +// GLSL: matCxR +mat3x2 :: distinct matrix[2, 3]f32 +mat4x2 :: distinct matrix[2, 4]f32 +mat2x3 :: distinct matrix[3, 2]f32 +mat4x3 :: distinct matrix[3, 4]f32 +mat2x4 :: distinct matrix[4, 2]f32 +mat3x4 :: distinct matrix[4, 3]f32 + +vec2 :: distinct [2]f32 +vec3 :: distinct [3]f32 +vec4 :: distinct [4]f32 + +ivec2 :: distinct [2]i32 +ivec3 :: distinct [3]i32 +ivec4 :: distinct [4]i32 + +uvec2 :: distinct [2]u32 +uvec3 :: distinct [3]u32 +uvec4 :: distinct [4]u32 + +bvec2 :: distinct [2]bool +bvec3 :: distinct [3]bool +bvec4 :: distinct [4]bool + +quat :: distinct quaternion128 + +// Double Precision (f64) Floating Point Types + +dmat2 :: distinct matrix[2, 2]f64 +dmat3 :: distinct matrix[3, 3]f64 +dmat4 :: distinct matrix[4, 4]f64 +dmat2x2 :: dmat2 +dmat3x3 :: dmat3 +dmat4x4 :: dmat4 + +dmat3x2 :: distinct matrix[2, 3]f64 +dmat4x2 :: distinct matrix[2, 4]f64 +dmat2x3 :: distinct matrix[3, 2]f64 +dmat4x3 :: distinct matrix[3, 4]f64 +dmat2x4 :: distinct matrix[4, 2]f64 +dmat3x4 :: distinct matrix[4, 3]f64 + +dvec2 :: distinct [2]f64 +dvec3 :: distinct [3]f64 +dvec4 :: distinct [4]f64 + +dquat :: distinct quaternion256 + +cos :: proc{ + cos_f32, + cos_f64, + cos_vec2, + cos_vec3, + cos_vec4, + cos_dvec2, + cos_dvec3, + cos_dvec4, +} +cos_vec2 :: proc "c" (x: vec2) -> vec2 { return {cos(x.x), cos(x.y)} } +cos_vec3 :: proc "c" (x: vec3) -> vec3 { return {cos(x.x), cos(x.y), cos(x.z)} } +cos_vec4 :: proc "c" (x: vec4) -> vec4 { return {cos(x.x), cos(x.y), cos(x.z), cos(x.w)} } +cos_dvec2 :: proc "c" (x: dvec2) -> dvec2 { return {cos(x.x), cos(x.y)} } +cos_dvec3 :: proc "c" (x: dvec3) -> dvec3 { return {cos(x.x), cos(x.y), cos(x.z)} } +cos_dvec4 :: proc "c" (x: dvec4) -> dvec4 { return {cos(x.x), cos(x.y), cos(x.z), cos(x.w)} } + +sin :: proc{ + sin_f32, + sin_f64, + sin_vec2, + sin_vec3, + sin_vec4, + sin_dvec2, + sin_dvec3, + sin_dvec4, +} +sin_vec2 :: proc "c" (x: vec2) -> vec2 { return {sin(x.x), sin(x.y)} } +sin_vec3 :: proc "c" (x: vec3) -> vec3 { return {sin(x.x), sin(x.y), sin(x.z)} } +sin_vec4 :: proc "c" (x: vec4) -> vec4 { return {sin(x.x), sin(x.y), sin(x.z), sin(x.w)} } +sin_dvec2 :: proc "c" (x: dvec2) -> dvec2 { return {sin(x.x), sin(x.y)} } +sin_dvec3 :: proc "c" (x: dvec3) -> dvec3 { return {sin(x.x), sin(x.y), sin(x.z)} } +sin_dvec4 :: proc "c" (x: dvec4) -> dvec4 { return {sin(x.x), sin(x.y), sin(x.z), sin(x.w)} } + +tan :: proc{ + tan_f32, + tan_f64, + tan_vec2, + tan_vec3, + tan_vec4, + tan_dvec2, + tan_dvec3, + tan_dvec4, +} +tan_vec2 :: proc "c" (x: vec2) -> vec2 { return {tan(x.x), tan(x.y)} } +tan_vec3 :: proc "c" (x: vec3) -> vec3 { return {tan(x.x), tan(x.y), tan(x.z)} } +tan_vec4 :: proc "c" (x: vec4) -> vec4 { return {tan(x.x), tan(x.y), tan(x.z), tan(x.w)} } +tan_dvec2 :: proc "c" (x: dvec2) -> dvec2 { return {tan(x.x), tan(x.y)} } +tan_dvec3 :: proc "c" (x: dvec3) -> dvec3 { return {tan(x.x), tan(x.y), tan(x.z)} } +tan_dvec4 :: proc "c" (x: dvec4) -> dvec4 { return {tan(x.x), tan(x.y), tan(x.z), tan(x.w)} } + +acos :: proc{ + acos_f32, + acos_f64, + acos_vec2, + acos_vec3, + acos_vec4, + acos_dvec2, + acos_dvec3, + acos_dvec4, +} +acos_vec2 :: proc "c" (x: vec2) -> vec2 { return {acos(x.x), acos(x.y)} } +acos_vec3 :: proc "c" (x: vec3) -> vec3 { return {acos(x.x), acos(x.y), acos(x.z)} } +acos_vec4 :: proc "c" (x: vec4) -> vec4 { return {acos(x.x), acos(x.y), acos(x.z), acos(x.w)} } +acos_dvec2 :: proc "c" (x: dvec2) -> dvec2 { return {acos(x.x), acos(x.y)} } +acos_dvec3 :: proc "c" (x: dvec3) -> dvec3 { return {acos(x.x), acos(x.y), acos(x.z)} } +acos_dvec4 :: proc "c" (x: dvec4) -> dvec4 { return {acos(x.x), acos(x.y), acos(x.z), acos(x.w)} } + +asin :: proc{ + asin_f32, + asin_f64, + asin_vec2, + asin_vec3, + asin_vec4, + asin_dvec2, + asin_dvec3, + asin_dvec4, +} +asin_vec2 :: proc "c" (x: vec2) -> vec2 { return {asin(x.x), asin(x.y)} } +asin_vec3 :: proc "c" (x: vec3) -> vec3 { return {asin(x.x), asin(x.y), asin(x.z)} } +asin_vec4 :: proc "c" (x: vec4) -> vec4 { return {asin(x.x), asin(x.y), asin(x.z), asin(x.w)} } +asin_dvec2 :: proc "c" (x: dvec2) -> dvec2 { return {asin(x.x), asin(x.y)} } +asin_dvec3 :: proc "c" (x: dvec3) -> dvec3 { return {asin(x.x), asin(x.y), asin(x.z)} } +asin_dvec4 :: proc "c" (x: dvec4) -> dvec4 { return {asin(x.x), asin(x.y), asin(x.z), asin(x.w)} } + +atan :: proc{ + atan_f32, + atan_f64, + atan_vec2, + atan_vec3, + atan_vec4, + atan_dvec2, + atan_dvec3, + atan_dvec4, + atan2_f32, + atan2_f64, + atan2_vec2, + atan2_vec3, + atan2_vec4, + atan2_dvec2, + atan2_dvec3, + atan2_dvec4, +} +atan_vec2 :: proc "c" (x: vec2) -> vec2 { return {atan(x.x), atan(x.y)} } +atan_vec3 :: proc "c" (x: vec3) -> vec3 { return {atan(x.x), atan(x.y), atan(x.z)} } +atan_vec4 :: proc "c" (x: vec4) -> vec4 { return {atan(x.x), atan(x.y), atan(x.z), atan(x.w)} } +atan_dvec2 :: proc "c" (x: dvec2) -> dvec2 { return {atan(x.x), atan(x.y)} } +atan_dvec3 :: proc "c" (x: dvec3) -> dvec3 { return {atan(x.x), atan(x.y), atan(x.z)} } +atan_dvec4 :: proc "c" (x: dvec4) -> dvec4 { return {atan(x.x), atan(x.y), atan(x.z), atan(x.w)} } + +atan2 :: proc{ + atan2_f32, + atan2_f64, + atan2_vec2, + atan2_vec3, + atan2_vec4, + atan2_dvec2, + atan2_dvec3, + atan2_dvec4, +} +atan2_vec2 :: proc "c" (y, x: vec2) -> vec2 { return {atan2(y.x, x.x), atan2(y.y, x.y)} } +atan2_vec3 :: proc "c" (y, x: vec3) -> vec3 { return {atan2(y.x, x.x), atan2(y.y, x.y), atan2(y.z, x.z)} } +atan2_vec4 :: proc "c" (y, x: vec4) -> vec4 { return {atan2(y.x, x.x), atan2(y.y, x.y), atan2(y.z, x.z), atan2(y.w, x.w)} } +atan2_dvec2 :: proc "c" (y, x: dvec2) -> dvec2 { return {atan2(y.x, x.x), atan2(y.y, x.y)} } +atan2_dvec3 :: proc "c" (y, x: dvec3) -> dvec3 { return {atan2(y.x, x.x), atan2(y.y, x.y), atan2(y.z, x.z)} } +atan2_dvec4 :: proc "c" (y, x: dvec4) -> dvec4 { return {atan2(y.x, x.x), atan2(y.y, x.y), atan2(y.z, x.z), atan2(y.w, x.w)} } + + + +cosh :: proc{ + cosh_f32, + cosh_f64, + cosh_vec2, + cosh_vec3, + cosh_vec4, + cosh_dvec2, + cosh_dvec3, + cosh_dvec4, +} +cosh_vec2 :: proc "c" (x: vec2) -> vec2 { return {cosh(x.x), cosh(x.y)} } +cosh_vec3 :: proc "c" (x: vec3) -> vec3 { return {cosh(x.x), cosh(x.y), cosh(x.z)} } +cosh_vec4 :: proc "c" (x: vec4) -> vec4 { return {cosh(x.x), cosh(x.y), cosh(x.z), cosh(x.w)} } +cosh_dvec2 :: proc "c" (x: dvec2) -> dvec2 { return {cosh(x.x), cosh(x.y)} } +cosh_dvec3 :: proc "c" (x: dvec3) -> dvec3 { return {cosh(x.x), cosh(x.y), cosh(x.z)} } +cosh_dvec4 :: proc "c" (x: dvec4) -> dvec4 { return {cosh(x.x), cosh(x.y), cosh(x.z), cosh(x.w)} } + + +sinh :: proc{ + sinh_f32, + sinh_f64, + sinh_vec2, + sinh_vec3, + sinh_vec4, + sinh_dvec2, + sinh_dvec3, + sinh_dvec4, +} +sinh_vec2 :: proc "c" (x: vec2) -> vec2 { return {sinh(x.x), sinh(x.y)} } +sinh_vec3 :: proc "c" (x: vec3) -> vec3 { return {sinh(x.x), sinh(x.y), sinh(x.z)} } +sinh_vec4 :: proc "c" (x: vec4) -> vec4 { return {sinh(x.x), sinh(x.y), sinh(x.z), sinh(x.w)} } +sinh_dvec2 :: proc "c" (x: dvec2) -> dvec2 { return {sinh(x.x), sinh(x.y)} } +sinh_dvec3 :: proc "c" (x: dvec3) -> dvec3 { return {sinh(x.x), sinh(x.y), sinh(x.z)} } +sinh_dvec4 :: proc "c" (x: dvec4) -> dvec4 { return {sinh(x.x), sinh(x.y), sinh(x.z), sinh(x.w)} } + +tanh :: proc{ + tanh_f32, + tanh_f64, + tanh_vec2, + tanh_vec3, + tanh_vec4, + tanh_dvec2, + tanh_dvec3, + tanh_dvec4, +} +tanh_vec2 :: proc "c" (x: vec2) -> vec2 { return {tanh(x.x), tanh(x.y)} } +tanh_vec3 :: proc "c" (x: vec3) -> vec3 { return {tanh(x.x), tanh(x.y), tanh(x.z)} } +tanh_vec4 :: proc "c" (x: vec4) -> vec4 { return {tanh(x.x), tanh(x.y), tanh(x.z), tanh(x.w)} } +tanh_dvec2 :: proc "c" (x: dvec2) -> dvec2 { return {tanh(x.x), tanh(x.y)} } +tanh_dvec3 :: proc "c" (x: dvec3) -> dvec3 { return {tanh(x.x), tanh(x.y), tanh(x.z)} } +tanh_dvec4 :: proc "c" (x: dvec4) -> dvec4 { return {tanh(x.x), tanh(x.y), tanh(x.z), tanh(x.w)} } + +acosh :: proc{ + acosh_f32, + acosh_f64, + acosh_vec2, + acosh_vec3, + acosh_vec4, + acosh_dvec2, + acosh_dvec3, + acosh_dvec4, +} +acosh_vec2 :: proc "c" (x: vec2) -> vec2 { return {acosh(x.x), acosh(x.y)} } +acosh_vec3 :: proc "c" (x: vec3) -> vec3 { return {acosh(x.x), acosh(x.y), acosh(x.z)} } +acosh_vec4 :: proc "c" (x: vec4) -> vec4 { return {acosh(x.x), acosh(x.y), acosh(x.z), acosh(x.w)} } +acosh_dvec2 :: proc "c" (x: dvec2) -> dvec2 { return {acosh(x.x), acosh(x.y)} } +acosh_dvec3 :: proc "c" (x: dvec3) -> dvec3 { return {acosh(x.x), acosh(x.y), acosh(x.z)} } +acosh_dvec4 :: proc "c" (x: dvec4) -> dvec4 { return {acosh(x.x), acosh(x.y), acosh(x.z), acosh(x.w)} } + +asinh :: proc{ + asinh_f32, + asinh_f64, + asinh_vec2, + asinh_vec3, + asinh_vec4, + asinh_dvec2, + asinh_dvec3, + asinh_dvec4, +} +asinh_vec2 :: proc "c" (x: vec2) -> vec2 { return {asinh(x.x), asinh(x.y)} } +asinh_vec3 :: proc "c" (x: vec3) -> vec3 { return {asinh(x.x), asinh(x.y), asinh(x.z)} } +asinh_vec4 :: proc "c" (x: vec4) -> vec4 { return {asinh(x.x), asinh(x.y), asinh(x.z), asinh(x.w)} } +asinh_dvec2 :: proc "c" (x: dvec2) -> dvec2 { return {asinh(x.x), asinh(x.y)} } +asinh_dvec3 :: proc "c" (x: dvec3) -> dvec3 { return {asinh(x.x), asinh(x.y), asinh(x.z)} } +asinh_dvec4 :: proc "c" (x: dvec4) -> dvec4 { return {asinh(x.x), asinh(x.y), asinh(x.z), asinh(x.w)} } + +atanh :: proc{ + atanh_f32, + atanh_f64, + atanh_vec2, + atanh_vec3, + atanh_vec4, + atanh_dvec2, + atanh_dvec3, + atanh_dvec4, +} +atanh_vec2 :: proc "c" (x: vec2) -> vec2 { return {atanh(x.x), atanh(x.y)} } +atanh_vec3 :: proc "c" (x: vec3) -> vec3 { return {atanh(x.x), atanh(x.y), atanh(x.z)} } +atanh_vec4 :: proc "c" (x: vec4) -> vec4 { return {atanh(x.x), atanh(x.y), atanh(x.z), atanh(x.w)} } +atanh_dvec2 :: proc "c" (x: dvec2) -> dvec2 { return {atanh(x.x), atanh(x.y)} } +atanh_dvec3 :: proc "c" (x: dvec3) -> dvec3 { return {atanh(x.x), atanh(x.y), atanh(x.z)} } +atanh_dvec4 :: proc "c" (x: dvec4) -> dvec4 { return {atanh(x.x), atanh(x.y), atanh(x.z), atanh(x.w)} } + +sqrt :: proc{ + sqrt_f32, + sqrt_f64, + sqrt_vec2, + sqrt_vec3, + sqrt_vec4, + sqrt_dvec2, + sqrt_dvec3, + sqrt_dvec4, +} +sqrt_vec2 :: proc "c" (x: vec2) -> vec2 { return {sqrt(x.x), sqrt(x.y)} } +sqrt_vec3 :: proc "c" (x: vec3) -> vec3 { return {sqrt(x.x), sqrt(x.y), sqrt(x.z)} } +sqrt_vec4 :: proc "c" (x: vec4) -> vec4 { return {sqrt(x.x), sqrt(x.y), sqrt(x.z), sqrt(x.w)} } +sqrt_dvec2 :: proc "c" (x: dvec2) -> dvec2 { return {sqrt(x.x), sqrt(x.y)} } +sqrt_dvec3 :: proc "c" (x: dvec3) -> dvec3 { return {sqrt(x.x), sqrt(x.y), sqrt(x.z)} } +sqrt_dvec4 :: proc "c" (x: dvec4) -> dvec4 { return {sqrt(x.x), sqrt(x.y), sqrt(x.z), sqrt(x.w)} } + +rsqrt :: inversesqrt +inversesqrt :: proc{ + inversesqrt_f32, + inversesqrt_f64, + inversesqrt_vec2, + inversesqrt_vec3, + inversesqrt_vec4, + inversesqrt_dvec2, + inversesqrt_dvec3, + inversesqrt_dvec4, +} +inversesqrt_vec2 :: proc "c" (x: vec2) -> vec2 { return {inversesqrt(x.x), inversesqrt(x.y)} } +inversesqrt_vec3 :: proc "c" (x: vec3) -> vec3 { return {inversesqrt(x.x), inversesqrt(x.y), inversesqrt(x.z)} } +inversesqrt_vec4 :: proc "c" (x: vec4) -> vec4 { return {inversesqrt(x.x), inversesqrt(x.y), inversesqrt(x.z), inversesqrt(x.w)} } +inversesqrt_dvec2 :: proc "c" (x: dvec2) -> dvec2 { return {inversesqrt(x.x), inversesqrt(x.y)} } +inversesqrt_dvec3 :: proc "c" (x: dvec3) -> dvec3 { return {inversesqrt(x.x), inversesqrt(x.y), inversesqrt(x.z)} } +inversesqrt_dvec4 :: proc "c" (x: dvec4) -> dvec4 { return {inversesqrt(x.x), inversesqrt(x.y), inversesqrt(x.z), inversesqrt(x.w)} } + + +pow :: proc{ + pow_f32, + pow_f64, + pow_vec2, + pow_vec3, + pow_vec4, + pow_dvec2, + pow_dvec3, + pow_dvec4, +} +pow_vec2 :: proc "c" (x, y: vec2) -> vec2 { return {pow(x.x, y.x), pow(x.y, y.y)} } +pow_vec3 :: proc "c" (x, y: vec3) -> vec3 { return {pow(x.x, y.x), pow(x.y, y.y), pow(x.z, y.z)} } +pow_vec4 :: proc "c" (x, y: vec4) -> vec4 { return {pow(x.x, y.x), pow(x.y, y.y), pow(x.z, y.z), pow(x.w, y.w)} } +pow_dvec2 :: proc "c" (x, y: dvec2) -> dvec2 { return {pow(x.x, y.x), pow(x.y, y.y)} } +pow_dvec3 :: proc "c" (x, y: dvec3) -> dvec3 { return {pow(x.x, y.x), pow(x.y, y.y), pow(x.z, y.z)} } +pow_dvec4 :: proc "c" (x, y: dvec4) -> dvec4 { return {pow(x.x, y.x), pow(x.y, y.y), pow(x.z, y.z), pow(x.w, y.w)} } + + + +exp :: proc{ + exp_f32, + exp_f64, + exp_vec2, + exp_vec3, + exp_vec4, + exp_dvec2, + exp_dvec3, + exp_dvec4, +} +exp_vec2 :: proc "c" (x: vec2) -> vec2 { return {exp(x.x), exp(x.y)} } +exp_vec3 :: proc "c" (x: vec3) -> vec3 { return {exp(x.x), exp(x.y), exp(x.z)} } +exp_vec4 :: proc "c" (x: vec4) -> vec4 { return {exp(x.x), exp(x.y), exp(x.z), exp(x.w)} } +exp_dvec2 :: proc "c" (x: dvec2) -> dvec2 { return {exp(x.x), exp(x.y)} } +exp_dvec3 :: proc "c" (x: dvec3) -> dvec3 { return {exp(x.x), exp(x.y), exp(x.z)} } +exp_dvec4 :: proc "c" (x: dvec4) -> dvec4 { return {exp(x.x), exp(x.y), exp(x.z), exp(x.w)} } + + + +log :: proc{ + log_f32, + log_f64, + log_vec2, + log_vec3, + log_vec4, + log_dvec2, + log_dvec3, + log_dvec4, +} +log_vec2 :: proc "c" (x: vec2) -> vec2 { return {log(x.x), log(x.y)} } +log_vec3 :: proc "c" (x: vec3) -> vec3 { return {log(x.x), log(x.y), log(x.z)} } +log_vec4 :: proc "c" (x: vec4) -> vec4 { return {log(x.x), log(x.y), log(x.z), log(x.w)} } +log_dvec2 :: proc "c" (x: dvec2) -> dvec2 { return {log(x.x), log(x.y)} } +log_dvec3 :: proc "c" (x: dvec3) -> dvec3 { return {log(x.x), log(x.y), log(x.z)} } +log_dvec4 :: proc "c" (x: dvec4) -> dvec4 { return {log(x.x), log(x.y), log(x.z), log(x.w)} } + + + +exp2 :: proc{ + exp2_f32, + exp2_f64, + exp2_vec2, + exp2_vec3, + exp2_vec4, + exp2_dvec2, + exp2_dvec3, + exp2_dvec4, +} +exp2_vec2 :: proc "c" (x: vec2) -> vec2 { return {exp2(x.x), exp2(x.y)} } +exp2_vec3 :: proc "c" (x: vec3) -> vec3 { return {exp2(x.x), exp2(x.y), exp2(x.z)} } +exp2_vec4 :: proc "c" (x: vec4) -> vec4 { return {exp2(x.x), exp2(x.y), exp2(x.z), exp2(x.w)} } +exp2_dvec2 :: proc "c" (x: dvec2) -> dvec2 { return {exp2(x.x), exp2(x.y)} } +exp2_dvec3 :: proc "c" (x: dvec3) -> dvec3 { return {exp2(x.x), exp2(x.y), exp2(x.z)} } +exp2_dvec4 :: proc "c" (x: dvec4) -> dvec4 { return {exp2(x.x), exp2(x.y), exp2(x.z), exp2(x.w)} } + + +sign :: proc{ + sign_i32, + sign_u32, + sign_f32, + sign_f64, + sign_vec2, + sign_vec3, + sign_vec4, + sign_dvec2, + sign_dvec3, + sign_dvec4, + sign_ivec2, + sign_ivec3, + sign_ivec4, + sign_uvec2, + sign_uvec3, + sign_uvec4, +} +sign_i32 :: proc "c" (x: i32) -> i32 { return -1 if x < 0 else +1 if x > 0 else 0 } +sign_u32 :: proc "c" (x: u32) -> u32 { return +1 if x > 0 else 0 } +sign_vec2 :: proc "c" (x: vec2) -> vec2 { return {sign(x.x), sign(x.y)} } +sign_vec3 :: proc "c" (x: vec3) -> vec3 { return {sign(x.x), sign(x.y), sign(x.z)} } +sign_vec4 :: proc "c" (x: vec4) -> vec4 { return {sign(x.x), sign(x.y), sign(x.z), sign(x.w)} } +sign_dvec2 :: proc "c" (x: dvec2) -> dvec2 { return {sign(x.x), sign(x.y)} } +sign_dvec3 :: proc "c" (x: dvec3) -> dvec3 { return {sign(x.x), sign(x.y), sign(x.z)} } +sign_dvec4 :: proc "c" (x: dvec4) -> dvec4 { return {sign(x.x), sign(x.y), sign(x.z), sign(x.w)} } +sign_ivec2 :: proc "c" (x: ivec2) -> ivec2 { return {sign(x.x), sign(x.y)} } +sign_ivec3 :: proc "c" (x: ivec3) -> ivec3 { return {sign(x.x), sign(x.y), sign(x.z)} } +sign_ivec4 :: proc "c" (x: ivec4) -> ivec4 { return {sign(x.x), sign(x.y), sign(x.z), sign(x.w)} } +sign_uvec2 :: proc "c" (x: uvec2) -> uvec2 { return {sign(x.x), sign(x.y)} } +sign_uvec3 :: proc "c" (x: uvec3) -> uvec3 { return {sign(x.x), sign(x.y), sign(x.z)} } +sign_uvec4 :: proc "c" (x: uvec4) -> uvec4 { return {sign(x.x), sign(x.y), sign(x.z), sign(x.w)} } + +floor :: proc{ + floor_f32, + floor_f64, + floor_vec2, + floor_vec3, + floor_vec4, + floor_dvec2, + floor_dvec3, + floor_dvec4, +} +floor_vec2 :: proc "c" (x: vec2) -> vec2 { return {floor(x.x), floor(x.y)} } +floor_vec3 :: proc "c" (x: vec3) -> vec3 { return {floor(x.x), floor(x.y), floor(x.z)} } +floor_vec4 :: proc "c" (x: vec4) -> vec4 { return {floor(x.x), floor(x.y), floor(x.z), floor(x.w)} } +floor_dvec2 :: proc "c" (x: dvec2) -> dvec2 { return {floor(x.x), floor(x.y)} } +floor_dvec3 :: proc "c" (x: dvec3) -> dvec3 { return {floor(x.x), floor(x.y), floor(x.z)} } +floor_dvec4 :: proc "c" (x: dvec4) -> dvec4 { return {floor(x.x), floor(x.y), floor(x.z), floor(x.w)} } + + +ceil :: proc{ + ceil_f32, + ceil_f64, + ceil_vec2, + ceil_vec3, + ceil_vec4, + ceil_dvec2, + ceil_dvec3, + ceil_dvec4, +} +ceil_vec2 :: proc "c" (x: vec2) -> vec2 { return {ceil(x.x), ceil(x.y)} } +ceil_vec3 :: proc "c" (x: vec3) -> vec3 { return {ceil(x.x), ceil(x.y), ceil(x.z)} } +ceil_vec4 :: proc "c" (x: vec4) -> vec4 { return {ceil(x.x), ceil(x.y), ceil(x.z), ceil(x.w)} } +ceil_dvec2 :: proc "c" (x: dvec2) -> dvec2 { return {ceil(x.x), ceil(x.y)} } +ceil_dvec3 :: proc "c" (x: dvec3) -> dvec3 { return {ceil(x.x), ceil(x.y), ceil(x.z)} } +ceil_dvec4 :: proc "c" (x: dvec4) -> dvec4 { return {ceil(x.x), ceil(x.y), ceil(x.z), ceil(x.w)} } + + +mod :: proc{ + mod_f32, + mod_f64, + mod_vec2, + mod_vec3, + mod_vec4, + mod_dvec2, + mod_dvec3, + mod_dvec4, +} +mod_vec2 :: proc "c" (x, y: vec2) -> vec2 { return {mod(x.x, y.x), mod(x.y, y.y)} } +mod_vec3 :: proc "c" (x, y: vec3) -> vec3 { return {mod(x.x, y.x), mod(x.y, y.y), mod(x.z, y.z)} } +mod_vec4 :: proc "c" (x, y: vec4) -> vec4 { return {mod(x.x, y.x), mod(x.y, y.y), mod(x.z, y.z), mod(x.w, y.w)} } +mod_dvec2 :: proc "c" (x, y: dvec2) -> dvec2 { return {mod(x.x, y.x), mod(x.y, y.y)} } +mod_dvec3 :: proc "c" (x, y: dvec3) -> dvec3 { return {mod(x.x, y.x), mod(x.y, y.y), mod(x.z, y.z)} } +mod_dvec4 :: proc "c" (x, y: dvec4) -> dvec4 { return {mod(x.x, y.x), mod(x.y, y.y), mod(x.z, y.z), mod(x.w, y.w)} } + + +fract :: proc{ + fract_f32, + fract_f64, + fract_vec2, + fract_vec3, + fract_vec4, + fract_dvec2, + fract_dvec3, + fract_dvec4, +} +fract_vec2 :: proc "c" (x: vec2) -> vec2 { return {fract(x.x), fract(x.y)} } +fract_vec3 :: proc "c" (x: vec3) -> vec3 { return {fract(x.x), fract(x.y), fract(x.z)} } +fract_vec4 :: proc "c" (x: vec4) -> vec4 { return {fract(x.x), fract(x.y), fract(x.z), fract(x.w)} } +fract_dvec2 :: proc "c" (x: dvec2) -> dvec2 { return {fract(x.x), fract(x.y)} } +fract_dvec3 :: proc "c" (x: dvec3) -> dvec3 { return {fract(x.x), fract(x.y), fract(x.z)} } +fract_dvec4 :: proc "c" (x: dvec4) -> dvec4 { return {fract(x.x), fract(x.y), fract(x.z), fract(x.w)} } + + + +radians :: proc{ + radians_f32, + radians_f64, + radians_vec2, + radians_vec3, + radians_vec4, + radians_dvec2, + radians_dvec3, + radians_dvec4, +} +radians_f32 :: proc "c" (degrees: f32) -> f32 { return degrees * TAU / 360.0 } +radians_f64 :: proc "c" (degrees: f64) -> f64 { return degrees * TAU / 360.0 } +radians_vec2 :: proc "c" (degrees: vec2) -> vec2 { return degrees * TAU / 360.0 } +radians_vec3 :: proc "c" (degrees: vec3) -> vec3 { return degrees * TAU / 360.0 } +radians_vec4 :: proc "c" (degrees: vec4) -> vec4 { return degrees * TAU / 360.0 } +radians_dvec2 :: proc "c" (degrees: dvec2) -> dvec2 { return degrees * TAU / 360.0 } +radians_dvec3 :: proc "c" (degrees: dvec3) -> dvec3 { return degrees * TAU / 360.0 } +radians_dvec4 :: proc "c" (degrees: dvec4) -> dvec4 { return degrees * TAU / 360.0 } + + +degrees :: proc{ + degrees_f32, + degrees_f64, + degrees_vec2, + degrees_vec3, + degrees_vec4, + degrees_dvec2, + degrees_dvec3, + degrees_dvec4, +} +degrees_f32 :: proc "c" (radians: f32) -> f32 { return radians * 360.0 / TAU } +degrees_f64 :: proc "c" (radians: f64) -> f64 { return radians * 360.0 / TAU } +degrees_vec2 :: proc "c" (radians: vec2) -> vec2 { return radians * 360.0 / TAU } +degrees_vec3 :: proc "c" (radians: vec3) -> vec3 { return radians * 360.0 / TAU } +degrees_vec4 :: proc "c" (radians: vec4) -> vec4 { return radians * 360.0 / TAU } +degrees_dvec2 :: proc "c" (radians: dvec2) -> dvec2 { return radians * 360.0 / TAU } +degrees_dvec3 :: proc "c" (radians: dvec3) -> dvec3 { return radians * 360.0 / TAU } +degrees_dvec4 :: proc "c" (radians: dvec4) -> dvec4 { return radians * 360.0 / TAU } + +min :: proc{ + min_i32, + min_u32, + min_f32, + min_f64, + min_vec2, + min_vec3, + min_vec4, + min_dvec2, + min_dvec3, + min_dvec4, + min_ivec2, + min_ivec3, + min_ivec4, + min_uvec2, + min_uvec3, + min_uvec4, +} +min_i32 :: proc "c" (x, y: i32) -> i32 { return builtin.min(x, y) } +min_u32 :: proc "c" (x, y: u32) -> u32 { return builtin.min(x, y) } +min_f32 :: proc "c" (x, y: f32) -> f32 { return builtin.min(x, y) } +min_f64 :: proc "c" (x, y: f64) -> f64 { return builtin.min(x, y) } +min_vec2 :: proc "c" (x, y: vec2) -> vec2 { return {min(x.x, y.x), min(x.y, y.y)} } +min_vec3 :: proc "c" (x, y: vec3) -> vec3 { return {min(x.x, y.x), min(x.y, y.y), min(x.z, y.z)} } +min_vec4 :: proc "c" (x, y: vec4) -> vec4 { return {min(x.x, y.x), min(x.y, y.y), min(x.z, y.z), min(x.w, y.w)} } +min_dvec2 :: proc "c" (x, y: dvec2) -> dvec2 { return {min(x.x, y.x), min(x.y, y.y)} } +min_dvec3 :: proc "c" (x, y: dvec3) -> dvec3 { return {min(x.x, y.x), min(x.y, y.y), min(x.z, y.z)} } +min_dvec4 :: proc "c" (x, y: dvec4) -> dvec4 { return {min(x.x, y.x), min(x.y, y.y), min(x.z, y.z), min(x.w, y.w)} } +min_ivec2 :: proc "c" (x, y: ivec2) -> ivec2 { return {min(x.x, y.x), min(x.y, y.y)} } +min_ivec3 :: proc "c" (x, y: ivec3) -> ivec3 { return {min(x.x, y.x), min(x.y, y.y), min(x.z, y.z)} } +min_ivec4 :: proc "c" (x, y: ivec4) -> ivec4 { return {min(x.x, y.x), min(x.y, y.y), min(x.z, y.z), min(x.w, y.w)} } +min_uvec2 :: proc "c" (x, y: uvec2) -> uvec2 { return {min(x.x, y.x), min(x.y, y.y)} } +min_uvec3 :: proc "c" (x, y: uvec3) -> uvec3 { return {min(x.x, y.x), min(x.y, y.y), min(x.z, y.z)} } +min_uvec4 :: proc "c" (x, y: uvec4) -> uvec4 { return {min(x.x, y.x), min(x.y, y.y), min(x.z, y.z), min(x.w, y.w)} } + + +max :: proc{ + max_i32, + max_u32, + max_f32, + max_f64, + max_vec2, + max_vec3, + max_vec4, + max_dvec2, + max_dvec3, + max_dvec4, + max_ivec2, + max_ivec3, + max_ivec4, + max_uvec2, + max_uvec3, + max_uvec4, +} +max_i32 :: proc "c" (x, y: i32) -> i32 { return builtin.max(x, y) } +max_u32 :: proc "c" (x, y: u32) -> u32 { return builtin.max(x, y) } +max_f32 :: proc "c" (x, y: f32) -> f32 { return builtin.max(x, y) } +max_f64 :: proc "c" (x, y: f64) -> f64 { return builtin.max(x, y) } +max_vec2 :: proc "c" (x, y: vec2) -> vec2 { return {max(x.x, y.x), max(x.y, y.y)} } +max_vec3 :: proc "c" (x, y: vec3) -> vec3 { return {max(x.x, y.x), max(x.y, y.y), max(x.z, y.z)} } +max_vec4 :: proc "c" (x, y: vec4) -> vec4 { return {max(x.x, y.x), max(x.y, y.y), max(x.z, y.z), max(x.w, y.w)} } +max_dvec2 :: proc "c" (x, y: dvec2) -> dvec2 { return {max(x.x, y.x), max(x.y, y.y)} } +max_dvec3 :: proc "c" (x, y: dvec3) -> dvec3 { return {max(x.x, y.x), max(x.y, y.y), max(x.z, y.z)} } +max_dvec4 :: proc "c" (x, y: dvec4) -> dvec4 { return {max(x.x, y.x), max(x.y, y.y), max(x.z, y.z), max(x.w, y.w)} } +max_ivec2 :: proc "c" (x, y: ivec2) -> ivec2 { return {max(x.x, y.x), max(x.y, y.y)} } +max_ivec3 :: proc "c" (x, y: ivec3) -> ivec3 { return {max(x.x, y.x), max(x.y, y.y), max(x.z, y.z)} } +max_ivec4 :: proc "c" (x, y: ivec4) -> ivec4 { return {max(x.x, y.x), max(x.y, y.y), max(x.z, y.z), max(x.w, y.w)} } +max_uvec2 :: proc "c" (x, y: uvec2) -> uvec2 { return {max(x.x, y.x), max(x.y, y.y)} } +max_uvec3 :: proc "c" (x, y: uvec3) -> uvec3 { return {max(x.x, y.x), max(x.y, y.y), max(x.z, y.z)} } +max_uvec4 :: proc "c" (x, y: uvec4) -> uvec4 { return {max(x.x, y.x), max(x.y, y.y), max(x.z, y.z), max(x.w, y.w)} } + + + +clamp :: proc{ + clamp_i32, + clamp_u32, + clamp_f32, + clamp_f64, + clamp_vec2, + clamp_vec3, + clamp_vec4, + clamp_dvec2, + clamp_dvec3, + clamp_dvec4, + clamp_ivec2, + clamp_ivec3, + clamp_ivec4, + clamp_uvec2, + clamp_uvec3, + clamp_uvec4, +} +clamp_i32 :: proc "c" (x, y, z: i32) -> i32 { return builtin.clamp(x, y, z) } +clamp_u32 :: proc "c" (x, y, z: u32) -> u32 { return builtin.clamp(x, y, z) } +clamp_f32 :: proc "c" (x, y, z: f32) -> f32 { return builtin.clamp(x, y, z) } +clamp_f64 :: proc "c" (x, y, z: f64) -> f64 { return builtin.clamp(x, y, z) } +clamp_vec2 :: proc "c" (x, y, z: vec2) -> vec2 { return {clamp(x.x, y.x, z.x), clamp(x.y, y.y, z.y)} } +clamp_vec3 :: proc "c" (x, y, z: vec3) -> vec3 { return {clamp(x.x, y.x, z.x), clamp(x.y, y.y, z.y), clamp(x.z, y.z, z.z)} } +clamp_vec4 :: proc "c" (x, y, z: vec4) -> vec4 { return {clamp(x.x, y.x, z.x), clamp(x.y, y.y, z.y), clamp(x.z, y.z, z.z), clamp(x.w, y.w, z.w)} } +clamp_dvec2 :: proc "c" (x, y, z: dvec2) -> dvec2 { return {clamp(x.x, y.x, z.x), clamp(x.y, y.y, z.y)} } +clamp_dvec3 :: proc "c" (x, y, z: dvec3) -> dvec3 { return {clamp(x.x, y.x, z.x), clamp(x.y, y.y, z.y), clamp(x.z, y.z, z.z)} } +clamp_dvec4 :: proc "c" (x, y, z: dvec4) -> dvec4 { return {clamp(x.x, y.x, z.x), clamp(x.y, y.y, z.y), clamp(x.z, y.z, z.z), clamp(x.w, y.w, z.w)} } +clamp_ivec2 :: proc "c" (x, y, z: ivec2) -> ivec2 { return {clamp(x.x, y.x, z.x), clamp(x.y, y.y, z.y)} } +clamp_ivec3 :: proc "c" (x, y, z: ivec3) -> ivec3 { return {clamp(x.x, y.x, z.x), clamp(x.y, y.y, z.y), clamp(x.z, y.z, z.z)} } +clamp_ivec4 :: proc "c" (x, y, z: ivec4) -> ivec4 { return {clamp(x.x, y.x, z.x), clamp(x.y, y.y, z.y), clamp(x.z, y.z, z.z), clamp(x.w, y.w, z.w)} } +clamp_uvec2 :: proc "c" (x, y, z: uvec2) -> uvec2 { return {clamp(x.x, y.x, z.x), clamp(x.y, y.y, z.y)} } +clamp_uvec3 :: proc "c" (x, y, z: uvec3) -> uvec3 { return {clamp(x.x, y.x, z.x), clamp(x.y, y.y, z.y), clamp(x.z, y.z, z.z)} } +clamp_uvec4 :: proc "c" (x, y, z: uvec4) -> uvec4 { return {clamp(x.x, y.x, z.x), clamp(x.y, y.y, z.y), clamp(x.z, y.z, z.z), clamp(x.w, y.w, z.w)} } + +saturate :: proc{ + saturate_i32, + saturate_u32, + saturate_f32, + saturate_f64, + saturate_vec2, + saturate_vec3, + saturate_vec4, + saturate_dvec2, + saturate_dvec3, + saturate_dvec4, + saturate_ivec2, + saturate_ivec3, + saturate_ivec4, + saturate_uvec2, + saturate_uvec3, + saturate_uvec4, +} +saturate_i32 :: proc "c" (x, y, z: i32) -> i32 { return builtin.clamp(x, 0, 1) } +saturate_u32 :: proc "c" (x, y, z: u32) -> u32 { return builtin.clamp(x, 0, 1) } +saturate_f32 :: proc "c" (x, y, z: f32) -> f32 { return builtin.clamp(x, 0, 1) } +saturate_f64 :: proc "c" (x, y, z: f64) -> f64 { return builtin.clamp(x, 0, 1) } +saturate_vec2 :: proc "c" (x, y, z: vec2) -> vec2 { return {builtin.clamp(x.x, 0, 1), builtin.clamp(x.y, 0, 1)} } +saturate_vec3 :: proc "c" (x, y, z: vec3) -> vec3 { return {builtin.clamp(x.x, 0, 1), builtin.clamp(x.y, 0, 1), builtin.clamp(x.z, 0, 1)} } +saturate_vec4 :: proc "c" (x, y, z: vec4) -> vec4 { return {builtin.clamp(x.x, 0, 1), builtin.clamp(x.y, 0, 1), builtin.clamp(x.z, 0, 1), builtin.clamp(x.w, 0, 1)} } +saturate_dvec2 :: proc "c" (x, y, z: dvec2) -> dvec2 { return {builtin.clamp(x.x, 0, 1), builtin.clamp(x.y, 0, 1)} } +saturate_dvec3 :: proc "c" (x, y, z: dvec3) -> dvec3 { return {builtin.clamp(x.x, 0, 1), builtin.clamp(x.y, 0, 1), builtin.clamp(x.z, 0, 1)} } +saturate_dvec4 :: proc "c" (x, y, z: dvec4) -> dvec4 { return {builtin.clamp(x.x, 0, 1), builtin.clamp(x.y, 0, 1), builtin.clamp(x.z, 0, 1), builtin.clamp(x.w, 0, 1)} } +saturate_ivec2 :: proc "c" (x, y, z: ivec2) -> ivec2 { return {builtin.clamp(x.x, 0, 1), builtin.clamp(x.y, 0, 1)} } +saturate_ivec3 :: proc "c" (x, y, z: ivec3) -> ivec3 { return {builtin.clamp(x.x, 0, 1), builtin.clamp(x.y, 0, 1), builtin.clamp(x.z, 0, 1)} } +saturate_ivec4 :: proc "c" (x, y, z: ivec4) -> ivec4 { return {builtin.clamp(x.x, 0, 1), builtin.clamp(x.y, 0, 1), builtin.clamp(x.z, 0, 1), builtin.clamp(x.w, 0, 1)} } +saturate_uvec2 :: proc "c" (x, y, z: uvec2) -> uvec2 { return {builtin.clamp(x.x, 0, 1), builtin.clamp(x.y, 0, 1)} } +saturate_uvec3 :: proc "c" (x, y, z: uvec3) -> uvec3 { return {builtin.clamp(x.x, 0, 1), builtin.clamp(x.y, 0, 1), builtin.clamp(x.z, 0, 1)} } +saturate_uvec4 :: proc "c" (x, y, z: uvec4) -> uvec4 { return {builtin.clamp(x.x, 0, 1), builtin.clamp(x.y, 0, 1), builtin.clamp(x.z, 0, 1), builtin.clamp(x.w, 0, 1)} } + + +mix :: proc{ + mix_f32, + mix_f64, + mix_vec2, + mix_vec3, + mix_vec4, + mix_dvec2, + mix_dvec3, + mix_dvec4, +} +mix_f32 :: proc "c" (x, y, t: f32) -> f32 { return x*(1-t) + y*t } +mix_f64 :: proc "c" (x, y, t: f64) -> f64 { return x*(1-t) + y*t } +mix_vec2 :: proc "c" (x, y, t: vec2) -> vec2 { return {mix(x.x, y.x, t.x), mix(x.y, y.y, t.y)} } +mix_vec3 :: proc "c" (x, y, t: vec3) -> vec3 { return {mix(x.x, y.x, t.x), mix(x.y, y.y, t.y), mix(x.z, y.z, t.z)} } +mix_vec4 :: proc "c" (x, y, t: vec4) -> vec4 { return {mix(x.x, y.x, t.x), mix(x.y, y.y, y.y), mix(x.z, y.z, t.z), mix(x.w, y.w, t.w)} } +mix_dvec2 :: proc "c" (x, y, t: dvec2) -> dvec2 { return {mix(x.x, y.x, t.x), mix(x.y, y.y, t.y)} } +mix_dvec3 :: proc "c" (x, y, t: dvec3) -> dvec3 { return {mix(x.x, y.x, t.x), mix(x.y, y.y, t.y), mix(x.z, y.z, t.z)} } +mix_dvec4 :: proc "c" (x, y, t: dvec4) -> dvec4 { return {mix(x.x, y.x, t.x), mix(x.y, y.y, y.y), mix(x.z, y.z, t.z), mix(x.w, y.w, t.w)} } + +lerp :: proc{ + lerp_f32, + lerp_f64, + lerp_vec2, + lerp_vec3, + lerp_vec4, + lerp_dvec2, + lerp_dvec3, + lerp_dvec4, +} +lerp_f32 :: proc "c" (x, y, t: f32) -> f32 { return x*(1-t) + y*t } +lerp_f64 :: proc "c" (x, y, t: f64) -> f64 { return x*(1-t) + y*t } +lerp_vec2 :: proc "c" (x, y, t: vec2) -> vec2 { return {lerp(x.x, y.x, t.x), lerp(x.y, y.y, t.y)} } +lerp_vec3 :: proc "c" (x, y, t: vec3) -> vec3 { return {lerp(x.x, y.x, t.x), lerp(x.y, y.y, t.y), lerp(x.z, y.z, t.z)} } +lerp_vec4 :: proc "c" (x, y, t: vec4) -> vec4 { return {lerp(x.x, y.x, t.x), lerp(x.y, y.y, y.y), lerp(x.z, y.z, t.z), lerp(x.w, y.w, t.w)} } +lerp_dvec2 :: proc "c" (x, y, t: dvec2) -> dvec2 { return {lerp(x.x, y.x, t.x), lerp(x.y, y.y, t.y)} } +lerp_dvec3 :: proc "c" (x, y, t: dvec3) -> dvec3 { return {lerp(x.x, y.x, t.x), lerp(x.y, y.y, t.y), lerp(x.z, y.z, t.z)} } +lerp_dvec4 :: proc "c" (x, y, t: dvec4) -> dvec4 { return {lerp(x.x, y.x, t.x), lerp(x.y, y.y, y.y), lerp(x.z, y.z, t.z), lerp(x.w, y.w, t.w)} } + + +step :: proc{ + step_f32, + step_f64, + step_vec2, + step_vec3, + step_vec4, + step_dvec2, + step_dvec3, + step_dvec4, +} +step_f32 :: proc "c" (edge, x: f32) -> f32 { return 0 if x < edge else 1 } +step_f64 :: proc "c" (edge, x: f64) -> f64 { return 0 if x < edge else 1 } +step_vec2 :: proc "c" (edge, x: vec2) -> vec2 { return {step(edge.x, x.x), step(edge.y, x.y)} } +step_vec3 :: proc "c" (edge, x: vec3) -> vec3 { return {step(edge.x, x.x), step(edge.y, x.y), step(edge.z, x.z)} } +step_vec4 :: proc "c" (edge, x: vec4) -> vec4 { return {step(edge.x, x.x), step(edge.y, x.y), step(edge.z, x.z), step(edge.w, x.w)} } +step_dvec2 :: proc "c" (edge, x: dvec2) -> dvec2 { return {step(edge.x, x.x), step(edge.y, x.y)} } +step_dvec3 :: proc "c" (edge, x: dvec3) -> dvec3 { return {step(edge.x, x.x), step(edge.y, x.y), step(edge.z, x.z)} } +step_dvec4 :: proc "c" (edge, x: dvec4) -> dvec4 { return {step(edge.x, x.x), step(edge.y, x.y), step(edge.z, x.z), step(edge.w, x.w)} } + + +abs :: proc{ + abs_i32, + abs_u32, + abs_f32, + abs_f64, + abs_vec2, + abs_vec3, + abs_vec4, + abs_dvec2, + abs_dvec3, + abs_dvec4, + abs_ivec2, + abs_ivec3, + abs_ivec4, + abs_uvec2, + abs_uvec3, + abs_uvec4, +} +abs_i32 :: proc "c" (x: i32) -> i32 { return builtin.abs(x) } +abs_u32 :: proc "c" (x: u32) -> u32 { return x } +abs_f32 :: proc "c" (x: f32) -> f32 { return builtin.abs(x) } +abs_f64 :: proc "c" (x: f64) -> f64 { return builtin.abs(x) } +abs_vec2 :: proc "c" (x: vec2) -> vec2 { return {abs(x.x), abs(x.y)} } +abs_vec3 :: proc "c" (x: vec3) -> vec3 { return {abs(x.x), abs(x.y), abs(x.z)} } +abs_vec4 :: proc "c" (x: vec4) -> vec4 { return {abs(x.x), abs(x.y), abs(x.z), abs(x.w)} } +abs_dvec2 :: proc "c" (x: dvec2) -> dvec2 { return {abs(x.x), abs(x.y)} } +abs_dvec3 :: proc "c" (x: dvec3) -> dvec3 { return {abs(x.x), abs(x.y), abs(x.z)} } +abs_dvec4 :: proc "c" (x: dvec4) -> dvec4 { return {abs(x.x), abs(x.y), abs(x.z), abs(x.w)} } +abs_ivec2 :: proc "c" (x: ivec2) -> ivec2 { return {abs(x.x), abs(x.y)} } +abs_ivec3 :: proc "c" (x: ivec3) -> ivec3 { return {abs(x.x), abs(x.y), abs(x.z)} } +abs_ivec4 :: proc "c" (x: ivec4) -> ivec4 { return {abs(x.x), abs(x.y), abs(x.z), abs(x.w)} } +abs_uvec2 :: proc "c" (x: uvec2) -> uvec2 { return x } +abs_uvec3 :: proc "c" (x: uvec3) -> uvec3 { return x } +abs_uvec4 :: proc "c" (x: uvec4) -> uvec4 { return x } + +dot :: proc{ + dot_i32, + dot_u32, + dot_f32, + dot_f64, + dot_vec2, + dot_vec3, + dot_vec4, + dot_dvec2, + dot_dvec3, + dot_dvec4, + dot_ivec2, + dot_ivec3, + dot_ivec4, + dot_uvec2, + dot_uvec3, + dot_uvec4, + dot_quat, + dot_dquat, +} +dot_i32 :: proc "c" (a, b: i32) -> i32 { return a*b } +dot_u32 :: proc "c" (a, b: u32) -> u32 { return a*b } +dot_f32 :: proc "c" (a, b: f32) -> f32 { return a*b } +dot_f64 :: proc "c" (a, b: f64) -> f64 { return a*b } +dot_vec2 :: proc "c" (a, b: vec2) -> f32 { return a.x*b.x + a.y*b.y } +dot_vec3 :: proc "c" (a, b: vec3) -> f32 { return a.x*b.x + a.y*b.y + a.z*b.z } +dot_vec4 :: proc "c" (a, b: vec4) -> f32 { return a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.w } +dot_dvec2 :: proc "c" (a, b: dvec2) -> f64 { return a.x*b.x + a.y*b.y } +dot_dvec3 :: proc "c" (a, b: dvec3) -> f64 { return a.x*b.x + a.y*b.y + a.z*b.z } +dot_dvec4 :: proc "c" (a, b: dvec4) -> f64 { return a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.w } +dot_ivec2 :: proc "c" (a, b: ivec2) -> i32 { return a.x*b.x + a.y*b.y } +dot_ivec3 :: proc "c" (a, b: ivec3) -> i32 { return a.x*b.x + a.y*b.y + a.z*b.z } +dot_ivec4 :: proc "c" (a, b: ivec4) -> i32 { return a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.w } +dot_uvec2 :: proc "c" (a, b: uvec2) -> u32 { return a.x*b.x + a.y*b.y } +dot_uvec3 :: proc "c" (a, b: uvec3) -> u32 { return a.x*b.x + a.y*b.y + a.z*b.z } +dot_uvec4 :: proc "c" (a, b: uvec4) -> u32 { return a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.w } +dot_quat :: proc "c" (a, b: quat) -> f32 { return a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.w } +dot_dquat :: proc "c" (a, b: dquat) -> f64 { return a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.w } + +length :: proc{ + length_f32, + length_f64, + length_vec2, + length_vec3, + length_vec4, + length_dvec2, + length_dvec3, + length_dvec4, + length_quat, + length_dquat, +} +length_f32 :: proc "c" (x: f32) -> f32 { return builtin.abs(x) } +length_f64 :: proc "c" (x: f64) -> f64 { return builtin.abs(x) } +length_vec2 :: proc "c" (x: vec2) -> f32 { return sqrt(x.x*x.x + x.y*x.y) } +length_vec3 :: proc "c" (x: vec3) -> f32 { return sqrt(x.x*x.x + x.y*x.y + x.z*x.z) } +length_vec4 :: proc "c" (x: vec4) -> f32 { return sqrt(x.x*x.x + x.y*x.y + x.z*x.z + x.w*x.w) } +length_dvec2 :: proc "c" (x: dvec2) -> f64 { return sqrt(x.x*x.x + x.y*x.y) } +length_dvec3 :: proc "c" (x: dvec3) -> f64 { return sqrt(x.x*x.x + x.y*x.y + x.z*x.z) } +length_dvec4 :: proc "c" (x: dvec4) -> f64 { return sqrt(x.x*x.x + x.y*x.y + x.z*x.z + x.w*x.w) } +length_quat :: proc "c" (x: quat) -> f32 { return sqrt(x.x*x.x + x.y*x.y + x.z*x.z + x.w*x.w) } +length_dquat :: proc "c" (x: dquat) -> f64 { return sqrt(x.x*x.x + x.y*x.y + x.z*x.z + x.w*x.w) } + + +distance :: proc{ + distance_f32, + distance_f64, + distance_vec2, + distance_vec3, + distance_vec4, + distance_dvec2, + distance_dvec3, + distance_dvec4, +} +distance_f32 :: proc "c" (x, y: f32) -> f32 { return length(y-x) } +distance_f64 :: proc "c" (x, y: f64) -> f64 { return length(y-x) } +distance_vec2 :: proc "c" (x, y: vec2) -> f32 { return length(y-x) } +distance_vec3 :: proc "c" (x, y: vec3) -> f32 { return length(y-x) } +distance_vec4 :: proc "c" (x, y: vec4) -> f32 { return length(y-x) } +distance_dvec2 :: proc "c" (x, y: dvec2) -> f64 { return length(y-x) } +distance_dvec3 :: proc "c" (x, y: dvec3) -> f64 { return length(y-x) } +distance_dvec4 :: proc "c" (x, y: dvec4) -> f64 { return length(y-x) } + + +cross :: proc{ + cross_vec3, + cross_dvec3, + cross_ivec3, +} + +cross_vec3 :: proc "c" (a, b: vec3) -> (c: vec3) { + c.x = a.y*b.z - b.y*a.z + c.y = a.z*b.x - b.z*a.x + c.z = a.x*b.y - b.x*a.y + return +} +cross_dvec3 :: proc "c" (a, b: dvec3) -> (c: dvec3) { + c.x = a.y*b.z - b.y*a.z + c.y = a.z*b.x - b.z*a.x + c.z = a.x*b.y - b.x*a.y + return +} +cross_ivec3 :: proc "c" (a, b: ivec3) -> (c: ivec3) { + c.x = a.y*b.z - b.y*a.z + c.y = a.z*b.x - b.z*a.x + c.z = a.x*b.y - b.x*a.y + return +} + +normalize :: proc{ + normalize_f32, + normalize_f64, + normalize_vec2, + normalize_vec3, + normalize_vec4, + normalize_dvec2, + normalize_dvec3, + normalize_dvec4, + normalize_quat, + normalize_dquat, +} +normalize_f32 :: proc "c" (x: f32) -> f32 { return 1.0 } +normalize_f64 :: proc "c" (x: f64) -> f64 { return 1.0 } +normalize_vec2 :: proc "c" (x: vec2) -> vec2 { return x / length(x) } +normalize_vec3 :: proc "c" (x: vec3) -> vec3 { return x / length(x) } +normalize_vec4 :: proc "c" (x: vec4) -> vec4 { return x / length(x) } +normalize_dvec2 :: proc "c" (x: dvec2) -> dvec2 { return x / length(x) } +normalize_dvec3 :: proc "c" (x: dvec3) -> dvec3 { return x / length(x) } +normalize_dvec4 :: proc "c" (x: dvec4) -> dvec4 { return x / length(x) } +normalize_quat :: proc "c" (x: quat) -> quat { return x / quat(length(x)) } +normalize_dquat :: proc "c" (x: dquat) -> dquat { return x / dquat(length(x)) } + + +faceForward :: proc{ + faceForward_f32, + faceForward_f64, + faceForward_vec2, + faceForward_vec3, + faceForward_vec4, + faceForward_dvec2, + faceForward_dvec3, + faceForward_dvec4, +} +faceForward_f32 :: proc "c" (N, I, Nref: f32) -> f32 { return N if dot(I, Nref) < 0 else -N } +faceForward_f64 :: proc "c" (N, I, Nref: f64) -> f64 { return N if dot(I, Nref) < 0 else -N } +faceForward_vec2 :: proc "c" (N, I, Nref: vec2) -> vec2 { return N if dot(I, Nref) < 0 else -N } +faceForward_vec3 :: proc "c" (N, I, Nref: vec3) -> vec3 { return N if dot(I, Nref) < 0 else -N } +faceForward_vec4 :: proc "c" (N, I, Nref: vec4) -> vec4 { return N if dot(I, Nref) < 0 else -N } +faceForward_dvec2 :: proc "c" (N, I, Nref: dvec2) -> dvec2 { return N if dot(I, Nref) < 0 else -N } +faceForward_dvec3 :: proc "c" (N, I, Nref: dvec3) -> dvec3 { return N if dot(I, Nref) < 0 else -N } +faceForward_dvec4 :: proc "c" (N, I, Nref: dvec4) -> dvec4 { return N if dot(I, Nref) < 0 else -N } + + +reflect :: proc{ + reflect_f32, + reflect_f64, + reflect_vec2, + reflect_vec3, + reflect_vec4, + reflect_dvec2, + reflect_dvec3, + reflect_dvec4, +} +reflect_f32 :: proc "c" (I, N: f32) -> f32 { return I - 2*N*dot(N, I) } +reflect_f64 :: proc "c" (I, N: f64) -> f64 { return I - 2*N*dot(N, I) } +reflect_vec2 :: proc "c" (I, N: vec2) -> vec2 { return I - 2*N*dot(N, I) } +reflect_vec3 :: proc "c" (I, N: vec3) -> vec3 { return I - 2*N*dot(N, I) } +reflect_vec4 :: proc "c" (I, N: vec4) -> vec4 { return I - 2*N*dot(N, I) } +reflect_dvec2 :: proc "c" (I, N: dvec2) -> dvec2 { return I - 2*N*dot(N, I) } +reflect_dvec3 :: proc "c" (I, N: dvec3) -> dvec3 { return I - 2*N*dot(N, I) } +reflect_dvec4 :: proc "c" (I, N: dvec4) -> dvec4 { return I - 2*N*dot(N, I) } + + + + +refract :: proc{ + refract_f32, + refract_f64, + refract_vec2, + refract_vec3, + refract_vec4, + refract_dvec2, + refract_dvec3, + refract_dvec4, +} +refract_f32 :: proc "c" (i, n, eta: f32) -> f32 { + cosi := dot(-i, n) + cost2 := 1 - eta*eta*(1 - cosi*cosi) + t := eta*i + ((eta*cosi - sqrt(abs(cost2))) * n) + return t * f32(i32(cost2 > 0)) +} +refract_f64 :: proc "c" (i, n, eta: f64) -> f64 { + cosi := dot(-i, n) + cost2 := 1 - eta*eta*(1 - cosi*cosi) + t := eta*i + ((eta*cosi - sqrt(abs(cost2))) * n) + return t * f64(i32(cost2 > 0)) +} +refract_vec2 :: proc "c" (i, n, eta: vec2) -> vec2 { + cosi := dot(-i, n) + cost2 := 1 - eta*eta*(1 - cosi*cosi) + t := eta*i + ((eta*cosi - sqrt(abs(cost2))) * n) + return t * vec2{f32(i32(cost2.x > 0)), f32(i32(cost2.y > 0))} +} +refract_vec3 :: proc "c" (i, n, eta: vec3) -> vec3 { + cosi := dot(-i, n) + cost2 := 1 - eta*eta*(1 - cosi*cosi) + t := eta*i + ((eta*cosi - sqrt(abs(cost2))) * n) + return t * vec3{f32(i32(cost2.x > 0)), f32(i32(cost2.y > 0)), f32(i32(cost2.z > 0))} +} +refract_vec4 :: proc "c" (i, n, eta: vec4) -> vec4 { + cosi := dot(-i, n) + cost2 := 1 - eta*eta*(1 - cosi*cosi) + t := eta*i + ((eta*cosi - sqrt(abs(cost2))) * n) + return t * vec4{f32(i32(cost2.x > 0)), f32(i32(cost2.y > 0)), f32(i32(cost2.z > 0)), f32(i32(cost2.w > 0))} +} +refract_dvec2 :: proc "c" (i, n, eta: dvec2) -> dvec2 { + cosi := dot(-i, n) + cost2 := 1 - eta*eta*(1 - cosi*cosi) + t := eta*i + ((eta*cosi - sqrt(abs(cost2))) * n) + return t * dvec2{f64(i32(cost2.x > 0)), f64(i32(cost2.y > 0))} +} +refract_dvec3 :: proc "c" (i, n, eta: dvec3) -> dvec3 { + cosi := dot(-i, n) + cost2 := 1 - eta*eta*(1 - cosi*cosi) + t := eta*i + ((eta*cosi - sqrt(abs(cost2))) * n) + return t * dvec3{f64(i32(cost2.x > 0)), f64(i32(cost2.y > 0)), f64(i32(cost2.z > 0))} +} +refract_dvec4 :: proc "c" (i, n, eta: dvec4) -> dvec4 { + cosi := dot(-i, n) + cost2 := 1 - eta*eta*(1 - cosi*cosi) + t := eta*i + ((eta*cosi - sqrt(abs(cost2))) * n) + return t * dvec4{f64(i32(cost2.x > 0)), f64(i32(cost2.y > 0)), f64(i32(cost2.z > 0)), f64(i32(cost2.w > 0))} +} + +scalarTripleProduct :: proc{ + scalarTripleProduct_vec3, + scalarTripleProduct_dvec3, + scalarTripleProduct_ivec3, +} +scalarTripleProduct_vec3 :: proc "c" (a, b, c: vec3) -> f32 { return dot(a, cross(b, c)) } +scalarTripleProduct_dvec3 :: proc "c" (a, b, c: dvec3) -> f64 { return dot(a, cross(b, c)) } +scalarTripleProduct_ivec3 :: proc "c" (a, b, c: ivec3) -> i32 { return dot(a, cross(b, c)) } + +vectorTripleProduct :: proc { + vectorTripleProduct_vec3, + vectorTripleProduct_dvec3, + vectorTripleProduct_ivec3, +} +vectorTripleProduct_vec3 :: proc "c" (a, b, c: vec3) -> vec3 { return cross(a, cross(b, c)) } +vectorTripleProduct_dvec3 :: proc "c" (a, b, c: dvec3) -> dvec3 { return cross(a, cross(b, c)) } +vectorTripleProduct_ivec3 :: proc "c" (a, b, c: ivec3) -> ivec3 { return cross(a, cross(b, c)) } + + +// Vector Relational Procedures + +lessThan :: proc{ + lessThan_f32, + lessThan_f64, + lessThan_i32, + lessThan_u32, + lessThan_vec2, + lessThan_dvec2, + lessThan_ivec2, + lessThan_uvec2, + lessThan_vec3, + lessThan_dvec3, + lessThan_ivec3, + lessThan_uvec3, + lessThan_vec4, + lessThan_dvec4, + lessThan_ivec4, + lessThan_uvec4, +} +lessThan_f32 :: proc "c" (a, b: f32) -> bool { return a < b } +lessThan_f64 :: proc "c" (a, b: f64) -> bool { return a < b } +lessThan_i32 :: proc "c" (a, b: i32) -> bool { return a < b } +lessThan_u32 :: proc "c" (a, b: u32) -> bool { return a < b } +lessThan_vec2 :: proc "c" (a, b: vec2) -> bvec2 { return {a.x < b.x, a.y < b.y} } +lessThan_dvec2 :: proc "c" (a, b: dvec2) -> bvec2 { return {a.x < b.x, a.y < b.y} } +lessThan_ivec2 :: proc "c" (a, b: ivec2) -> bvec2 { return {a.x < b.x, a.y < b.y} } +lessThan_uvec2 :: proc "c" (a, b: uvec2) -> bvec2 { return {a.x < b.x, a.y < b.y} } +lessThan_vec3 :: proc "c" (a, b: vec3) -> bvec3 { return {a.x < b.x, a.y < b.y, a.z < b.z} } +lessThan_dvec3 :: proc "c" (a, b: dvec3) -> bvec3 { return {a.x < b.x, a.y < b.y, a.z < b.z} } +lessThan_ivec3 :: proc "c" (a, b: ivec3) -> bvec3 { return {a.x < b.x, a.y < b.y, a.z < b.z} } +lessThan_uvec3 :: proc "c" (a, b: uvec3) -> bvec3 { return {a.x < b.x, a.y < b.y, a.z < b.z} } +lessThan_vec4 :: proc "c" (a, b: vec4) -> bvec4 { return {a.x < b.x, a.y < b.y, a.z < b.z, a.w < b.w} } +lessThan_dvec4 :: proc "c" (a, b: dvec4) -> bvec4 { return {a.x < b.x, a.y < b.y, a.z < b.z, a.w < b.w} } +lessThan_ivec4 :: proc "c" (a, b: ivec4) -> bvec4 { return {a.x < b.x, a.y < b.y, a.z < b.z, a.w < b.w} } +lessThan_uvec4 :: proc "c" (a, b: uvec4) -> bvec4 { return {a.x < b.x, a.y < b.y, a.z < b.z, a.w < b.w} } + + +lessThanEqual :: proc{ + lessThanEqual_f32, + lessThanEqual_f64, + lessThanEqual_i32, + lessThanEqual_u32, + lessThanEqual_vec2, + lessThanEqual_dvec2, + lessThanEqual_ivec2, + lessThanEqual_uvec2, + lessThanEqual_vec3, + lessThanEqual_dvec3, + lessThanEqual_ivec3, + lessThanEqual_uvec3, + lessThanEqual_vec4, + lessThanEqual_dvec4, + lessThanEqual_ivec4, + lessThanEqual_uvec4, +} +lessThanEqual_f32 :: proc "c" (a, b: f32) -> bool { return a <= b } +lessThanEqual_f64 :: proc "c" (a, b: f64) -> bool { return a <= b } +lessThanEqual_i32 :: proc "c" (a, b: i32) -> bool { return a <= b } +lessThanEqual_u32 :: proc "c" (a, b: u32) -> bool { return a <= b } +lessThanEqual_vec2 :: proc "c" (a, b: vec2) -> bvec2 { return {a.x <= b.x, a.y <= b.y} } +lessThanEqual_dvec2 :: proc "c" (a, b: dvec2) -> bvec2 { return {a.x <= b.x, a.y <= b.y} } +lessThanEqual_ivec2 :: proc "c" (a, b: ivec2) -> bvec2 { return {a.x <= b.x, a.y <= b.y} } +lessThanEqual_uvec2 :: proc "c" (a, b: uvec2) -> bvec2 { return {a.x <= b.x, a.y <= b.y} } +lessThanEqual_vec3 :: proc "c" (a, b: vec3) -> bvec3 { return {a.x <= b.x, a.y <= b.y, a.z <= b.z} } +lessThanEqual_dvec3 :: proc "c" (a, b: dvec3) -> bvec3 { return {a.x <= b.x, a.y <= b.y, a.z <= b.z} } +lessThanEqual_ivec3 :: proc "c" (a, b: ivec3) -> bvec3 { return {a.x <= b.x, a.y <= b.y, a.z <= b.z} } +lessThanEqual_uvec3 :: proc "c" (a, b: uvec3) -> bvec3 { return {a.x <= b.x, a.y <= b.y, a.z <= b.z} } +lessThanEqual_vec4 :: proc "c" (a, b: vec4) -> bvec4 { return {a.x <= b.x, a.y <= b.y, a.z <= b.z, a.w <= b.w} } +lessThanEqual_dvec4 :: proc "c" (a, b: dvec4) -> bvec4 { return {a.x <= b.x, a.y <= b.y, a.z <= b.z, a.w <= b.w} } +lessThanEqual_ivec4 :: proc "c" (a, b: ivec4) -> bvec4 { return {a.x <= b.x, a.y <= b.y, a.z <= b.z, a.w <= b.w} } +lessThanEqual_uvec4 :: proc "c" (a, b: uvec4) -> bvec4 { return {a.x <= b.x, a.y <= b.y, a.z <= b.z, a.w <= b.w} } + + +greaterThan :: proc{ + greaterThan_f32, + greaterThan_f64, + greaterThan_i32, + greaterThan_u32, + greaterThan_vec2, + greaterThan_dvec2, + greaterThan_ivec2, + greaterThan_uvec2, + greaterThan_vec3, + greaterThan_dvec3, + greaterThan_ivec3, + greaterThan_uvec3, + greaterThan_vec4, + greaterThan_dvec4, + greaterThan_ivec4, + greaterThan_uvec4, +} +greaterThan_f32 :: proc "c" (a, b: f32) -> bool { return a > b } +greaterThan_f64 :: proc "c" (a, b: f64) -> bool { return a > b } +greaterThan_i32 :: proc "c" (a, b: i32) -> bool { return a > b } +greaterThan_u32 :: proc "c" (a, b: u32) -> bool { return a > b } +greaterThan_vec2 :: proc "c" (a, b: vec2) -> bvec2 { return {a.x > b.x, a.y > b.y} } +greaterThan_dvec2 :: proc "c" (a, b: dvec2) -> bvec2 { return {a.x > b.x, a.y > b.y} } +greaterThan_ivec2 :: proc "c" (a, b: ivec2) -> bvec2 { return {a.x > b.x, a.y > b.y} } +greaterThan_uvec2 :: proc "c" (a, b: uvec2) -> bvec2 { return {a.x > b.x, a.y > b.y} } +greaterThan_vec3 :: proc "c" (a, b: vec3) -> bvec3 { return {a.x > b.x, a.y > b.y, a.z > b.z} } +greaterThan_dvec3 :: proc "c" (a, b: dvec3) -> bvec3 { return {a.x > b.x, a.y > b.y, a.z > b.z} } +greaterThan_ivec3 :: proc "c" (a, b: ivec3) -> bvec3 { return {a.x > b.x, a.y > b.y, a.z > b.z} } +greaterThan_uvec3 :: proc "c" (a, b: uvec3) -> bvec3 { return {a.x > b.x, a.y > b.y, a.z > b.z} } +greaterThan_vec4 :: proc "c" (a, b: vec4) -> bvec4 { return {a.x > b.x, a.y > b.y, a.z > b.z, a.w > b.w} } +greaterThan_dvec4 :: proc "c" (a, b: dvec4) -> bvec4 { return {a.x > b.x, a.y > b.y, a.z > b.z, a.w > b.w} } +greaterThan_ivec4 :: proc "c" (a, b: ivec4) -> bvec4 { return {a.x > b.x, a.y > b.y, a.z > b.z, a.w > b.w} } +greaterThan_uvec4 :: proc "c" (a, b: uvec4) -> bvec4 { return {a.x > b.x, a.y > b.y, a.z > b.z, a.w > b.w} } + + +greaterThanEqual :: proc{ + greaterThanEqual_f32, + greaterThanEqual_f64, + greaterThanEqual_i32, + greaterThanEqual_u32, + greaterThanEqual_vec2, + greaterThanEqual_dvec2, + greaterThanEqual_ivec2, + greaterThanEqual_uvec2, + greaterThanEqual_vec3, + greaterThanEqual_dvec3, + greaterThanEqual_ivec3, + greaterThanEqual_uvec3, + greaterThanEqual_vec4, + greaterThanEqual_dvec4, + greaterThanEqual_ivec4, + greaterThanEqual_uvec4, +} +greaterThanEqual_f32 :: proc "c" (a, b: f32) -> bool { return a >= b } +greaterThanEqual_f64 :: proc "c" (a, b: f64) -> bool { return a >= b } +greaterThanEqual_i32 :: proc "c" (a, b: i32) -> bool { return a >= b } +greaterThanEqual_u32 :: proc "c" (a, b: u32) -> bool { return a >= b } +greaterThanEqual_vec2 :: proc "c" (a, b: vec2) -> bvec2 { return {a.x >= b.x, a.y >= b.y} } +greaterThanEqual_dvec2 :: proc "c" (a, b: dvec2) -> bvec2 { return {a.x >= b.x, a.y >= b.y} } +greaterThanEqual_ivec2 :: proc "c" (a, b: ivec2) -> bvec2 { return {a.x >= b.x, a.y >= b.y} } +greaterThanEqual_uvec2 :: proc "c" (a, b: uvec2) -> bvec2 { return {a.x >= b.x, a.y >= b.y} } +greaterThanEqual_vec3 :: proc "c" (a, b: vec3) -> bvec3 { return {a.x >= b.x, a.y >= b.y, a.z >= b.z} } +greaterThanEqual_dvec3 :: proc "c" (a, b: dvec3) -> bvec3 { return {a.x >= b.x, a.y >= b.y, a.z >= b.z} } +greaterThanEqual_ivec3 :: proc "c" (a, b: ivec3) -> bvec3 { return {a.x >= b.x, a.y >= b.y, a.z >= b.z} } +greaterThanEqual_uvec3 :: proc "c" (a, b: uvec3) -> bvec3 { return {a.x >= b.x, a.y >= b.y, a.z >= b.z} } +greaterThanEqual_vec4 :: proc "c" (a, b: vec4) -> bvec4 { return {a.x >= b.x, a.y >= b.y, a.z >= b.z, a.w >= b.w} } +greaterThanEqual_dvec4 :: proc "c" (a, b: dvec4) -> bvec4 { return {a.x >= b.x, a.y >= b.y, a.z >= b.z, a.w >= b.w} } +greaterThanEqual_ivec4 :: proc "c" (a, b: ivec4) -> bvec4 { return {a.x >= b.x, a.y >= b.y, a.z >= b.z, a.w >= b.w} } +greaterThanEqual_uvec4 :: proc "c" (a, b: uvec4) -> bvec4 { return {a.x >= b.x, a.y >= b.y, a.z >= b.z, a.w >= b.w} } + + +equal :: proc{ + equal_f32, + equal_f64, + equal_i32, + equal_u32, + equal_vec2, + equal_dvec2, + equal_ivec2, + equal_uvec2, + equal_vec3, + equal_dvec3, + equal_ivec3, + equal_uvec3, + equal_vec4, + equal_dvec4, + equal_ivec4, + equal_uvec4, +} +equal_f32 :: proc "c" (a, b: f32) -> bool { return a == b } +equal_f64 :: proc "c" (a, b: f64) -> bool { return a == b } +equal_i32 :: proc "c" (a, b: i32) -> bool { return a == b } +equal_u32 :: proc "c" (a, b: u32) -> bool { return a == b } +equal_vec2 :: proc "c" (a, b: vec2) -> bvec2 { return {a.x == b.x, a.y == b.y} } +equal_dvec2 :: proc "c" (a, b: dvec2) -> bvec2 { return {a.x == b.x, a.y == b.y} } +equal_ivec2 :: proc "c" (a, b: ivec2) -> bvec2 { return {a.x == b.x, a.y == b.y} } +equal_uvec2 :: proc "c" (a, b: uvec2) -> bvec2 { return {a.x == b.x, a.y == b.y} } +equal_vec3 :: proc "c" (a, b: vec3) -> bvec3 { return {a.x == b.x, a.y == b.y, a.z == b.z} } +equal_dvec3 :: proc "c" (a, b: dvec3) -> bvec3 { return {a.x == b.x, a.y == b.y, a.z == b.z} } +equal_ivec3 :: proc "c" (a, b: ivec3) -> bvec3 { return {a.x == b.x, a.y == b.y, a.z == b.z} } +equal_uvec3 :: proc "c" (a, b: uvec3) -> bvec3 { return {a.x == b.x, a.y == b.y, a.z == b.z} } +equal_vec4 :: proc "c" (a, b: vec4) -> bvec4 { return {a.x == b.x, a.y == b.y, a.z == b.z, a.w == b.w} } +equal_dvec4 :: proc "c" (a, b: dvec4) -> bvec4 { return {a.x == b.x, a.y == b.y, a.z == b.z, a.w == b.w} } +equal_ivec4 :: proc "c" (a, b: ivec4) -> bvec4 { return {a.x == b.x, a.y == b.y, a.z == b.z, a.w == b.w} } +equal_uvec4 :: proc "c" (a, b: uvec4) -> bvec4 { return {a.x == b.x, a.y == b.y, a.z == b.z, a.w == b.w} } + +notEqual :: proc{ + notEqual_f32, + notEqual_f64, + notEqual_i32, + notEqual_u32, + notEqual_vec2, + notEqual_dvec2, + notEqual_ivec2, + notEqual_uvec2, + notEqual_vec3, + notEqual_dvec3, + notEqual_ivec3, + notEqual_uvec3, + notEqual_vec4, + notEqual_dvec4, + notEqual_ivec4, + notEqual_uvec4, +} +notEqual_f32 :: proc "c" (a, b: f32) -> bool { return a != b } +notEqual_f64 :: proc "c" (a, b: f64) -> bool { return a != b } +notEqual_i32 :: proc "c" (a, b: i32) -> bool { return a != b } +notEqual_u32 :: proc "c" (a, b: u32) -> bool { return a != b } +notEqual_vec2 :: proc "c" (a, b: vec2) -> bvec2 { return {a.x != b.x, a.y != b.y} } +notEqual_dvec2 :: proc "c" (a, b: dvec2) -> bvec2 { return {a.x != b.x, a.y != b.y} } +notEqual_ivec2 :: proc "c" (a, b: ivec2) -> bvec2 { return {a.x != b.x, a.y != b.y} } +notEqual_uvec2 :: proc "c" (a, b: uvec2) -> bvec2 { return {a.x != b.x, a.y != b.y} } +notEqual_vec3 :: proc "c" (a, b: vec3) -> bvec3 { return {a.x != b.x, a.y != b.y, a.z != b.z} } +notEqual_dvec3 :: proc "c" (a, b: dvec3) -> bvec3 { return {a.x != b.x, a.y != b.y, a.z != b.z} } +notEqual_ivec3 :: proc "c" (a, b: ivec3) -> bvec3 { return {a.x != b.x, a.y != b.y, a.z != b.z} } +notEqual_uvec3 :: proc "c" (a, b: uvec3) -> bvec3 { return {a.x != b.x, a.y != b.y, a.z != b.z} } +notEqual_vec4 :: proc "c" (a, b: vec4) -> bvec4 { return {a.x != b.x, a.y != b.y, a.z != b.z, a.w != b.w} } +notEqual_dvec4 :: proc "c" (a, b: dvec4) -> bvec4 { return {a.x != b.x, a.y != b.y, a.z != b.z, a.w != b.w} } +notEqual_ivec4 :: proc "c" (a, b: ivec4) -> bvec4 { return {a.x != b.x, a.y != b.y, a.z != b.z, a.w != b.w} } +notEqual_uvec4 :: proc "c" (a, b: uvec4) -> bvec4 { return {a.x != b.x, a.y != b.y, a.z != b.z, a.w != b.w} } + + +any :: proc{ + any_bool, + any_bvec2, + any_bvec3, + any_bvec4, +} +any_bool :: proc "c" (v: bool) -> bool { return v } +any_bvec2 :: proc "c" (v: bvec2) -> bool { return v.x || v.y } +any_bvec3 :: proc "c" (v: bvec3) -> bool { return v.x || v.y || v.z } +any_bvec4 :: proc "c" (v: bvec4) -> bool { return v.x || v.y || v.z || v.w } + +all :: proc{ + all_bool, + all_bvec2, + all_bvec3, + all_bvec4, +} +all_bool :: proc "c" (v: bool) -> bool { return v } +all_bvec2 :: proc "c" (v: bvec2) -> bool { return v.x && v.y } +all_bvec3 :: proc "c" (v: bvec3) -> bool { return v.x && v.y && v.z } +all_bvec4 :: proc "c" (v: bvec4) -> bool { return v.x && v.y && v.z && v.w } + +not :: proc{ + not_bool, + not_bvec2, + not_bvec3, + not_bvec4, +} +not_bool :: proc "c" (v: bool) -> bool { return !v } +not_bvec2 :: proc "c" (v: bvec2) -> bvec2 { return {!v.x, !v.y} } +not_bvec3 :: proc "c" (v: bvec3) -> bvec3 { return {!v.x, !v.y, !v.z} } +not_bvec4 :: proc "c" (v: bvec4) -> bvec4 { return {!v.x, !v.y, !v.z, !v.w} } + + + +/// Matrix Utilities + +identity :: proc "c" ($M: typeid/matrix[$N, N]$T) -> M { return 1 } + +mat4Perspective :: proc "c" (fovy, aspect, near, far: f32) -> (m: mat4) { + tan_half_fovy := tan(0.5 * fovy) + m[0, 0] = 1 / (aspect*tan_half_fovy) + m[1, 1] = 1 / (tan_half_fovy) + m[2, 2] = -(far + near) / (far - near) + m[3, 2] = -1 + m[2, 3] = -2*far*near / (far - near) + return +} +mat4PerspectiveInfinite :: proc "c" (fovy, aspect, near: f32) -> (m: mat4) { + tan_half_fovy := tan(0.5 * fovy) + m[0, 0] = 1 / (aspect*tan_half_fovy) + m[1, 1] = 1 / (tan_half_fovy) + m[2, 2] = -1 + m[3, 2] = -1 + m[2, 3] = -2*near + return +} +mat4Ortho3d :: proc "c" (left, right, bottom, top, near, far: f32) -> (m: mat4) { + m[0, 0] = +2 / (right - left) + m[1, 1] = +2 / (top - bottom) + m[2, 2] = -2 / (far - near) + m[0, 3] = -(right + left) / (right - left) + m[1, 3] = -(top + bottom) / (top - bottom) + m[2, 3] = -(far + near) / (far- near) + m[3, 3] = 1 + return m +} +mat4LookAt :: proc "c" (eye, centre, up: vec3) -> (m: mat4) { + f := normalize(centre - eye) + s := normalize(cross(f, up)) + u := cross(s, f) + + fe := dot(f, eye) + + m[0] = {+s.x, +u.x, -f.x, 0} + m[1] = {+s.y, +u.y, -f.y, 0} + m[2] = {+s.z, +u.z, -f.z, 0} + m[3] = {-dot(s, eye), -dot(u, eye), +fe, 1} + return +} +mat4Rotate :: proc "c" (v: vec3, radians: f32) -> (rot: mat4) { + c := cos(radians) + s := sin(radians) + + a := normalize(v) + t := a * (1-c) + + rot = 1 + + rot[0, 0] = c + t[0]*a[0] + rot[1, 0] = 0 + t[0]*a[1] + s*a[2] + rot[2, 0] = 0 + t[0]*a[2] - s*a[1] + rot[3, 0] = 0 + + rot[0, 1] = 0 + t[1]*a[0] - s*a[2] + rot[1, 1] = c + t[1]*a[1] + rot[2, 1] = 0 + t[1]*a[2] + s*a[0] + rot[3, 1] = 0 + + rot[0, 2] = 0 + t[2]*a[0] + s*a[1] + rot[1, 2] = 0 + t[2]*a[1] - s*a[0] + rot[2, 2] = c + t[2]*a[2] + rot[3, 2] = 0 + + return rot +} +mat4Translate :: proc "c" (v: vec3) -> (m: mat4) { + m = 1 + m[3].xyz = v.xyz + return +} +mat4Scale :: proc "c" (v: vec3) -> (m: mat4) { + m[0, 0] = v[0] + m[1, 1] = v[1] + m[2, 2] = v[2] + m[3, 3] = 1 + return +} +mat4Orientation :: proc "c" (normal, up: vec3) -> mat4 { + if normal == up { + return 1 + } + + rotation_axis := cross(up, normal) + angle := acos(dot(normal, up)) + + return mat4Rotate(rotation_axis, angle) +} +mat4FromQuat :: proc "c" (q: quat) -> (m: mat4) { + qxx := q.x * q.x + qyy := q.y * q.y + qzz := q.z * q.z + qxz := q.x * q.z + qxy := q.x * q.y + qyz := q.y * q.z + qwx := q.w * q.x + qwy := q.w * q.y + qwz := q.w * q.z + + m[0, 0] = 1 - 2 * (qyy + qzz) + m[1, 0] = 2 * (qxy + qwz) + m[2, 0] = 2 * (qxz - qwy) + + m[0, 1] = 2 * (qxy - qwz) + m[1, 1] = 1 - 2 * (qxx + qzz) + m[2, 1] = 2 * (qyz + qwx) + + m[0, 2] = 2 * (qxz + qwy) + m[1, 2] = 2 * (qyz - qwx) + m[2, 2] = 1 - 2 * (qxx + qyy) + + m[3, 3] = 1 + + return +} + + +dmat4Perspective :: proc "c" (fovy, aspect, near, far: f64) -> (m: dmat4) { + tan_half_fovy := tan(0.5 * fovy) + m[0, 0] = 1 / (aspect*tan_half_fovy) + m[1, 1] = 1 / (tan_half_fovy) + m[2, 2] = -(far + near) / (far - near) + m[3, 2] = -1 + m[2, 3] = -2*far*near / (far - near) + return +} +dmat4PerspectiveInfinite :: proc "c" (fovy, aspect, near: f64) -> (m: dmat4) { + tan_half_fovy := tan(0.5 * fovy) + m[0, 0] = 1 / (aspect*tan_half_fovy) + m[1, 1] = 1 / (tan_half_fovy) + m[2, 2] = -1 + m[3, 2] = -1 + m[2, 3] = -2*near + return +} +dmat4Ortho3d :: proc "c" (left, right, bottom, top, near, far: f64) -> (m: dmat4) { + m[0, 0] = +2 / (right - left) + m[1, 1] = +2 / (top - bottom) + m[2, 2] = -2 / (far - near) + m[0, 3] = -(right + left) / (right - left) + m[1, 3] = -(top + bottom) / (top - bottom) + m[2, 3] = -(far + near) / (far- near) + m[3, 3] = 1 + return m +} +dmat4LookAt :: proc "c" (eye, centre, up: dvec3) -> (m: dmat4) { + f := normalize(centre - eye) + s := normalize(cross(f, up)) + u := cross(s, f) + + fe := dot(f, eye) + + m[0] = {+s.x, +u.x, -f.x, 0} + m[1] = {+s.y, +u.y, -f.y, 0} + m[2] = {+s.z, +u.z, -f.z, 0} + m[3] = {-dot(s, eye), -dot(u, eye), +fe, 1} + return +} +dmat4Rotate :: proc "c" (v: dvec3, radians: f64) -> (rot: dmat4) { + c := cos(radians) + s := sin(radians) + + a := normalize(v) + t := a * (1-c) + + rot = 1 + + rot[0, 0] = c + t[0]*a[0] + rot[1, 0] = 0 + t[0]*a[1] + s*a[2] + rot[2, 0] = 0 + t[0]*a[2] - s*a[1] + rot[3, 0] = 0 + + rot[0, 1] = 0 + t[1]*a[0] - s*a[2] + rot[1, 1] = c + t[1]*a[1] + rot[2, 1] = 0 + t[1]*a[2] + s*a[0] + rot[3, 1] = 0 + + rot[0, 2] = 0 + t[2]*a[0] + s*a[1] + rot[1, 2] = 0 + t[2]*a[1] - s*a[0] + rot[2, 2] = c + t[2]*a[2] + rot[3, 2] = 0 + + return rot +} +dmat4Translate :: proc "c" (v: dvec3) -> (m: dmat4) { + m = 1 + m[3].xyz = v.xyz + return +} +dmat4Scale :: proc "c" (v: dvec3) -> (m: dmat4) { + m[0, 0] = v[0] + m[1, 1] = v[1] + m[2, 2] = v[2] + m[3, 3] = 1 + return +} +dmat4Orientation :: proc "c" (normal, up: dvec3) -> dmat4 { + if normal == up { + return 1 + } + + rotation_axis := cross(up, normal) + angle := acos(dot(normal, up)) + + return dmat4Rotate(rotation_axis, angle) +} +dmat4FromDquat :: proc "c" (q: dquat) -> (m: dmat4) { + qxx := q.x * q.x + qyy := q.y * q.y + qzz := q.z * q.z + qxz := q.x * q.z + qxy := q.x * q.y + qyz := q.y * q.z + qwx := q.w * q.x + qwy := q.w * q.y + qwz := q.w * q.z + + m[0, 0] = 1 - 2 * (qyy + qzz) + m[1, 0] = 2 * (qxy + qwz) + m[2, 0] = 2 * (qxz - qwy) + + m[0, 1] = 2 * (qxy - qwz) + m[1, 1] = 1 - 2 * (qxx + qzz) + m[2, 1] = 2 * (qyz + qwx) + + m[0, 2] = 2 * (qxz + qwy) + m[1, 2] = 2 * (qyz - qwx) + m[2, 2] = 1 - 2 * (qxx + qyy) + + m[3, 3] = 1 + + return +} + +nlerp :: proc{ + quatNlerp, + dquatNlerp, +} +slerp :: proc{ + quatSlerp, + dquatSlerp, +} + + +quatAxisAngle :: proc "c" (axis: vec3, radians: f32) -> (q: quat) { + t := radians*0.5 + v := normalize(axis) * sin(t) + q.x = v.x + q.y = v.y + q.z = v.z + q.w = cos(t) + return +} +quatNlerp :: proc "c" (a, b: quat, t: f32) -> (c: quat) { + c.x = a.x + (b.x-a.x)*t + c.y = a.y + (b.y-a.y)*t + c.z = a.z + (b.z-a.z)*t + c.w = a.w + (b.w-a.w)*t + return c/builtin.abs(c) +} + +quatSlerp :: proc "c" (x, y: quat, t: f32) -> (q: quat) { + a, b := x, y + cos_angle := dot(a, b) + if cos_angle < 0 { + b = -b + cos_angle = -cos_angle + } + if cos_angle > 1 - F32_EPSILON { + q.x = a.x + (b.x-a.x)*t + q.y = a.y + (b.y-a.y)*t + q.z = a.z + (b.z-a.z)*t + q.w = a.w + (b.w-a.w)*t + return + } + + angle := acos(cos_angle) + sin_angle := sin(angle) + factor_a := sin((1-t) * angle) / sin_angle + factor_b := sin(t * angle) / sin_angle + + q.x = factor_a * a.x + factor_b * b.x + q.y = factor_a * a.y + factor_b * b.y + q.z = factor_a * a.z + factor_b * b.z + q.w = factor_a * a.w + factor_b * b.w + return +} +quatFromMat3 :: proc "c" (m: mat3) -> (q: quat) { + four_x_squared_minus_1 := m[0, 0] - m[1, 1] - m[2, 2] + four_y_squared_minus_1 := m[1, 1] - m[0, 0] - m[2, 2] + four_z_squared_minus_1 := m[2, 2] - m[0, 0] - m[1, 1] + four_w_squared_minus_1 := m[0, 0] + m[1, 1] + m[2, 2] + + biggest_index := 0 + four_biggest_squared_minus_1 := four_w_squared_minus_1 + if four_x_squared_minus_1 > four_biggest_squared_minus_1 { + four_biggest_squared_minus_1 = four_x_squared_minus_1 + biggest_index = 1 + } + if four_y_squared_minus_1 > four_biggest_squared_minus_1 { + four_biggest_squared_minus_1 = four_y_squared_minus_1 + biggest_index = 2 + } + if four_z_squared_minus_1 > four_biggest_squared_minus_1 { + four_biggest_squared_minus_1 = four_z_squared_minus_1 + biggest_index = 3 + } + + biggest_val := sqrt(four_biggest_squared_minus_1 + 1) * 0.5 + mult := 0.25 / biggest_val + + q = 1 + switch biggest_index { + case 0: + q.w = biggest_val + q.x = (m[2, 1] - m[1, 2]) * mult + q.y = (m[0, 2] - m[2, 0]) * mult + q.z = (m[1, 0] - m[0, 1]) * mult + case 1: + q.w = (m[2, 1] - m[1, 2]) * mult + q.x = biggest_val + q.y = (m[1, 0] + m[0, 1]) * mult + q.z = (m[0, 2] + m[2, 0]) * mult + case 2: + q.w = (m[0, 2] - m[2, 0]) * mult + q.x = (m[1, 0] + m[0, 1]) * mult + q.y = biggest_val + q.z = (m[2, 1] + m[1, 2]) * mult + case 3: + q.w = (m[1, 0] - m[0, 1]) * mult + q.x = (m[0, 2] + m[2, 0]) * mult + q.y = (m[2, 1] + m[1, 2]) * mult + q.z = biggest_val + } + return +} +quatFromMat4 :: proc "c" (m: mat4) -> (q: quat) { + return quatFromMat3(mat3(m)) +} + +quatMulVec3 :: proc "c" (q: quat, v: vec3) -> vec3 { + xyz := vec3{q.x, q.y, q.z} + t := cross(xyz, v) + return v + q.w*t + cross(xyz, t) +} + +dquatAxisAngle :: proc "c" (axis: dvec3, radians: f64) -> (q: dquat) { + t := radians*0.5 + v := normalize(axis) * sin(t) + q.x = v.x + q.y = v.y + q.z = v.z + q.w = cos(t) + return +} +dquatNlerp :: proc "c" (a, b: dquat, t: f64) -> (c: dquat) { + c.x = a.x + (b.x-a.x)*t + c.y = a.y + (b.y-a.y)*t + c.z = a.z + (b.z-a.z)*t + c.w = a.w + (b.w-a.w)*t + return c/builtin.abs(c) +} + +dquatSlerp :: proc "c" (x, y: dquat, t: f64) -> (q: dquat) { + a, b := x, y + cos_angle := dot(a, b) + if cos_angle < 0 { + b = -b + cos_angle = -cos_angle + } + if cos_angle > 1 - F64_EPSILON { + q.x = a.x + (b.x-a.x)*t + q.y = a.y + (b.y-a.y)*t + q.z = a.z + (b.z-a.z)*t + q.w = a.w + (b.w-a.w)*t + return + } + + angle := acos(cos_angle) + sin_angle := sin(angle) + factor_a := sin((1-t) * angle) / sin_angle + factor_b := sin(t * angle) / sin_angle + + q.x = factor_a * a.x + factor_b * b.x + q.y = factor_a * a.y + factor_b * b.y + q.z = factor_a * a.z + factor_b * b.z + q.w = factor_a * a.w + factor_b * b.w + return +} +dquatFromdMat3 :: proc "c" (m: dmat3) -> (q: dquat) { + four_x_squared_minus_1 := m[0, 0] - m[1, 1] - m[2, 2] + four_y_squared_minus_1 := m[1, 1] - m[0, 0] - m[2, 2] + four_z_squared_minus_1 := m[2, 2] - m[0, 0] - m[1, 1] + four_w_squared_minus_1 := m[0, 0] + m[1, 1] + m[2, 2] + + biggest_index := 0 + four_biggest_squared_minus_1 := four_w_squared_minus_1 + if four_x_squared_minus_1 > four_biggest_squared_minus_1 { + four_biggest_squared_minus_1 = four_x_squared_minus_1 + biggest_index = 1 + } + if four_y_squared_minus_1 > four_biggest_squared_minus_1 { + four_biggest_squared_minus_1 = four_y_squared_minus_1 + biggest_index = 2 + } + if four_z_squared_minus_1 > four_biggest_squared_minus_1 { + four_biggest_squared_minus_1 = four_z_squared_minus_1 + biggest_index = 3 + } + + biggest_val := sqrt(four_biggest_squared_minus_1 + 1) * 0.5 + mult := 0.25 / biggest_val + + q = 1 + switch biggest_index { + case 0: + q.w = biggest_val + q.x = (m[2, 1] - m[1, 2]) * mult + q.y = (m[0, 2] - m[2, 0]) * mult + q.z = (m[1, 0] - m[0, 1]) * mult + case 1: + q.w = (m[2, 1] - m[1, 2]) * mult + q.x = biggest_val + q.y = (m[1, 0] + m[0, 1]) * mult + q.z = (m[0, 2] + m[2, 0]) * mult + case 2: + q.w = (m[0, 2] - m[2, 0]) * mult + q.x = (m[1, 0] + m[0, 1]) * mult + q.y = biggest_val + q.z = (m[2, 1] + m[1, 2]) * mult + case 3: + q.w = (m[1, 0] - m[0, 1]) * mult + q.x = (m[0, 2] + m[2, 0]) * mult + q.y = (m[2, 1] + m[1, 2]) * mult + q.z = biggest_val + } + return +} +dquatFromDmat4 :: proc "c" (m: dmat4) -> (q: dquat) { + return dquatFromdMat3(dmat3(m)) +} + +dquatMulDvec3 :: proc "c" (q: dquat, v: dvec3) -> dvec3 { + xyz := dvec3{q.x, q.y, q.z} + t := cross(xyz, v) + return v + q.w*t + cross(xyz, t) +} + + + + +inverse_mat2 :: proc "c" (m: mat2) -> mat2 { return builtin.inverse(m) } +inverse_mat3 :: proc "c" (m: mat3) -> mat3 { return builtin.inverse(m) } +inverse_mat4 :: proc "c" (m: mat4) -> mat4 { return builtin.inverse(m) } +inverse_quat :: proc "c" (q: quat) -> quat { return 1/q } + +inverse :: proc{ + inverse_mat2, + inverse_mat3, + inverse_mat4, + inverse_quat, +} + +transpose :: builtin.transpose +inverse_transpose :: builtin.inverse_transpose +adjugate :: builtin.adjugate +hermitian_adjoint :: builtin.hermitian_adjoint +minor :: builtin.matrix_minor +determinant :: builtin.determinant +trace :: builtin.matrix_trace \ No newline at end of file diff --git a/core/math/linalg/glsl/linalg_glsl_math.odin b/core/math/linalg/glsl/linalg_glsl_math.odin new file mode 100644 index 000000000..68f43a2f7 --- /dev/null +++ b/core/math/linalg/glsl/linalg_glsl_math.odin @@ -0,0 +1,63 @@ +package math_linalg_glsl + +import "core:math" + +cos_f32 :: proc "c" (x: f32) -> f32 { return math.cos(x) } +sin_f32 :: proc "c" (x: f32) -> f32 { return math.sin(x) } +tan_f32 :: proc "c" (x: f32) -> f32 { return math.tan(x) } +acos_f32 :: proc "c" (x: f32) -> f32 { return math.acos(x) } +asin_f32 :: proc "c" (x: f32) -> f32 { return math.asin(x) } +atan_f32 :: proc "c" (x: f32) -> f32 { return math.atan(x) } +atan2_f32 :: proc "c" (y, x: f32) -> f32 { return math.atan2(y, x) } +cosh_f32 :: proc "c" (x: f32) -> f32 { return math.cosh(x) } +sinh_f32 :: proc "c" (x: f32) -> f32 { return math.sinh(x) } +tanh_f32 :: proc "c" (x: f32) -> f32 { return math.tanh(x) } +acosh_f32 :: proc "c" (x: f32) -> f32 { return math.acosh(x) } +asinh_f32 :: proc "c" (x: f32) -> f32 { return math.asinh(x) } +atanh_f32 :: proc "c" (x: f32) -> f32 { return math.atanh(x) } +sqrt_f32 :: proc "c" (x: f32) -> f32 { return math.sqrt(x) } +inversesqrt_f32 :: proc "c" (x: f32) -> f32 { return 1.0/math.sqrt(x) } +pow_f32 :: proc "c" (x, y: f32) -> f32 { return math.pow(x, y) } +exp_f32 :: proc "c" (x: f32) -> f32 { return math.exp(x) } +log_f32 :: proc "c" (x: f32) -> f32 { return math.ln(x) } +exp2_f32 :: proc "c" (x: f32) -> f32 { return math.pow(f32(2), x) } +sign_f32 :: proc "c" (x: f32) -> f32 { return math.sign(x) } +floor_f32 :: proc "c" (x: f32) -> f32 { return math.floor(x) } +ceil_f32 :: proc "c" (x: f32) -> f32 { return math.ceil(x) } +mod_f32 :: proc "c" (x, y: f32) -> f32 { return math.mod(x, y) } +fract_f32 :: proc "c" (x: f32) -> f32 { + if x >= 0 { + return x - math.trunc(x) + } + return math.trunc(-x) + x +} + +cos_f64 :: proc "c" (x: f64) -> f64 { return math.cos(x) } +sin_f64 :: proc "c" (x: f64) -> f64 { return math.sin(x) } +tan_f64 :: proc "c" (x: f64) -> f64 { return math.tan(x) } +acos_f64 :: proc "c" (x: f64) -> f64 { return math.acos(x) } +asin_f64 :: proc "c" (x: f64) -> f64 { return math.asin(x) } +atan_f64 :: proc "c" (x: f64) -> f64 { return math.atan(x) } +atan2_f64 :: proc "c" (y, x: f64) -> f64 { return math.atan2(y, x) } +cosh_f64 :: proc "c" (x: f64) -> f64 { return math.cosh(x) } +sinh_f64 :: proc "c" (x: f64) -> f64 { return math.sinh(x) } +tanh_f64 :: proc "c" (x: f64) -> f64 { return math.tanh(x) } +acosh_f64 :: proc "c" (x: f64) -> f64 { return math.acosh(x) } +asinh_f64 :: proc "c" (x: f64) -> f64 { return math.asinh(x) } +atanh_f64 :: proc "c" (x: f64) -> f64 { return math.atanh(x) } +sqrt_f64 :: proc "c" (x: f64) -> f64 { return math.sqrt(x) } +inversesqrt_f64 :: proc "c" (x: f64) -> f64 { return 1.0/math.sqrt(x) } +pow_f64 :: proc "c" (x, y: f64) -> f64 { return math.pow(x, y) } +exp_f64 :: proc "c" (x: f64) -> f64 { return math.exp(x) } +log_f64 :: proc "c" (x: f64) -> f64 { return math.ln(x) } +exp2_f64 :: proc "c" (x: f64) -> f64 { return math.pow(f64(2), x) } +sign_f64 :: proc "c" (x: f64) -> f64 { return math.sign(x) } +floor_f64 :: proc "c" (x: f64) -> f64 { return math.floor(x) } +ceil_f64 :: proc "c" (x: f64) -> f64 { return math.ceil(x) } +mod_f64 :: proc "c" (x, y: f64) -> f64 { return math.mod(x, y) } +fract_f64 :: proc "c" (x: f64) -> f64 { + if x >= 0 { + return x - math.trunc(x) + } + return math.trunc(-x) + x +} diff --git a/core/math/math.odin b/core/math/math.odin index 3b26a972f..445bf0c64 100644 --- a/core/math/math.odin +++ b/core/math/math.odin @@ -96,96 +96,96 @@ foreign _ { ldexp_f64 :: proc(val: f64, exp: i32) -> f64 --- } -sqrt_f16le :: proc(x: f16le) -> f16le { return #force_inline f16le(sqrt_f16(f16(x))) } -sqrt_f16be :: proc(x: f16be) -> f16be { return #force_inline f16be(sqrt_f16(f16(x))) } -sqrt_f32le :: proc(x: f32le) -> f32le { return #force_inline f32le(sqrt_f32(f32(x))) } -sqrt_f32be :: proc(x: f32be) -> f32be { return #force_inline f32be(sqrt_f32(f32(x))) } -sqrt_f64le :: proc(x: f64le) -> f64le { return #force_inline f64le(sqrt_f64(f64(x))) } -sqrt_f64be :: proc(x: f64be) -> f64be { return #force_inline f64be(sqrt_f64(f64(x))) } +sqrt_f16le :: proc "contextless" (x: f16le) -> f16le { return #force_inline f16le(sqrt_f16(f16(x))) } +sqrt_f16be :: proc "contextless" (x: f16be) -> f16be { return #force_inline f16be(sqrt_f16(f16(x))) } +sqrt_f32le :: proc "contextless" (x: f32le) -> f32le { return #force_inline f32le(sqrt_f32(f32(x))) } +sqrt_f32be :: proc "contextless" (x: f32be) -> f32be { return #force_inline f32be(sqrt_f32(f32(x))) } +sqrt_f64le :: proc "contextless" (x: f64le) -> f64le { return #force_inline f64le(sqrt_f64(f64(x))) } +sqrt_f64be :: proc "contextless" (x: f64be) -> f64be { return #force_inline f64be(sqrt_f64(f64(x))) } sqrt :: proc{ sqrt_f16, sqrt_f16le, sqrt_f16be, sqrt_f32, sqrt_f32le, sqrt_f32be, sqrt_f64, sqrt_f64le, sqrt_f64be, } -sin_f16le :: proc(θ: f16le) -> f16le { return #force_inline f16le(sin_f16(f16(θ))) } -sin_f16be :: proc(θ: f16be) -> f16be { return #force_inline f16be(sin_f16(f16(θ))) } -sin_f32le :: proc(θ: f32le) -> f32le { return #force_inline f32le(sin_f32(f32(θ))) } -sin_f32be :: proc(θ: f32be) -> f32be { return #force_inline f32be(sin_f32(f32(θ))) } -sin_f64le :: proc(θ: f64le) -> f64le { return #force_inline f64le(sin_f64(f64(θ))) } -sin_f64be :: proc(θ: f64be) -> f64be { return #force_inline f64be(sin_f64(f64(θ))) } +sin_f16le :: proc "contextless" (θ: f16le) -> f16le { return #force_inline f16le(sin_f16(f16(θ))) } +sin_f16be :: proc "contextless" (θ: f16be) -> f16be { return #force_inline f16be(sin_f16(f16(θ))) } +sin_f32le :: proc "contextless" (θ: f32le) -> f32le { return #force_inline f32le(sin_f32(f32(θ))) } +sin_f32be :: proc "contextless" (θ: f32be) -> f32be { return #force_inline f32be(sin_f32(f32(θ))) } +sin_f64le :: proc "contextless" (θ: f64le) -> f64le { return #force_inline f64le(sin_f64(f64(θ))) } +sin_f64be :: proc "contextless" (θ: f64be) -> f64be { return #force_inline f64be(sin_f64(f64(θ))) } sin :: proc{ sin_f16, sin_f16le, sin_f16be, sin_f32, sin_f32le, sin_f32be, sin_f64, sin_f64le, sin_f64be, } -cos_f16le :: proc(θ: f16le) -> f16le { return #force_inline f16le(cos_f16(f16(θ))) } -cos_f16be :: proc(θ: f16be) -> f16be { return #force_inline f16be(cos_f16(f16(θ))) } -cos_f32le :: proc(θ: f32le) -> f32le { return #force_inline f32le(cos_f32(f32(θ))) } -cos_f32be :: proc(θ: f32be) -> f32be { return #force_inline f32be(cos_f32(f32(θ))) } -cos_f64le :: proc(θ: f64le) -> f64le { return #force_inline f64le(cos_f64(f64(θ))) } -cos_f64be :: proc(θ: f64be) -> f64be { return #force_inline f64be(cos_f64(f64(θ))) } +cos_f16le :: proc "contextless" (θ: f16le) -> f16le { return #force_inline f16le(cos_f16(f16(θ))) } +cos_f16be :: proc "contextless" (θ: f16be) -> f16be { return #force_inline f16be(cos_f16(f16(θ))) } +cos_f32le :: proc "contextless" (θ: f32le) -> f32le { return #force_inline f32le(cos_f32(f32(θ))) } +cos_f32be :: proc "contextless" (θ: f32be) -> f32be { return #force_inline f32be(cos_f32(f32(θ))) } +cos_f64le :: proc "contextless" (θ: f64le) -> f64le { return #force_inline f64le(cos_f64(f64(θ))) } +cos_f64be :: proc "contextless" (θ: f64be) -> f64be { return #force_inline f64be(cos_f64(f64(θ))) } cos :: proc{ cos_f16, cos_f16le, cos_f16be, cos_f32, cos_f32le, cos_f32be, cos_f64, cos_f64le, cos_f64be, } -pow_f16le :: proc(x, power: f16le) -> f16le { return #force_inline f16le(pow_f16(f16(x), f16(power))) } -pow_f16be :: proc(x, power: f16be) -> f16be { return #force_inline f16be(pow_f16(f16(x), f16(power))) } -pow_f32le :: proc(x, power: f32le) -> f32le { return #force_inline f32le(pow_f32(f32(x), f32(power))) } -pow_f32be :: proc(x, power: f32be) -> f32be { return #force_inline f32be(pow_f32(f32(x), f32(power))) } -pow_f64le :: proc(x, power: f64le) -> f64le { return #force_inline f64le(pow_f64(f64(x), f64(power))) } -pow_f64be :: proc(x, power: f64be) -> f64be { return #force_inline f64be(pow_f64(f64(x), f64(power))) } +pow_f16le :: proc "contextless" (x, power: f16le) -> f16le { return #force_inline f16le(pow_f16(f16(x), f16(power))) } +pow_f16be :: proc "contextless" (x, power: f16be) -> f16be { return #force_inline f16be(pow_f16(f16(x), f16(power))) } +pow_f32le :: proc "contextless" (x, power: f32le) -> f32le { return #force_inline f32le(pow_f32(f32(x), f32(power))) } +pow_f32be :: proc "contextless" (x, power: f32be) -> f32be { return #force_inline f32be(pow_f32(f32(x), f32(power))) } +pow_f64le :: proc "contextless" (x, power: f64le) -> f64le { return #force_inline f64le(pow_f64(f64(x), f64(power))) } +pow_f64be :: proc "contextless" (x, power: f64be) -> f64be { return #force_inline f64be(pow_f64(f64(x), f64(power))) } pow :: proc{ pow_f16, pow_f16le, pow_f16be, pow_f32, pow_f32le, pow_f32be, pow_f64, pow_f64le, pow_f64be, } -fmuladd_f16le :: proc(a, b, c: f16le) -> f16le { return #force_inline f16le(fmuladd_f16(f16(a), f16(b), f16(c))) } -fmuladd_f16be :: proc(a, b, c: f16be) -> f16be { return #force_inline f16be(fmuladd_f16(f16(a), f16(b), f16(c))) } -fmuladd_f32le :: proc(a, b, c: f32le) -> f32le { return #force_inline f32le(fmuladd_f32(f32(a), f32(b), f32(c))) } -fmuladd_f32be :: proc(a, b, c: f32be) -> f32be { return #force_inline f32be(fmuladd_f32(f32(a), f32(b), f32(c))) } -fmuladd_f64le :: proc(a, b, c: f64le) -> f64le { return #force_inline f64le(fmuladd_f64(f64(a), f64(b), f64(c))) } -fmuladd_f64be :: proc(a, b, c: f64be) -> f64be { return #force_inline f64be(fmuladd_f64(f64(a), f64(b), f64(c))) } +fmuladd_f16le :: proc "contextless" (a, b, c: f16le) -> f16le { return #force_inline f16le(fmuladd_f16(f16(a), f16(b), f16(c))) } +fmuladd_f16be :: proc "contextless" (a, b, c: f16be) -> f16be { return #force_inline f16be(fmuladd_f16(f16(a), f16(b), f16(c))) } +fmuladd_f32le :: proc "contextless" (a, b, c: f32le) -> f32le { return #force_inline f32le(fmuladd_f32(f32(a), f32(b), f32(c))) } +fmuladd_f32be :: proc "contextless" (a, b, c: f32be) -> f32be { return #force_inline f32be(fmuladd_f32(f32(a), f32(b), f32(c))) } +fmuladd_f64le :: proc "contextless" (a, b, c: f64le) -> f64le { return #force_inline f64le(fmuladd_f64(f64(a), f64(b), f64(c))) } +fmuladd_f64be :: proc "contextless" (a, b, c: f64be) -> f64be { return #force_inline f64be(fmuladd_f64(f64(a), f64(b), f64(c))) } fmuladd :: proc{ fmuladd_f16, fmuladd_f16le, fmuladd_f16be, fmuladd_f32, fmuladd_f32le, fmuladd_f32be, fmuladd_f64, fmuladd_f64le, fmuladd_f64be, } -ln_f16le :: proc(x: f16le) -> f16le { return #force_inline f16le(ln_f16(f16(x))) } -ln_f16be :: proc(x: f16be) -> f16be { return #force_inline f16be(ln_f16(f16(x))) } -ln_f32le :: proc(x: f32le) -> f32le { return #force_inline f32le(ln_f32(f32(x))) } -ln_f32be :: proc(x: f32be) -> f32be { return #force_inline f32be(ln_f32(f32(x))) } -ln_f64le :: proc(x: f64le) -> f64le { return #force_inline f64le(ln_f64(f64(x))) } -ln_f64be :: proc(x: f64be) -> f64be { return #force_inline f64be(ln_f64(f64(x))) } +ln_f16le :: proc "contextless" (x: f16le) -> f16le { return #force_inline f16le(ln_f16(f16(x))) } +ln_f16be :: proc "contextless" (x: f16be) -> f16be { return #force_inline f16be(ln_f16(f16(x))) } +ln_f32le :: proc "contextless" (x: f32le) -> f32le { return #force_inline f32le(ln_f32(f32(x))) } +ln_f32be :: proc "contextless" (x: f32be) -> f32be { return #force_inline f32be(ln_f32(f32(x))) } +ln_f64le :: proc "contextless" (x: f64le) -> f64le { return #force_inline f64le(ln_f64(f64(x))) } +ln_f64be :: proc "contextless" (x: f64be) -> f64be { return #force_inline f64be(ln_f64(f64(x))) } ln :: proc{ ln_f16, ln_f16le, ln_f16be, ln_f32, ln_f32le, ln_f32be, ln_f64, ln_f64le, ln_f64be, } -exp_f16le :: proc(x: f16le) -> f16le { return #force_inline f16le(exp_f16(f16(x))) } -exp_f16be :: proc(x: f16be) -> f16be { return #force_inline f16be(exp_f16(f16(x))) } -exp_f32le :: proc(x: f32le) -> f32le { return #force_inline f32le(exp_f32(f32(x))) } -exp_f32be :: proc(x: f32be) -> f32be { return #force_inline f32be(exp_f32(f32(x))) } -exp_f64le :: proc(x: f64le) -> f64le { return #force_inline f64le(exp_f64(f64(x))) } -exp_f64be :: proc(x: f64be) -> f64be { return #force_inline f64be(exp_f64(f64(x))) } +exp_f16le :: proc "contextless" (x: f16le) -> f16le { return #force_inline f16le(exp_f16(f16(x))) } +exp_f16be :: proc "contextless" (x: f16be) -> f16be { return #force_inline f16be(exp_f16(f16(x))) } +exp_f32le :: proc "contextless" (x: f32le) -> f32le { return #force_inline f32le(exp_f32(f32(x))) } +exp_f32be :: proc "contextless" (x: f32be) -> f32be { return #force_inline f32be(exp_f32(f32(x))) } +exp_f64le :: proc "contextless" (x: f64le) -> f64le { return #force_inline f64le(exp_f64(f64(x))) } +exp_f64be :: proc "contextless" (x: f64be) -> f64be { return #force_inline f64be(exp_f64(f64(x))) } exp :: proc{ exp_f16, exp_f16le, exp_f16be, exp_f32, exp_f32le, exp_f32be, exp_f64, exp_f64le, exp_f64be, } -ldexp_f16le :: proc(val: f16le, exp: i32) -> f16le { return #force_inline f16le(ldexp_f16(f16(val), exp)) } -ldexp_f16be :: proc(val: f16be, exp: i32) -> f16be { return #force_inline f16be(ldexp_f16(f16(val), exp)) } -ldexp_f32le :: proc(val: f32le, exp: i32) -> f32le { return #force_inline f32le(ldexp_f32(f32(val), exp)) } -ldexp_f32be :: proc(val: f32be, exp: i32) -> f32be { return #force_inline f32be(ldexp_f32(f32(val), exp)) } -ldexp_f64le :: proc(val: f64le, exp: i32) -> f64le { return #force_inline f64le(ldexp_f64(f64(val), exp)) } -ldexp_f64be :: proc(val: f64be, exp: i32) -> f64be { return #force_inline f64be(ldexp_f64(f64(val), exp)) } +ldexp_f16le :: proc "contextless" (val: f16le, exp: i32) -> f16le { return #force_inline f16le(ldexp_f16(f16(val), exp)) } +ldexp_f16be :: proc "contextless" (val: f16be, exp: i32) -> f16be { return #force_inline f16be(ldexp_f16(f16(val), exp)) } +ldexp_f32le :: proc "contextless" (val: f32le, exp: i32) -> f32le { return #force_inline f32le(ldexp_f32(f32(val), exp)) } +ldexp_f32be :: proc "contextless" (val: f32be, exp: i32) -> f32be { return #force_inline f32be(ldexp_f32(f32(val), exp)) } +ldexp_f64le :: proc "contextless" (val: f64le, exp: i32) -> f64le { return #force_inline f64le(ldexp_f64(f64(val), exp)) } +ldexp_f64be :: proc "contextless" (val: f64be, exp: i32) -> f64be { return #force_inline f64be(ldexp_f64(f64(val), exp)) } ldexp :: proc{ ldexp_f16, ldexp_f16le, ldexp_f16be, ldexp_f32, ldexp_f32le, ldexp_f32be, @@ -193,82 +193,82 @@ ldexp :: proc{ } -log_f16 :: proc(x, base: f16) -> f16 { return ln(x) / ln(base) } -log_f16le :: proc(x, base: f16le) -> f16le { return f16le(log_f16(f16(x), f16(base))) } -log_f16be :: proc(x, base: f16be) -> f16be { return f16be(log_f16(f16(x), f16(base))) } +log_f16 :: proc "contextless" (x, base: f16) -> f16 { return ln(x) / ln(base) } +log_f16le :: proc "contextless" (x, base: f16le) -> f16le { return f16le(log_f16(f16(x), f16(base))) } +log_f16be :: proc "contextless" (x, base: f16be) -> f16be { return f16be(log_f16(f16(x), f16(base))) } -log_f32 :: proc(x, base: f32) -> f32 { return ln(x) / ln(base) } -log_f32le :: proc(x, base: f32le) -> f32le { return f32le(log_f32(f32(x), f32(base))) } -log_f32be :: proc(x, base: f32be) -> f32be { return f32be(log_f32(f32(x), f32(base))) } +log_f32 :: proc "contextless" (x, base: f32) -> f32 { return ln(x) / ln(base) } +log_f32le :: proc "contextless" (x, base: f32le) -> f32le { return f32le(log_f32(f32(x), f32(base))) } +log_f32be :: proc "contextless" (x, base: f32be) -> f32be { return f32be(log_f32(f32(x), f32(base))) } -log_f64 :: proc(x, base: f64) -> f64 { return ln(x) / ln(base) } -log_f64le :: proc(x, base: f64le) -> f64le { return f64le(log_f64(f64(x), f64(base))) } -log_f64be :: proc(x, base: f64be) -> f64be { return f64be(log_f64(f64(x), f64(base))) } +log_f64 :: proc "contextless" (x, base: f64) -> f64 { return ln(x) / ln(base) } +log_f64le :: proc "contextless" (x, base: f64le) -> f64le { return f64le(log_f64(f64(x), f64(base))) } +log_f64be :: proc "contextless" (x, base: f64be) -> f64be { return f64be(log_f64(f64(x), f64(base))) } log :: proc{ log_f16, log_f16le, log_f16be, log_f32, log_f32le, log_f32be, log_f64, log_f64le, log_f64be, } -log2_f16 :: proc(x: f16) -> f16 { return ln(x)/LN2 } -log2_f16le :: proc(x: f16le) -> f16le { return f16le(log2_f16(f16(x))) } -log2_f16be :: proc(x: f16be) -> f16be { return f16be(log2_f16(f16(x))) } +log2_f16 :: proc "contextless" (x: f16) -> f16 { return ln(x)/LN2 } +log2_f16le :: proc "contextless" (x: f16le) -> f16le { return f16le(log2_f16(f16(x))) } +log2_f16be :: proc "contextless" (x: f16be) -> f16be { return f16be(log2_f16(f16(x))) } -log2_f32 :: proc(x: f32) -> f32 { return ln(x)/LN2 } -log2_f32le :: proc(x: f32le) -> f32le { return f32le(log2_f32(f32(x))) } -log2_f32be :: proc(x: f32be) -> f32be { return f32be(log2_f32(f32(x))) } +log2_f32 :: proc "contextless" (x: f32) -> f32 { return ln(x)/LN2 } +log2_f32le :: proc "contextless" (x: f32le) -> f32le { return f32le(log2_f32(f32(x))) } +log2_f32be :: proc "contextless" (x: f32be) -> f32be { return f32be(log2_f32(f32(x))) } -log2_f64 :: proc(x: f64) -> f64 { return ln(x)/LN2 } -log2_f64le :: proc(x: f64le) -> f64le { return f64le(log2_f64(f64(x))) } -log2_f64be :: proc(x: f64be) -> f64be { return f64be(log2_f64(f64(x))) } +log2_f64 :: proc "contextless" (x: f64) -> f64 { return ln(x)/LN2 } +log2_f64le :: proc "contextless" (x: f64le) -> f64le { return f64le(log2_f64(f64(x))) } +log2_f64be :: proc "contextless" (x: f64be) -> f64be { return f64be(log2_f64(f64(x))) } log2 :: proc{ log2_f16, log2_f16le, log2_f16be, log2_f32, log2_f32le, log2_f32be, log2_f64, log2_f64le, log2_f64be, } -log10_f16 :: proc(x: f16) -> f16 { return ln(x)/LN10 } -log10_f16le :: proc(x: f16le) -> f16le { return f16le(log10_f16(f16(x))) } -log10_f16be :: proc(x: f16be) -> f16be { return f16be(log10_f16(f16(x))) } +log10_f16 :: proc "contextless" (x: f16) -> f16 { return ln(x)/LN10 } +log10_f16le :: proc "contextless" (x: f16le) -> f16le { return f16le(log10_f16(f16(x))) } +log10_f16be :: proc "contextless" (x: f16be) -> f16be { return f16be(log10_f16(f16(x))) } -log10_f32 :: proc(x: f32) -> f32 { return ln(x)/LN10 } -log10_f32le :: proc(x: f32le) -> f32le { return f32le(log10_f32(f32(x))) } -log10_f32be :: proc(x: f32be) -> f32be { return f32be(log10_f32(f32(x))) } +log10_f32 :: proc "contextless" (x: f32) -> f32 { return ln(x)/LN10 } +log10_f32le :: proc "contextless" (x: f32le) -> f32le { return f32le(log10_f32(f32(x))) } +log10_f32be :: proc "contextless" (x: f32be) -> f32be { return f32be(log10_f32(f32(x))) } -log10_f64 :: proc(x: f64) -> f64 { return ln(x)/LN10 } -log10_f64le :: proc(x: f64le) -> f64le { return f64le(log10_f64(f64(x))) } -log10_f64be :: proc(x: f64be) -> f64be { return f64be(log10_f64(f64(x))) } +log10_f64 :: proc "contextless" (x: f64) -> f64 { return ln(x)/LN10 } +log10_f64le :: proc "contextless" (x: f64le) -> f64le { return f64le(log10_f64(f64(x))) } +log10_f64be :: proc "contextless" (x: f64be) -> f64be { return f64be(log10_f64(f64(x))) } log10 :: proc{ log10_f16, log10_f16le, log10_f16be, log10_f32, log10_f32le, log10_f32be, log10_f64, log10_f64le, log10_f64be, } -tan_f16 :: proc(θ: f16) -> f16 { return sin(θ)/cos(θ) } -tan_f16le :: proc(θ: f16le) -> f16le { return f16le(tan_f16(f16(θ))) } -tan_f16be :: proc(θ: f16be) -> f16be { return f16be(tan_f16(f16(θ))) } +tan_f16 :: proc "contextless" (θ: f16) -> f16 { return sin(θ)/cos(θ) } +tan_f16le :: proc "contextless" (θ: f16le) -> f16le { return f16le(tan_f16(f16(θ))) } +tan_f16be :: proc "contextless" (θ: f16be) -> f16be { return f16be(tan_f16(f16(θ))) } -tan_f32 :: proc(θ: f32) -> f32 { return sin(θ)/cos(θ) } -tan_f32le :: proc(θ: f32le) -> f32le { return f32le(tan_f32(f32(θ))) } -tan_f32be :: proc(θ: f32be) -> f32be { return f32be(tan_f32(f32(θ))) } +tan_f32 :: proc "contextless" (θ: f32) -> f32 { return sin(θ)/cos(θ) } +tan_f32le :: proc "contextless" (θ: f32le) -> f32le { return f32le(tan_f32(f32(θ))) } +tan_f32be :: proc "contextless" (θ: f32be) -> f32be { return f32be(tan_f32(f32(θ))) } -tan_f64 :: proc(θ: f64) -> f64 { return sin(θ)/cos(θ) } -tan_f64le :: proc(θ: f64le) -> f64le { return f64le(tan_f64(f64(θ))) } -tan_f64be :: proc(θ: f64be) -> f64be { return f64be(tan_f64(f64(θ))) } +tan_f64 :: proc "contextless" (θ: f64) -> f64 { return sin(θ)/cos(θ) } +tan_f64le :: proc "contextless" (θ: f64le) -> f64le { return f64le(tan_f64(f64(θ))) } +tan_f64be :: proc "contextless" (θ: f64be) -> f64be { return f64be(tan_f64(f64(θ))) } tan :: proc{ tan_f16, tan_f16le, tan_f16be, tan_f32, tan_f32le, tan_f32be, tan_f64, tan_f64le, tan_f64be, } -lerp :: proc(a, b: $T, t: $E) -> (x: T) { return a*(1-t) + b*t } -saturate :: proc(a: $T) -> (x: T) { return clamp(a, 0, 1) } +lerp :: proc "contextless" (a, b: $T, t: $E) -> (x: T) { return a*(1-t) + b*t } +saturate :: proc "contextless" (a: $T) -> (x: T) { return clamp(a, 0, 1) } -unlerp :: proc(a, b, x: $T) -> (t: T) where intrinsics.type_is_float(T), !intrinsics.type_is_array(T) { +unlerp :: proc "contextless" (a, b, x: $T) -> (t: T) where intrinsics.type_is_float(T), !intrinsics.type_is_array(T) { return (x-a)/(b-a) } -remap :: proc(old_value, old_min, old_max, new_min, new_max: $T) -> (x: T) where intrinsics.type_is_numeric(T), !intrinsics.type_is_array(T) { +remap :: proc "contextless" (old_value, old_min, old_max, new_min, new_max: $T) -> (x: T) where intrinsics.type_is_numeric(T), !intrinsics.type_is_array(T) { old_range := old_max - old_min new_range := new_max - new_min if old_range == 0 { @@ -277,33 +277,33 @@ remap :: proc(old_value, old_min, old_max, new_min, new_max: $T) -> (x: T) where return ((old_value - old_min) / old_range) * new_range + new_min } -wrap :: proc(x, y: $T) -> T where intrinsics.type_is_numeric(T), !intrinsics.type_is_array(T) { +wrap :: proc "contextless" (x, y: $T) -> T where intrinsics.type_is_numeric(T), !intrinsics.type_is_array(T) { tmp := mod(x, y) return y + tmp if tmp < 0 else tmp } -angle_diff :: proc(a, b: $T) -> T where intrinsics.type_is_numeric(T), !intrinsics.type_is_array(T) { +angle_diff :: proc "contextless" (a, b: $T) -> T where intrinsics.type_is_numeric(T), !intrinsics.type_is_array(T) { dist := wrap(b - a, TAU) return wrap(dist*2, TAU) - dist } -angle_lerp :: proc(a, b, t: $T) -> T where intrinsics.type_is_numeric(T), !intrinsics.type_is_array(T) { +angle_lerp :: proc "contextless" (a, b, t: $T) -> T where intrinsics.type_is_numeric(T), !intrinsics.type_is_array(T) { return a + angle_diff(a, b) * t } -step :: proc(edge, x: $T) -> T where intrinsics.type_is_numeric(T), !intrinsics.type_is_array(T) { +step :: proc "contextless" (edge, x: $T) -> T where intrinsics.type_is_numeric(T), !intrinsics.type_is_array(T) { return 0 if x < edge else 1 } -smoothstep :: proc(edge0, edge1, x: $T) -> T where intrinsics.type_is_numeric(T), !intrinsics.type_is_array(T) { +smoothstep :: proc "contextless" (edge0, edge1, x: $T) -> T where intrinsics.type_is_numeric(T), !intrinsics.type_is_array(T) { t := clamp((x - edge0) / (edge1 - edge0), 0, 1) return t * t * (3 - 2*t) } -bias :: proc(t, b: $T) -> T where intrinsics.type_is_numeric(T) { +bias :: proc "contextless" (t, b: $T) -> T where intrinsics.type_is_numeric(T) { return t / (((1/b) - 2) * (1 - t) + 1) } -gain :: proc(t, g: $T) -> T where intrinsics.type_is_numeric(T) { +gain :: proc "contextless" (t, g: $T) -> T where intrinsics.type_is_numeric(T) { if t < 0.5 { return bias(t*2, g)*0.5 } @@ -311,93 +311,93 @@ gain :: proc(t, g: $T) -> T where intrinsics.type_is_numeric(T) { } -sign_f16 :: proc(x: f16) -> f16 { return f16(int(0 < x) - int(x < 0)) } -sign_f16le :: proc(x: f16le) -> f16le { return f16le(int(0 < x) - int(x < 0)) } -sign_f16be :: proc(x: f16be) -> f16be { return f16be(int(0 < x) - int(x < 0)) } -sign_f32 :: proc(x: f32) -> f32 { return f32(int(0 < x) - int(x < 0)) } -sign_f32le :: proc(x: f32le) -> f32le { return f32le(int(0 < x) - int(x < 0)) } -sign_f32be :: proc(x: f32be) -> f32be { return f32be(int(0 < x) - int(x < 0)) } -sign_f64 :: proc(x: f64) -> f64 { return f64(int(0 < x) - int(x < 0)) } -sign_f64le :: proc(x: f64le) -> f64le { return f64le(int(0 < x) - int(x < 0)) } -sign_f64be :: proc(x: f64be) -> f64be { return f64be(int(0 < x) - int(x < 0)) } +sign_f16 :: proc "contextless" (x: f16) -> f16 { return f16(int(0 < x) - int(x < 0)) } +sign_f16le :: proc "contextless" (x: f16le) -> f16le { return f16le(int(0 < x) - int(x < 0)) } +sign_f16be :: proc "contextless" (x: f16be) -> f16be { return f16be(int(0 < x) - int(x < 0)) } +sign_f32 :: proc "contextless" (x: f32) -> f32 { return f32(int(0 < x) - int(x < 0)) } +sign_f32le :: proc "contextless" (x: f32le) -> f32le { return f32le(int(0 < x) - int(x < 0)) } +sign_f32be :: proc "contextless" (x: f32be) -> f32be { return f32be(int(0 < x) - int(x < 0)) } +sign_f64 :: proc "contextless" (x: f64) -> f64 { return f64(int(0 < x) - int(x < 0)) } +sign_f64le :: proc "contextless" (x: f64le) -> f64le { return f64le(int(0 < x) - int(x < 0)) } +sign_f64be :: proc "contextless" (x: f64be) -> f64be { return f64be(int(0 < x) - int(x < 0)) } sign :: proc{ sign_f16, sign_f16le, sign_f16be, sign_f32, sign_f32le, sign_f32be, sign_f64, sign_f64le, sign_f64be, } -sign_bit_f16 :: proc(x: f16) -> bool { +sign_bit_f16 :: proc "contextless" (x: f16) -> bool { return (transmute(u16)x) & (1<<15) != 0 } -sign_bit_f16le :: proc(x: f16le) -> bool { return #force_inline sign_bit_f16(f16(x)) } -sign_bit_f16be :: proc(x: f16be) -> bool { return #force_inline sign_bit_f16(f16(x)) } -sign_bit_f32 :: proc(x: f32) -> bool { +sign_bit_f16le :: proc "contextless" (x: f16le) -> bool { return #force_inline sign_bit_f16(f16(x)) } +sign_bit_f16be :: proc "contextless" (x: f16be) -> bool { return #force_inline sign_bit_f16(f16(x)) } +sign_bit_f32 :: proc "contextless" (x: f32) -> bool { return (transmute(u32)x) & (1<<31) != 0 } -sign_bit_f32le :: proc(x: f32le) -> bool { return #force_inline sign_bit_f32(f32(x)) } -sign_bit_f32be :: proc(x: f32be) -> bool { return #force_inline sign_bit_f32(f32(x)) } -sign_bit_f64 :: proc(x: f64) -> bool { +sign_bit_f32le :: proc "contextless" (x: f32le) -> bool { return #force_inline sign_bit_f32(f32(x)) } +sign_bit_f32be :: proc "contextless" (x: f32be) -> bool { return #force_inline sign_bit_f32(f32(x)) } +sign_bit_f64 :: proc "contextless" (x: f64) -> bool { return (transmute(u64)x) & (1<<63) != 0 } -sign_bit_f64le :: proc(x: f64le) -> bool { return #force_inline sign_bit_f64(f64(x)) } -sign_bit_f64be :: proc(x: f64be) -> bool { return #force_inline sign_bit_f64(f64(x)) } +sign_bit_f64le :: proc "contextless" (x: f64le) -> bool { return #force_inline sign_bit_f64(f64(x)) } +sign_bit_f64be :: proc "contextless" (x: f64be) -> bool { return #force_inline sign_bit_f64(f64(x)) } sign_bit :: proc{ sign_bit_f16, sign_bit_f16le, sign_bit_f16be, sign_bit_f32, sign_bit_f32le, sign_bit_f32be, sign_bit_f64, sign_bit_f64le, sign_bit_f64be, } -copy_sign_f16 :: proc(x, y: f16) -> f16 { +copy_sign_f16 :: proc "contextless" (x, y: f16) -> f16 { ix := transmute(u16)x iy := transmute(u16)y ix &= 0x7fff ix |= iy & 0x8000 return transmute(f16)ix } -copy_sign_f16le :: proc(x, y: f16le) -> f16le { return #force_inline f16le(copy_sign_f16(f16(x), f16(y))) } -copy_sign_f16be :: proc(x, y: f16be) -> f16be { return #force_inline f16be(copy_sign_f16(f16(x), f16(y))) } -copy_sign_f32 :: proc(x, y: f32) -> f32 { +copy_sign_f16le :: proc "contextless" (x, y: f16le) -> f16le { return #force_inline f16le(copy_sign_f16(f16(x), f16(y))) } +copy_sign_f16be :: proc "contextless" (x, y: f16be) -> f16be { return #force_inline f16be(copy_sign_f16(f16(x), f16(y))) } +copy_sign_f32 :: proc "contextless" (x, y: f32) -> f32 { ix := transmute(u32)x iy := transmute(u32)y ix &= 0x7fff_ffff ix |= iy & 0x8000_0000 return transmute(f32)ix } -copy_sign_f32le :: proc(x, y: f32le) -> f32le { return #force_inline f32le(copy_sign_f32(f32(x), f32(y))) } -copy_sign_f32be :: proc(x, y: f32be) -> f32be { return #force_inline f32be(copy_sign_f32(f32(x), f32(y))) } -copy_sign_f64 :: proc(x, y: f64) -> f64 { +copy_sign_f32le :: proc "contextless" (x, y: f32le) -> f32le { return #force_inline f32le(copy_sign_f32(f32(x), f32(y))) } +copy_sign_f32be :: proc "contextless" (x, y: f32be) -> f32be { return #force_inline f32be(copy_sign_f32(f32(x), f32(y))) } +copy_sign_f64 :: proc "contextless" (x, y: f64) -> f64 { ix := transmute(u64)x iy := transmute(u64)y ix &= 0x7fff_ffff_ffff_ffff ix |= iy & 0x8000_0000_0000_0000 return transmute(f64)ix } -copy_sign_f64le :: proc(x, y: f64le) -> f64le { return #force_inline f64le(copy_sign_f64(f64(x), f64(y))) } -copy_sign_f64be :: proc(x, y: f64be) -> f64be { return #force_inline f64be(copy_sign_f64(f64(x), f64(y))) } +copy_sign_f64le :: proc "contextless" (x, y: f64le) -> f64le { return #force_inline f64le(copy_sign_f64(f64(x), f64(y))) } +copy_sign_f64be :: proc "contextless" (x, y: f64be) -> f64be { return #force_inline f64be(copy_sign_f64(f64(x), f64(y))) } copy_sign :: proc{ copy_sign_f16, copy_sign_f16le, copy_sign_f16be, copy_sign_f32, copy_sign_f32le, copy_sign_f32be, copy_sign_f64, copy_sign_f64le, copy_sign_f64be, } -to_radians_f16 :: proc(degrees: f16) -> f16 { return degrees * RAD_PER_DEG } -to_radians_f16le :: proc(degrees: f16le) -> f16le { return degrees * RAD_PER_DEG } -to_radians_f16be :: proc(degrees: f16be) -> f16be { return degrees * RAD_PER_DEG } -to_radians_f32 :: proc(degrees: f32) -> f32 { return degrees * RAD_PER_DEG } -to_radians_f32le :: proc(degrees: f32le) -> f32le { return degrees * RAD_PER_DEG } -to_radians_f32be :: proc(degrees: f32be) -> f32be { return degrees * RAD_PER_DEG } -to_radians_f64 :: proc(degrees: f64) -> f64 { return degrees * RAD_PER_DEG } -to_radians_f64le :: proc(degrees: f64le) -> f64le { return degrees * RAD_PER_DEG } -to_radians_f64be :: proc(degrees: f64be) -> f64be { return degrees * RAD_PER_DEG } -to_degrees_f16 :: proc(radians: f16) -> f16 { return radians * DEG_PER_RAD } -to_degrees_f16le :: proc(radians: f16le) -> f16le { return radians * DEG_PER_RAD } -to_degrees_f16be :: proc(radians: f16be) -> f16be { return radians * DEG_PER_RAD } -to_degrees_f32 :: proc(radians: f32) -> f32 { return radians * DEG_PER_RAD } -to_degrees_f32le :: proc(radians: f32le) -> f32le { return radians * DEG_PER_RAD } -to_degrees_f32be :: proc(radians: f32be) -> f32be { return radians * DEG_PER_RAD } -to_degrees_f64 :: proc(radians: f64) -> f64 { return radians * DEG_PER_RAD } -to_degrees_f64le :: proc(radians: f64le) -> f64le { return radians * DEG_PER_RAD } -to_degrees_f64be :: proc(radians: f64be) -> f64be { return radians * DEG_PER_RAD } +to_radians_f16 :: proc "contextless" (degrees: f16) -> f16 { return degrees * RAD_PER_DEG } +to_radians_f16le :: proc "contextless" (degrees: f16le) -> f16le { return degrees * RAD_PER_DEG } +to_radians_f16be :: proc "contextless" (degrees: f16be) -> f16be { return degrees * RAD_PER_DEG } +to_radians_f32 :: proc "contextless" (degrees: f32) -> f32 { return degrees * RAD_PER_DEG } +to_radians_f32le :: proc "contextless" (degrees: f32le) -> f32le { return degrees * RAD_PER_DEG } +to_radians_f32be :: proc "contextless" (degrees: f32be) -> f32be { return degrees * RAD_PER_DEG } +to_radians_f64 :: proc "contextless" (degrees: f64) -> f64 { return degrees * RAD_PER_DEG } +to_radians_f64le :: proc "contextless" (degrees: f64le) -> f64le { return degrees * RAD_PER_DEG } +to_radians_f64be :: proc "contextless" (degrees: f64be) -> f64be { return degrees * RAD_PER_DEG } +to_degrees_f16 :: proc "contextless" (radians: f16) -> f16 { return radians * DEG_PER_RAD } +to_degrees_f16le :: proc "contextless" (radians: f16le) -> f16le { return radians * DEG_PER_RAD } +to_degrees_f16be :: proc "contextless" (radians: f16be) -> f16be { return radians * DEG_PER_RAD } +to_degrees_f32 :: proc "contextless" (radians: f32) -> f32 { return radians * DEG_PER_RAD } +to_degrees_f32le :: proc "contextless" (radians: f32le) -> f32le { return radians * DEG_PER_RAD } +to_degrees_f32be :: proc "contextless" (radians: f32be) -> f32be { return radians * DEG_PER_RAD } +to_degrees_f64 :: proc "contextless" (radians: f64) -> f64 { return radians * DEG_PER_RAD } +to_degrees_f64le :: proc "contextless" (radians: f64le) -> f64le { return radians * DEG_PER_RAD } +to_degrees_f64be :: proc "contextless" (radians: f64be) -> f64be { return radians * DEG_PER_RAD } to_radians :: proc{ to_radians_f16, to_radians_f16le, to_radians_f16be, to_radians_f32, to_radians_f32le, to_radians_f32be, @@ -409,8 +409,8 @@ to_degrees :: proc{ to_degrees_f64, to_degrees_f64le, to_degrees_f64be, } -trunc_f16 :: proc(x: f16) -> f16 { - trunc_internal :: proc(f: f16) -> f16 { +trunc_f16 :: proc "contextless" (x: f16) -> f16 { + trunc_internal :: proc "contextless" (f: f16) -> f16 { mask :: 0x1f shift :: 16 - 6 bias :: 0xf @@ -438,11 +438,11 @@ trunc_f16 :: proc(x: f16) -> f16 { } return trunc_internal(x) } -trunc_f16le :: proc(x: f16le) -> f16le { return #force_inline f16le(trunc_f16(f16(x))) } -trunc_f16be :: proc(x: f16be) -> f16be { return #force_inline f16be(trunc_f16(f16(x))) } +trunc_f16le :: proc "contextless" (x: f16le) -> f16le { return #force_inline f16le(trunc_f16(f16(x))) } +trunc_f16be :: proc "contextless" (x: f16be) -> f16be { return #force_inline f16be(trunc_f16(f16(x))) } -trunc_f32 :: proc(x: f32) -> f32 { - trunc_internal :: proc(f: f32) -> f32 { +trunc_f32 :: proc "contextless" (x: f32) -> f32 { + trunc_internal :: proc "contextless" (f: f32) -> f32 { mask :: 0xff shift :: 32 - 9 bias :: 0x7f @@ -470,11 +470,11 @@ trunc_f32 :: proc(x: f32) -> f32 { } return trunc_internal(x) } -trunc_f32le :: proc(x: f32le) -> f32le { return #force_inline f32le(trunc_f32(f32(x))) } -trunc_f32be :: proc(x: f32be) -> f32be { return #force_inline f32be(trunc_f32(f32(x))) } +trunc_f32le :: proc "contextless" (x: f32le) -> f32le { return #force_inline f32le(trunc_f32(f32(x))) } +trunc_f32be :: proc "contextless" (x: f32be) -> f32be { return #force_inline f32be(trunc_f32(f32(x))) } -trunc_f64 :: proc(x: f64) -> f64 { - trunc_internal :: proc(f: f64) -> f64 { +trunc_f64 :: proc "contextless" (x: f64) -> f64 { + trunc_internal :: proc "contextless" (f: f64) -> f64 { mask :: 0x7ff shift :: 64 - 12 bias :: 0x3ff @@ -502,40 +502,40 @@ trunc_f64 :: proc(x: f64) -> f64 { } return trunc_internal(x) } -trunc_f64le :: proc(x: f64le) -> f64le { return #force_inline f64le(trunc_f64(f64(x))) } -trunc_f64be :: proc(x: f64be) -> f64be { return #force_inline f64be(trunc_f64(f64(x))) } +trunc_f64le :: proc "contextless" (x: f64le) -> f64le { return #force_inline f64le(trunc_f64(f64(x))) } +trunc_f64be :: proc "contextless" (x: f64be) -> f64be { return #force_inline f64be(trunc_f64(f64(x))) } trunc :: proc{ trunc_f16, trunc_f16le, trunc_f16be, trunc_f32, trunc_f32le, trunc_f32be, trunc_f64, trunc_f64le, trunc_f64be, } -round_f16 :: proc(x: f16) -> f16 { +round_f16 :: proc "contextless" (x: f16) -> f16 { return ceil(x - 0.5) if x < 0 else floor(x + 0.5) } -round_f16le :: proc(x: f16le) -> f16le { +round_f16le :: proc "contextless" (x: f16le) -> f16le { return ceil(x - 0.5) if x < 0 else floor(x + 0.5) } -round_f16be :: proc(x: f16be) -> f16be { +round_f16be :: proc "contextless" (x: f16be) -> f16be { return ceil(x - 0.5) if x < 0 else floor(x + 0.5) } -round_f32 :: proc(x: f32) -> f32 { +round_f32 :: proc "contextless" (x: f32) -> f32 { return ceil(x - 0.5) if x < 0 else floor(x + 0.5) } -round_f32le :: proc(x: f32le) -> f32le { +round_f32le :: proc "contextless" (x: f32le) -> f32le { return ceil(x - 0.5) if x < 0 else floor(x + 0.5) } -round_f32be :: proc(x: f32be) -> f32be { +round_f32be :: proc "contextless" (x: f32be) -> f32be { return ceil(x - 0.5) if x < 0 else floor(x + 0.5) } -round_f64 :: proc(x: f64) -> f64 { +round_f64 :: proc "contextless" (x: f64) -> f64 { return ceil(x - 0.5) if x < 0 else floor(x + 0.5) } -round_f64le :: proc(x: f64le) -> f64le { +round_f64le :: proc "contextless" (x: f64le) -> f64le { return ceil(x - 0.5) if x < 0 else floor(x + 0.5) } -round_f64be :: proc(x: f64be) -> f64be { +round_f64be :: proc "contextless" (x: f64be) -> f64be { return ceil(x - 0.5) if x < 0 else floor(x + 0.5) } round :: proc{ @@ -545,17 +545,17 @@ round :: proc{ } -ceil_f16 :: proc(x: f16) -> f16 { return -floor(-x) } -ceil_f16le :: proc(x: f16le) -> f16le { return -floor(-x) } -ceil_f16be :: proc(x: f16be) -> f16be { return -floor(-x) } +ceil_f16 :: proc "contextless" (x: f16) -> f16 { return -floor(-x) } +ceil_f16le :: proc "contextless" (x: f16le) -> f16le { return -floor(-x) } +ceil_f16be :: proc "contextless" (x: f16be) -> f16be { return -floor(-x) } -ceil_f32 :: proc(x: f32) -> f32 { return -floor(-x) } -ceil_f32le :: proc(x: f32le) -> f32le { return -floor(-x) } -ceil_f32be :: proc(x: f32be) -> f32be { return -floor(-x) } +ceil_f32 :: proc "contextless" (x: f32) -> f32 { return -floor(-x) } +ceil_f32le :: proc "contextless" (x: f32le) -> f32le { return -floor(-x) } +ceil_f32be :: proc "contextless" (x: f32be) -> f32be { return -floor(-x) } -ceil_f64 :: proc(x: f64) -> f64 { return -floor(-x) } -ceil_f64le :: proc(x: f64le) -> f64le { return -floor(-x) } -ceil_f64be :: proc(x: f64be) -> f64be { return -floor(-x) } +ceil_f64 :: proc "contextless" (x: f64) -> f64 { return -floor(-x) } +ceil_f64le :: proc "contextless" (x: f64le) -> f64le { return -floor(-x) } +ceil_f64be :: proc "contextless" (x: f64be) -> f64be { return -floor(-x) } ceil :: proc{ ceil_f16, ceil_f16le, ceil_f16be, @@ -563,7 +563,7 @@ ceil :: proc{ ceil_f64, ceil_f64le, ceil_f64be, } -floor_f16 :: proc(x: f16) -> f16 { +floor_f16 :: proc "contextless" (x: f16) -> f16 { if x == 0 || is_nan(x) || is_inf(x) { return x } @@ -577,9 +577,9 @@ floor_f16 :: proc(x: f16) -> f16 { d, _ := modf(x) return d } -floor_f16le :: proc(x: f16le) -> f16le { return #force_inline f16le(floor_f16(f16(x))) } -floor_f16be :: proc(x: f16be) -> f16be { return #force_inline f16be(floor_f16(f16(x))) } -floor_f32 :: proc(x: f32) -> f32 { +floor_f16le :: proc "contextless" (x: f16le) -> f16le { return #force_inline f16le(floor_f16(f16(x))) } +floor_f16be :: proc "contextless" (x: f16be) -> f16be { return #force_inline f16be(floor_f16(f16(x))) } +floor_f32 :: proc "contextless" (x: f32) -> f32 { if x == 0 || is_nan(x) || is_inf(x) { return x } @@ -593,9 +593,9 @@ floor_f32 :: proc(x: f32) -> f32 { d, _ := modf(x) return d } -floor_f32le :: proc(x: f32le) -> f32le { return #force_inline f32le(floor_f32(f32(x))) } -floor_f32be :: proc(x: f32be) -> f32be { return #force_inline f32be(floor_f32(f32(x))) } -floor_f64 :: proc(x: f64) -> f64 { +floor_f32le :: proc "contextless" (x: f32le) -> f32le { return #force_inline f32le(floor_f32(f32(x))) } +floor_f32be :: proc "contextless" (x: f32be) -> f32be { return #force_inline f32be(floor_f32(f32(x))) } +floor_f64 :: proc "contextless" (x: f64) -> f64 { if x == 0 || is_nan(x) || is_inf(x) { return x } @@ -609,8 +609,8 @@ floor_f64 :: proc(x: f64) -> f64 { d, _ := modf(x) return d } -floor_f64le :: proc(x: f64le) -> f64le { return #force_inline f64le(floor_f64(f64(x))) } -floor_f64be :: proc(x: f64be) -> f64be { return #force_inline f64be(floor_f64(f64(x))) } +floor_f64le :: proc "contextless" (x: f64le) -> f64le { return #force_inline f64le(floor_f64(f64(x))) } +floor_f64be :: proc "contextless" (x: f64be) -> f64be { return #force_inline f64be(floor_f64(f64(x))) } floor :: proc{ floor_f16, floor_f16le, floor_f16be, floor_f32, floor_f32le, floor_f32be, @@ -618,7 +618,7 @@ floor :: proc{ } -floor_div :: proc(x, y: $T) -> T +floor_div :: proc "contextless" (x, y: $T) -> T where intrinsics.type_is_integer(T) { a := x / y r := x % y @@ -628,7 +628,7 @@ floor_div :: proc(x, y: $T) -> T return a } -floor_mod :: proc(x, y: $T) -> T +floor_mod :: proc "contextless" (x, y: $T) -> T where intrinsics.type_is_integer(T) { r := x % y if (r > 0 && y < 0) || (r < 0 && y > 0) { @@ -637,7 +637,7 @@ floor_mod :: proc(x, y: $T) -> T return r } -modf_f16 :: proc(x: f16) -> (int: f16, frac: f16) { +modf_f16 :: proc "contextless" (x: f16) -> (int: f16, frac: f16) { shift :: 16 - 5 - 1 mask :: 0x1f bias :: 15 @@ -663,15 +663,15 @@ modf_f16 :: proc(x: f16) -> (int: f16, frac: f16) { frac = x - int return } -modf_f16le :: proc(x: f16le) -> (int: f16le, frac: f16le) { +modf_f16le :: proc "contextless" (x: f16le) -> (int: f16le, frac: f16le) { i, f := #force_inline modf_f16(f16(x)) return f16le(i), f16le(f) } -modf_f16be :: proc(x: f16be) -> (int: f16be, frac: f16be) { +modf_f16be :: proc "contextless" (x: f16be) -> (int: f16be, frac: f16be) { i, f := #force_inline modf_f16(f16(x)) return f16be(i), f16be(f) } -modf_f32 :: proc(x: f32) -> (int: f32, frac: f32) { +modf_f32 :: proc "contextless" (x: f32) -> (int: f32, frac: f32) { shift :: 32 - 8 - 1 mask :: 0xff bias :: 127 @@ -697,15 +697,15 @@ modf_f32 :: proc(x: f32) -> (int: f32, frac: f32) { frac = x - int return } -modf_f32le :: proc(x: f32le) -> (int: f32le, frac: f32le) { +modf_f32le :: proc "contextless" (x: f32le) -> (int: f32le, frac: f32le) { i, f := #force_inline modf_f32(f32(x)) return f32le(i), f32le(f) } -modf_f32be :: proc(x: f32be) -> (int: f32be, frac: f32be) { +modf_f32be :: proc "contextless" (x: f32be) -> (int: f32be, frac: f32be) { i, f := #force_inline modf_f32(f32(x)) return f32be(i), f32be(f) } -modf_f64 :: proc(x: f64) -> (int: f64, frac: f64) { +modf_f64 :: proc "contextless" (x: f64) -> (int: f64, frac: f64) { shift :: 64 - 11 - 1 mask :: 0x7ff bias :: 1023 @@ -731,11 +731,11 @@ modf_f64 :: proc(x: f64) -> (int: f64, frac: f64) { frac = x - int return } -modf_f64le :: proc(x: f64le) -> (int: f64le, frac: f64le) { +modf_f64le :: proc "contextless" (x: f64le) -> (int: f64le, frac: f64le) { i, f := #force_inline modf_f64(f64(x)) return f64le(i), f64le(f) } -modf_f64be :: proc(x: f64be) -> (int: f64be, frac: f64be) { +modf_f64be :: proc "contextless" (x: f64be) -> (int: f64be, frac: f64be) { i, f := #force_inline modf_f64(f64(x)) return f64be(i), f64be(f) } @@ -746,7 +746,7 @@ modf :: proc{ } split_decimal :: modf -mod_f16 :: proc(x, y: f16) -> (n: f16) { +mod_f16 :: proc "contextless" (x, y: f16) -> (n: f16) { z := abs(y) n = remainder(abs(x), z) if sign(n) < 0 { @@ -754,9 +754,9 @@ mod_f16 :: proc(x, y: f16) -> (n: f16) { } return copy_sign(n, x) } -mod_f16le :: proc(x, y: f16le) -> (n: f16le) { return #force_inline f16le(mod_f16(f16(x), f16(y))) } -mod_f16be :: proc(x, y: f16be) -> (n: f16be) { return #force_inline f16be(mod_f16(f16(x), f16(y))) } -mod_f32 :: proc(x, y: f32) -> (n: f32) { +mod_f16le :: proc "contextless" (x, y: f16le) -> (n: f16le) { return #force_inline f16le(mod_f16(f16(x), f16(y))) } +mod_f16be :: proc "contextless" (x, y: f16be) -> (n: f16be) { return #force_inline f16be(mod_f16(f16(x), f16(y))) } +mod_f32 :: proc "contextless" (x, y: f32) -> (n: f32) { z := abs(y) n = remainder(abs(x), z) if sign(n) < 0 { @@ -764,9 +764,9 @@ mod_f32 :: proc(x, y: f32) -> (n: f32) { } return copy_sign(n, x) } -mod_f32le :: proc(x, y: f32le) -> (n: f32le) { return #force_inline f32le(mod_f32(f32(x), f32(y))) } -mod_f32be :: proc(x, y: f32be) -> (n: f32be) { return #force_inline f32be(mod_f32(f32(x), f32(y))) } -mod_f64 :: proc(x, y: f64) -> (n: f64) { +mod_f32le :: proc "contextless" (x, y: f32le) -> (n: f32le) { return #force_inline f32le(mod_f32(f32(x), f32(y))) } +mod_f32be :: proc "contextless" (x, y: f32be) -> (n: f32be) { return #force_inline f32be(mod_f32(f32(x), f32(y))) } +mod_f64 :: proc "contextless" (x, y: f64) -> (n: f64) { z := abs(y) n = remainder(abs(x), z) if sign(n) < 0 { @@ -774,30 +774,30 @@ mod_f64 :: proc(x, y: f64) -> (n: f64) { } return copy_sign(n, x) } -mod_f64le :: proc(x, y: f64le) -> (n: f64le) { return #force_inline f64le(mod_f64(f64(x), f64(y))) } -mod_f64be :: proc(x, y: f64be) -> (n: f64be) { return #force_inline f64be(mod_f64(f64(x), f64(y))) } +mod_f64le :: proc "contextless" (x, y: f64le) -> (n: f64le) { return #force_inline f64le(mod_f64(f64(x), f64(y))) } +mod_f64be :: proc "contextless" (x, y: f64be) -> (n: f64be) { return #force_inline f64be(mod_f64(f64(x), f64(y))) } mod :: proc{ mod_f16, mod_f16le, mod_f16be, mod_f32, mod_f32le, mod_f32be, mod_f64, mod_f64le, mod_f64be, } -remainder_f16 :: proc(x, y: f16 ) -> f16 { return x - round(x/y) * y } -remainder_f16le :: proc(x, y: f16le) -> f16le { return x - round(x/y) * y } -remainder_f16be :: proc(x, y: f16be) -> f16be { return x - round(x/y) * y } -remainder_f32 :: proc(x, y: f32 ) -> f32 { return x - round(x/y) * y } -remainder_f32le :: proc(x, y: f32le) -> f32le { return x - round(x/y) * y } -remainder_f32be :: proc(x, y: f32be) -> f32be { return x - round(x/y) * y } -remainder_f64 :: proc(x, y: f64 ) -> f64 { return x - round(x/y) * y } -remainder_f64le :: proc(x, y: f64le) -> f64le { return x - round(x/y) * y } -remainder_f64be :: proc(x, y: f64be) -> f64be { return x - round(x/y) * y } +remainder_f16 :: proc "contextless" (x, y: f16 ) -> f16 { return x - round(x/y) * y } +remainder_f16le :: proc "contextless" (x, y: f16le) -> f16le { return x - round(x/y) * y } +remainder_f16be :: proc "contextless" (x, y: f16be) -> f16be { return x - round(x/y) * y } +remainder_f32 :: proc "contextless" (x, y: f32 ) -> f32 { return x - round(x/y) * y } +remainder_f32le :: proc "contextless" (x, y: f32le) -> f32le { return x - round(x/y) * y } +remainder_f32be :: proc "contextless" (x, y: f32be) -> f32be { return x - round(x/y) * y } +remainder_f64 :: proc "contextless" (x, y: f64 ) -> f64 { return x - round(x/y) * y } +remainder_f64le :: proc "contextless" (x, y: f64le) -> f64le { return x - round(x/y) * y } +remainder_f64be :: proc "contextless" (x, y: f64be) -> f64be { return x - round(x/y) * y } remainder :: proc{ remainder_f16, remainder_f16le, remainder_f16be, remainder_f32, remainder_f32le, remainder_f32be, remainder_f64, remainder_f64le, remainder_f64be, } -gcd :: proc(x, y: $T) -> T +gcd :: proc "contextless" (x, y: $T) -> T where intrinsics.type_is_ordered_numeric(T) { x, y := x, y for y != 0 { @@ -807,36 +807,36 @@ gcd :: proc(x, y: $T) -> T return abs(x) } -lcm :: proc(x, y: $T) -> T +lcm :: proc "contextless" (x, y: $T) -> T where intrinsics.type_is_ordered_numeric(T) { return x / gcd(x, y) * y } -frexp_f16 :: proc(x: f16) -> (significand: f16, exponent: int) { +frexp_f16 :: proc "contextless" (x: f16) -> (significand: f16, exponent: int) { f, e := frexp_f64(f64(x)) return f16(f), e } -frexp_f16le :: proc(x: f16le) -> (significand: f16le, exponent: int) { +frexp_f16le :: proc "contextless" (x: f16le) -> (significand: f16le, exponent: int) { f, e := frexp_f64(f64(x)) return f16le(f), e } -frexp_f16be :: proc(x: f16be) -> (significand: f16be, exponent: int) { +frexp_f16be :: proc "contextless" (x: f16be) -> (significand: f16be, exponent: int) { f, e := frexp_f64(f64(x)) return f16be(f), e } -frexp_f32 :: proc(x: f32) -> (significand: f32, exponent: int) { +frexp_f32 :: proc "contextless" (x: f32) -> (significand: f32, exponent: int) { f, e := frexp_f64(f64(x)) return f32(f), e } -frexp_f32le :: proc(x: f32le) -> (significand: f32le, exponent: int) { +frexp_f32le :: proc "contextless" (x: f32le) -> (significand: f32le, exponent: int) { f, e := frexp_f64(f64(x)) return f32le(f), e } -frexp_f32be :: proc(x: f32be) -> (significand: f32be, exponent: int) { +frexp_f32be :: proc "contextless" (x: f32be) -> (significand: f32be, exponent: int) { f, e := frexp_f64(f64(x)) return f32be(f), e } -frexp_f64 :: proc(x: f64) -> (significand: f64, exponent: int) { +frexp_f64 :: proc "contextless" (x: f64) -> (significand: f64, exponent: int) { switch { case x == 0: return 0, 0 @@ -856,11 +856,11 @@ frexp_f64 :: proc(x: f64) -> (significand: f64, exponent: int) { } return } -frexp_f64le :: proc(x: f64le) -> (significand: f64le, exponent: int) { +frexp_f64le :: proc "contextless" (x: f64le) -> (significand: f64le, exponent: int) { f, e := frexp_f64(f64(x)) return f64le(f), e } -frexp_f64be :: proc(x: f64be) -> (significand: f64be, exponent: int) { +frexp_f64be :: proc "contextless" (x: f64be) -> (significand: f64be, exponent: int) { f, e := frexp_f64(f64(x)) return f64be(f), e } @@ -873,7 +873,7 @@ frexp :: proc{ -binomial :: proc(n, k: int) -> int { +binomial :: proc "contextless" (n, k: int) -> int { switch { case k <= 0: return 1 case 2*k > n: return binomial(n, n-k) @@ -886,7 +886,7 @@ binomial :: proc(n, k: int) -> int { return b } -factorial :: proc(n: int) -> int { +factorial :: proc "contextless" (n: int) -> int { when size_of(int) == size_of(i64) { @static table := [21]int{ 1, @@ -928,13 +928,10 @@ factorial :: proc(n: int) -> int { 479_001_600, } } - - assert(n >= 0, "parameter must not be negative") - assert(n < len(table), "parameter is too large to lookup in the table") return table[n] } -classify_f16 :: proc(x: f16) -> Float_Class { +classify_f16 :: proc "contextless" (x: f16) -> Float_Class { switch { case x == 0: i := transmute(i16)x @@ -958,9 +955,9 @@ classify_f16 :: proc(x: f16) -> Float_Class { } return .Normal } -classify_f16le :: proc(x: f16le) -> Float_Class { return #force_inline classify_f16(f16(x)) } -classify_f16be :: proc(x: f16be) -> Float_Class { return #force_inline classify_f16(f16(x)) } -classify_f32 :: proc(x: f32) -> Float_Class { +classify_f16le :: proc "contextless" (x: f16le) -> Float_Class { return #force_inline classify_f16(f16(x)) } +classify_f16be :: proc "contextless" (x: f16be) -> Float_Class { return #force_inline classify_f16(f16(x)) } +classify_f32 :: proc "contextless" (x: f32) -> Float_Class { switch { case x == 0: i := transmute(i32)x @@ -984,9 +981,9 @@ classify_f32 :: proc(x: f32) -> Float_Class { } return .Normal } -classify_f32le :: proc(x: f32le) -> Float_Class { return #force_inline classify_f32(f32(x)) } -classify_f32be :: proc(x: f32be) -> Float_Class { return #force_inline classify_f32(f32(x)) } -classify_f64 :: proc(x: f64) -> Float_Class { +classify_f32le :: proc "contextless" (x: f32le) -> Float_Class { return #force_inline classify_f32(f32(x)) } +classify_f32be :: proc "contextless" (x: f32be) -> Float_Class { return #force_inline classify_f32(f32(x)) } +classify_f64 :: proc "contextless" (x: f64) -> Float_Class { switch { case x == 0: i := transmute(i64)x @@ -1009,23 +1006,23 @@ classify_f64 :: proc(x: f64) -> Float_Class { } return .Normal } -classify_f64le :: proc(x: f64le) -> Float_Class { return #force_inline classify_f64(f64(x)) } -classify_f64be :: proc(x: f64be) -> Float_Class { return #force_inline classify_f64(f64(x)) } +classify_f64le :: proc "contextless" (x: f64le) -> Float_Class { return #force_inline classify_f64(f64(x)) } +classify_f64be :: proc "contextless" (x: f64be) -> Float_Class { return #force_inline classify_f64(f64(x)) } classify :: proc{ classify_f16, classify_f16le, classify_f16be, classify_f32, classify_f32le, classify_f32be, classify_f64, classify_f64le, classify_f64be, } -is_nan_f16 :: proc(x: f16) -> bool { return classify(x) == .NaN } -is_nan_f16le :: proc(x: f16le) -> bool { return classify(x) == .NaN } -is_nan_f16be :: proc(x: f16be) -> bool { return classify(x) == .NaN } -is_nan_f32 :: proc(x: f32) -> bool { return classify(x) == .NaN } -is_nan_f32le :: proc(x: f32le) -> bool { return classify(x) == .NaN } -is_nan_f32be :: proc(x: f32be) -> bool { return classify(x) == .NaN } -is_nan_f64 :: proc(x: f64) -> bool { return classify(x) == .NaN } -is_nan_f64le :: proc(x: f64le) -> bool { return classify(x) == .NaN } -is_nan_f64be :: proc(x: f64be) -> bool { return classify(x) == .NaN } +is_nan_f16 :: proc "contextless" (x: f16) -> bool { return classify(x) == .NaN } +is_nan_f16le :: proc "contextless" (x: f16le) -> bool { return classify(x) == .NaN } +is_nan_f16be :: proc "contextless" (x: f16be) -> bool { return classify(x) == .NaN } +is_nan_f32 :: proc "contextless" (x: f32) -> bool { return classify(x) == .NaN } +is_nan_f32le :: proc "contextless" (x: f32le) -> bool { return classify(x) == .NaN } +is_nan_f32be :: proc "contextless" (x: f32be) -> bool { return classify(x) == .NaN } +is_nan_f64 :: proc "contextless" (x: f64) -> bool { return classify(x) == .NaN } +is_nan_f64le :: proc "contextless" (x: f64le) -> bool { return classify(x) == .NaN } +is_nan_f64be :: proc "contextless" (x: f64be) -> bool { return classify(x) == .NaN } is_nan :: proc{ is_nan_f16, is_nan_f16le, is_nan_f16be, is_nan_f32, is_nan_f32le, is_nan_f32be, @@ -1036,7 +1033,7 @@ is_nan :: proc{ // If sign > 0, is_inf reports whether f is positive infinity. // If sign < 0, is_inf reports whether f is negative infinity. // If sign == 0, is_inf reports whether f is either infinity. -is_inf_f16 :: proc(x: f16, sign: int = 0) -> bool { +is_inf_f16 :: proc "contextless" (x: f16, sign: int = 0) -> bool { class := classify(abs(x)) switch { case sign > 0: @@ -1046,14 +1043,14 @@ is_inf_f16 :: proc(x: f16, sign: int = 0) -> bool { } return class == .Inf || class == .Neg_Inf } -is_inf_f16le :: proc(x: f16le, sign: int = 0) -> bool { +is_inf_f16le :: proc "contextless" (x: f16le, sign: int = 0) -> bool { return #force_inline is_inf_f16(f16(x), sign) } -is_inf_f16be :: proc(x: f16be, sign: int = 0) -> bool { +is_inf_f16be :: proc "contextless" (x: f16be, sign: int = 0) -> bool { return #force_inline is_inf_f16(f16(x), sign) } -is_inf_f32 :: proc(x: f32, sign: int = 0) -> bool { +is_inf_f32 :: proc "contextless" (x: f32, sign: int = 0) -> bool { class := classify(abs(x)) switch { case sign > 0: @@ -1063,14 +1060,14 @@ is_inf_f32 :: proc(x: f32, sign: int = 0) -> bool { } return class == .Inf || class == .Neg_Inf } -is_inf_f32le :: proc(x: f32le, sign: int = 0) -> bool { +is_inf_f32le :: proc "contextless" (x: f32le, sign: int = 0) -> bool { return #force_inline is_inf_f32(f32(x), sign) } -is_inf_f32be :: proc(x: f32be, sign: int = 0) -> bool { +is_inf_f32be :: proc "contextless" (x: f32be, sign: int = 0) -> bool { return #force_inline is_inf_f32(f32(x), sign) } -is_inf_f64 :: proc(x: f64, sign: int = 0) -> bool { +is_inf_f64 :: proc "contextless" (x: f64, sign: int = 0) -> bool { class := classify(abs(x)) switch { case sign > 0: @@ -1080,10 +1077,10 @@ is_inf_f64 :: proc(x: f64, sign: int = 0) -> bool { } return class == .Inf || class == .Neg_Inf } -is_inf_f64le :: proc(x: f64le, sign: int = 0) -> bool { +is_inf_f64le :: proc "contextless" (x: f64le, sign: int = 0) -> bool { return #force_inline is_inf_f64(f64(x), sign) } -is_inf_f64be :: proc(x: f64be, sign: int = 0) -> bool { +is_inf_f64be :: proc "contextless" (x: f64be, sign: int = 0) -> bool { return #force_inline is_inf_f64(f64(x), sign) } is_inf :: proc{ @@ -1092,25 +1089,25 @@ is_inf :: proc{ is_inf_f64, is_inf_f64le, is_inf_f64be, } -inf_f16 :: proc(sign: int) -> f16 { +inf_f16 :: proc "contextless" (sign: int) -> f16 { return f16(inf_f64(sign)) } -inf_f16le :: proc(sign: int) -> f16le { +inf_f16le :: proc "contextless" (sign: int) -> f16le { return f16le(inf_f64(sign)) } -inf_f16be :: proc(sign: int) -> f16be { +inf_f16be :: proc "contextless" (sign: int) -> f16be { return f16be(inf_f64(sign)) } -inf_f32 :: proc(sign: int) -> f32 { +inf_f32 :: proc "contextless" (sign: int) -> f32 { return f32(inf_f64(sign)) } -inf_f32le :: proc(sign: int) -> f32le { +inf_f32le :: proc "contextless" (sign: int) -> f32le { return f32le(inf_f64(sign)) } -inf_f32be :: proc(sign: int) -> f32be { +inf_f32be :: proc "contextless" (sign: int) -> f32be { return f32be(inf_f64(sign)) } -inf_f64 :: proc(sign: int) -> f64 { +inf_f64 :: proc "contextless" (sign: int) -> f64 { v: u64 if sign >= 0 { v = 0x7ff00000_00000000 @@ -1119,47 +1116,47 @@ inf_f64 :: proc(sign: int) -> f64 { } return transmute(f64)v } -inf_f64le :: proc(sign: int) -> f64le { +inf_f64le :: proc "contextless" (sign: int) -> f64le { return f64le(inf_f64(sign)) } -inf_f64be :: proc(sign: int) -> f64be { +inf_f64be :: proc "contextless" (sign: int) -> f64be { return f64be(inf_f64(sign)) } -nan_f16 :: proc() -> f16 { +nan_f16 :: proc "contextless" () -> f16 { return f16(nan_f64()) } -nan_f16le :: proc() -> f16le { +nan_f16le :: proc "contextless" () -> f16le { return f16le(nan_f64()) } -nan_f16be :: proc() -> f16be { +nan_f16be :: proc "contextless" () -> f16be { return f16be(nan_f64()) } -nan_f32 :: proc() -> f32 { +nan_f32 :: proc "contextless" () -> f32 { return f32(nan_f64()) } -nan_f32le :: proc() -> f32le { +nan_f32le :: proc "contextless" () -> f32le { return f32le(nan_f64()) } -nan_f32be :: proc() -> f32be { +nan_f32be :: proc "contextless" () -> f32be { return f32be(nan_f64()) } -nan_f64 :: proc() -> f64 { +nan_f64 :: proc "contextless" () -> f64 { v: u64 = 0x7ff80000_00000001 return transmute(f64)v } -nan_f64le :: proc() -> f64le { +nan_f64le :: proc "contextless" () -> f64le { return f64le(nan_f64()) } -nan_f64be :: proc() -> f64be { +nan_f64be :: proc "contextless" () -> f64be { return f64be(nan_f64()) } -is_power_of_two :: proc(x: int) -> bool { +is_power_of_two :: proc "contextless" (x: int) -> bool { return x > 0 && (x & (x-1)) == 0 } -next_power_of_two :: proc(x: int) -> int { +next_power_of_two :: proc "contextless" (x: int) -> int { k := x -1 when size_of(int) == 8 { k = k | (k >> 32) @@ -1173,7 +1170,7 @@ next_power_of_two :: proc(x: int) -> int { return k } -sum :: proc(x: $T/[]$E) -> (res: E) +sum :: proc "contextless" (x: $T/[]$E) -> (res: E) where intrinsics.type_is_numeric(E) { for i in x { res += i @@ -1181,7 +1178,7 @@ sum :: proc(x: $T/[]$E) -> (res: E) return } -prod :: proc(x: $T/[]$E) -> (res: E) +prod :: proc "contextless" (x: $T/[]$E) -> (res: E) where intrinsics.type_is_numeric(E) { for i in x { res *= i @@ -1189,7 +1186,7 @@ prod :: proc(x: $T/[]$E) -> (res: E) return } -cumsum_inplace :: proc(x: $T/[]$E) -> T +cumsum_inplace :: proc "contextless" (x: $T/[]$E) -> T where intrinsics.type_is_numeric(E) { for i in 1.. T } -cumsum :: proc(dst, src: $T/[]$E) -> T +cumsum :: proc "contextless" (dst, src: $T/[]$E) -> T where intrinsics.type_is_numeric(E) { N := min(len(dst), len(src)) if N > 0 { @@ -1210,32 +1207,32 @@ cumsum :: proc(dst, src: $T/[]$E) -> T } -atan2_f16 :: proc(y, x: f16) -> f16 { +atan2_f16 :: proc "contextless" (y, x: f16) -> f16 { // TODO(bill): Better atan2_f16 return f16(atan2_f64(f64(y), f64(x))) } -atan2_f16le :: proc(y, x: f16le) -> f16le { +atan2_f16le :: proc "contextless" (y, x: f16le) -> f16le { // TODO(bill): Better atan2_f16 return f16le(atan2_f64(f64(y), f64(x))) } -atan2_f16be :: proc(y, x: f16be) -> f16be { +atan2_f16be :: proc "contextless" (y, x: f16be) -> f16be { // TODO(bill): Better atan2_f16 return f16be(atan2_f64(f64(y), f64(x))) } -atan2_f32 :: proc(y, x: f32) -> f32 { +atan2_f32 :: proc "contextless" (y, x: f32) -> f32 { // TODO(bill): Better atan2_f32 return f32(atan2_f64(f64(y), f64(x))) } -atan2_f32le :: proc(y, x: f32le) -> f32le { +atan2_f32le :: proc "contextless" (y, x: f32le) -> f32le { // TODO(bill): Better atan2_f32 return f32le(atan2_f64(f64(y), f64(x))) } -atan2_f32be :: proc(y, x: f32be) -> f32be { +atan2_f32be :: proc "contextless" (y, x: f32be) -> f32be { // TODO(bill): Better atan2_f32 return f32be(atan2_f64(f64(y), f64(x))) } -atan2_f64 :: proc(y, x: f64) -> f64 { +atan2_f64 :: proc "contextless" (y, x: f64) -> f64 { // TODO(bill): Faster atan2_f64 if possible // The original C code: @@ -1246,7 +1243,7 @@ atan2_f64 :: proc(y, x: f64) -> f64 { INF :: 0h7FF0_0000_0000_0000 PI :: 0h4009_21fb_5444_2d18 - atan :: proc(x: f64) -> f64 { + atan :: proc "contextless" (x: f64) -> f64 { if x == 0 { return x } @@ -1256,7 +1253,7 @@ atan2_f64 :: proc(y, x: f64) -> f64 { return -s_atan(-x) } // s_atan reduces its argument (known to be positive) to the range [0, 0.66] and calls x_atan. - s_atan :: proc(x: f64) -> f64 { + s_atan :: proc "contextless" (x: f64) -> f64 { MORE_BITS :: 6.123233995736765886130e-17 // pi/2 = PIO2 + MORE_BITS TAN3PI08 :: 2.41421356237309504880 // tan(3*pi/8) if x <= 0.66 { @@ -1268,7 +1265,7 @@ atan2_f64 :: proc(y, x: f64) -> f64 { return PI/4 + x_atan((x-1)/(x+1)) + 0.5*MORE_BITS } // x_atan evaluates a series valid in the range [0, 0.66]. - x_atan :: proc(x: f64) -> f64 { + x_atan :: proc "contextless" (x: f64) -> f64 { P0 :: -8.750608600031904122785e-01 P1 :: -1.615753718733365076637e+01 P2 :: -7.500855792314704667340e+01 @@ -1320,11 +1317,11 @@ atan2_f64 :: proc(y, x: f64) -> f64 { } return q } -atan2_f64le :: proc(y, x: f64le) -> f64le { +atan2_f64le :: proc "contextless" (y, x: f64le) -> f64le { // TODO(bill): Better atan2_f32 return f64le(atan2_f64(f64(y), f64(x))) } -atan2_f64be :: proc(y, x: f64be) -> f64be { +atan2_f64be :: proc "contextless" (y, x: f64be) -> f64be { // TODO(bill): Better atan2_f32 return f64be(atan2_f64(f64(y), f64(x))) } @@ -1335,31 +1332,43 @@ atan2 :: proc{ atan2_f64, atan2_f64le, atan2_f64be, } -atan :: proc(x: $T) -> T where intrinsics.type_is_float(T) { +atan :: proc "contextless" (x: $T) -> T where intrinsics.type_is_float(T) { return atan2(x, 1) } -asin :: proc(x: $T) -> T where intrinsics.type_is_float(T) { +asin :: proc "contextless" (x: $T) -> T where intrinsics.type_is_float(T) { return atan2(x, 1 + sqrt(1 - x*x)) } -acos :: proc(x: $T) -> T where intrinsics.type_is_float(T) { +acos :: proc "contextless" (x: $T) -> T where intrinsics.type_is_float(T) { return 2 * atan2(sqrt(1 - x), sqrt(1 + x)) } -sinh :: proc(x: $T) -> T where intrinsics.type_is_float(T) { +sinh :: proc "contextless" (x: $T) -> T where intrinsics.type_is_float(T) { return (exp(x) - exp(-x))*0.5 } -cosh :: proc(x: $T) -> T where intrinsics.type_is_float(T) { +cosh :: proc "contextless" (x: $T) -> T where intrinsics.type_is_float(T) { return (exp(x) + exp(-x))*0.5 } -tanh :: proc(x: $T) -> T where intrinsics.type_is_float(T) { +tanh :: proc "contextless" (x: $T) -> T where intrinsics.type_is_float(T) { t := exp(2*x) return (t - 1) / (t + 1) } +asinh :: proc "contextless" (x: $T) -> T where intrinsics.type_is_float(T) { + return ln(x + sqrt(x*x + 1)) +} + +acosh :: proc "contextless" (x: $T) -> T where intrinsics.type_is_float(T) { + return ln(x + sqrt(x*x - 1)) +} + +atanh :: proc "contextless" (x: $T) -> T where intrinsics.type_is_float(T) { + return 0.5*ln((1+x)/(1-x)) +} + F16_DIG :: 3 F16_EPSILON :: 0.00097656 F16_GUARD :: 0 diff --git a/core/runtime/internal.odin b/core/runtime/internal.odin index 2b8dcd36a..5ab91e627 100644 --- a/core/runtime/internal.odin +++ b/core/runtime/internal.odin @@ -3,7 +3,7 @@ package runtime import "core:intrinsics" @(private) -RUNTIME_LINKAGE :: "strong" when ODIN_USE_SEPARATE_MODULES else "internal" +RUNTIME_LINKAGE :: "strong" when (ODIN_USE_SEPARATE_MODULES || ODIN_BUILD_MODE == "dynamic") else "internal" @(private) byte_slice :: #force_inline proc "contextless" (data: rawptr, len: int) -> []byte #no_bounds_check { diff --git a/core/runtime/procs.odin b/core/runtime/procs.odin index d3233c31b..c69e5b00a 100644 --- a/core/runtime/procs.odin +++ b/core/runtime/procs.odin @@ -1,7 +1,7 @@ package runtime -when ODIN_ARCH == "wasm32" || ODIN_ARCH == "wasm64" { - @(link_name="memset", require) +when ODIN_ARCH == "wasm32" || ODIN_ARCH == "wasm64" || ODIN_NO_CRT { + @(link_name="memset", linkage="strong", require) memset :: proc "c" (ptr: rawptr, val: i32, len: int) -> rawptr { if ptr != nil && len != 0 { b := byte(val) @@ -13,7 +13,7 @@ when ODIN_ARCH == "wasm32" || ODIN_ARCH == "wasm64" { return ptr } - @(link_name="memmove", require) + @(link_name="memmove", linkage="strong", require) memmove :: proc "c" (dst, src: rawptr, len: int) -> rawptr { if dst != src { d, s := ([^]byte)(dst), ([^]byte)(src) @@ -25,32 +25,7 @@ when ODIN_ARCH == "wasm32" || ODIN_ARCH == "wasm64" { return dst } -} else when ODIN_NO_CRT { - @(link_name="memset", linkage=RUNTIME_LINKAGE, require) - memset :: proc "c" (ptr: rawptr, val: i32, len: int) -> rawptr { - if ptr != nil && len != 0 { - b := byte(val) - p := ([^]byte)(ptr) - for i in 0.. rawptr { - if dst != src { - d, s := ([^]byte)(dst), ([^]byte)(src) - d_end, s_end := d[len:], s[len:] - for i := len-1; i >= 0; i -= 1 { - d[i] = s[i] - } - } - return dst - - } - @(link_name="memcpy", linkage=RUNTIME_LINKAGE, require) + @(link_name="memcpy", linkage="strong", require) memcpy :: proc "c" (dst, src: rawptr, len: int) -> rawptr { if dst != src { d, s := ([^]byte)(dst), ([^]byte)(src) diff --git a/examples/all/all_main.odin b/examples/all/all_main.odin index 2351a87f8..92026fe2c 100644 --- a/examples/all/all_main.odin +++ b/examples/all/all_main.odin @@ -29,6 +29,7 @@ import big "core:math/big" import bits "core:math/bits" import fixed "core:math/fixed" import linalg "core:math/linalg" +import glm "core:math/linalg/glsl" import rand "core:math/rand" import mem "core:mem" import ast "core:odin/ast" @@ -84,6 +85,7 @@ _ :: big _ :: bits _ :: fixed _ :: linalg +_ :: glm _ :: rand _ :: mem _ :: ast diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 63752ce68..fa8922f61 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -166,6 +166,7 @@ struct BuildContext { String ODIN_VENDOR; // compiler vendor String ODIN_VERSION; // compiler version String ODIN_ROOT; // Odin ROOT + String ODIN_BUILD_MODE; bool ODIN_DEBUG; // Odin in debug mode bool ODIN_DISABLE_ASSERT; // Whether the default 'assert' et al is disabled in code or not bool ODIN_DEFAULT_TO_NIL_ALLOCATOR; // Whether the default allocator is a "nil" allocator or not (i.e. it does nothing) @@ -815,6 +816,24 @@ void init_build_context(TargetMetrics *cross_target) { bc->ODIN_VENDOR = str_lit("odin"); bc->ODIN_VERSION = ODIN_VERSION; bc->ODIN_ROOT = odin_root_dir(); + switch (bc->build_mode) { + default: + case BuildMode_Executable: + bc->ODIN_BUILD_MODE = str_lit("executable"); + break; + case BuildMode_DynamicLibrary: + bc->ODIN_BUILD_MODE = str_lit("dynamic"); + break; + case BuildMode_Object: + bc->ODIN_BUILD_MODE = str_lit("object"); + break; + case BuildMode_Assembly: + bc->ODIN_BUILD_MODE = str_lit("assembly"); + break; + case BuildMode_LLVM_IR: + bc->ODIN_BUILD_MODE = str_lit("llvm-ir"); + break; + } bc->copy_file_contents = true; diff --git a/src/checker.cpp b/src/checker.cpp index 591377726..1a92b1c06 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -778,6 +778,8 @@ void init_universal(void) { add_global_string_constant("ODIN_VENDOR", bc->ODIN_VENDOR); add_global_string_constant("ODIN_VERSION", bc->ODIN_VERSION); add_global_string_constant("ODIN_ROOT", bc->ODIN_ROOT); + + add_global_string_constant("ODIN_BUILD_MODE", bc->ODIN_BUILD_MODE); add_global_bool_constant("ODIN_DEBUG", bc->ODIN_DEBUG); add_global_bool_constant("ODIN_DISABLE_ASSERT", bc->ODIN_DISABLE_ASSERT); add_global_bool_constant("ODIN_DEFAULT_TO_NIL_ALLOCATOR", bc->ODIN_DEFAULT_TO_NIL_ALLOCATOR); diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp index 1359d93c2..ab50b8c1e 100644 --- a/src/llvm_backend_utility.cpp +++ b/src/llvm_backend_utility.cpp @@ -1168,7 +1168,7 @@ lbValue lb_emit_array_ep(lbProcedure *p, lbValue s, lbValue index) { Type *t = s.type; GB_ASSERT_MSG(is_type_pointer(t), "%s", type_to_string(t)); Type *st = base_type(type_deref(t)); - GB_ASSERT_MSG(is_type_array(st) || is_type_enumerated_array(st), "%s", type_to_string(st)); + GB_ASSERT_MSG(is_type_array(st) || is_type_enumerated_array(st) || is_type_matrix(st), "%s", type_to_string(st)); GB_ASSERT_MSG(is_type_integer(core_type(index.type)), "%s", type_to_string(index.type)); LLVMValueRef indices[2] = {}; @@ -1186,7 +1186,7 @@ lbValue lb_emit_array_epi(lbProcedure *p, lbValue s, isize index) { Type *t = s.type; GB_ASSERT(is_type_pointer(t)); Type *st = base_type(type_deref(t)); - GB_ASSERT_MSG(is_type_array(st) || is_type_enumerated_array(st), "%s", type_to_string(st)); + GB_ASSERT_MSG(is_type_array(st) || is_type_enumerated_array(st) || is_type_matrix(st), "%s", type_to_string(st)); GB_ASSERT(0 <= index); Type *ptr = base_array_type(st); diff --git a/src/main.cpp b/src/main.cpp index 55439337d..e79e7203d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1185,7 +1185,7 @@ bool parse_build_flags(Array args) { break; } - if (str == "dll" || str == "shared") { + if (str == "dll" || str == "shared" || str == "dynamic") { build_context.build_mode = BuildMode_DynamicLibrary; } else if (str == "obj" || str == "object") { build_context.build_mode = BuildMode_Object;