love-demo/collada_scene/node_state.lua

117 lines
3.6 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 load_transform = function(transform)
if transform.type == collada_types.transform_type.LOOKAT then
assert(false)
elseif transform.type == collada_types.transform_type.MATRIX then
return mat4.load_table(transform.matrix)
elseif transform.type == collada_types.transform_type.ROTATE then
return vec4.load_table(transform.rotate)
elseif transform.type == collada_types.transform_type.SCALE then
return vec3.load_table(transform.scale)
elseif transform.type == collada_types.transform_type.TRANSLATE then
return vec3.load_table(transform.translate)
else
assert(false)
end
end
local transform_matrix = function (loaded_transform)
local type = loaded_transform.type
local value = loaded_transform.value
if type == collada_types.transform_type.LOOKAT then
assert(false)
elseif type == collada_types.transform_type.MATRIX then
return value
elseif type == collada_types.transform_type.ROTATE then
return mat4.rotation_axis(value, scalar.convert_to_radians(value.f[3]))
elseif type == collada_types.transform_type.SCALE then
return mat4.scaling_from_vector(value)
elseif type == collada_types.transform_type.TRANSLATE then
return mat4.translation_from_vector(value)
else
assert(false)
end
end
local instance_transforms_from_node = function(node)
local transforms = {}
local transform_index = 0
for _, transform in ipairs(node.transforms) do
local value = load_transform(transform)
local loaded_transform = {
type = transform.type,
value = value,
}
transforms[transform_index] = loaded_transform
transform_index = transform_index + 1
end
return transforms
end
local collada_scene_node_state
collada_scene_node_state = {
__index = {
node_instance_world = function(this, node, transforms)
local world
if node.parent_index >= 0 then
world = this.node_instances[node.parent_index].world
assert(world ~= nil)
else
world = mat4.identity()
end
local transforms_count = #node.transforms
local transform_index = 0
while transform_index < transforms_count do
local m = transform_matrix(transforms[transform_index])
world = m * world
transform_index = transform_index + 1
end
return world
end,
node_instance_new = function(this, node)
local transforms = instance_transforms_from_node(node)
local world = this:node_instance_world(node, transforms)
local node_instance = {
transforms = transforms,
transforms_count = transforms_count,
world = world,
}
return node_instance
end,
node_instances_new = function(this, nodes)
local node_index = 0
for _, node in ipairs(nodes) do
local node_instance = this:node_instance_new(node)
this.node_instances[node_index] = node_instance
node_index = node_index + 1
end
end,
},
__call = function(_t, nodes)
local value = {
nodes = nodes,
node_instances = {},
}
setmetatable(value, collada_scene_node_state)
value:node_instances_new(nodes)
return value
end,
}
setmetatable(collada_scene_node_state, collada_scene_node_state)
return collada_scene_node_state