84 lines
3 KiB
Lua
84 lines
3 KiB
Lua
-- 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
|