LoreMuseum/g3d/objloader.lua

126 lines
3.8 KiB
Lua

-- written by groverbuger for g3d
-- february 2021
-- MIT license
----------------------------------------------------------------------------------------------------
-- simple obj loader
----------------------------------------------------------------------------------------------------
-- stitch two tables together and return the result
local function concatTables(t1,t2,t3)
local ret = {}
for i,v in ipairs(t1) do
ret[#ret +1] = v
end
for i,v in ipairs(t2) do
ret[#ret +1] = v
end
for i,v in ipairs(t3) do
ret[#ret +1] = v
end
return ret
end
-- give path of file
-- returns a lua table representation
local function objLoader(path)
local verts = {}
local faces = {}
local uvs = {}
local normals = {}
-- 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
-- if the first word in this line is a "v", then this defines a vertex
if words[1] == "v" then
verts[#verts+1] = {tonumber(words[2]), tonumber(words[3]), tonumber(words[4])}
end
-- if the first word in this line is a "vt", then this defines a texture coordinate
if words[1] == "vt" then
uvs[#uvs+1] = {tonumber(words[2]), tonumber(words[3])}
end
-- if the first word in this line is a "vn", then this defines a vertex normal
if words[1] == "vn" then
normals[#normals+1] = {tonumber(words[2]), tonumber(words[3]), tonumber(words[4])}
end
-- if the first word in this line is a "f", then this is a face
-- a face takes three arguments which refer to points, each of those points take three arguments
-- the arguments a point takes is v,vt,vn
if words[1] == "f" then
local store = {}
assert(#words == 4, "Faces in "..path.." must be triangulated before they can be used in g3d!")
for i=2, #words do
local num = ""
local word = words[i]
local ii = 1
local char = word:sub(ii,ii)
while true do
char = word:sub(ii,ii)
if char ~= "/" then
num = num .. char
else
break
end
ii = ii + 1
end
store[#store+1] = tonumber(num)
local num = ""
ii = ii + 1
while true do
char = word:sub(ii,ii)
if ii <= #word and char ~= "/" then
num = num .. char
else
break
end
ii = ii + 1
end
store[#store+1] = tonumber(num)
local num = ""
ii = ii + 1
while true do
char = word:sub(ii,ii)
if ii <= #word and char ~= "/" then
num = num .. char
else
break
end
ii = ii + 1
end
store[#store+1] = tonumber(num)
end
faces[#faces+1] = store
end
end
-- put it all together in the right order
local compiled = {}
for i,face in pairs(faces) do
compiled[#compiled +1] = concatTables(verts[face[1]], uvs[face[2]], normals[face[3]])
compiled[#compiled +1] = concatTables(verts[face[4]], uvs[face[5]], normals[face[6]])
compiled[#compiled +1] = concatTables(verts[face[7]], uvs[face[8]], normals[face[9]])
end
return compiled
end
return objLoader