From ff3545d4095f137c2d6c19cc938f739e43968afb Mon Sep 17 00:00:00 2001 From: James Lambert Date: Thu, 29 Dec 2022 21:58:29 -0700 Subject: [PATCH] Work on animation export code --- skelatool64/doc/index.html | 7 +- skelatool64/doc/modules/sk_animation.html | 179 ++++++++++++++ .../doc/modules/sk_definition_writer.html | 3 +- skelatool64/doc/modules/sk_input.html | 3 +- skelatool64/doc/modules/sk_math.html | 38 ++- skelatool64/doc/modules/sk_mesh.html | 3 +- skelatool64/doc/modules/sk_scene.html | 135 ++++++++++- skelatool64/doc/modules/sk_transform.html | 87 ++++++- skelatool64/lua/sk_animation.lua | 227 ++++++++++++++++++ skelatool64/lua/sk_math.lua | 42 ++++ skelatool64/lua/sk_scene.lua | 52 +++- .../lua_generator/LuaDisplayListSettings.cpp | 3 + skelatool64/src/lua_generator/LuaFiles.h | 3 +- skelatool64/src/lua_generator/LuaGeometry.cpp | 16 ++ skelatool64/src/lua_generator/LuaGeometry.h | 1 + skelatool64/src/lua_generator/LuaScene.cpp | 69 ++++++ .../src/lua_generator/LuaTransform.cpp | 53 ++++ tools/export_level.lua | 1 + tools/level_scripts/animation.lua | 6 + 19 files changed, 908 insertions(+), 20 deletions(-) create mode 100644 skelatool64/doc/modules/sk_animation.html create mode 100644 skelatool64/lua/sk_animation.lua create mode 100644 tools/level_scripts/animation.lua diff --git a/skelatool64/doc/index.html b/skelatool64/doc/index.html index 2992c4f..52e3c78 100644 --- a/skelatool64/doc/index.html +++ b/skelatool64/doc/index.html @@ -34,6 +34,7 @@
  • sk_input
  • sk_mesh
  • sk_transform
  • +
  • sk_animation
  • sk_definition_writer
  • sk_math
  • sk_scene
  • @@ -59,6 +60,10 @@ sk_transform + + sk_animation + + sk_definition_writer @@ -77,7 +82,7 @@
    generated by LDoc 1.4.6 -Last updated 2022-12-22 22:02:27 +Last updated 2022-12-29 21:32:18
    diff --git a/skelatool64/doc/modules/sk_animation.html b/skelatool64/doc/modules/sk_animation.html new file mode 100644 index 0000000..d2e5579 --- /dev/null +++ b/skelatool64/doc/modules/sk_animation.html @@ -0,0 +1,179 @@ + + + + + Reference + + + + +
    + +
    + +
    +
    +
    + + +
    + + + + + + +
    + +

    Module sk_animation

    +

    +

    + + +

    Functions

    + + + + + + + + + +
    build_armature (animation_nodes)
    export_animations (name_hint, armature, animations, file_suffix, animation_file_suffix)
    +

    Class Armature

    + + + + + +
    Armature:has_node ()
    + +
    +
    + + +

    Functions

    + +
    +
    + + build_armature (animation_nodes) +
    +
    + + + +

    Parameters:

    +
      +
    • animation_nodes + {sk_scene.Node,...} + +
    • +
    + +

    Returns:

    +
      + + Armature + +
    + + + + +
    +
    + + export_animations (name_hint, armature, animations, file_suffix, animation_file_suffix) +
    +
    + + + +

    Parameters:

    +
      +
    • name_hint + string + +
    • +
    • armature + Armature + +
    • +
    • animations + {sk_scene.Animation,...} + +
    • +
    • file_suffix + string + +
    • +
    • animation_file_suffix + string + +
    • +
    + + + + + +
    +
    +

    Class Armature

    + +
    +
    + + Armature:has_node () +
    +
    + + + + + + + + +
    +
    + + +
    +
    +
    +generated by LDoc 1.4.6 +Last updated 2022-12-29 21:32:18 +
    +
    + + diff --git a/skelatool64/doc/modules/sk_definition_writer.html b/skelatool64/doc/modules/sk_definition_writer.html index af547ec..923d920 100644 --- a/skelatool64/doc/modules/sk_definition_writer.html +++ b/skelatool64/doc/modules/sk_definition_writer.html @@ -42,6 +42,7 @@
  • sk_input
  • sk_mesh
  • sk_transform
  • +
  • sk_animation
  • sk_definition_writer
  • sk_math
  • sk_scene
  • @@ -541,7 +542,7 @@
    generated by LDoc 1.4.6 -Last updated 2022-12-22 22:02:27 +Last updated 2022-12-29 21:32:18
    diff --git a/skelatool64/doc/modules/sk_input.html b/skelatool64/doc/modules/sk_input.html index 2ba5e09..1368c8c 100644 --- a/skelatool64/doc/modules/sk_input.html +++ b/skelatool64/doc/modules/sk_input.html @@ -41,6 +41,7 @@
  • sk_input
  • sk_mesh
  • sk_transform
  • +
  • sk_animation
  • sk_definition_writer
  • sk_math
  • sk_scene
  • @@ -135,7 +136,7 @@
    generated by LDoc 1.4.6 -Last updated 2022-12-22 22:02:27 +Last updated 2022-12-29 21:32:18
    diff --git a/skelatool64/doc/modules/sk_math.html b/skelatool64/doc/modules/sk_math.html index 5ba9b88..c0d824b 100644 --- a/skelatool64/doc/modules/sk_math.html +++ b/skelatool64/doc/modules/sk_math.html @@ -44,6 +44,7 @@
  • sk_input
  • sk_mesh
  • sk_transform
  • +
  • sk_animation
  • sk_definition_writer
  • sk_math
  • sk_scene
  • @@ -171,6 +172,10 @@ Quaternion:conjugate () + + Quaternion:slerp (b, t) + +
    @@ -857,6 +862,37 @@ + +
    + + Quaternion:slerp (b, t) +
    +
    + + + +

    Parameters:

    + + +

    Returns:

    +
      + + Quaternion + +
    + + + +
    @@ -865,7 +901,7 @@
    generated by LDoc 1.4.6 -Last updated 2022-12-22 22:02:27 +Last updated 2022-12-29 21:32:18
    diff --git a/skelatool64/doc/modules/sk_mesh.html b/skelatool64/doc/modules/sk_mesh.html index e16ca10..1739a3b 100644 --- a/skelatool64/doc/modules/sk_mesh.html +++ b/skelatool64/doc/modules/sk_mesh.html @@ -42,6 +42,7 @@
  • sk_input
  • sk_mesh
  • sk_transform
  • +
  • sk_animation
  • sk_definition_writer
  • sk_math
  • sk_scene
  • @@ -302,7 +303,7 @@
    generated by LDoc 1.4.6 -Last updated 2022-12-22 22:02:27 +Last updated 2022-12-29 21:32:18
    diff --git a/skelatool64/doc/modules/sk_scene.html b/skelatool64/doc/modules/sk_scene.html index 8219c34..1b43fc0 100644 --- a/skelatool64/doc/modules/sk_scene.html +++ b/skelatool64/doc/modules/sk_scene.html @@ -42,6 +42,7 @@
  • sk_input
  • sk_mesh
  • sk_transform
  • +
  • sk_animation
  • sk_definition_writer
  • sk_math
  • sk_scene
  • @@ -89,6 +90,22 @@ NodeWithArguments A pairing of nodes and pre parsed node arguments + + Vector3Key + + + + QuaternionKey + + + + Channel + + + + Animation + +
    @@ -288,6 +305,122 @@ + +
    + + Vector3Key +
    +
    + + + +

    Fields:

    + + + + + + +
    +
    + + QuaternionKey +
    +
    + + + +

    Fields:

    + + + + + + +
    +
    + + Channel +
    +
    + + + +

    Fields:

    + + + + + + +
    +
    + + Animation +
    +
    + + + +

    Fields:

    + + + + + +
    @@ -296,7 +429,7 @@
    generated by LDoc 1.4.6 -Last updated 2022-12-22 22:02:27 +Last updated 2022-12-29 21:32:18
    diff --git a/skelatool64/doc/modules/sk_transform.html b/skelatool64/doc/modules/sk_transform.html index b07de14..21d0fd0 100644 --- a/skelatool64/doc/modules/sk_transform.html +++ b/skelatool64/doc/modules/sk_transform.html @@ -32,6 +32,7 @@

    Contents

    @@ -41,6 +42,7 @@
  • sk_input
  • sk_mesh
  • sk_transform
  • +
  • sk_animation
  • sk_definition_writer
  • sk_math
  • sk_scene
  • @@ -55,18 +57,70 @@

    +

    Functions

    + + + + + +
    from_pos_rot_scale (pos[, rot[, scale]])

    Class Transform

    + + + +
    Transform:decompose ()
    Transform:__mul (other)


    +

    Functions

    + +
    +
    + + from_pos_rot_scale (pos[, rot[, scale]]) +
    +
    + + + +

    Parameters:

    +
      +
    • pos + sk_math.Vector3 + +
    • +
    • rot + sk_math.Quaternion + + (optional) +
    • +
    • scale + sk_math.Scale + + (optional) +
    • +
    + +

    Returns:

    +
      + + Transform + +
    + + + + +
    +

    Class Transform

    @@ -86,13 +140,40 @@
    1. vector3.Vector3 - scale
    2. + position
    3. quaternion.Quaternion rotation
    4. vector3.Vector3 - position
    5. + scale +
    + + + + + +
    + + Transform:__mul (other) +
    +
    + + + +

    Parameters:

    +
      +
    • other + Transform or sk_math.Vector3 + +
    • +
    + +

    Returns:

    +
      + + Transform +
    @@ -106,7 +187,7 @@
    generated by LDoc 1.4.6 -Last updated 2022-12-22 22:02:27 +Last updated 2022-12-29 21:32:18
    diff --git a/skelatool64/lua/sk_animation.lua b/skelatool64/lua/sk_animation.lua new file mode 100644 index 0000000..6c942f6 --- /dev/null +++ b/skelatool64/lua/sk_animation.lua @@ -0,0 +1,227 @@ +--- @module sk_animation + +local sk_scene = require('sk_scene') +local sk_input = require('sk_input') +local sk_math = require('sk_math') +local sk_transform = require('sk_transform') +local sk_definition_writer = require('sk_definition_writer') + +local node_order = {} +local current_node_index = 1 + +sk_scene.for_each_node(sk_scene.scene.root, function(node) + node_order[node] = current_node_index + current_node_index = current_node_index + 1 +end) + +local function find_interpolated_point(key_list, time) + for index, key in pairs(key_list) do + if key.time >= time then + if index == 1 then + return key.value, key.value, 0 + else + local prev_key = key_list[index - 1] + + local delta_time = key.time - prev_key.time + + if delta_time == 0.0 then + return key.value, key.value, 0 + else + return prev_key.value, key.value, (time - prev_key.time) / delta_time + end + end + end + end + + if #key_list > 0 then + return key_list[#key_list].value, key_list[#key_list].value, 1 + end + + return nil, nil, 0 +end + +local function evaluate_channel_at(channel, time) + local prev_pos, next_pos, pos_lerp = find_interpolated_point(channel.position_keys, time) + local prev_rot, next_rot, rot_lerp = find_interpolated_point(channel.rotation_keys, time) + local prev_scale, next_scale, scale_lerp = find_interpolated_point(channel.scaling_keys, time) + + return (prev_pos and prev_pos:lerp(next_pos, pos_lerp) or sk_math.vector3(0, 0, 0)), + (prev_rot and prev_rot:slerp(next_rot, rot_lerp) or sk_math.quaternion(0, 0, 0, 1)), + (prev_scale and prev_scale:lerp(next_scale, scale_lerp) or sk_math.vector3(1, 1, 1)) +end + +local function evaluate_animation_at(node_pose, animation, time) + for _, channel in pairs(animation.channels) do + local node = sk_scene.node_with_name(channel.node_name) + + if node then + local pos, rot, scale = evaluate_channel_at(channel, time) + + local local_transform = sk_transform.from_pos_rot_scale(pos, rot, scale) + + if node.parent then + node_pose[node] = local_transform + else + node_pose[node] = sk_input.settings.fixed_point_transform * local_transform + end + end + end +end + +local Armature = {} + +--- @function build_armature +--- @tparam {sk_scene.Node,...} animation_nodes +--- @treturn Armature +local function build_armature(animation_nodes) + local nodes = {table.unpack(animation_nodes)} + + table.sort(nodes, function(a, b) + return (node_order[a] or 0) < (node_order[b] or 0) + end) + + local nodes_as_set = {} + + for _, node in pairs(nodes) do + nodes_as_set[node] = true + end + + return setmetatable({ + nodes = nodes, + nodes_as_set = nodes_as_set, + }, Armature) +end + +local function add_to_node_pose(node_pose, node) + if node_pose[node] then + return + end + + if node.parent then + node_pose[node] = node.transformation + + add_to_node_pose(node_pose, node.parent) + else + node_pose[node] = node.full_transformation + end +end + +local function build_node_pose(node, node_pose) + local result = nil + + while node do + result = result and (node_pose[node] * result) or node_pose[node] + node = node.parent + end + + return result +end + +local function build_quat_pose(quat) + if quat.w < 0 then + return { + math.floor((-quat.x * 32767) + 0.5), + math.floor((-quat.y * 32767) + 0.5), + math.floor((-quat.z * 32767) + 0.5) + } + else + return { + math.floor((quat.x * 32767) + 0.5), + math.floor((quat.y * 32767) + 0.5), + math.floor((quat.z * 32767) + 0.5) + } + end +end + +local function build_armature_pose(armature, node_pose, result) + for _, node in pairs(armature.nodes) do + local pose = build_node_pose(node, node_pose) + + local pos, rot = pose:decompose() + + pos = pos * sk_input.settings.fixed_point_scale + + table.insert(result, { + sk_math.vector3(math.floor(pos.x + 0.5), math.floor(pos.y + 0.5), math.floor(pos.z + 0.5)), + build_quat_pose(rot) + }) + end +end + +local function build_animation(armature, animation) + local n_frames = math.ceil(animation.duration * sk_input.settings.ticks_per_second / animation.ticks_per_second) + + local node_pose = {} + + for _, node in pairs(armature.nodes) do + add_to_node_pose(node_pose, node) + end + + local frames = {} + + for frame_index = 1,n_frames do + local time = (frame_index - 1) * animation.ticks_per_second / sk_input.settings.ticks_per_second + -- populate node_pose from animation + evaluate_animation_at(node_pose, animation, time) + -- generate frame for armature + build_armature_pose(armature, node_pose, frames) + end + + return frames, n_frames +end + +--- @function export_animations +--- @tparam string name_hint +--- @tparam Armature armature +--- @tparam {sk_scene.Animation,...} animations +--- @tparam string file_suffix +--- @tparam string animation_file_suffix +local function export_animations(name_hint, armature, animations, file_suffix, animation_file_suffix) + for _, animation in pairs(animations) do + local animation_frames, n_frames = build_animation(armature, animation) + sk_definition_writer.add_definition(name_hint .. animation.name .. '_frames', 'struct SKAnimationBoneFrame[]', animation_file_suffix, animation_frames) + + local clip = { + nFrames = n_frames, + nBones = #armature.nodes, + frames = sk_definition_writer.reference_to(animation_frames, 1), + fps = sk_input.settings.ticks_per_second + } + + sk_definition_writer.add_definition(name_hint .. animation.name .. '_clip', 'struct SKAnimationClip', file_suffix, clip) + end +end + +local function build_armature_for_animations(animations) + local nodes_at_set = {} + + for _, animation in pairs(sk_scene.scene.animations) do + for _, channel in pairs(animation.channels) do + nodes_at_set[sk_scene.node_with_name(channel.node_name)] = true + end + end + + local all_nodes = {} + + for node, _ in pairs(nodes_at_set) do + table.insert(all_nodes, node) + end + + return build_armature(all_nodes) +end + +--- @type Armature +--- @tfield {sk_scene.Node,...} nodes +Armature.__index = Armature; + +--- @function has_node +Armature.has_node = function(armature, node) + return armature.nodes_as_set[node] or false +end + +return { + build_armature = build_armature, + export_animations = export_animations, + build_armature_for_animations = build_armature_for_animations, + Armature = Armature, +} \ No newline at end of file diff --git a/skelatool64/lua/sk_math.lua b/skelatool64/lua/sk_math.lua index cac8e42..d9aeab5 100644 --- a/skelatool64/lua/sk_math.lua +++ b/skelatool64/lua/sk_math.lua @@ -356,6 +356,48 @@ function Quaternion.__mul(a, b) end end +--- @function slerp +--- @tparam Quaternion b +--- @tparam number t +--- @treturn Quaternion +function Quaternion.slerp(a, b, t) + -- calc cosine theta + local cosom = a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w; + + -- adjust signs (if necessary) + local endQ = quaternion(b.x, b.y, b.z, b.w); + + if cosom < 0 then + cosom = -cosom + -- Reverse all signs + endQ.x = -endQ.x + endQ.y = -endQ.y + endQ.z = -endQ.z + endQ.w = -endQ.w + end + + -- Calculate coefficients + local sclp, sclq; + if (1 - cosom) > 0.0001 then + -- Standard case (slerp) + local omega = math.acos(cosom); -- extract theta from dot product's cos theta + local sinom = math.sin( omega); + sclp = math.sin( (1 - t) * omega) / sinom; + sclq = math.sin( t * omega) / sinom; + else + -- Very close, do linear interp (because it's faster) + sclp = 1 - t; + sclq = t; + end + + return quaternion( + sclp * a.x + sclq * endQ.x, + sclp * a.y + sclq * endQ.y, + sclp * a.z + sclq * endQ.z, + sclp * a.w + sclq * endQ.w + ) +end + return { vector3 = vector3, Vector3 = Vector3, diff --git a/skelatool64/lua/sk_scene.lua b/skelatool64/lua/sk_scene.lua index 84ca775..ce3ccaf 100644 --- a/skelatool64/lua/sk_scene.lua +++ b/skelatool64/lua/sk_scene.lua @@ -2,7 +2,7 @@ local node_name_cache = nil -local exports = {} +local exports -- Defintions from LuaScene.cpp @@ -19,7 +19,7 @@ local exports = {} ---@function export_default_mesh ---@treturn sk_definition_writer.RawType model ---@treturn sk_definition_writer.RawType material -exports.export_default_mesh = function () +local function export_default_mesh() -- implmentation overridden by LuaScene.cpp end @@ -34,7 +34,7 @@ end ---@function nodes_for_type ---@tparam string prefix the string prefix to search ---@treturn NodeWithArguments -exports.nodes_for_type = function(prefix) +local function nodes_for_type(prefix) end @@ -53,9 +53,6 @@ local function find_named_argument(arg_list, name) return nil end -exports.find_named_argument = find_named_argument - - ---Finds a named value in a list of arguments ---@function find_flag_argument ---@tfield {string,...} arg_list @@ -71,8 +68,6 @@ local function find_flag_argument(arg_list, name) return false end -exports.find_flag_argument = find_flag_argument - local function build_node_with_name_cache(node) node_name_cache[node.name] = node @@ -85,13 +80,50 @@ end ---@function node_with_name ---@tparam string name ---@treturn Node result -exports.node_with_name = function (name) +local function node_with_name(name) if (not node_name_cache) then node_name_cache = {} - build_node_with_name_cache(scene.root) + build_node_with_name_cache(exports.scene.root) end return node_name_cache[name] end +local function for_each_node(node, callback) + callback(node) + + for _, child in pairs(node.children) do + for_each_node(child, callback) + end +end + +---@table Vector3Key +---@tfield number time +---@tfield sk_math.Vector3 value + +---@table QuaternionKey +---@tfield number time +---@tfield sk_math.Quaternion value + +---@table Channel +---@tfield string node_name +---@tfield {Vector3Key,...} position_keys +---@tfield {QuaternionKey,...} rotation_keys +---@tfield {Vector3Key,...} scaling_keys + +---@table Animation +---@tfield string name +---@tfield number duration +---@tfield number ticks_per_second +---@tfield {Channel,...} channels + +exports = { + export_default_mesh = export_default_mesh, + nodes_for_type = nodes_for_type, + find_named_argument = find_named_argument, + find_flag_argument = find_flag_argument, + node_with_name = node_with_name, + for_each_node = for_each_node, +} + return exports \ No newline at end of file diff --git a/skelatool64/src/lua_generator/LuaDisplayListSettings.cpp b/skelatool64/src/lua_generator/LuaDisplayListSettings.cpp index 0f9eee0..99c57b0 100644 --- a/skelatool64/src/lua_generator/LuaDisplayListSettings.cpp +++ b/skelatool64/src/lua_generator/LuaDisplayListSettings.cpp @@ -90,6 +90,9 @@ int luaInputModuleLoader(lua_State* L) { toLua(L, defaults->mFixedPointScale); lua_setfield(L, -2, "fixed_point_scale"); + toLua(L, defaults->mTicksPerSecond); + lua_setfield(L, -2, "ticks_per_second"); + lua_setfield(L, -2, "settings"); lua_pushstring(L, levelFilename); diff --git a/skelatool64/src/lua_generator/LuaFiles.h b/skelatool64/src/lua_generator/LuaFiles.h index 929cd59..b7945ca 100644 --- a/skelatool64/src/lua_generator/LuaFiles.h +++ b/skelatool64/src/lua_generator/LuaFiles.h @@ -1,3 +1,4 @@ EMIT(sk_definition_writer) EMIT(sk_math) -EMIT(sk_scene) \ No newline at end of file +EMIT(sk_scene) +EMIT(sk_animation) \ No newline at end of file diff --git a/skelatool64/src/lua_generator/LuaGeometry.cpp b/skelatool64/src/lua_generator/LuaGeometry.cpp index 086be9c..7d52d2b 100644 --- a/skelatool64/src/lua_generator/LuaGeometry.cpp +++ b/skelatool64/src/lua_generator/LuaGeometry.cpp @@ -37,5 +37,21 @@ void fromLua(lua_State* L, aiVector3D& vector) { lua_getfield(L, -1, "z"); fromLua(L, vector.z); + lua_pop(L, 1); +} + +void fromLua(lua_State* L, aiQuaternion& quaternion) { + lua_getfield(L, -1, "x"); + fromLua(L, quaternion.x); + + lua_getfield(L, -1, "y"); + fromLua(L, quaternion.y); + + lua_getfield(L, -1, "z"); + fromLua(L, quaternion.z); + + lua_getfield(L, -1, "w"); + fromLua(L, quaternion.w); + lua_pop(L, 1); } \ No newline at end of file diff --git a/skelatool64/src/lua_generator/LuaGeometry.h b/skelatool64/src/lua_generator/LuaGeometry.h index abc3c01..f7d0775 100644 --- a/skelatool64/src/lua_generator/LuaGeometry.h +++ b/skelatool64/src/lua_generator/LuaGeometry.h @@ -9,5 +9,6 @@ void toLua(lua_State* L, const aiVector3D& vector); void toLua(lua_State* L, const aiAABB& box); void fromLua(lua_State* L, aiVector3D& vector); +void fromLua(lua_State* L, aiQuaternion& quaternion); #endif \ No newline at end of file diff --git a/skelatool64/src/lua_generator/LuaScene.cpp b/skelatool64/src/lua_generator/LuaScene.cpp index 1ff3b88..da755c8 100644 --- a/skelatool64/src/lua_generator/LuaScene.cpp +++ b/skelatool64/src/lua_generator/LuaScene.cpp @@ -44,6 +44,72 @@ int luaNodeToString(lua_State* L) { return 1; } +void toLua(lua_State* L, const aiVectorKey& positionKey) { + lua_newtable(L); + int tableIndex = lua_gettop(L); + + toLua(L, positionKey.mTime); + lua_setfield(L, tableIndex, "time"); + + toLua(L, positionKey.mValue); + lua_setfield(L, tableIndex, "value"); +} + +void toLua(lua_State* L, const aiQuatKey& quatKey) { + lua_newtable(L); + int tableIndex = lua_gettop(L); + + toLua(L, quatKey.mTime); + lua_setfield(L, tableIndex, "time"); + + toLua(L, quatKey.mValue); + lua_setfield(L, tableIndex, "value"); +} + +void toLua(lua_State* L, const aiNodeAnim* channel) { + if (!channel) { + lua_pushnil(L); + return; + } + + lua_newtable(L); + int tableIndex = lua_gettop(L); + + toLua(L, channel->mNodeName.C_Str()); + lua_setfield(L, tableIndex, "node_name"); + + toLua(L, channel->mPositionKeys, channel->mNumPositionKeys); + lua_setfield(L, tableIndex, "position_keys"); + + toLua(L, channel->mRotationKeys, channel->mNumRotationKeys); + lua_setfield(L, tableIndex, "rotation_keys"); + + toLua(L, channel->mScalingKeys, channel->mNumScalingKeys); + lua_setfield(L, tableIndex, "scaling_keys"); +} + +void toLua(lua_State* L, const aiAnimation* animation) { + if (!animation) { + lua_pushnil(L); + return; + } + + lua_newtable(L); + int tableIndex = lua_gettop(L); + + toLua(L, animation->mName.C_Str()); + lua_setfield(L, tableIndex, "name"); + + toLua(L, animation->mDuration); + lua_setfield(L, tableIndex, "duration"); + + toLua(L, animation->mTicksPerSecond); + lua_setfield(L, tableIndex, "ticks_per_second"); + + toLua(L, animation->mChannels, animation->mNumChannels); + lua_setfield(L, tableIndex, "channels"); +} + void toLua(lua_State* L, const aiNode* node) { if (!node) { lua_pushnil(L); @@ -178,6 +244,9 @@ void toLua(lua_State* L, const aiScene* scene, CFileDefinition& fileDefinition) lua_seti(L, -2, i + 1); } lua_setfield(L, tableIndex, "meshes"); + + toLua(L, scene->mAnimations, scene->mNumAnimations); + lua_setfield(L, tableIndex, "animations"); } int luaExportDefaultMesh(lua_State* L) { diff --git a/skelatool64/src/lua_generator/LuaTransform.cpp b/skelatool64/src/lua_generator/LuaTransform.cpp index 6835cd6..f65ef5e 100644 --- a/skelatool64/src/lua_generator/LuaTransform.cpp +++ b/skelatool64/src/lua_generator/LuaTransform.cpp @@ -3,6 +3,42 @@ #include "LuaTransform.h" #include "LuaBasicTypes.h" +#include "LuaUtils.h" + +/*** + @function from_pos_rot_scale + @tparam sk_math.Vector3 pos + @tparam[opt] sk_math.Quaternion rot + @tparam[opt] sk_math.Scale scale + @treturn Transform + */ +int luaTransformFromPosRotationScale(lua_State* L) { + if (lua_gettop(L) > 3) { + lua_settop(L, 3); + } + + aiVector3D scale; + + if (lua_gettop(L) == 3) { + fromLua(L, scale); + } else { + scale = aiVector3D(1, 1, 1); + } + + aiQuaternion rot; + + if (lua_gettop(L) == 2) { + fromLua(L, rot); + } + + aiVector3D pos; + + fromLua(L, pos); + + aiMatrix4x4 fullTransform(scale, rot, pos); + toLua(L, fullTransform); + return 1; +} /*** A 4x4 matrix transform @@ -100,6 +136,11 @@ bool luaIsTransform(lua_State* L, int idx) { return result; } +/** + @function __mul + @tparam Transform|sk_math.Vector3 other + @treturn Transform + */ int luaTransformMul(lua_State* L) { aiMatrix4x4* a = (aiMatrix4x4*)luaL_checkudata(L, 1, "aiMatrix4x4"); @@ -126,6 +167,15 @@ int luaTransformMul(lua_State* L) { return 1; } +int buildTransformModule(lua_State* L) { + lua_newtable(L); + + lua_pushcfunction(L, luaTransformFromPosRotationScale); + lua_setfield(L, -2, "from_pos_rot_scale"); + + return 1; +} + void generateLuaTransform(lua_State* L) { luaL_newmetatable(L, "aiMatrix4x4"); @@ -136,4 +186,7 @@ void generateLuaTransform(lua_State* L) { lua_setfield(L, -2, "__mul"); lua_pop(L, 1); + + lua_pushcfunction(L, buildTransformModule); + luaSetModuleLoader(L, "sk_transform"); } \ No newline at end of file diff --git a/tools/export_level.lua b/tools/export_level.lua index 56bd86d..9308003 100644 --- a/tools/export_level.lua +++ b/tools/export_level.lua @@ -8,6 +8,7 @@ local trigger = require('tools.level_scripts.trigger') local world = require('tools.level_scripts.world') local entities = require('tools.level_scripts.entities') local signals = require('tools.level_scripts.signals') +local animation = require('tools.level_scripts.animation') sk_definition_writer.add_definition("level", "struct LevelDefinition", "_geo", { collisionQuads = sk_definition_writer.reference_to(collision_export.collision_objects, 1), diff --git a/tools/level_scripts/animation.lua b/tools/level_scripts/animation.lua new file mode 100644 index 0000000..9cc0a65 --- /dev/null +++ b/tools/level_scripts/animation.lua @@ -0,0 +1,6 @@ +local sk_scene = require('sk_scene') +local sk_animation = require('sk_animation') + +local armature = sk_animation.build_armature_for_animations(sk_scene.scene.animations) + +sk_animation.export_animations('animation', armature, sk_scene.scene.animations, '_geo', '_anim') \ No newline at end of file