Shining-in-the-Darkness-Lua.../g3d/objloader.lua

84 lines
3 KiB
Lua
Raw Permalink Normal View History

2024-06-05 14:16:51 +03:00
-- written by groverbuger for g3d
-- september 2021
-- MIT license
----------------------------------------------------------------------------------------------------
-- simple obj loader
----------------------------------------------------------------------------------------------------
local inspect = require "inspect"
-- give path of file
-- returns a lua table representation
return function (path, flipU, flipV)
local positions, faces, uvs, normals, model = {}, {}, {}, {}, {}
-- go line by line through the file
for line in love.filesystem.lines(path) do
local words = {}
-- split the line into words
for word in line:gmatch "([^%s]+)" do
table.insert(words, word)
end
local firstWord = words[1]
if firstWord == "v" then
-- if the first word in this line is a "v", then this defines a vertex's position
table.insert(positions, {tonumber(words[2]), tonumber(words[3]), tonumber(words[4])})
--print(table.concat(positions[#positions],";"))
elseif firstWord == "vt" then
-- if the first word in this line is a "vt", then this defines a texture coordinate
-- Blender 2.9+ V axis points UP, whereas LÖVE's Y axis points DOWN
-- Not sure if any other software has U axis inverted, but why not add this just in case?
local U, V = tonumber(words[2]), tonumber(words[3])
if flipU then U = 1 - U end
if flipV then V = 1 - V end
table.insert(uvs, {U,V})
elseif firstWord == "vn" then
-- if the first word in this line is a "vn", then this defines a vertex normal
table.insert(normals, {tonumber(words[2]), tonumber(words[3]), tonumber(words[4])})
elseif firstWord == "f" then
-- if the first word in this line is a "f", then this is a face
-- a face takes three point definitions
-- the arguments a point definition takes are vertex, vertex texture, vertex normal in that order
assert(#words == 4, ("Faces in %s must be triangulated before they can be used in g3d!"):format(path))
local face = {v = {}, vt = {}, n = {}}
for i=2, #words do
local v, vt, n = words[i]:match "(%d+)/(%d+)/(%d+)"
--print(v,vt,n)
if not (v and vt and n) then
v, vt = words[i]:match "(%d+)/(%d+)"
n = 1
end
table.insert(face.v, tonumber(v))
table.insert(face.vt, tonumber(vt))
table.insert(face.n, tonumber(n))
end
table.insert(faces, face)
end
end
-- put it all together in the right order
for _, face in pairs(faces) do
for i=1, 3 do
local vert = {unpack(positions[face.v[i]])}
for _, uv in ipairs(uvs[face.vt[i]]) do table.insert(vert, uv) end
if (normals[face.n[i]]) then
for _, normal in ipairs(normals[face.n[i]]) do table.insert(vert, normal) end
end
table.insert(model, vert)
end
end
return model
end