local glm = honey.glm local module = {} setmetatable(module, {__index=_G}) setfenv(1, module) Vec3 = {} Mat4 = {} Quaternion = {} --===== Vec3 =====-- function Vec3.new(_, values) local self = {} self.data = glm.vec3_create() setmetatable(self, Vec3) if values then self[1] = values[1] self[2] = values[2] self[3] = values[3] end return self end setmetatable(Vec3, {__call=Vec3.new}) function Vec3.__index(self, key) if type(key) == 'number' then return glm.vec3_get(self.data, key-1) else return Vec3[key] end end function Vec3.__newindex(self, key, value) glm.vec3_set(self.data, key-1, value) end function Vec3.__tostring(self) return string.format("Vec3{%.4f, %.4f, %.4f}", self[1], self[2], self[3]) end --===== arithmetic =====-- local function swapIfNumber(self, other) if type(self) == "number" and type(other) == "table" then return other, self else return self, other end end function Vec3.__add(self, other) local self, other = swapIfNumber(self, other) local dest = Vec3() if type(other) == "number" then glm.vec3_adds(self.data, other, dest.data) elseif type(other) == "table" then glm.vec3_add(self.data, other.data, dest.data) else error(string.format("cannot add %s to Vec3", type(other))) end return dest end function Vec3.__sub(self, other) local dest = Vec3() if type(other) == "number" then glm.vec3_subs(self.data, other, dest.data) elseif type(other) == "table" then glm.vec3_sub(self.data, other.data, dest.data) else error(string.format("cannot subtract %s from Vec3", type(other))) end return dest end function Vec3.__mul(self, other) local self, other = swapIfNumber(self, other) local dest = Vec3() if type(other) == "number" then glm.vec3_scale(self.data, other, dest.data) elseif type(other) == "table" then glm.vec3_mul(self.data, other.data, dest.data) else error(string.format("cannot multiply %s and Vec3", type(other))) end return dest end function Vec3.__div(self, other) local dest = Vec3() if type(other) == "number" then glm.vec3_divs(self.data, other, dest.data) elseif type(other) == "table" then glm.vec3_div(self.data, other.data, dest.data) else error(string.format("cannot divide Vec3 by %s", type(other))) end return dest end function Vec3.copyTo(self, dest) glm.vec3_copy(self.data, dest.data) end function Vec3.zero(self) glm.vec3_zero(self.data) end function Vec3.zero(self) glm.vec3_zero(self.data) end function Vec3.one(self) glm.vec3_one(self.data) end function Vec3.dot(self, other) return glm.vec3_dot(self.data, other.data) end function Vec3.crossTo(self, other, dest) glm.vec3_cross(self.data, other.data, dest.data) end function Vec3.cross(self, other) local dest = Vec3() self:crossTo(other, dest) return dest end function Vec3.crossnTo(self, other, dest) glm.vec3_crossn(self.data, other.data, dest.data) end function Vec3.crossn(self, other) local dest = Vec3() self:crossTo(other, dest) return dest end function Vec3.norm2(self) return glm.vec3_norm2(self.data) end function Vec3.norm(self) return glm.vec3_norm(self.data) end function Vec3.normalize(self) glm.vec3_normalize(self.data) end function Vec3.normalizeTo(self, dest) glm.vec3_normalize_to(self.data, dest.data) end ---------------------------------------- local RowLookup = {} function RowLookup.new(_, row, data) local self = { row=row, data=data, } setmetatable(self, RowLookup) return self end setmetatable(RowLookup, {__call=RowLookup.new}) function RowLookup.__index(self, col) return glm.mat4_get(self.data, col-1, self.row-1) end function RowLookup.__newindex(self, col, value) return glm.mat4_set(self.data, col-1, self.row-1, value) end --===== Mat4 =====-- function Mat4.new(_, values) local self = {} self.type = "mat4" self.data = glm.mat4_create() setmetatable(self, Mat4) if values then self[1][1] = values[1] self[1][2] = values[2] self[1][3] = values[3] self[1][4] = values[4] self[2][1] = values[5] self[2][2] = values[6] self[2][3] = values[7] self[2][4] = values[8] self[3][1] = values[9] self[3][2] = values[10] self[3][3] = values[11] self[3][4] = values[12] self[4][1] = values[13] self[4][2] = values[14] self[4][3] = values[15] self[4][4] = values[16] end return self end setmetatable(Mat4, {__call=Mat4.new}) function Mat4.__index(self, key) if type(key) == "number" then return RowLookup(key, self.data) else return Mat4[key] end end function Mat4.__tostring(self) return string.format( "Mat4{%0.4f, %0.4f, %0.4f, %0.4f, " .. "%0.4f, %0.4f, %0.4f, %0.4f, " .. "%0.4f, %0.4f, %0.4f, %0.4f, " .. "%0.4f, %0.4f, %0.4f, %0.4f}", self[1][1], self[1][2], self[1][3], self[1][4], self[2][1], self[2][2], self[2][3], self[2][4], self[3][1], self[3][2], self[3][3], self[3][4], self[4][1], self[4][2], self[4][3], self[4][4] ) end function Mat4.__mul(self, other) if other.type == "mat4" then local dest = Mat4() glm.mat4_mul(self.data, other.data, dest.data) return dest elseif other.type == "vec4" then -- todo elseif other.type == "vec3" then local dest = Vec3() glm.mat4_mulv3(self.data, other.data, 1.0, dest.data) return dest else error(string.format("cannot multiply Mat4 by %s", type(other))) end end function Mat4.copyTo(self, dest) glm.mat4_copy(self.data, dest.data) end function Mat4.identity(self) glm.mat4_identity(self.data) return self end function Mat4.zero(self) glm.mat4_zero(self.data) return self end function Mat4.mul(self, other) glm.mat4_mul(self.data, other.data, self.data) return self end function Mat4.translate(self, vec) glm.translate(self.data, vec.data) return self end function Mat4.rotateX(self, angle) glm.rotate_x(self.data, angle, self.data) return self end function Mat4.rotateY(self, angle) glm.rotate_y(self.data, angle, self.data) return self end function Mat4.rotateZ(self, angle) glm.rotate_z(self.data, angle, self.data) return self end function Mat4.scale(self, vec) glm.scale(self.data, vec.data) return self end function Mat4.perspective(self, fovy, aspect, near, far) glm.perspective(fovy, aspect, near, far, self.data) return self end function Mat4.perspectiveResize(self, aspect) glm.perspective_resize(aspect, self.data) return self end --===== Quaternion =====-- Quaternion.__index = Quaternion function Quaternion.new(_, tbl) local tbl = tbl or { 0, 0, 0, 0 } local self = {} self.data = glm.quat_create() glm.quat_init(self.data, unpack(tbl)) setmetatable(self, Quaternion) return self end setmetatable(Quaternion, {__call=Quaternion.new}) function Quaternion.toMat4(self) local m = Mat4() glm.quat_mat4(self.data, m.data) return m end --------------------------- return module