LEEF update

This commit is contained in:
FatalErr42O 2024-12-01 12:35:36 -08:00
parent 8453de9caf
commit edf8aeb9ed
8 changed files with 70 additions and 87 deletions

View File

@ -1,10 +1,10 @@
# MTUL-b3d
# LEEF-b3d
a b3d library that use's [Appgurue's work](https://github.com/appgurueu/modlib), a b3d reader, and expands it's usefulness into node reading, global transformation solving,
and more- mostly in one package. Online documentation can be found [here](https://minetest-unification-library.github.io/MTUL-b3d/).
and more- mostly in one package. Online documentation can be found [here](https://minetest-unification-library.github.io/LEEF-b3d/).
dependencies
* MTUL-core: provides binary reading (potential rename)
* MTUL-cpml: OPTIONAL allows use of b3d_nodes library (for node solving)
* LEEF-core: provides binary reading (potential rename)
* LEEF-math: OPTIONAL allows use of b3d_nodes library (for node solving)
features:
* read a b3d file
@ -15,7 +15,7 @@ features:
* solve the global transformation of a node (mat4)
todo:
* allow use of `get_node_by_name()` without CPML. (move to b3d_reader or set alias?)
* allow use of `get_node_by_name()` without MATH. (move to b3d_reader or set alias?)
* document b3d table contents (I already wrote most of the documentation in modlib's wiki...)
* finish b3d writer (NOTE: must offset "frame" by +1 as the reader is modified to match irrlicht)

View File

@ -9,27 +9,26 @@
has it's own respective directory for licensing purposes.
]]
mtul.b3d_reader = {}
mtul.b3d_writer = {}
mtul.loaded_modules.b3d = true
leef = leef or {}
leef.b3d_reader = {}
leef.b3d_writer = {}
leef.loaded_modules.b3d = true
local modpath = minetest.get_modpath("mtul_b3d")
local modpath = minetest.get_modpath("leef_b3d")
--placed in a seperate directory for the license
dofile(modpath.."/modlib/read_b3d.lua")
dofile(modpath.."/modlib/write_b3d.lua")
--dofile(modpath.."/modlib/to_gltf.lua")
--prevent accidental access of unavailable features:
if mtul.loaded_modules.cpml then
mtul.b3d_nodes = dofile(modpath.."/nodes.lua")
mtul.loaded_modules.b3d_nodes = true
mtul.b3d_nodes.loaded = true
if leef.math then
leef.b3d_nodes = dofile(modpath.."/nodes.lua")
else
mtul.b3d_nodes = {}
setmetatable(mtul.b3d_nodes, {
leef.b3d_nodes = {}
setmetatable(leef.b3d_nodes, {
__index = function(_, k)
if k ~= "loaded" then
error("MTUL-CPML not present, b3d_nodes module inaccessible.")
error("LEEF-Math not present, b3d_nodes not loaded.")
else
return false
end

View File

@ -1,5 +1,5 @@
project="MTUL b3d"
title="MTUL b3d reader/writer documentation"
project="LEEF b3d"
title="LEEF b3d reader/writer documentation"
description="A library containing hopefully all you need to read, solve and navigate a b3d. Aswell as (eventually) write one."
format="markdown"
backtick_references=false

View File

@ -1,6 +1,6 @@
name = mtul_b3d
title = MTUL b3d standalone
description = a b3d reader for minetest, cloned from modlib. Requires MTUL-core, also requires MTUL-CPML for nodes module.
depends = mtul_filesystem
optional_depends = mtul_cpml
name = leef_b3d
title = LEEF b3d
description = a b3d reader for minetest, cloned from modlib. Requires LEEF-core, requires LEEF-Math for nodes module.
depends = leef_filesystem
optional_depends = leef_math
author = FatalError42O, Appgurue

View File

@ -2,7 +2,7 @@
-- note: capitlization of name indicates a "chunk" defined by the blitz3d format (see b3d_specification.txt)
--@module b3d_reader
local read_int, read_single = mtul.binary.read_int, mtul.binary.read_single
local read_int, read_single = leef.binary.read_int, leef.binary.read_single
local function tbl_append(table, other_table)
local length = #table
for index, value in ipairs(other_table) do
@ -20,14 +20,14 @@ end
--reads a model directly (based on name). Note that "node_only" abstracts chunks not necessary to finding the position/transform of a bone/node.
--- read b3d models by their name. This simplifies read_from_stream.
-- @function mtul.b3d_reader.read_model
-- @function leef.b3d_reader.read_model
-- @param modelname string, the name of model you are trying to read.
-- @param node_only bool, specifies wether to ignore textures, meshes, or anything else. Use this if you're only trying to solve bone transforms.
-- @return b3d table (documentation needed!)
function mtul.b3d_reader.read_model(modelname, node_only)
function leef.b3d_reader.read_model(modelname, node_only)
assert(modelname, "no modelname provided")
-- @todo remove core dependancy on
local path = assert(mtul.paths.media_paths[modelname], "no model found by the name "..modelname.."'")
local path = assert(leef.paths.media_paths[modelname], "no model found by the name "..modelname.."'")
local out
local ignored
if node_only then
@ -35,8 +35,8 @@ function mtul.b3d_reader.read_model(modelname, node_only)
end
local stream = io.open(path, "rb")
if not stream then return end --if the file wasn't found we probably shouldnt just assert.
out = mtul.b3d_reader.read_from_stream(stream, ignored)
assert(stream:read(1)==nil, "MTUL b3d_reader: unknown error, EOF not reached")
out = leef.b3d_reader.read_from_stream(stream, ignored)
assert(stream:read(1)==nil, "LEEF b3d_reader: unknown error, EOF not reached")
stream:close()
return out
end
@ -66,14 +66,14 @@ end
-- @field 6 "BONE" node vertex weights
-- @field 7 "ANIM" animation information
-- @field 8 "KEYS" keyframes
-- @table ignore_chunks
-- @table chunks
--- read directly from file
-- @function mtul.b3d_reader.read_from_stream
-- @function leef.b3d_reader.read_from_stream
-- @param stream the file object (from the io library) to read from. Make sure you open it as "rb" (read binary.)
-- @param ignore_chunks a list of @{ignore_chunks} to be ignored
-- @return @{BB3D}
function mtul.b3d_reader.read_from_stream(stream, ignore_chunks)
-- @param ignore_chunks a list of @{chunks} to be ignored (documentation needed)
-- @return @{BB3D} (documentation needed!)
function leef.b3d_reader.read_from_stream(stream, ignore_chunks)
local left = 8
local ignored = {}
@ -164,12 +164,6 @@ function mtul.b3d_reader.read_from_stream(stream, ignore_chunks)
local chunk
local chunks = {
TEXS = function()
--- textures
--@field file
--@field flags
--@field pos table {float, float}
--@field pos table {float, float}
--@table TEXS
local textures = {}
while content() do
local tex = {}
@ -184,14 +178,6 @@ function mtul.b3d_reader.read_from_stream(stream, ignore_chunks)
return textures
end,
BRUS = function()
--- brushes (materials)
-- @field name
-- @field color
-- @field shininess
-- @field blend
-- @field fx
-- @field texture_id
-- @table BRUS
local brushes = {}
local n_texs = int()
assert(n_texs <= 8)
@ -344,13 +330,11 @@ function mtul.b3d_reader.read_from_stream(stream, ignore_chunks)
return ret
end,
NODE = function()
--- a node chunk possibly containing the following chunks.
--- node
-- a node chunk possibly containing the following chunks.
-- there are three possible "types" of nodes. All bones will contain the following chunks:
-- `position`, `rotation`, `scale`.
-- Bones will have a bone field which will contain IDs from it's parent node's mesh chunk.
-- Meshes will have a mesh field containing information about their mesh.
-- Pivots will have neither of those and simply serve as parents to child nodes. <3
--
-- position, rotation, scale. Bones will have a
-- bone field which will contain IDs from it's parent node's mesh chunk.
-- @field name
-- @field type string which is either "pivot", "bone" or "mesh"
-- @field children a list of child nodes, Transoformations (position, rotation, scale) will be applied to the children.
@ -415,11 +399,12 @@ function mtul.b3d_reader.read_from_stream(stream, ignore_chunks)
end)
return node
end,
--- note: in `b3d_writer` the node_paths field is ignored
-- @field node_paths all nodes in the model indexed by a table @{node_paths}
--- b3d table
-- note: in the b3d writer the node_paths field is ignored
-- @field node_paths all of the nodes in the model @{b3d_nodes}
-- @field node a table containing the root @{NODE} of the model.
-- @field textures a list of @{TEXS} chunks
-- @field brushes a list of @{BRUS} chunks
-- @field textures @{TEXS} texture information
-- @field brushes @{BRUS} material information
-- @field version `{major=float, minor=float}` this functionally means nothing, but it's version information.
-- @table BB3D
BB3D = function()
@ -473,7 +458,7 @@ function mtul.b3d_reader.read_from_stream(stream, ignore_chunks)
--also, Fatal here: for the sake of my reputation (which is nonexistent), typically I wouldn't nest these functions
--because I am not a physcopath and or a german named Lars, but for the sake of consistency it has to happen.
--(Not that its *always* a bad idea, but unless you're baking in parameters it's sort of useless and potentially wasteful)
local copy_path = function(tbl)
local copy_path = leef.table and leef.table.shallow_copy or function(tbl)
local new_table = {}
for i, v in pairs(tbl) do
new_table[i] = v
@ -497,10 +482,10 @@ function mtul.b3d_reader.read_from_stream(stream, ignore_chunks)
make_paths(self.node, {}, self.node_paths)
--b3d metatable unimplemented
return setmetatable(self, mtul._b3d_metatable or {})
return setmetatable(self, leef._b3d_metatable or {})
end
--- node paths
-- a list of nodes indexed by a list which containing every related parent node aswell as itself.
-- a list of nodes indexed by a hieracrchy of nodes i.e. "path.to.node"
-- @field (...) node
-- @table node_paths

View File

@ -9,7 +9,7 @@
--! Highly experimental; expect bugs!
-- glTF constants
local write_int, write_uint, write_single = mtul.binary.write_int, mtul.binary.write_uint, mtul.binary.write_single
local write_int, write_uint, write_single = leef.binary.write_int, leef.binary.write_uint, leef.binary.write_single
local array_buffer = 34962 -- "Buffer containing vertex attributes, such as vertices, texcoords or colors."
local element_array_buffer = 34963 -- "Buffer used for element indices."
local component_type = {
@ -76,7 +76,7 @@ local function write_quaternion(write_byte, quat)
return write_floats(write_byte, quaternion_to_gltf(quat), 4)
end
function mtul.b3d.to_gltf(self)
function leef.b3d.to_gltf(self)
-- Accessor helper: Stores arrays of raw data in a buffer, produces views & accessors.
-- Everything is dumped in the same large buffer.
local buffer_rope = {} -- buffer content (table of strings)

View File

@ -3,7 +3,7 @@
--Writer
local write_int, write_single = mtul.binary.write_int, mtul.binary.write_single
local write_int, write_single = leef.binary.write_int, leef.binary.write_single
local string_char = string.char
local function write_rope(self)
@ -37,7 +37,7 @@ local function write_rope(self)
end
local function float(val)
write_single(byte, mtul.binary.fround(val))
write_single(byte, leef.binary.fround(val))
end
local function float_array(arr, len)
@ -151,8 +151,7 @@ local function write_rope(self)
chunk("KEYS", function()
int(flags)
for _, frame in ipairs(keys) do
--reader offsets by 1, so writer should to.
int(frame.frame+1)
int(frame.frame)
if frame.position then vector3(frame.position) end
if frame.scale then vector3(frame.scale) end
if frame.rotation then quaternion(frame.rotation) end
@ -219,18 +218,18 @@ local function write_rope(self)
end
--- output a string of binary in the blitz 3d format
-- @function mtul.b3d_writer.write_string
-- @param self @{b3d_reader.BB3D|BB3D chunk}
-- @function leef.b3d_writer.write_string
-- @param self @{BB3D}
-- @return string containing the binary file
function mtul.b3d_writer.write_string(self)
function leef.b3d_writer.write_string(self)
return table.concat(write_rope(self))
end
--- output in the blitz3d format file reference
-- @function mtul.b3d_writer.write_model_to_file
-- @param self @{b3d_reader.BB3D|BB3D chunk}
-- @function leef.b3d_writer.write_model_to_file
-- @param self @{BB3D}
-- @param stream io file object to write to
function mtul.b3d_writer.write_model_to_file(self, stream)
function leef.b3d_writer.write_model_to_file(self, stream)
for _, str in ipairs(write_rope(self)) do
stream:write(str)
end

View File

@ -1,18 +1,18 @@
--- allows you to get information about nodes (bones or meshes) within a b3d table (generated with `b3d_reader`)
--- located in `mtul.b3d_nodes`.
--- WARNING! mtul-cpml must be present for this module to run!
--- located in `leef.b3d_nodes`.
--- WARNING! leef_math must be present for this module to run!
--@module b3d_nodes
--@warning for this module mtul_cpml is required, trying to use these functions without mtul_cpml ran will error.
--@warning for this module leef_math is required, trying to use these functions without leef_math ran will error.
--gets node by name
--this breaks if you have multiple nodes with the same name.
--if there are meshes that go by the same name, you can set "bone" param to true.
local b3d_nodes = {}
local mat4 = mtul.math.mat4
local quat = mtul.math.quat
local mat4 = leef.math.mat4
local quat = leef.math.quat
--- get a node by it's name
-- @function mtul.b3d_nodes.get_node_by_name
-- @function leef.b3d_nodes.get_node_by_name
-- @param self the b3d table (from b3d_reader)
-- @param node_name the name of the node to fine
-- @param is_bone (optional) bool to indicate wether the node is a bone or not (incase there's a mesh named the same thing). False will only return meshes and pivots, true will only return bones. Nil will return any.
@ -28,7 +28,7 @@ function b3d_nodes.get_node_by_name(self, node_name, is_bone)
end
end
--don't know why I'd ever just not return nil?
--error("MTUL-b3d, b3d_nodes: no node found by the name '"..tostring(node_name).."'")
--error("LEEF-b3d, b3d_nodes: no node found by the name '"..tostring(node_name).."'")
end
--non-methods:
@ -44,12 +44,12 @@ local interpolate = function(a, b, ratio)
end
--- get the local "TRS" (translation, rotation, scale) of a bone in animation. This is used for global transformation calculations.
--- quaternion is returned as a string indexed table because it needs to be a cpml object to be interpolated, also has to be usable anyway.
-- @function mtul.b3d_nodes.get_animated_local_trs
--- quaternion is returned as a string indexed table because it needs to be a math object to be interpolated, also has to be usable anyway.
-- @function leef.b3d_nodes.get_animated_local_trs
-- @param node table, the node from within a b3d table to read (as outputed by b3d_reader).
-- @param target_frame float, the frame to find the TRS in, can be inbetween frames/keyframes (of course).
-- @return `position` ordered table: {x, y, z}
-- @return `rotation` quat from `mtul_cpml`: (example) {w=0,x=0,y=0,z=1}
-- @return `rotation` quat from `leef_math`: (example) {w=0,x=0,y=0,z=1}
-- @return `scale` ordered table: {x, y, z}
--outputs need cleaning up.
function b3d_nodes.get_animated_local_trs(node, target_frame)
@ -90,11 +90,11 @@ end
--param 3 (outputs) is either "rotation" or "transform"- determines what's calculated. You can use this if you dont want uncessary calculations. If nil outputs both
--- get a node's global mat4 transform and rotation.
-- @function mtul.b3d_nodes.get_node_global_transform
-- @function leef.b3d_nodes.get_node_global_transform
-- @param node table, the node from within a b3d table to read (as outputed by `b3d_reader`).
-- @param frame float, the frame to find the transform and rotation in.
-- @param outputs (optional) string, either "rotation" or "transform". Set to nil to return both.
-- @return `global_transform`, a matrix 4x4, note that CPML's tranforms are column major (i.e. 1st column is 1, 2, 3, 4). (see `mtul_cpml` docs)
-- @return `global_transform`, a matrix 4x4, note that MATH's tranforms are column major (i.e. 1st column is 1, 2, 3, 4). (see `leef_math` docs)
-- @return `rotation quat`, the quaternion rotation in global space. (cannot be assumed to be normalized, this uses raw interpolated data from the b3d reader)
function b3d_nodes.get_node_global_transform(node, frame, outputs)
local global_transform
@ -137,7 +137,7 @@ end
--Returns X, Y, Z. is_bone is optional, if "node" is the name of a node (and not the node table), parameter 1 (self) and parameter 3 (is_bone) is used to find it.
--- find the position of a node in global model space.
--@function mtul.b3d_nodes.get_node_global_position
--@function leef.b3d_nodes.get_node_global_position
--@param self b3d table, (optional if node is a node table and not name)
--@param node string or table, either the node from b3d table or a the name of the node to find.
--@param is_bone (optional) if node is string, this is used to find it (see `get_node_by_name`)
@ -156,7 +156,7 @@ function b3d_nodes.get_node_global_position(self, node, is_bone, frame)
return transform[13], transform[14], transform[15]
end
--- find the global rotation of a node in model space.
--@function mtul.b3d_nodes.get_node_rotation
--@function leef.b3d_nodes.get_node_rotation
--@param self b3d table, (optional if node is a node table and not name)
--@param node string or table, either the node from b3d table or a the name of the node to find.
--@param is_bone (optional) if node is string, this is used to find it (see `get_node_by_name`)