124 lines
4.4 KiB
Lua
124 lines
4.4 KiB
Lua
local _math = require '_math'
|
|
local mat4 = _math.mat4
|
|
local vec3 = _math.vec3
|
|
local vec4 = _math.vec4
|
|
local scalar = _math.scalar
|
|
|
|
local collada_types = require 'collada_types'
|
|
|
|
local fract = function(f)
|
|
return f - math.floor(f)
|
|
end
|
|
|
|
local loop = function(f, n)
|
|
return fract(f / n) * n
|
|
end
|
|
|
|
local find_frame_ix = function(source, t)
|
|
for i = 1, source.count - 1 do
|
|
if source.float_array[i] <= t and source.float_array[i+1] > t then
|
|
return i - 1 -- 0-based index
|
|
end
|
|
end
|
|
return -1
|
|
end
|
|
|
|
local linear_interpolate_iv = function(source, frame_ix, t)
|
|
local prev = source.float_array[(frame_ix + 0) * source.stride + 1]
|
|
local next = source.float_array[(frame_ix + 1) * source.stride + 1]
|
|
return (t - prev) / (next - prev)
|
|
end
|
|
|
|
local linear_interpolate_value = function(source, frame_ix, parameter_ix, iv)
|
|
local prev = source.float_array[(frame_ix + 0) * source.stride + parameter_ix + 1]
|
|
local next = source.float_array[(frame_ix + 1) * source.stride + parameter_ix + 1]
|
|
return prev + iv * (next - prev)
|
|
end
|
|
|
|
local apply_transform_target = function(transform, channel_target_attribute, value)
|
|
if transform.type == collada_types.transform_type.TRANSLATE or transform.type == collada_types.transform_type.SCALE then
|
|
if channel_target_attribute == collada_types.target_attribute.X then
|
|
transform.value = vec3.set_x(transform.value, value)
|
|
elseif channel_target_attribute == collada_types.target_attribute.Y then
|
|
transform.value = vec3.set_y(transform.value, value)
|
|
elseif channel_target_attribute == collada_types.target_attribute.Z then
|
|
transform.value = vec3.set_z(transform.value, value)
|
|
else
|
|
assert(false)
|
|
end
|
|
elseif transform.type == collada_types.transform_type.ROTATE then
|
|
if channel_target_attribute == collada_types.target_attribute.X then
|
|
transform.value = vec4.set_x(transform.value, value)
|
|
elseif channel_target_attribute == collada_types.target_attribute.Y then
|
|
transform.value = vec4.set_y(transform.value, value)
|
|
elseif channel_target_attribute == collada_types.target_attribute.Z then
|
|
transform.value = vec4.set_z(transform.value, value)
|
|
elseif channel_target_attribute == collada_types.target_attribute.ANGLE then
|
|
transform.value = vec4.set_w(transform.value, value)
|
|
else
|
|
assert(false)
|
|
end
|
|
else
|
|
assert(false)
|
|
end
|
|
end
|
|
|
|
local animate_channel_segment = function(channel, transform, frame_ix, t)
|
|
local target_attributes = {channel.target_attribute}
|
|
if channel.target_attribute == collada_types.target_attribute.ALL then
|
|
if transform.type == collada_types.transform_type.TRANSLATE or transform.type == collada_types.transform_type.SCALE then
|
|
target_attributes = translate_scale_target_attributes
|
|
elseif transform.type == collada_types.transform_type.ROTATE then
|
|
target_attributes = rotate_target_attributes
|
|
else
|
|
assert(false)
|
|
end
|
|
end
|
|
|
|
target_attributes_count = #target_attributes
|
|
|
|
-- parameter_ix: 0-based index
|
|
for parameter_ix = 0, target_attributes_count-1 do
|
|
local interpolation = channel.source_sampler.interpolation.interpolation_array[frame_ix]
|
|
local value
|
|
if false then
|
|
else
|
|
local iv = linear_interpolate_iv(channel.source_sampler.input, frame_ix, t)
|
|
value = linear_interpolate_value(channel.source_sampler.output, frame_ix, parameter_ix, iv)
|
|
end
|
|
|
|
apply_transform_target(transform, target_attributes[parameter_ix + 1], value)
|
|
end
|
|
end
|
|
|
|
local animate_node = function(node, node_instance, t)
|
|
for _, channel in ipairs(node.channels) do
|
|
local transform = node_instance.transforms[channel.target_transform_index]
|
|
assert(transform ~= nil)
|
|
-- frame_ix: 0-based index
|
|
local frame_ix = find_frame_ix(channel.source_sampler.input, t)
|
|
assert(frame_ix >= 0)
|
|
animate_channel_segment(channel, transform, frame_ix, t)
|
|
end
|
|
end
|
|
|
|
local update = function(_t, node_state)
|
|
local t = loop(_t / 2.0, 3.333333)
|
|
|
|
local node_index = 0
|
|
for _, node in ipairs(node_state.nodes) do
|
|
node_instance = node_state.node_instances[node_index]
|
|
|
|
animate_node(node, node_instance, t)
|
|
|
|
local world = node_state:node_instance_world(node, node_instance.transforms)
|
|
node_instance.world = world
|
|
|
|
node_index = node_index + 1
|
|
end
|
|
end
|
|
|
|
return {
|
|
update = update,
|
|
}
|