---@class Obj ---@field model string ---@field texture string ---@field texture_size integer ---@field position Vector3 ---@field triangles table local Obj = {} local Vector3 = require "types.vector3" Obj.__index = Obj local function string_split(str, delimiter) local res = {} local i = 0 local f local match = '(.-)' .. delimiter .. '()' if string.find(str, delimiter) == nil then return {str} end for sub, j in string.gmatch(str, match) do i = i + 1 res[i] = sub f = j end if i ~= 0 then res[i+1] = string.sub(str, f) end return res end ---parses the obj file and triangulates it for drawing ---@param model string path to obj model ---@param texture {file: string, size: number} ---@param position Vector3? ---@return Obj function Obj.create(model, texture, position) local pos if position ~= nil then pos = position else pos = Vector3() end local obj = { model = model, texture = texture.file, texture_size = texture.size, position = pos:copy(), triangles = {} } obj.position = obj.position:copy() setmetatable(obj, Obj) -- adapted from https://github.com/karai17/lua-obj/blob/master/obj_loader.lua -- Copyright (c) 2014 Landon Manning - LManning17@gmail.com - LandonManning.com -- MIT local file = file_read{file = obj.model} local lines = string_split(file, "\r?\n") local obj_data = { v = {}, vt = {}, f = {}, } for _, line in ipairs(lines) do local l = string_split(line, "%s+") if l[1] == "v" then local v = { x = tonumber(l[2]), y = tonumber(l[3]), z = tonumber(l[4]), } table.insert(obj_data.v, v) elseif l[1] == "vt" then local vt = { x = tonumber(l[2]) * obj.texture_size, y = tonumber(l[3]) * obj.texture_size, } table.insert(obj_data.vt, vt) elseif l[1] == "f" then local f = {} for i = 2, #l do local split = string_split(l[i], "/") local v = {} v.v = tonumber(split[1]) if split[2] ~= "" then v.vt = tonumber(split[2]) end -- v.vn = tonumber(split[3]) table.insert(f, v) end table.insert(obj_data.f, f) end end for _, face in ipairs(obj_data.f) do for i = 2, #face - 1 do local triangle = { v0 = obj_data.v[face[1].v], v1 = obj_data.v[face[i].v], v2 = obj_data.v[face[i + 1].v], uv0 = obj_data.vt[face[1].vt], uv1 = obj_data.vt[face[i].vt], uv2 = obj_data.vt[face[i + 1].vt], texture = obj.texture } table.insert(obj.triangles, triangle) end end return obj end function Obj:draw() for _, triangle in ipairs(self.triangles) do local newt = util.shallow_copy(triangle) newt.v0 = Vector3(triangle.v0) + self.position newt.v1 = Vector3(triangle.v1) + self.position newt.v2 = Vector3(triangle.v2) + self.position draw_triangle(newt) end end return Obj