Work on animation export code

This commit is contained in:
James Lambert 2022-12-29 21:58:29 -07:00
parent 0b0daca75c
commit ff3545d409
19 changed files with 908 additions and 20 deletions

View file

@ -34,6 +34,7 @@
<li><a href="modules/sk_input.html">sk_input</a></li>
<li><a href="modules/sk_mesh.html">sk_mesh</a></li>
<li><a href="modules/sk_transform.html">sk_transform</a></li>
<li><a href="modules/sk_animation.html">sk_animation</a></li>
<li><a href="modules/sk_definition_writer.html">sk_definition_writer</a></li>
<li><a href="modules/sk_math.html">sk_math</a></li>
<li><a href="modules/sk_scene.html">sk_scene</a></li>
@ -59,6 +60,10 @@
<td class="name" nowrap><a href="modules/sk_transform.html">sk_transform</a></td>
<td class="summary"></td>
</tr>
<tr>
<td class="name" nowrap><a href="modules/sk_animation.html">sk_animation</a></td>
<td class="summary"></td>
</tr>
<tr>
<td class="name" nowrap><a href="modules/sk_definition_writer.html">sk_definition_writer</a></td>
<td class="summary"></td>
@ -77,7 +82,7 @@
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
<i style="float:right;">Last updated 2022-12-22 22:02:27 </i>
<i style="float:right;">Last updated 2022-12-29 21:32:18 </i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>

View file

@ -0,0 +1,179 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<head>
<title>Reference</title>
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
</head>
<body>
<div id="container">
<div id="product">
<div id="product_logo"></div>
<div id="product_name"><big><b></b></big></div>
<div id="product_description"></div>
</div> <!-- id="product" -->
<div id="main">
<!-- Menu -->
<div id="navigation">
<br/>
<h1>skeletool64</h1>
<ul>
<li><a href="../index.html">Index</a></li>
</ul>
<h2>Contents</h2>
<ul>
<li><a href="#Functions">Functions</a></li>
<li><a href="#Class_Armature">Class Armature </a></li>
</ul>
<h2>Modules</h2>
<ul class="nowrap">
<li><a href="../modules/sk_input.html">sk_input</a></li>
<li><a href="../modules/sk_mesh.html">sk_mesh</a></li>
<li><a href="../modules/sk_transform.html">sk_transform</a></li>
<li><strong>sk_animation</strong></li>
<li><a href="../modules/sk_definition_writer.html">sk_definition_writer</a></li>
<li><a href="../modules/sk_math.html">sk_math</a></li>
<li><a href="../modules/sk_scene.html">sk_scene</a></li>
</ul>
</div>
<div id="content">
<h1>Module <code>sk_animation</code></h1>
<p></p>
<p></p>
<h2><a href="#Functions">Functions</a></h2>
<table class="function_list">
<tr>
<td class="name" nowrap><a href="#build_armature">build_armature (animation_nodes)</a></td>
<td class="summary"></td>
</tr>
<tr>
<td class="name" nowrap><a href="#export_animations">export_animations (name_hint, armature, animations, file_suffix, animation_file_suffix)</a></td>
<td class="summary"></td>
</tr>
</table>
<h2><a href="#Class_Armature">Class Armature </a></h2>
<table class="function_list">
<tr>
<td class="name" nowrap><a href="#Armature:has_node">Armature:has_node ()</a></td>
<td class="summary"></td>
</tr>
</table>
<br/>
<br/>
<h2 class="section-header "><a name="Functions"></a>Functions</h2>
<dl class="function">
<dt>
<a name = "build_armature"></a>
<strong>build_armature (animation_nodes)</strong>
</dt>
<dd>
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">animation_nodes</span>
<span class="types"><span class="type">{sk_scene.Node,...}</span></span>
</li>
</ul>
<h3>Returns:</h3>
<ol>
<span class="types"><a class="type" href="../modules/sk_animation.html#Armature">Armature</a></span>
</ol>
</dd>
<dt>
<a name = "export_animations"></a>
<strong>export_animations (name_hint, armature, animations, file_suffix, animation_file_suffix)</strong>
</dt>
<dd>
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">name_hint</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
</li>
<li><span class="parameter">armature</span>
<span class="types"><a class="type" href="../modules/sk_animation.html#Armature">Armature</a></span>
</li>
<li><span class="parameter">animations</span>
<span class="types"><span class="type">{sk_scene.Animation,...}</span></span>
</li>
<li><span class="parameter">file_suffix</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
</li>
<li><span class="parameter">animation_file_suffix</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
</li>
</ul>
</dd>
</dl>
<h2 class="section-header "><a name="Class_Armature"></a>Class Armature </h2>
<dl class="function">
<dt>
<a name = "Armature:has_node"></a>
<strong>Armature:has_node ()</strong>
</dt>
<dd>
</dd>
</dl>
</div> <!-- id="content" -->
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
<i style="float:right;">Last updated 2022-12-29 21:32:18 </i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>
</html>

View file

@ -42,6 +42,7 @@
<li><a href="../modules/sk_input.html">sk_input</a></li>
<li><a href="../modules/sk_mesh.html">sk_mesh</a></li>
<li><a href="../modules/sk_transform.html">sk_transform</a></li>
<li><a href="../modules/sk_animation.html">sk_animation</a></li>
<li><strong>sk_definition_writer</strong></li>
<li><a href="../modules/sk_math.html">sk_math</a></li>
<li><a href="../modules/sk_scene.html">sk_scene</a></li>
@ -541,7 +542,7 @@
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
<i style="float:right;">Last updated 2022-12-22 22:02:27 </i>
<i style="float:right;">Last updated 2022-12-29 21:32:18 </i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>

View file

@ -41,6 +41,7 @@
<li><strong>sk_input</strong></li>
<li><a href="../modules/sk_mesh.html">sk_mesh</a></li>
<li><a href="../modules/sk_transform.html">sk_transform</a></li>
<li><a href="../modules/sk_animation.html">sk_animation</a></li>
<li><a href="../modules/sk_definition_writer.html">sk_definition_writer</a></li>
<li><a href="../modules/sk_math.html">sk_math</a></li>
<li><a href="../modules/sk_scene.html">sk_scene</a></li>
@ -135,7 +136,7 @@
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
<i style="float:right;">Last updated 2022-12-22 22:02:27 </i>
<i style="float:right;">Last updated 2022-12-29 21:32:18 </i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>

View file

@ -44,6 +44,7 @@
<li><a href="../modules/sk_input.html">sk_input</a></li>
<li><a href="../modules/sk_mesh.html">sk_mesh</a></li>
<li><a href="../modules/sk_transform.html">sk_transform</a></li>
<li><a href="../modules/sk_animation.html">sk_animation</a></li>
<li><a href="../modules/sk_definition_writer.html">sk_definition_writer</a></li>
<li><strong>sk_math</strong></li>
<li><a href="../modules/sk_scene.html">sk_scene</a></li>
@ -171,6 +172,10 @@
<td class="name" nowrap><a href="#Quaternion:conjugate">Quaternion:conjugate ()</a></td>
<td class="summary"></td>
</tr>
<tr>
<td class="name" nowrap><a href="#Quaternion:slerp">Quaternion:slerp (b, t)</a></td>
<td class="summary"></td>
</tr>
</table>
<br/>
@ -857,6 +862,37 @@
</dd>
<dt>
<a name = "Quaternion:slerp"></a>
<strong>Quaternion:slerp (b, t)</strong>
</dt>
<dd>
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">b</span>
<span class="types"><a class="type" href="../modules/sk_math.html#Quaternion">Quaternion</a></span>
</li>
<li><span class="parameter">t</span>
<span class="types"><span class="type">number</span></span>
</li>
</ul>
<h3>Returns:</h3>
<ol>
<span class="types"><a class="type" href="../modules/sk_math.html#Quaternion">Quaternion</a></span>
</ol>
</dd>
</dl>
@ -865,7 +901,7 @@
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
<i style="float:right;">Last updated 2022-12-22 22:02:27 </i>
<i style="float:right;">Last updated 2022-12-29 21:32:18 </i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>

View file

@ -42,6 +42,7 @@
<li><a href="../modules/sk_input.html">sk_input</a></li>
<li><strong>sk_mesh</strong></li>
<li><a href="../modules/sk_transform.html">sk_transform</a></li>
<li><a href="../modules/sk_animation.html">sk_animation</a></li>
<li><a href="../modules/sk_definition_writer.html">sk_definition_writer</a></li>
<li><a href="../modules/sk_math.html">sk_math</a></li>
<li><a href="../modules/sk_scene.html">sk_scene</a></li>
@ -302,7 +303,7 @@
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
<i style="float:right;">Last updated 2022-12-22 22:02:27 </i>
<i style="float:right;">Last updated 2022-12-29 21:32:18 </i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>

View file

@ -42,6 +42,7 @@
<li><a href="../modules/sk_input.html">sk_input</a></li>
<li><a href="../modules/sk_mesh.html">sk_mesh</a></li>
<li><a href="../modules/sk_transform.html">sk_transform</a></li>
<li><a href="../modules/sk_animation.html">sk_animation</a></li>
<li><a href="../modules/sk_definition_writer.html">sk_definition_writer</a></li>
<li><a href="../modules/sk_math.html">sk_math</a></li>
<li><strong>sk_scene</strong></li>
@ -89,6 +90,22 @@
<td class="name" nowrap><a href="#NodeWithArguments">NodeWithArguments</a></td>
<td class="summary">A pairing of nodes and pre parsed node arguments</td>
</tr>
<tr>
<td class="name" nowrap><a href="#Vector3Key">Vector3Key</a></td>
<td class="summary"></td>
</tr>
<tr>
<td class="name" nowrap><a href="#QuaternionKey">QuaternionKey</a></td>
<td class="summary"></td>
</tr>
<tr>
<td class="name" nowrap><a href="#Channel">Channel</a></td>
<td class="summary"></td>
</tr>
<tr>
<td class="name" nowrap><a href="#Animation">Animation</a></td>
<td class="summary"></td>
</tr>
</table>
<br/>
@ -288,6 +305,122 @@
</dd>
<dt>
<a name = "Vector3Key"></a>
<strong>Vector3Key</strong>
</dt>
<dd>
<h3>Fields:</h3>
<ul>
<li><span class="parameter">time</span>
<span class="types"><span class="type">number</span></span>
</li>
<li><span class="parameter">value</span>
<span class="types"><span class="type">sk_math.Vector3</span></span>
</li>
</ul>
</dd>
<dt>
<a name = "QuaternionKey"></a>
<strong>QuaternionKey</strong>
</dt>
<dd>
<h3>Fields:</h3>
<ul>
<li><span class="parameter">time</span>
<span class="types"><span class="type">number</span></span>
</li>
<li><span class="parameter">value</span>
<span class="types"><span class="type">sk_math.Quaternion</span></span>
</li>
</ul>
</dd>
<dt>
<a name = "Channel"></a>
<strong>Channel</strong>
</dt>
<dd>
<h3>Fields:</h3>
<ul>
<li><span class="parameter">node_name</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
</li>
<li><span class="parameter">position_keys</span>
<span class="types"><a class="type" href="../modules/sk_scene.html#Vector3Key">{Vector3Key,...}</a></span>
</li>
<li><span class="parameter">rotation_keys</span>
<span class="types"><a class="type" href="../modules/sk_scene.html#QuaternionKey">{QuaternionKey,...}</a></span>
</li>
<li><span class="parameter">scaling_keys</span>
<span class="types"><a class="type" href="../modules/sk_scene.html#Vector3Key">{Vector3Key,...}</a></span>
</li>
</ul>
</dd>
<dt>
<a name = "Animation"></a>
<strong>Animation</strong>
</dt>
<dd>
<h3>Fields:</h3>
<ul>
<li><span class="parameter">name</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
</li>
<li><span class="parameter">duration</span>
<span class="types"><span class="type">number</span></span>
</li>
<li><span class="parameter">ticks_per_second</span>
<span class="types"><span class="type">number</span></span>
</li>
<li><span class="parameter">channels</span>
<span class="types"><a class="type" href="../modules/sk_scene.html#Channel">{Channel,...}</a></span>
</li>
</ul>
</dd>
</dl>
@ -296,7 +429,7 @@
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
<i style="float:right;">Last updated 2022-12-22 22:02:27 </i>
<i style="float:right;">Last updated 2022-12-29 21:32:18 </i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>

View file

@ -32,6 +32,7 @@
<h2>Contents</h2>
<ul>
<li><a href="#Functions">Functions</a></li>
<li><a href="#Class_Transform">Class Transform </a></li>
</ul>
@ -41,6 +42,7 @@
<li><a href="../modules/sk_input.html">sk_input</a></li>
<li><a href="../modules/sk_mesh.html">sk_mesh</a></li>
<li><strong>sk_transform</strong></li>
<li><a href="../modules/sk_animation.html">sk_animation</a></li>
<li><a href="../modules/sk_definition_writer.html">sk_definition_writer</a></li>
<li><a href="../modules/sk_math.html">sk_math</a></li>
<li><a href="../modules/sk_scene.html">sk_scene</a></li>
@ -55,18 +57,70 @@
<p></p>
<h2><a href="#Functions">Functions</a></h2>
<table class="function_list">
<tr>
<td class="name" nowrap><a href="#from_pos_rot_scale">from_pos_rot_scale (pos[, rot[, scale]])</a></td>
<td class="summary"></td>
</tr>
</table>
<h2><a href="#Class_Transform">Class Transform </a></h2>
<table class="function_list">
<tr>
<td class="name" nowrap><a href="#Transform:decompose">Transform:decompose ()</a></td>
<td class="summary"></td>
</tr>
<tr>
<td class="name" nowrap><a href="#Transform:__mul">Transform:__mul (other)</a></td>
<td class="summary"></td>
</tr>
</table>
<br/>
<br/>
<h2 class="section-header "><a name="Functions"></a>Functions</h2>
<dl class="function">
<dt>
<a name = "from_pos_rot_scale"></a>
<strong>from_pos_rot_scale (pos[, rot[, scale]])</strong>
</dt>
<dd>
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">pos</span>
<span class="types"><span class="type">sk_math.Vector3</span></span>
</li>
<li><span class="parameter">rot</span>
<span class="types"><span class="type">sk_math.Quaternion</span></span>
(<em>optional</em>)
</li>
<li><span class="parameter">scale</span>
<span class="types"><span class="type">sk_math.Scale</span></span>
(<em>optional</em>)
</li>
</ul>
<h3>Returns:</h3>
<ol>
<span class="types"><a class="type" href="../modules/sk_transform.html#Transform">Transform</a></span>
</ol>
</dd>
</dl>
<h2 class="section-header has-description"><a name="Class_Transform"></a>Class Transform </h2>
<div class="section-description">
@ -86,13 +140,40 @@
<ol>
<li>
<span class="types"><span class="type">vector3.Vector3</span></span>
scale</li>
position</li>
<li>
<span class="types"><span class="type">quaternion.Quaternion</span></span>
rotation</li>
<li>
<span class="types"><span class="type">vector3.Vector3</span></span>
position</li>
scale</li>
</ol>
</dd>
<dt>
<a name = "Transform:__mul"></a>
<strong>Transform:__mul (other)</strong>
</dt>
<dd>
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">other</span>
<span class="types"><a class="type" href="../modules/sk_transform.html#Transform">Transform</a> or <span class="type">sk_math.Vector3</span></span>
</li>
</ul>
<h3>Returns:</h3>
<ol>
<span class="types"><a class="type" href="../modules/sk_transform.html#Transform">Transform</a></span>
</ol>
@ -106,7 +187,7 @@
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
<i style="float:right;">Last updated 2022-12-22 22:02:27 </i>
<i style="float:right;">Last updated 2022-12-29 21:32:18 </i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>

View file

@ -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,
}

View file

@ -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,

View file

@ -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

View file

@ -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);

View file

@ -1,3 +1,4 @@
EMIT(sk_definition_writer)
EMIT(sk_math)
EMIT(sk_scene)
EMIT(sk_scene)
EMIT(sk_animation)

View file

@ -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);
}

View file

@ -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

View file

@ -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) {

View file

@ -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");
}

View file

@ -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),

View file

@ -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')