94 lines
2.6 KiB
Lua
94 lines
2.6 KiB
Lua
function meshport.parse_vector_element(elementStr)
|
|
local elementType
|
|
local vec = {}
|
|
|
|
-- Get the element type and vector. `vec.z` will be left `nil` for two-dimensional vectors.
|
|
elementType, vec.x, vec.y, vec.z = string.match(elementStr, "^(%a+)%s([%d%.%-]+)%s([%d%.%-]+)%s?([%d%.%-]*)")
|
|
|
|
for k, v in pairs(vec) do
|
|
vec[k] = tonumber(v)
|
|
end
|
|
|
|
-- Return the element type and value.
|
|
if elementType == "v" then
|
|
-- Invert X axis to match the Minetest coordinate system.
|
|
vec.x = -vec.x
|
|
return "verts", vec
|
|
elseif elementType == "vt" then
|
|
return "tex_coords", vec
|
|
elseif elementType == "vn" then
|
|
vec.x = -vec.x
|
|
return "vert_norms", vec
|
|
end
|
|
end
|
|
|
|
function meshport.parse_face_element(elements, elementStr)
|
|
-- Split the face element into strings containing the indices of elements associated with each vertex.
|
|
local vertStrs = string.split(string.match(elementStr, "^f%s([%d/%s]+)"), " ")
|
|
local elementIndices
|
|
|
|
local face = {
|
|
verts = {},
|
|
tex_coords = {},
|
|
vert_norms = {},
|
|
}
|
|
|
|
for i, vertStr in ipairs(vertStrs) do
|
|
-- Split the string into a table of indices for position, texture coordinate, and/or vertex normal elements.
|
|
elementIndices = string.split(vertStr, "/", true)
|
|
|
|
for k, v in pairs(elementIndices) do
|
|
elementIndices[k] = tonumber(v)
|
|
end
|
|
|
|
-- Set the position, texture coordinate, and vertex normal of the face. `or 0` prevents a nil index error.
|
|
face.verts[i] = elements.verts[elementIndices[1] or 0]
|
|
face.tex_coords[i] = elements.tex_coords[elementIndices[2] or 0]
|
|
face.vert_norms[i] = elements.vert_norms[elementIndices[3] or 0]
|
|
end
|
|
|
|
return face
|
|
end
|
|
|
|
function meshport.parse_obj(path)
|
|
local faces = meshport.Faces:new()
|
|
local file = io.open(path, "r")
|
|
|
|
local elements = {
|
|
verts = {},
|
|
tex_coords = {},
|
|
vert_norms = {},
|
|
}
|
|
|
|
local groups = {}
|
|
local curGroup
|
|
local elementType
|
|
|
|
for line in file:lines() do
|
|
elementType = string.sub(line, 1, 1)
|
|
|
|
if elementType == "v" then
|
|
-- Parse the vector element. Used for "v", "vt", and "vn".
|
|
local type, value = meshport.parse_vector_element(line)
|
|
table.insert(elements[type], value)
|
|
elseif elementType == "f" then
|
|
-- If the face is not part of any group, use the placeholder group `0`.
|
|
if not curGroup then
|
|
table.insert(groups, 0)
|
|
curGroup = table.indexof(groups, 0)
|
|
end
|
|
|
|
-- Parse the face element.
|
|
local face = meshport.parse_face_element(elements, line)
|
|
-- Assign materials according to the group.
|
|
face.tile_idx = curGroup
|
|
faces:insert_face(face)
|
|
elseif elementType == "g" then
|
|
-- If this group has not been used yet, then add it to the list.
|
|
curGroup = meshport.find_or_insert(groups, string.match(line, "^g%s(.+)"))
|
|
end
|
|
end
|
|
|
|
return faces
|
|
end
|