meshport/api.lua
2019-06-27 21:56:35 -07:00

190 lines
4.8 KiB
Lua

meshport.Faces = {}
function meshport.Faces:new()
local o = {
faces = {},
}
self.__index = self
setmetatable(o, self)
return o
end
function meshport.Faces:insert_face(face)
table.insert(self.faces, face)
end
function meshport.Faces:copy()
local newFaces = meshport.Faces:new()
-- Using `table.copy` on all of `self.faces` does not work here.
newFaces.faces = table.copy(self.faces)
-- for _, face in ipairs(self.faces) do
-- table.insert(newFaces.faces, table.copy(face))
-- end
return newFaces
end
function meshport.Faces:translate(vec)
for _, face in ipairs(self.faces) do
for i, vert in ipairs(face.verts) do
face.verts[i] = vector.add(vert, vec)
end
end
end
function meshport.Faces:rotate_by_facedir(facedir)
if facedir == 0 then
return
end
for _, face in ipairs(self.faces) do
-- Rotate vertices.
for i = 1, #face.verts do
face.verts[i] = meshport.rotate_vector_by_facedir(face.verts[i], facedir)
end
-- Rotate vertex normals.
for i = 1, #face.vert_norms do
face.vert_norms[i] = meshport.rotate_vector_by_facedir(face.vert_norms[i], facedir)
end
end
end
function meshport.Faces:apply_tiles(nodeDef)
local tile
for _, face in ipairs(self.faces) do
tile = meshport.get_tile(nodeDef.tiles, face.tile_idx)
face.texture = tile.name or tile
end
end
meshport.Mesh = {}
function meshport.Mesh:new()
local o = {
verts = {},
vert_norms = {},
tex_coords = {},
faces = {},
}
setmetatable(o, self)
self.__index = self
return o
end
function meshport.Mesh:insert_face(face)
local indices = {
verts = {},
vert_norms = {},
tex_coords = {},
}
local elementStr, vec
-- Add vertices to mesh.
for i, vert in ipairs(face.verts) do
-- Invert Z axis to comply with Blender's coordinate system.
vec = meshport.clean_vector({x = vert.x, y = vert.y, z = -vert.z})
elementStr = string.format("v %f %f %f\n", vec.x, vec.y, vec.z)
indices.verts[i] = meshport.find_or_insert(self.verts, elementStr)
end
-- Add texture coordinates (UV map).
for i, texCoord in ipairs(face.tex_coords) do
elementStr = string.format("vt %f %f\n", texCoord.x, texCoord.y)
indices.tex_coords[i] = meshport.find_or_insert(self.tex_coords, elementStr)
end
-- Add vertex normals.
for i, vertNorm in ipairs(face.vert_norms) do
-- Invert Z axis.
vec = meshport.clean_vector({x = vertNorm.x, y = vertNorm.y, z = -vertNorm.z})
elementStr = string.format("vn %f %f %f\n", vec.x, vec.y, vec.z)
indices.vert_norms[i] = meshport.find_or_insert(self.vert_norms, elementStr)
end
-- Add faces to mesh.
local vertStrs = {}
local vertList = {}
for i = 1, #indices.verts do
vertList = table.insert(vertStrs, table.concat({
indices.verts[i],
-- If there is a vertex normal but not a texture coordinate, insert a blank string here.
indices.tex_coords[i] or (indices.vert_norms[i] and ""),
indices.vert_norms[i],
}, "/"))
end
self.faces[face.texture] = self.faces[face.texture] or {}
table.insert(self.faces[face.texture], string.format("f %s\n", table.concat(vertStrs, " ")))
end
function meshport.Mesh:write_obj(path)
local objFile = io.open(path .. DIR_DELIM .. "/model.obj", "w")
objFile:write("# Created using meshport (https://github.com/random-geek/meshport).\n")
objFile:write("mtllib materials.mtl\n")
-- Write vertices.
for _, vert in ipairs(self.verts) do
objFile:write(vert)
end
-- Write texture coordinates.
for _, texCoord in ipairs(self.tex_coords) do
objFile:write(texCoord)
end
-- Write vertex normals.
for _, vertNorm in ipairs(self.vert_norms) do
objFile:write(vertNorm)
end
-- Write faces, sorted in order of material.
for mat, faces in pairs(self.faces) do
objFile:write(string.format("usemtl %s\n", mat))
for _, face in ipairs(faces) do
objFile:write(face)
end
end
objFile:close()
end
function meshport.Mesh:write_mtl(path, playerName)
local textures = meshport.get_asset_paths("textures")
local matFile = io.open(path .. "/materials.mtl", "w")
matFile:write("# Created using meshport (https://github.com/random-geek/meshport).\n\n")
-- Write material information.
for mat, _ in pairs(self.faces) do
matFile:write(string.format("newmtl %s\n", mat))
-- Attempt to get the base texture, ignoring texture modifiers.
local texName = string.match(mat, "[%w%s%-_%.]+%.png") or mat
if textures[texName] then
if texName ~= mat then
meshport.print(playerName, "warning", string.format("Ignoring texture modifers in material %q.", mat))
end
matFile:write(string.format("map_Kd %s\n\n", textures[texName]))
else
meshport.print(playerName, "warning",
string.format("Could not find texture %q. Using a dummy material instead.", texName))
matFile:write(string.format("Kd %f %f %f\n\n", math.random(), math.random(), math.random()))
end
matFile:write("\n\n")
end
matFile:close()
end