local I = mat4.identity()
local Z = mat4.zero()
local T = mat4.translate(tx, ty, tz)
local S = mat4.scale(sx, sy, sz)
local R = mat4.rotate_euler(pitch, yaw, roll)
local Mq = mat4.from_quaternion(q)
local T = mat4.translate(10, 5, 0)
local R = mat4.rotate_euler(0, 90, 0)
local S = mat4.scale(2, 2, 2)
local M = T * R * S
local out = M:transform(vector3(1,0,0))
log(out)
local q = quat_from_euler(0, 0, 90)
local v = vector3(1,0,0)
local r = q:rotate(v) -- (0,1,0)
local t = inverse_lerp(0, 100, 25) -- 0.25
local v = remap(0, 1, -1, 1, t) -- -0.5
log("=========== MATH HELPERS TESTS START ===========")
local function approx(a,b,eps)
eps = eps or 0.000001
return math.abs(a-b) <= eps
end
local function assert_eq(a,b,msg)
if a ~= b then
log("[ASSERT FAIL] "..msg.." | expected="..tostring(b).." got="..tostring(a))
else
log("[PASS] "..msg)
end
end
local function assert_approx(a,b,msg)
if approx(a,b) then
log("[PASS] "..msg)
else
log("[ASSERT FAIL] "..msg.." | expected="..tostring(b).." got="..tostring(a))
end
end
----------------------------------------------------------------
-- clamp(x, min, max)
----------------------------------------------------------------
assert_approx(clamp(-1, 0, 1), 0, "clamp below")
assert_approx(clamp(0.5, 0, 1), 0.5,"clamp inside")
assert_approx(clamp(2, 0, 1), 1, "clamp above")
-- swapped min/max should still work
assert_approx(clamp(5, 10, 0), 5, "clamp swapped bounds")
----------------------------------------------------------------
-- saturate(x) -> [0,1]
----------------------------------------------------------------
assert_approx(saturate(-1), 0, "saturate below")
assert_approx(saturate(0.3), 0.3, "saturate inside")
assert_approx(saturate(5), 1, "saturate above")
----------------------------------------------------------------
-- sign(x)
----------------------------------------------------------------
assert_eq(sign( 5), 1, "sign positive")
assert_eq(sign(-2), -1, "sign negative")
assert_eq(sign( 0), 0, "sign zero")
----------------------------------------------------------------
-- round, round_up, round_down
----------------------------------------------------------------
assert_approx(round(2.3), 2, "round 2.3")
assert_approx(round(2.5), 3, "round 2.5")
assert_approx(round(-2.3), -2, "round -2.3")
assert_approx(round(-2.5), -3, "round -2.5")
assert_approx(round_up(2.1), 3, "round_up 2.1")
assert_approx(round_up(-2.1), -2, "round_up -2.1")
assert_approx(round_down(2.9), 2, "round_down 2.9")
assert_approx(round_down(-2.1), -3, "round_down -2.1")
----------------------------------------------------------------
-- fract(x)
----------------------------------------------------------------
assert_approx(fract(1.25), 0.25, "fract 1.25")
-- our implementation keeps negative fractional part in [0,1)
assert_approx(fract(-1.25), 0.75, "fract -1.25")
----------------------------------------------------------------
-- wrap(x, min, max)
----------------------------------------------------------------
assert_approx(wrap(5, 0, 4), 1, "wrap 5 in [0,4]")
assert_approx(wrap(-1, 0, 4), 3, "wrap -1 in [0,4]")
assert_approx(wrap(9, 2, 6), 5, "wrap 9 in [2,6]")
assert_approx(wrap(2, 2, 6), 2, "wrap 2 (edge)")
----------------------------------------------------------------
-- lerp / inverse_lerp
----------------------------------------------------------------
assert_approx(lerp(0, 10, 0.0), 0, "lerp t=0")
assert_approx(lerp(0, 10, 1.0), 10, "lerp t=1")
assert_approx(lerp(0, 10, 0.25), 2.5,"lerp t=0.25")
assert_approx(inverse_lerp(0, 10, 2.5), 0.25, "inverse_lerp 2.5 in [0,10]")
assert_approx(inverse_lerp(0, 10, 0), 0.0, "inverse_lerp 0")
assert_approx(inverse_lerp(0, 10, 10), 1.0, "inverse_lerp 10")
----------------------------------------------------------------
-- remap(a1,b1,a2,b2,v)
----------------------------------------------------------------
assert_approx(remap(0, 10, 0, 100, 2.5), 25, "remap 2.5 [0,10]->[0,100]")
assert_approx(remap(0, 1, -1, 1, 0.5), 0, "remap 0.5 [0,1]->[-1,1]")
assert_approx(remap(-1, 1, 0, 1, 0), 0.5, "remap 0 [-1,1]->[0,1]")
----------------------------------------------------------------
-- smoothstep(edge0,edge1,x)
----------------------------------------------------------------
assert_approx(smoothstep(0,1, -0.5), 0.0, "smoothstep below")
assert_approx(smoothstep(0,1, 0.0), 0.0, "smoothstep 0")
assert_approx(smoothstep(0,1, 1.0), 1.0, "smoothstep 1")
-- at x=0.5 we expect 0.5 for 3t^2-2t^3
local s05 = smoothstep(0,1,0.5)
assert_approx(s05, 0.5, "smoothstep 0.5")
----------------------------------------------------------------
-- step(edge, x)
----------------------------------------------------------------
assert_approx(step(0.5, 0.3), 0.0, "step below")
assert_approx(step(0.5, 0.5), 1.0, "step equal")
assert_approx(step(0.5, 0.9), 1.0, "step above")
----------------------------------------------------------------
-- is_nan / is_inf
----------------------------------------------------------------
local nan = 0/0
local pinf = 1/0
local ninf = -1/0
assert_eq(is_nan(nan), true, "is_nan on NaN")
assert_eq(is_nan(0), false, "is_nan on 0")
assert_eq(is_inf(pinf), true, "is_inf +inf")
assert_eq(is_inf(ninf), true, "is_inf -inf")
assert_eq(is_inf(123), false, "is_inf 123")
log("=========== MATH HELPERS TESTS END ===========")
function main()
return 1;
end