Browse Source

`core:math/linalg/glsl` - GLSL-like mathematics types and operations

gingerBill 3 years ago
parent
commit
017fe10762
2 changed files with 1186 additions and 0 deletions
  1. 1152 0
      core/math/linalg/glsl/linalg_glsl.odin
  2. 34 0
      core/math/linalg/glsl/linalg_glsl_math.odin

+ 1152 - 0
core/math/linalg/glsl/linalg_glsl.odin

@@ -0,0 +1,1152 @@
+package math_linalg_glsl
+
+import "core:builtin"
+
+foreign import math "webgl_math"
+
+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
+
+mat2 :: distinct matrix[2, 2]f32
+mat3 :: distinct matrix[3, 3]f32
+mat4 :: distinct matrix[4, 4]f32
+mat2x2 :: mat2
+mat3x3 :: mat3
+mat4x4 :: mat4
+
+// Should this be renamed the other way around?
+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
+
+cos :: proc{
+	cos_f32,
+	cos_vec2,
+	cos_vec3,
+	cos_vec4,
+}
+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)} }
+
+
+sin :: proc{
+	sin_f32,
+	sin_vec2,
+	sin_vec3,
+	sin_vec4,
+}
+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)} }
+
+
+tan :: proc{
+	tan_f32,
+	tan_vec2,
+	tan_vec3,
+	tan_vec4,
+}
+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)} }
+
+
+acos :: proc{
+	acos_f32,
+	acos_vec2,
+	acos_vec3,
+	acos_vec4,
+}
+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)} }
+
+
+asin :: proc{
+	asin_f32,
+	asin_vec2,
+	asin_vec3,
+	asin_vec4,
+}
+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)} }
+
+
+atan :: proc{
+	atan_f32,
+	atan_vec2,
+	atan_vec3,
+	atan_vec4,
+	atan2_f32,
+	atan2_vec2,
+	atan2_vec3,
+	atan2_vec4,
+}
+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)} }
+
+
+atan2 :: proc{
+	atan2_f32,
+	atan2_vec2,
+	atan2_vec3,
+	atan2_vec4,
+}
+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)} }
+
+
+
+cosh :: proc{
+	cosh_f32,
+	cosh_vec2,
+	cosh_vec3,
+	cosh_vec4,
+}
+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)} }
+
+
+sinh :: proc{
+	sinh_f32,
+	sinh_vec2,
+	sinh_vec3,
+	sinh_vec4,
+}
+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)} }
+
+
+tanh :: proc{
+	tanh_f32,
+	tanh_vec2,
+	tanh_vec3,
+	tanh_vec4,
+}
+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)} }
+
+
+acosh :: proc{
+	acosh_f32,
+	acosh_vec2,
+	acosh_vec3,
+	acosh_vec4,
+}
+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)} }
+
+
+asinh :: proc{
+	asinh_f32,
+	asinh_vec2,
+	asinh_vec3,
+	asinh_vec4,
+}
+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)} }
+
+
+atanh :: proc{
+	atanh_f32,
+	atanh_vec2,
+	atanh_vec3,
+	atanh_vec4,
+}
+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)} }
+
+
+sqrt :: proc{
+	sqrt_f32,
+	sqrt_vec2,
+	sqrt_vec3,
+	sqrt_vec4,
+}
+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)} }
+
+
+rsqrt :: inversesqrt
+inversesqrt :: proc{
+	inversesqrt_f32,
+	inversesqrt_vec2,
+	inversesqrt_vec3,
+	inversesqrt_vec4,
+}
+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)} }
+
+
+
+pow :: proc{
+	pow_f32,
+	pow_vec2,
+	pow_vec3,
+	pow_vec4,
+}
+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)} }
+
+
+exp :: proc{
+	exp_f32,
+	exp_vec2,
+	exp_vec3,
+	exp_vec4,
+}
+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)} }
+
+
+log :: proc{
+	log_f32,
+	log_vec2,
+	log_vec3,
+	log_vec4,
+}
+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)} }
+
+
+exp2 :: proc{
+	exp2_f32,
+	exp2_vec2,
+	exp2_vec3,
+	exp2_vec4,
+}
+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)} }
+
+
+sign :: proc{
+	sign_i32,
+	sign_u32,
+	sign_f32,
+	sign_vec2,
+	sign_vec3,
+	sign_vec4,
+	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_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_vec2,
+	floor_vec3,
+	floor_vec4,
+}
+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)} }
+
+
+ceil :: proc{
+	ceil_f32,
+	ceil_vec2,
+	ceil_vec3,
+	ceil_vec4,
+}
+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)} }
+
+
+mod :: proc{
+	mod_f32,
+	mod_vec2,
+	mod_vec3,
+	mod_vec4,
+}
+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)} }
+
+
+fract :: proc{
+	fract_f32,
+	fract_vec2,
+	fract_vec3,
+	fract_vec4,
+}
+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)} }
+
+
+
+radians :: proc{
+	radians_f32,
+	radians_vec2,
+	radians_vec3,
+	radians_vec4,
+}
+radians_f32  :: proc "c" (degrees: f32)  -> f32  { 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 }
+
+
+degrees :: proc{
+	degrees_f32,
+	degrees_vec2,
+	degrees_vec3,
+	degrees_vec4,
+}
+degrees_f32  :: proc "c" (radians: f32)  -> f32  { 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 }
+
+
+min :: proc{
+	min_i32,  
+	min_u32,  
+	min_f32,  
+	min_vec2, 
+	min_vec3, 
+	min_vec4, 
+	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_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_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_vec2, 
+	max_vec3, 
+	max_vec4, 
+	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_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_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_vec2, 
+	clamp_vec3, 
+	clamp_vec4, 
+	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_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_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_vec2,
+	saturate_vec3,
+	saturate_vec4,
+	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_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_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_vec2,
+	mix_vec3,
+	mix_vec4,
+}
+mix_f32  :: proc "c" (x, y, t: f32) -> f32   { 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)} }
+
+lerp :: proc{
+	lerp_f32,
+	lerp_vec2,
+	lerp_vec3,
+	lerp_vec4,
+}
+lerp_f32  :: proc "c" (x, y, t: f32) -> f32   { 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)} }
+
+
+step :: proc{
+	step_f32,
+	step_vec2,
+	step_vec3,
+	step_vec4,
+}
+step_f32  :: proc "c" (edge, x: f32) -> f32   { 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)} }
+
+
+abs :: proc{
+	abs_i32,
+	abs_u32,
+	abs_f32,
+	abs_vec2,
+	abs_vec3,
+	abs_vec4,
+	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_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_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_vec2,
+	dot_vec3,
+	dot_vec4,
+	dot_ivec2,
+	dot_ivec3,
+	dot_ivec4,
+	dot_uvec2,
+	dot_uvec3,
+	dot_uvec4,
+	dot_quat,
+}
+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_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_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 }
+
+length :: proc{
+	length_f32,
+	length_vec2,
+	length_vec3,
+	length_vec4,
+	length_quat,
+}
+length_f32  :: proc "c" (x: f32)  -> f32 { 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_quat :: proc "c" (x: quat) -> f32 { return sqrt(x.x*x.x + x.y*x.y + x.z*x.z + x.w*x.w) }
+
+
+distance :: proc{
+	distance_f32,
+	distance_vec2,
+	distance_vec3,
+	distance_vec4,
+}
+distance_f32  :: proc "c" (x, y: f32)  -> f32 { 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) }
+
+
+cross :: proc{
+	cross_vec3,
+	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_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_vec2,
+	normalize_vec3,
+	normalize_vec4,
+	normalize_quat,
+}
+normalize_f32  :: proc "c" (x: f32)  -> f32  { 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_quat :: proc "c" (x: quat) -> quat { return x / quat(length(x)) }
+
+
+faceForward :: proc{
+	faceForward_f32,
+	faceForward_vec2,
+	faceForward_vec3,
+	faceForward_vec4,
+}
+faceForward_f32  :: proc "c" (N, I, Nref: f32)  -> f32  { 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 }
+
+
+reflect :: proc{
+	reflect_f32,
+	reflect_vec2,
+	reflect_vec3,
+	reflect_vec4,
+}
+reflect_f32  :: proc "c" (I, N: f32)  -> f32  { 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) }
+
+
+
+refract :: proc{
+	refract_f32,
+	refract_vec2,
+	refract_vec3,
+	refract_vec4,
+}
+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_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))}
+}
+
+scalarTripleProduct :: proc "c" (a, b, c: vec3) -> f32  { return dot(a, cross(b, c)) }
+vectorTripleProduct :: proc "c" (a, b, c: vec3) -> vec3 { return cross(a, cross(b, c)) }
+
+
+// Vector Relational Procedures
+
+lessThan :: proc{
+	lessThan_f32,
+	lessThan_i32,
+	lessThan_u32,
+	lessThan_vec2,
+	lessThan_ivec2,
+	lessThan_uvec2,
+	lessThan_vec3,
+	lessThan_ivec3,
+	lessThan_uvec3,
+	lessThan_vec4,
+	lessThan_ivec4,
+	lessThan_uvec4,
+}
+lessThan_f32   :: proc "c" (a, b: f32) -> 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_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_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_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_i32,
+	lessThanEqual_u32,
+	lessThanEqual_vec2,
+	lessThanEqual_ivec2,
+	lessThanEqual_uvec2,
+	lessThanEqual_vec3,
+	lessThanEqual_ivec3,
+	lessThanEqual_uvec3,
+	lessThanEqual_vec4,
+	lessThanEqual_ivec4,
+	lessThanEqual_uvec4,
+}
+lessThanEqual_f32   :: proc "c" (a, b: f32) -> 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_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_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_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_i32,
+	greaterThan_u32,
+	greaterThan_vec2,
+	greaterThan_ivec2,
+	greaterThan_uvec2,
+	greaterThan_vec3,
+	greaterThan_ivec3,
+	greaterThan_uvec3,
+	greaterThan_vec4,
+	greaterThan_ivec4,
+	greaterThan_uvec4,
+}
+greaterThan_f32   :: proc "c" (a, b: f32) -> 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_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_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_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_i32,
+	greaterThanEqual_u32,
+	greaterThanEqual_vec2,
+	greaterThanEqual_ivec2,
+	greaterThanEqual_uvec2,
+	greaterThanEqual_vec3,
+	greaterThanEqual_ivec3,
+	greaterThanEqual_uvec3,
+	greaterThanEqual_vec4,
+	greaterThanEqual_ivec4,
+	greaterThanEqual_uvec4,
+}
+greaterThanEqual_f32   :: proc "c" (a, b: f32) -> 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_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_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_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_i32,
+	equal_u32,
+	equal_vec2,
+	equal_ivec2,
+	equal_uvec2,
+	equal_vec3,
+	equal_ivec3,
+	equal_uvec3,
+	equal_vec4,
+	equal_ivec4,
+	equal_uvec4,
+}
+equal_f32   :: proc "c" (a, b: f32) -> 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_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_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_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_i32,
+	notEqual_u32,
+	notEqual_vec2,
+	notEqual_ivec2,
+	notEqual_uvec2,
+	notEqual_vec3,
+	notEqual_ivec3,
+	notEqual_uvec3,
+	notEqual_vec4,
+	notEqual_ivec4,
+	notEqual_uvec4,
+}
+notEqual_f32   :: proc "c" (a, b: f32) -> 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_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_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_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]f32) -> 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
+	// return mat4{
+	// 	+s.x, +s.y, +s.z, -dot(s, eye),
+	// 	+u.x, +u.y, +u.z, -dot(u, eye),
+	// 	-f.x, -f.y, -f.z, +fe,
+	// 	0, 0, 0, 1,
+	// }
+}
+
+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
+}
+
+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
+}
+
+quatDot :: proc "c" (a, b: quat) -> f32 {
+	return dot(transmute(vec4)a, transmute(vec4)b)
+}
+
+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 := quatDot(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)
+}
+
+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

+ 34 - 0
core/math/linalg/glsl/linalg_glsl_math.odin

@@ -0,0 +1,34 @@
+//+build !freestanding !wasm32
+package math_linalg_glsl
+
+import "core:math"
+
+cos_f32         :: proc "c" (x: f32) -> f32 { return math.cos_f32(x) }
+sin_f32         :: proc "c" (x: f32) -> f32 { return math.sin_f32(x) }
+tan_f32         :: proc "c" (x: f32) -> f32 { return math.tan_f32(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_f32(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/sqrt_f32(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_f32(x) }
+exp2_f32        :: proc "c" (x: f32) -> f32 { return pow(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_f32(x)
+	}
+	return math.trunc_f32(-x) + x
+}