-- Vector math emulation library for tools -- C++ projects use native vectors (see LuaVec module) local sqrt = math.sqrt local vector_mt -- monkey patch type function to support vectors local old_type = type type = function(v) if getmetatable(v) == vector_mt then return "vector" end return old_type(v) end local function arith_error(op, v0, v1) error(string.format("attempt to perform arithmetic (%s) on %s and %s", op, type(v0), type(v1)), 3) end vector_mt = { __add = function(v0, v1) if type(v0) == "table" and type(v1) == "table" then return vector(v0.x + v1.x, v0.y + v1.y, v0.z + v1.z, v0.w + v1.w) else arith_error("add", v0, v1) end end, __sub = function(v0, v1) if type(v0) == "table" and type(v1) == "table" then return vector(v0.x - v1.x, v0.y - v1.y, v0.z - v1.z, v0.w - v1.w) else arith_error("sub", v0, v1) end end, __mul = function(v0, v1) if type(v0) == "number" then return vector(v0 * v1.x, v0 * v1.y, v0 * v1.z, v0 * v1.w) elseif type(v1) == "number" then return vector(v0.x * v1, v0.y * v1, v0.z * v1, v0.w * v1) elseif type(v0) == "table" and type(v1) == "table" then return vector(v0.x * v1.x, v0.y * v1.y, v0.z * v1.z, v0.w * v1.w) else arith_error("mul", v0, v1) end end, __div = function(v0, v1) if type(v0) == "number" then return vector(v0 / v1.x, v0 / v1.y, v0 / v1.z, v0 / v1.w) elseif type(v1) == "number" then return vector(v0.x / v1, v0.y / v1, v0.z / v1, v0.w / v1) elseif type(v0) == "table" and type(v1) == "table" then return vector(v0.x / v1.x, v0.y / v1.y, v0.z / v1.z, v0.w / v1.w) else arith_error("div", v0, v1) end end, __unm = function(v) return vector(-v.x, -v.y, -v.z, -v.w) end, __tostring = function(v) return string.format("vector(%f, %f, %f, %f)", v.x, v.y, v.z, v.w) end, __serialize = function(v) return string.format("vector(%.17g,%.17g,%.17g,%.17g)", v.x, v.y, v.z, v.w) end, } function vector(x, y, z, w) local t = { x = x or 0.0, y = y or 0.0, z = z or 0.0, w = w or 0.0 } setmetatable(t, vector_mt) return t end function dot2(v0, v1) return v0.x * v1.x + v0.y * v1.y end function dot3(v0, v1) return v0.x * v1.x + v0.y * v1.y + v0.z * v1.z end function dot4(v0, v1) return v0.x * v1.x + v0.y * v1.y + v0.z * v1.z + v0.w * v1.w end function cross3(v0, v1) return vector(v0.y * v1.z - v0.z * v1.y, v0.z * v1.x - v0.x * v1.z, v0.x * v1.y - v0.y * v1.x) end function length2(v) return sqrt(v.x * v.x + v.y * v.y) end function length3(v) return sqrt(v.x * v.x + v.y * v.y + v.z * v.z) end function length4(v) return sqrt(v.x * v.x + v.y * v.y + v.z * v.z + v.w * v.w) end function length_squared2(v) return v.x * v.x + v.y * v.y end function length_squared3(v) return v.x * v.x + v.y * v.y + v.z * v.z end function length_squared4(v) return v.x * v.x + v.y * v.y + v.z * v.z + v.w * v.w end function normalize2(v) local s = 1.0 / length2(v); return vector(v.x * s, v.y * s) end function normalize3(v) local s = 1.0 / length3(v); return vector(v.x * s, v.y * s, v.z * s) end function normalize4(v) local s = 1.0 / length4(v); return vector(v.x * s, v.y * s, v.z * s, v.w * s) end function lerp2(v0, v1, t) return vector(v0.x * (1.0 - t) + v1.x * t, v0.y * (1.0 - t) + v1.y * t) end function lerp3(v0, v1, t) return vector(v0.x * (1.0 - t) + v1.x * t, v0.y * (1.0 - t) + v1.y * t, v0.z * (1.0 - t) + v1.z * t) end function lerp4(v0, v1, t) return vector(v0.x * (1.0 - t) + v1.x * t, v0.y * (1.0 - t) + v1.y * t, v0.z * (1.0 - t) + v1.z * t, v0.w * (1.0 - t) + v1.w * t) end function distance2(v0, v1) return sqrt(distance_squared2(v0, v1)) end function distance3(v0, v1) return sqrt(distance_squared3(v0, v1)) end function distance4(v0, v1) return sqrt(distance_squared4(v0, v1)) end function distance_squared2(v0, v1) local v0x,v0y,v1x,v1y = v0.x,v0.y,v1.x,v1.y; return (v0x - v1x) * (v0x - v1x) + (v0y - v1y) * (v0y - v1y) end function distance_squared3(v0, v1) local v0x,v0y,v0z,v1x,v1y,v1z = v0.x,v0.y,v0.z,v1.x,v1.y,v1.z; return (v0x - v1x) * (v0x - v1x) + (v0y - v1y) * (v0y - v1y) + (v0z - v1z) * (v0z - v1z) end function distance_squared4(v0, v1) local v0x,v0y,v0z,v0w,v1x,v1y,v1z,v1w = v0.x,v0.y,v0.z,v0.w,v1.x,v1.y,v1.z,v1.w; return (v0x - v1x) * (v0x - v1x) + (v0y - v1y) * (v0y - v1y) + (v0z - v1z) * (v0z - v1z) + (v0w - v1w) * (v0w - v1w) end