epidermis/models.lua

58 lines
2.1 KiB
Lua

local mlvec = modlib.vector
local media_paths = epidermis.media_paths
local bad_character_b3d_path = modlib.mod.get_resource"character_without_normals.b3d"
local bad_character_b3d_hash = minetest.sha1(modlib.file.read(bad_character_b3d_path))
local fixed_character_b3d_path = modlib.mod.get_resource"character_with_normals.b3d"
return setmetatable({}, {__index = function(self, filename)
local _, ext = modlib.file.get_extension(filename)
if not ext or ext:lower() ~= "b3d" then
-- Only B3D support currently
return
end
local path = assert(media_paths[filename], filename)
-- HACK replace a "bad" character.b3d with a fixed version that includes normals
-- Susceptible to SHA1 collisions, but so is MT's media loading process
-- See https://github.com/minetest/minetest_game/pull/2902
if filename == "character.b3d" and minetest.sha1(modlib.file.read(path)) == bad_character_b3d_hash then
path = fixed_character_b3d_path
end
local model = io.open(path, "rb")
local character = assert(modlib.b3d.read(model))
assert(not model:read(1))
model:close()
local mesh = assert(character.node.mesh)
local vertices = assert(mesh.vertices)
for _, vertex in ipairs(vertices) do
-- Minetest hardcodes a blocksize of 10 model units
vertex.pos = mlvec.divide_scalar(vertex.pos, 10)
end
-- Triangle sets by texture index
local tris_by_tex = {}
local func = modlib.func
for _, set in pairs(assert(mesh.triangle_sets)) do
local tris = set.vertex_ids
for _, tri in pairs(tris) do
modlib.table.map(tri, func.curry(func.index, vertices))
tri.poses = {tri[1].pos, tri[2].pos, tri[3].pos}
end
local brush_id = tris.brush_id or mesh.brush_id
local tex_id
if brush_id then
tex_id = assert(character.brushes[brush_id].texture_id[1])
else
-- No brush, default to first texture
tex_id = 1
end
tris_by_tex[tex_id] = tris_by_tex[tex_id] and modlib.table.append(tris_by_tex[tex_id], tris) or tris
end
self[filename] = {
vertices = vertices,
triangle_sets = tris_by_tex,
frames = (character.node.animation or {}).frames or 1
}
return self[filename]
end})