diff --git a/math/mat.jai b/math/mat.jai index 66f6022..99b2cf2 100644 --- a/math/mat.jai +++ b/math/mat.jai @@ -400,3 +400,84 @@ inverse :: (m: Mat4) -> Mat4 { return transpose(r); } + + +#scope_file; + +#if RUN_TESTS #run { + test.run(basic.tprint("%: Mat2", UNITS), t => { + { + identity := m2_identity; + a: Mat2 = Mat2.{.[1, 2, 3, 4]}; + test.expect(t, a*identity == a); + } + { + rotator := rotation_mat2(from_rad(PI)); + v2 := v2f(1.0, 0.5); + v2 = rotator*v2; + test.expect(t, v2_eq(v2, v2f(-1.0, -0.5))); + v2 = rotator*v2; + test.expect(t, v2_eq(v2, v2f(1.0, 0.5))); + } + { + m := m2(1.0, 3.0, 2.0, 2.0); + det := determinate(m); + test.expect(t, det == -4); + } + { + rotator := rotation_mat2(from_rad(PI)); + inv_rotator := inverse(rotator); + v2 := v2f(0.1, 1.0); + + test.expect(t, inv_rotator*rotator == m2_identity); + test.expect(t, inv_rotator*(rotator*v2) == v2); + v2 = rotator*v2; + v2 = inv_rotator*v2; + } + }); + + test.run(basic.tprint("%: Mat4", UNITS), t => { + { + identity := m4_identity; + a: Mat4 = Mat4.{.[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]}; + test.expect(t, a*identity == a); + } + { + UP_VECTOR :: Vec3.{.[0.0, 1.0, 0.0]}; + camera := v3f(1.0, 0.0, 1.0); + looking_at := v3f(0.0, 0.0, 0.0); + look_at := make_look_at(camera, looking_at, UP_VECTOR); + } + { + translator := translate(v3f(10.0, 5.0, 2.0)); + v3 := v3f(1.0, 2.0, 1.0); + v4 := v4f(v3, 1.0); + test.expect(t, v4 == v4f(1.0, 2.0, 1.0, 1.0)); + test.expect(t, translator*v4 == v4f(11.0, 7.0, 3.0, 1.0)); + } + { + rotator := rotation_mat4(v3f(0.0, 1.0, 0.0), from_rad(PI)); + v4 := v4f(1.0, 0.5, 0.1, 1.0); + v4 = rotator*v4; + test.expect(t, v4_eq(v4, v4f(-1.0, 0.5, -0.1, 1.0))); + v4 = rotator*v4; + test.expect(t, v4_eq(v4, v4f(1.0, 0.5, 0.1, 1.0))); + } + { + rotator_x := rotation_mat4(v3f(1.0, 0.0, 0.0), from_rad(0.4*PI)); + rotator_y := rotation_mat4(v3f(0.0, 1.0, 0.0), from_rad(PI)); + camera_rotator := rotator_x*rotator_y; + det := determinate(camera_rotator); + } + { + rotator := rotation_mat4(v3f(0.0, 0.0, 1.0), from_rad(PI)); + inv_rotator := inverse(rotator); + v4 := v4f(0.1, 1.0, 0.0, 1.0); + + test.expect(t, inv_rotator*rotator == m4_identity); + + v4 = rotator*v4; + v4 = inv_rotator*v4; + } + }); +} diff --git a/math/module.jai b/math/module.jai index b1d50e2..4bc54d4 100644 --- a/math/module.jai +++ b/math/module.jai @@ -25,333 +25,15 @@ F64_Min, F64_Max :: #run meta.lo_for(float64), #run meta.hi_for(float64); #scope_module; -#if RUN_TESTS #run { - test :: #import "jc/test"; - - vec2_tests(); - vec3_tests(); - vec4_tests(); - vecn_tests(); - mat2_tests(); - mat4_tests(); - quat_tests(); -} - -#scope_file; - -meta :: #import "jc/meta"; +meta :: #import "jc/meta"; +math :: #import "Math"; // @future basic :: #import "Basic"; // @future -math :: #import "Math"; - -test :: #import "jc/test"; - -vec2_tests :: () { - dot_print("Vec2 % tests", UNITS); - t: test.T; - { - a: Vec2 = v2f(0.0, 1.0); - b: Vec2 = v2f(1.0, 2.0); - test.expect(*t, a + b == v2f(1.0, 3.0)); - test.expect(*t, b - a == v2f(1.0, 1.0)); - test.expect(*t, a*b == v2f(0.0, 2.0)); - test.expect(*t, a/b == v2f(0.0, 0.5)); - } - - { - a: Vec(2, int) = v2i(2, 1); - b: Vec(2, int) = v2i(1, 0); - test.expect(*t, a + b == v2i(3, 1)); - test.expect(*t, b - a == v2i(-1, -1)); - test.expect(*t, a*b == v2i(2, 0)); - test.expect(*t, b/a == v2i(0, 0)); - } - { - a: Vec2 = v2f(2.3, -4.1); - b: Vec2 = v2f(1.0, 3.6); - c := min(a, b); - test.expect(*t, c == v2f(1.0, -4.1)); - c = max(a, b); - test.expect(*t, c == v2f(2.3, 3.6)); - } +#if RUN_TESTS { + test :: #import "jc/test"; } -vec3_tests :: () { - dot_print("Vec3 % tests", UNITS); - t: test.T; - { - a: Vec3 = v3f(0.0, 1.0, 2.0); - b: Vec3 = v3f(1.0, 2.0, 3.0); - test.expect(*t, a + b == v3f(1.0, 3.0, 5.0)); - test.expect(*t, b - a == v3f(1.0, 1.0, 1.0)); - test.expect(*t, a*b == v3f(0.0, 2.0, 6.0)); - test.expect(*t, a/b == v3f(0.0, 0.5, 0.66666667)); - - a = v3f(1.0, 1.0, 0.0); - b = v3f(1.0, 0.0, 0.0); - test.expect(*t, reflect(a, b) == v3f(1.0, -1.0, 0.0)); - test.expect(*t, round(v3f(1.2, 1.7, 1.5)) == v3f(1.0, 2.0, 2.0)); - test.expect(*t, round(v3f(-1.2, -1.7, -1.5)) == v3f(-1.0, -2.0, -2.0)); - - a = v3f(1.0, 0.0, 0.0); - b = v3f(0.0, 1.0, 0.0); - test.expect(*t, cross(a, b) == v3f(0.0, 0.0, 1.0)); - } - { - a: Vec3 = v3f(2.3, 4.1, 9.0); - b: Vec3 = v3f(1.0, -3.6, 5.0); - c := min(a, b); - test.expect(*t, c == v3f(1.0, -3.6, 5.0)); - c = max(a, b); - test.expect(*t, c == v3f(2.3, 4.1, 9.0)); - } -} - -vec4_tests :: () { - dot_print("Vec4 % tests", UNITS); - t: test.T; - { - a: Vec4 = v4f(2.25, 1.0, 2.0, 1.0); - b: Vec4 = v4f(4.0, 2.0, 3.0, 1.0); - test.expect(*t, a + b == v4f(6.25, 3.0, 5.0, 2.0)); - test.expect(*t, b - a == v4f(1.75, 1.0, 1.0, 0.0)); - test.expect(*t, a*b == v4f(9.0, 2.0, 6.0, 1.0)); - test.expect(*t, a/b == v4f(0.5625, 0.5, 2.0/3.0, 1.0)); - } -} - -vecn_tests :: () { - dot_print("VecN % tests", UNITS); - t: test.T; - { - a: Vec(16, float); - b: Vec(16, float); - for *a { - it.* = xx it_index; - } - for *b { - it.* = xx(it_index + 1); - } - test.expect(*t, a + b == Vec(16, float).{.[1.0, 3.0, 5.0, 7.0, 9.0, 11.0, 13.0, 15.0, 17.0, 19.0, 21.0, 23.0, 25.0, 27.0, 29.0, 31.0]}); - test.expect(*t, b - a == Vec(16, float).{.[1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0]}); - test.expect(*t, a*b == Vec(16, float).{.[0.0, 2.0, 6.0, 12.0, 20.0, 30.0, 42.0, 56.0, 72.0, 90.0, 110.0, 132.0, 156.0, 182.0, 210.0, 240.0]}); - - test.expect(*t, min(a, b) == a); - test.expect(*t, max(a, b) == b); - test.expect(*t, max(a, 12) == Vec(16, float).{.[0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 12.0, 12.0, 12.0]}); - test.expect(*t, min(a, 13.2) == Vec(16, float).{.[13.2, 13.2, 13.2, 13.2, 13.2, 13.2, 13.2, 13.2, 13.2, 13.2, 13.2, 13.2, 13.2, 13.2, 14.0, 15.0]}); - test.expect(*t, clamp(a, 7.25, 12.0) == Vec(16, float).{.[7.25, 7.25, 7.25, 7.25, 7.25, 7.25, 7.25, 7.25, 8, 9, 10, 11, 12, 12, 12, 12]}); - - a1: Vec(16, float) = Vec(16, float).{.[1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 4.7, -1.2, -1.0, -1.5, 11.2, 14.0, 15.0, 14.0, 15.0, 65536.2]}; - basic.print(">> a1: %\n", a1); - basic.print(">> ceil(a1): %\n", ceil(a1)); - basic.print(">> floor(a1): %\n", floor(a1)); - test.expect(*t, ceil(a1) == Vec(16, float).{.[2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 5.0, -1.0, -1.0, -1.0, 12.0, 14.0, 15.0, 14.0, 15.0, 65537]}); - test.expect(*t, floor(a1) == Vec(16, float).{.[1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 4.0, -2.0, -1.0, -2.0, 11.0, 14.0, 15.0, 14.0, 15.0, 65536]}); - - test.expect(*t, dot(a, b) == 1360.0); - test.expect(*t, abs(a) == a); - c := a; - for *c { // Check making every other component negative - if it_index%2 == 0 - it.* = -it.*; - } - test.expect(*t, abs(c) == a); - test.expect(*t, float_eq(length(normalize(a)), 1)); - test.expect(*t, a + 2 == Vec(16, float).{.[2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17]}); - test.expect(*t, a - 2 == Vec(16, float).{.[-2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]}); - test.expect(*t, a*2 == Vec(16, float).{.[0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30]}); - } -} - -mat2_tests :: () { - dot_print("Mat2 % tests", UNITS); - t: test.T; - { - identity := m2_identity; - a: Mat2 = Mat2.{.[1, 2, 3, 4]}; - test.expect(*t, a*identity == a); - } - { - basic.print("rotation matrix\n"); - rotator := rotation_mat2(from_rad(PI)); - v2 := v2f(1.0, 0.5); - basic.print("rotating: %\n", v2); - v2 = rotator*v2; - basic.print("after rotate: %\n", v2); - test.expect(*t, v2_eq(v2, v2f(-1.0, -0.5))); - v2 = rotator*v2; - basic.print("rotate back: %\n", v2); - test.expect(*t, v2_eq(v2, v2f(1.0, 0.5))); - } - { - basic.print("determinate\n"); - m := m2(1.0, 3.0, 2.0, 2.0); - basic.print("m2: %\n", m); - det := determinate(m); - basic.print("determinate: %\n", det); - test.expect(*t, det == -4); - } - { - basic.print("inverse test\n"); - rotator := rotation_mat2(from_rad(PI)); - inv_rotator := inverse(rotator); - v2 := v2f(0.1, 1.0); - basic.print(" : %\n", rotator); - basic.print("inv: %\n", inv_rotator); - - basic.print("inv_mat*mat = %\n", inv_rotator*rotator); - test.expect(*t, inv_rotator*rotator == m2_identity); - - test.expect(*t, inv_rotator*(rotator*v2) == v2); - basic.print("v2 : %\n", v2); - v2 = rotator*v2; - basic.print("rot : %\n", v2); - v2 = inv_rotator*v2; - basic.print("inv : %\n", v2); - } -} - -mat4_tests :: () { - dot_print("Mat4 % tests", UNITS); - t: test.T; - { - identity := m4_identity; - a: Mat4 = Mat4.{.[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]}; - test.expect(*t, a*identity == a); - } - { - UP_VECTOR :: Vec3.{.[0.0, 1.0, 0.0]}; - camera := v3f(1.0, 0.0, 1.0); - looking_at := v3f(0.0, 0.0, 0.0); - look_at := make_look_at(camera, looking_at, UP_VECTOR); - basic.print("lookat matrix: %\n", look_at); - basic.print("lookat from 0,1,0: %\n", look_at*v4f(0.0, 1.0, 0.0, 1.0)); - } - { - translator := translate(v3f(10.0, 5.0, 2.0)); - v3 := v3f(1.0, 2.0, 1.0); - v4 := v4f(v3, 1.0); - test.expect(*t, v4 == v4f(1.0, 2.0, 1.0, 1.0)); - test.expect(*t, translator*v4 == v4f(11.0, 7.0, 3.0, 1.0)); - } - { - basic.print("rotation matrix\n"); - rotator := rotation_mat4(v3f(0.0, 1.0, 0.0), from_rad(PI)); - v4 := v4f(1.0, 0.5, 0.1, 1.0); - basic.print("rotating: %\n", v4); - v4 = rotator*v4; - basic.print("after rotate: %\n", v4); - test.expect(*t, v4_eq(v4, v4f(-1.0, 0.5, -0.1, 1.0))); - v4 = rotator*v4; - basic.print("rotate back: %\n", v4); - test.expect(*t, v4_eq(v4, v4f(1.0, 0.5, 0.1, 1.0))); - } - { - rotator_x := rotation_mat4(v3f(1.0, 0.0, 0.0), from_rad(0.4*PI)); - rotator_y := rotation_mat4(v3f(0.0, 1.0, 0.0), from_rad(PI)); - camera_rotator := rotator_x*rotator_y; - basic.print("big rotator: %\n", camera_rotator); - det := determinate(camera_rotator); - basic.print("determinate: %\n", det); - } - { - basic.print("inverse test\n"); - rotator := rotation_mat4(v3f(0.0, 0.0, 1.0), from_rad(PI)); - inv_rotator := inverse(rotator); - v4 := v4f(0.1, 1.0, 0.0, 1.0); - basic.print(" : %\n", rotator); - basic.print("inv: %\n", inv_rotator); - - basic.print("inv_mat*mat = %\n", inv_rotator*rotator); - test.expect(*t, inv_rotator*rotator == m4_identity); - - basic.print("v4 : %\n", v4); - v4 = rotator*v4; - basic.print("rot : %\n", v4); - v4 = inv_rotator*v4; - basic.print("inv : %\n", v4); - } -} - -quat_tests :: () { - dot_print("Quaternion % tests", UNITS); - t: test.T; - { - qi := quat_identity; - basic.print("qi lensq: %\n", length_squared(qi)); - basic.print("qi len : %\n", length(qi)); - q: Quat = rotation_quat(from_rad(PI), v3f(0.0, 1.0, 0.0)); - q2: Quat = rotation_quat(from_rad(PI), v3f(1.0, 0.0, 1.0)); - basic.print("q : %\n", q); - basic.print("q2 : %\n", q2); - basic.print("dot : %\n", dot(q, q2)); - basic.print("mul : %\n", q*q2); - qc := conjugate(q); - basic.print("conjugate : %\n", qc); - inv_q := inverse(q); - basic.print("inverse : %\n", inv_q); - test.expect(*t, q*inv_q == qi); - - q1 := quat(2, 0, 0, 0); - q2 = quat(1, 1, -1, 0); - basic.print("q1: %\n", q1); - basic.print("q2: %\n", q2); - basic.print("q1*q2: %\n", q1*q2); - basic.print("dot(q2,q2): %\n", dot(q2, q2)); - basic.print("dot(q1,q2): %\n", dot(q1, q2)); - basic.print("q1*q2*conj(q1): %\n", q1*q2*conjugate(q1)); - c := q1*q2*conjugate(q1); - test.expect(*t, float_eq(c.w, 0.0)); - - q = rotation_quat(from_rad(PI/4.0), v3f(0.0, 0.0, 1.0)); - p := v3f(2.0, 0.0, 0.0); - basic.print("q: %\n", q); - basic.print("p: %\n", p); - c1 := q*quat(p, 0)*conjugate(q); - basic.print("q*quat(p, 0)*conjugate(q): %\n", c1); - c2 := q*p; - basic.print("q*p : %\n", c2); - test.expect(*t, v3_eq(c2, v3f(math.sqrt(2.0), math.sqrt(2.0), 0.0))); - test.expect(*t, v3_eq(c1.xyz, c2)); - - basic.print("quaternion to matrix rotation\n"); - q = rotation_quat(from_rad(PI), v3f(0.0, 1.0, 0.0)); - basic.print("q: %\n", q); - m := rotation_mat4(q); - print_mat4(m); - p1 := v4f(2.0, 0.0, 0.0, 1.0); - basic.print("p : %\n", p1); - basic.print("p': %\n", m*p1); - test.expect(*t, v4_eq(m*p1, v4f(-2.0, 0.0, -0.0, 1.0))); - - q1 = rotation_quat(from_rad(PI), v3f(0.0, 1.0, 0.0)); - q2 = rotation_quat(from_rad(2.0*PI), v3f(0.0, 1.0, 0.0)); - perc := 0.5; - q = slerp(q1, q2, perc); - basic.print("q1: %\n", q1); - basic.print("q2: %\n", q2); - basic.print("slerp q1, q2, %: %\n", perc, q); - - q = rotation_quat(from_rad(PI/4.0), v3f(0.0, 0.0, 1.0)); - print_mat4(rotation_mat4(q)); - } -} - -dot_print :: (fmt: string, args: ..Any, width: int = 30) { - dots := "................................................................."; - str := basic.tprint(fmt, args); - dots.count = width - str.count; - basic.print("%0%", str, dots); - basic.print("\n"); -} - -check :: (cond: bool, loc := #caller_location) -> bool { - if !cond { - basic.print("\tTest failed at %:%\n", loc.fully_pathed_filename, loc.line_number); - } - return cond; -} +// @temp(judah): move these to the right files v2_eq :: (a: Vec2, b: Vec2) -> bool { return float_eq(a.x, b.x) && float_eq(a.y, b.y); @@ -367,13 +49,7 @@ v4_eq :: (a: Vec4, b: Vec4) -> bool { // Smallest difference where a float is basically that value EPSILON :: 0.001; + float_eq :: (f: float, with: float) -> bool { return f > with - EPSILON && f < with + EPSILON; } - -print_mat4 :: (m: Mat4) { - basic.print("| % % % % |\n", m._00, m._01, m._02, m._03); - basic.print("| % % % % |\n", m._10, m._11, m._12, m._13); - basic.print("| % % % % |\n", m._20, m._21, m._22, m._23); - basic.print("| % % % % |\n", m._30, m._31, m._32, m._33); -} diff --git a/math/vec.jai b/math/vec.jai index 0753c63..ba71d26 100644 --- a/math/vec.jai +++ b/math/vec.jai @@ -640,6 +640,141 @@ cross :: (a: Vec3, b: Vec3) -> Vec3 { #scope_file -meta :: #import "jc/meta"; -math :: #import "Math"; // @future -basic :: #import "Basic"; // @future +#if RUN_TESTS #run,stallable { + test.run(basic.tprint("%: Vec2", UNITS), t => { + { + a: Vec2 = v2f(0.0, 1.0); + b: Vec2 = v2f(1.0, 2.0); + + test.expect(t, a + b == v2f(1.0, 3.0)); + test.expect(t, b - a == v2f(1.0, 1.0)); + test.expect(t, a*b == v2f(0.0, 2.0)); + test.expect(t, a/b == v2f(0.0, 0.5)); + } + + { + a: Vec(2, int) = v2i(2, 1); + b: Vec(2, int) = v2i(1, 0); + test.expect(t, a + b == v2i(3, 1)); + test.expect(t, b - a == v2i(-1, -1)); + test.expect(t, a*b == v2i(2, 0)); + test.expect(t, b/a == v2i(0, 0)); + } + { + a: Vec2 = v2f(2.3, -4.1); + b: Vec2 = v2f(1.0, 3.6); + c := min(a, b); + test.expect(t, c == v2f(1.0, -4.1)); + c = max(a, b); + test.expect(t, c == v2f(2.3, 3.6)); + } + }); + + test.run(basic.tprint("%: Vec3", UNITS), t => { + { + a: Vec3 = v3f(0.0, 1.0, 2.0); + b: Vec3 = v3f(1.0, 2.0, 3.0); + test.expect(t, a + b == v3f(1.0, 3.0, 5.0)); + test.expect(t, b - a == v3f(1.0, 1.0, 1.0)); + test.expect(t, a*b == v3f(0.0, 2.0, 6.0)); + test.expect(t, a/b == v3f(0.0, 0.5, 0.66666667)); + + a = v3f(1.0, 1.0, 0.0); + b = v3f(1.0, 0.0, 0.0); + test.expect(t, reflect(a, b) == v3f(1.0, -1.0, 0.0)); + test.expect(t, round(v3f(1.2, 1.7, 1.5)) == v3f(1.0, 2.0, 2.0)); + test.expect(t, round(v3f(-1.2, -1.7, -1.5)) == v3f(-1.0, -2.0, -2.0)); + + a = v3f(1.0, 0.0, 0.0); + b = v3f(0.0, 1.0, 0.0); + test.expect(t, cross(a, b) == v3f(0.0, 0.0, 1.0)); + } + { + a: Vec3 = v3f(2.3, 4.1, 9.0); + b: Vec3 = v3f(1.0, -3.6, 5.0); + c := min(a, b); + test.expect(t, c == v3f(1.0, -3.6, 5.0)); + c = max(a, b); + test.expect(t, c == v3f(2.3, 4.1, 9.0)); + } + }); + + test.run(basic.tprint("%: Vec4", UNITS), t => { + a: Vec4 = v4f(2.25, 1.0, 2.0, 1.0); + b: Vec4 = v4f(4.0, 2.0, 3.0, 1.0); + test.expect(t, a + b == v4f(6.25, 3.0, 5.0, 2.0)); + test.expect(t, b - a == v4f(1.75, 1.0, 1.0, 0.0)); + test.expect(t, a*b == v4f(9.0, 2.0, 6.0, 1.0)); + test.expect(t, a/b == v4f(0.5625, 0.5, 2.0/3.0, 1.0)); + }); + + test.run(basic.tprint("%: VecN", UNITS), t => { + a: Vec(16, float); + b: Vec(16, float); + for *a { + it.* = xx it_index; + } + for *b { + it.* = xx(it_index + 1); + } + test.expect(t, a + b == Vec(16, float).{.[1.0, 3.0, 5.0, 7.0, 9.0, 11.0, 13.0, 15.0, 17.0, 19.0, 21.0, 23.0, 25.0, 27.0, 29.0, 31.0]}); + test.expect(t, b - a == Vec(16, float).{.[1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0]}); + test.expect(t, a*b == Vec(16, float).{.[0.0, 2.0, 6.0, 12.0, 20.0, 30.0, 42.0, 56.0, 72.0, 90.0, 110.0, 132.0, 156.0, 182.0, 210.0, 240.0]}); + + test.expect(t, min(a, b) == a); + test.expect(t, max(a, b) == b); + test.expect(t, max(a, 12) == Vec(16, float).{.[0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 12.0, 12.0, 12.0]}); + test.expect(t, min(a, 13.2) == Vec(16, float).{.[13.2, 13.2, 13.2, 13.2, 13.2, 13.2, 13.2, 13.2, 13.2, 13.2, 13.2, 13.2, 13.2, 13.2, 14.0, 15.0]}); + test.expect(t, clamp(a, 7.25, 12.0) == Vec(16, float).{.[7.25, 7.25, 7.25, 7.25, 7.25, 7.25, 7.25, 7.25, 8, 9, 10, 11, 12, 12, 12, 12]}); + + a1: Vec(16, float) = Vec(16, float).{.[1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 4.7, -1.2, -1.0, -1.5, 11.2, 14.0, 15.0, 14.0, 15.0, 65536.2]}; + test.expect(t, ceil(a1) == Vec(16, float).{.[2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 5.0, -1.0, -1.0, -1.0, 12.0, 14.0, 15.0, 14.0, 15.0, 65537]}); + test.expect(t, floor(a1) == Vec(16, float).{.[1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 4.0, -2.0, -1.0, -2.0, 11.0, 14.0, 15.0, 14.0, 15.0, 65536]}); + + test.expect(t, dot(a, b) == 1360.0); + test.expect(t, abs(a) == a); + + c := a; + for *c { // Check making every other component negative + if it_index%2 == 0 then it.* = -it.*; + } + + test.expect(t, abs(c) == a); + test.expect(t, float_eq(length(normalize(a)), 1)); + test.expect(t, a + 2 == Vec(16, float).{.[2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17]}); + test.expect(t, a - 2 == Vec(16, float).{.[-2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]}); + test.expect(t, a*2 == Vec(16, float).{.[0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30]}); + }); + + test.run(basic.tprint("%: Quat", UNITS), t => { + qi := quat_identity; + q: Quat = rotation_quat(from_rad(PI), v3f(0.0, 1.0, 0.0)); + q2: Quat = rotation_quat(from_rad(PI), v3f(1.0, 0.0, 1.0)); + qc := conjugate(q); + inv_q := inverse(q); + test.expect(t, q*inv_q == qi); + + q1 := quat(2, 0, 0, 0); + q2 = quat(1, 1, -1, 0); + c := q1*q2*conjugate(q1); + test.expect(t, float_eq(c.w, 0.0)); + + q = rotation_quat(from_rad(PI/4.0), v3f(0.0, 0.0, 1.0)); + p := v3f(2.0, 0.0, 0.0); + c1 := q*quat(p, 0)*conjugate(q); + c2 := q*p; + test.expect(t, v3_eq(c2, v3f(math.sqrt(2.0), math.sqrt(2.0), 0.0))); + test.expect(t, v3_eq(c1.xyz, c2)); + + q = rotation_quat(from_rad(PI), v3f(0.0, 1.0, 0.0)); + m := rotation_mat4(q); + p1 := v4f(2.0, 0.0, 0.0, 1.0); + test.expect(t, v4_eq(m*p1, v4f(-2.0, 0.0, -0.0, 1.0))); + + q1 = rotation_quat(from_rad(PI), v3f(0.0, 1.0, 0.0)); + q2 = rotation_quat(from_rad(2.0*PI), v3f(0.0, 1.0, 0.0)); + perc := 0.5; + q = slerp(q1, q2, perc); + q = rotation_quat(from_rad(PI/4.0), v3f(0.0, 0.0, 1.0)); + }); +}