collada: implement animated rotate and scale

This also improves the correctness of channel source interpretation.
This commit is contained in:
Zack Buhman 2026-01-27 21:53:50 -06:00
parent 6a2a74a0f6
commit 683115e0c1
13 changed files with 1742 additions and 785 deletions

View File

@ -50,7 +50,11 @@ SHADERS = \
$(BUILD_TYPE)/effect/collada.fxo \
$(BUILD_TYPE)/effect/collada_scene.fxo
$(BUILD_TYPE)/%.res: %.rc $(SHADERS)
BUFFERS = \
models/curve_interpolation/curve_interpolation.vtx \
models/curve_interpolation/curve_interpolation.idx
$(BUILD_TYPE)/%.res: %.rc $(SHADERS) $(BUFFERS)
@mkdir -p $(@D)
$(WINDRES) -O coff -I$(BUILD_TYPE)/effect -o $@ $<
@ -67,7 +71,8 @@ OBJS = \
$(BUILD_TYPE)/render_state.obj \
$(BUILD_TYPE)/input.obj \
$(BUILD_TYPE)/collada.obj \
$(BUILD_TYPE)/collada_scene.obj
$(BUILD_TYPE)/collada_scene.obj \
$(BUILD_TYPE)/scenes/curve_interpolation.obj
$(BUILD_TYPE)/d3d10.exe: $(OBJS)
@mkdir -p $(@D)

View File

@ -475,8 +475,10 @@ def render_input_elements_list(state):
yield "},"
yield "};"
def render_descriptor():
yield "descriptor const descriptor = {"
def render_descriptor(namespace):
yield f"extern collada::descriptor const descriptor;"
yield ""
yield "collada::descriptor const descriptor = {"
yield ".nodes = nodes,"
yield ".nodes_count = (sizeof (nodes)) / (sizeof (nodes[0])),"
yield ""
@ -494,18 +496,6 @@ def render_animation_children(state, collada, animation_name, animations):
yield "&animation_{animation_name},"
yield "};"
def array_c_type(accessor):
if accessor.params[0].name == "INTERPOLATION":
return "interpolation"
assert all(param.type == "float" for param in accessor.params)
if accessor.stride == 1:
return "float"
elif accessor.stride in {2, 3, 4}:
assert list(param.name for param in accessor.params) == ["X", "Y", "Z", "W"][:accessor.stride], accessor.params
return f"float{accessor.stride}"
else:
assert False, accessor.stride
def render_array(state, collada, accessor, array):
array_name = sanitize_name(state, array.id, array)
# render the array
@ -518,30 +508,26 @@ def render_array(state, collada, accessor, array):
assert name in {"BEZIER", "LINEAR"}, name
yield f"interpolation::{name},"
yield "};"
return "interpolation"
elif type(array) is types.FloatArray:
c_type = array_c_type(accessor)
yield f"{c_type} const array_{array_name}[] = {{"
yield f"float const array_{array_name}[] = {{"
it = iter(array.floats)
for i in range(accessor.count):
vector = ", ".join(f"{float(f)}f" for f in islice(it, accessor.stride))
if accessor.stride == 1:
yield f"{vector},"
else:
yield f"{{ {vector} }},"
yield f"{vector},"
yield "};"
else:
assert False, type(array)
def render_source(state, collada, field_name, source):
array_name = sanitize_name(state, source.array_element.id, source.array_element)
c_type = array_c_type(source.technique_common.accessor)
c_type = "interpolation" if type(source.array_element) is types.NameArray else "float"
source_name = sanitize_name(state, source.id, source)
#yield f"source const source_{source_name} = {{"
yield f"// {source_name}"
yield f".{field_name} = {{"
yield f".{c_type}_array = array_{array_name},"
yield f".count = {source.technique_common.accessor.count},"
yield f".stride = {source.technique_common.accessor.stride},"
yield "},"
def render_sampler(state, collada, sampler):
@ -549,13 +535,32 @@ def render_sampler(state, collada, sampler):
enumerate(["INPUT", "OUTPUT", "IN_TANGENT", "OUT_TANGENT", "INTERPOLATION"]))
inputs = sorted((input for input in sampler.inputs if input.semantic in order),
key=lambda input: order[input.semantic])
inputs_semantics = [input.semantic for input in inputs]
assert len(inputs_semantics) == len(set(inputs_semantics))
assert "INPUT" in inputs_semantics
assert "OUTPUT" in inputs_semantics
assert "INTERPOLATION" in inputs_semantics
# sampler validation
counts = set()
for input in inputs:
source = collada.lookup(input.source, types.SourceCore)
if input.semantic == "INTERPOLATION":
nonlinear_interpolation_params = [e for e in source.array_element.names if e != "LINEAR"]
if nonlinear_interpolation_params:
assert "IN_TANGENT" in inputs_semantics
assert "OUT_TANGENT" in inputs_semantics
counts.add(source.technique_common.accessor.count)
assert len(counts) == 1
# render the source arrays first
for input in inputs:
assert type(input) is types.InputUnshared
source = collada.lookup(input.source, types.SourceCore)
yield from render_array(state, collada, source.technique_common.accessor, source.array_element)
# render the sampler
sampler_name = sanitize_name(state, sampler.id, sampler)
yield f"sampler const sampler_{sampler_name} = {{"
for input in inputs:
@ -565,7 +570,7 @@ def render_sampler(state, collada, sampler):
yield "};"
target_attributes = {
"A", "ANGLE", "B", "G", "P", "Q", "R", "S", "T", "TIME", "U", "V", "W", "X", "Y", "Z"
"A", "ANGLE", "B", "G", "P", "Q", "R", "S", "T", "TIME", "U", "V", "W", "X", "Y", "Z", "ALL"
}
def find_transform_index_in_node(node, transform):
@ -588,11 +593,14 @@ def render_channel(state, collada, channel):
sampler_name = sanitize_name(state, sampler.id, sampler)
assert '/' in channel.target, channel.target
assert '.' in channel.target, channel.target
assert "(" not in channel.target, channel.target
node_id, rest = channel.target.split("/")
node_transform_sid, target_attribute = rest.split(".")
if '.' in rest:
node_transform_sid, target_attribute = rest.split(".")
else:
node_transform_sid = rest
target_attribute = 'ALL'
assert target_attribute in target_attributes
node = collada.lookup(f"#{node_id}", types.Node)
@ -659,10 +667,20 @@ def render_all(collada, namespace):
# root elements
render(render_library_visual_scenes(state, collada))
render(render_input_elements_list(state))
render(render_descriptor())
render(render_descriptor(namespace))
render(render_end_of_namespace())
return state, out
def render_hpp(namespace):
yield f"namespace {namespace} {{"
yield "extern collada::descriptor const descriptor;"
yield "}"
def render_all_hpp(namespace):
render, out = renderer()
render(render_hpp(namespace))
return out
if __name__ == "__main__":
import sys
collada = parse.parse_collada_file(sys.argv[1])

View File

@ -7,15 +7,16 @@ from collada import header
def usage():
name = sys.argv[0]
print("usage:")
print(f" {name} [input_collada.dae] [output_header.hpp] [output_vertex.vtx] [output_vertex.idx]")
print(f" {name} [input_collada.dae] [output_source.cpp] [output_header.hpp] [output_vertex.vtx] [output_vertex.idx]")
sys.exit(1)
def main():
try:
input_collada = sys.argv[1]
output_header = sys.argv[2]
output_vertex = sys.argv[3]
output_index = sys.argv[4]
output_source = sys.argv[2]
output_header = sys.argv[3]
output_vertex = sys.argv[4]
output_index = sys.argv[5]
assert input_collada.lower().endswith(".dae")
assert output_header.lower().endswith(".hpp")
assert output_vertex.lower().endswith(".vtx")
@ -25,10 +26,16 @@ def main():
collada = parse.parse_collada_file(input_collada)
namespace = path.splitext(path.split(input_collada)[1])[0]
state, out = header.render_all(collada, namespace)
state, out_source = header.render_all(collada, namespace)
out_header = header.render_all_hpp(namespace)
with open(output_source, 'wb') as f:
source_buf = out_source.getvalue()
assert "\r\n" in source_buf
f.write(source_buf.encode('utf-8'))
with open(output_header, 'wb') as f:
header_buf = out.getvalue()
header_buf = out_header.getvalue()
assert "\r\n" in header_buf
f.write(header_buf.encode('utf-8'))

View File

@ -15,9 +15,7 @@ namespace collada_scene {
union {
lookat lookat;
XMMATRIX matrix;
XMVECTOR rotate;
XMVECTOR scale;
XMVECTOR translate;
XMVECTOR vector;
};
collada::transform_type type;
};

View File

@ -220,12 +220,10 @@ namespace collada {
struct source {
union {
float const * const float_array;
float2 const * const float2_array;
float3 const * const float3_array;
float4 const * const float4_array;
enum interpolation const * const interpolation_array;
};
int const count;
int const stride;
};
struct sampler {
@ -253,6 +251,7 @@ namespace collada {
X, // first cartesian coordinate
Y, // second cartesian coordinate
Z, // third cartesian coordinate
ALL,
};
struct channel {

View File

@ -1,700 +1,3 @@
#include "collada_types.hpp"
namespace curve_interpolation {
using namespace collada;
float const array_node_cube_translation_x_input_array[] = {
0.0f,
1.666667f,
3.333333f,
5.0f,
};
float const array_node_cube_translation_x_output_array[] = {
10.0f,
-10.0f,
10.0f,
-10.0f,
};
float2 const array_node_cube_translation_x_intangent_array[] = {
{ -0.3332306f, 10.0f },
{ 1.111167f, -10.0f },
{ 2.778333f, 10.0f },
{ 4.4445f, -9.219337f },
};
float2 const array_node_cube_translation_x_outtangent_array[] = {
{ 0.5555f, 10.0f },
{ 2.222167f, -10.0f },
{ 3.888333f, 10.0f },
{ 4.000208f, -8.594958f },
};
enum interpolation const array_node_cube_translation_x_interpolation_array[] = {
interpolation::BEZIER,
interpolation::BEZIER,
interpolation::BEZIER,
interpolation::BEZIER,
};
sampler const sampler_node_cube_translation_x_sampler = {
// node_cube_translation_x_input
.input = {
.float_array = array_node_cube_translation_x_input_array,
.count = 4,
},
// node_cube_translation_x_output
.output = {
.float_array = array_node_cube_translation_x_output_array,
.count = 4,
},
// node_cube_translation_x_intangent
.in_tangent = {
.float2_array = array_node_cube_translation_x_intangent_array,
.count = 4,
},
// node_cube_translation_x_outtangent
.out_tangent = {
.float2_array = array_node_cube_translation_x_outtangent_array,
.count = 4,
},
// node_cube_translation_x_interpolation
.interpolation = {
.interpolation_array = array_node_cube_translation_x_interpolation_array,
.count = 4,
},
};
float const array_node_cube_translation_y_input_array[] = {
-0.8333334f,
0.8333334f,
2.5f,
4.166667f,
};
float const array_node_cube_translation_y_output_array[] = {
-10.05776f,
10.05852f,
-9.941484f,
10.05852f,
};
float2 const array_node_cube_translation_y_intangent_array[] = {
{ -1.166264f, -10.05776f },
{ 0.2778334f, 10.05852f },
{ 1.9445f, -9.941484f },
{ 3.611667f, 10.05852f },
};
float2 const array_node_cube_translation_y_outtangent_array[] = {
{ -0.2783333f, -10.05776f },
{ 1.388833f, 10.05852f },
{ 3.0555f, -9.941484f },
{ 4.499598f, 10.05852f },
};
enum interpolation const array_node_cube_translation_y_interpolation_array[] = {
interpolation::BEZIER,
interpolation::BEZIER,
interpolation::BEZIER,
interpolation::BEZIER,
};
sampler const sampler_node_cube_translation_y_sampler = {
// node_cube_translation_y_input
.input = {
.float_array = array_node_cube_translation_y_input_array,
.count = 4,
},
// node_cube_translation_y_output
.output = {
.float_array = array_node_cube_translation_y_output_array,
.count = 4,
},
// node_cube_translation_y_intangent
.in_tangent = {
.float2_array = array_node_cube_translation_y_intangent_array,
.count = 4,
},
// node_cube_translation_y_outtangent
.out_tangent = {
.float2_array = array_node_cube_translation_y_outtangent_array,
.count = 4,
},
// node_cube_translation_y_interpolation
.interpolation = {
.interpolation_array = array_node_cube_translation_y_interpolation_array,
.count = 4,
},
};
channel const node_channel_node_cube_translation_x = {
.source_sampler = &sampler_node_cube_translation_x_sampler,
.target_transform_index = 0,
.target_attribute = target_attribute::X,
};
channel const node_channel_node_cube_translation_y = {
.source_sampler = &sampler_node_cube_translation_y_sampler,
.target_transform_index = 0,
.target_attribute = target_attribute::Y,
};
effect const effect_material__15 = {
.type = effect_type::BLINN,
.blinn = {
.emission = {
.color = {0.0f, 0.0f, 0.0f, 1.0f},
},
.ambient = {
.color = {0.6705883f, 0.5843138f, 1.0f, 1.0f},
},
.diffuse = {
.color = {0.6705883f, 0.5843138f, 1.0f, 1.0f},
},
.specular = {
.color = {0.0f, 0.0f, 0.0f, 1.0f},
},
.shininess = 10.0f,
.reflective = {
.color = {0.0f, 0.0f, 0.0f, 1.0f},
},
.reflectivity = 0.0f,
.transparent = {
.color = {1.0f, 1.0f, 1.0f, 1.0f},
},
.transparency = 1.0f,
.index_of_refraction = 0.0f,
}
};
effect const effect_material__16 = {
.type = effect_type::BLINN,
.blinn = {
.emission = {
.color = {0.0f, 0.0f, 0.0f, 1.0f},
},
.ambient = {
.color = {0.5803922f, 1.0f, 0.9647059f, 1.0f},
},
.diffuse = {
.color = {0.5803922f, 1.0f, 0.9647059f, 1.0f},
},
.specular = {
.color = {0.0f, 0.0f, 0.0f, 1.0f},
},
.shininess = 10.0f,
.reflective = {
.color = {0.0f, 0.0f, 0.0f, 1.0f},
},
.reflectivity = 0.0f,
.transparent = {
.color = {1.0f, 1.0f, 1.0f, 1.0f},
},
.transparency = 1.0f,
.index_of_refraction = 0.0f,
}
};
effect const effect_material__17 = {
.type = effect_type::BLINN,
.blinn = {
.emission = {
.color = {0.0f, 0.0f, 0.0f, 1.0f},
},
.ambient = {
.color = {0.6509804f, 1.0f, 0.5803922f, 1.0f},
},
.diffuse = {
.color = {0.6509804f, 1.0f, 0.5803922f, 1.0f},
},
.specular = {
.color = {0.0f, 0.0f, 0.0f, 1.0f},
},
.shininess = 10.0f,
.reflective = {
.color = {0.0f, 0.0f, 0.0f, 1.0f},
},
.reflectivity = 0.0f,
.transparent = {
.color = {1.0f, 1.0f, 1.0f, 1.0f},
},
.transparency = 1.0f,
.index_of_refraction = 0.0f,
}
};
effect const effect_material__18 = {
.type = effect_type::BLINN,
.blinn = {
.emission = {
.color = {0.0f, 0.0f, 0.0f, 1.0f},
},
.ambient = {
.color = {0.9333334f, 1.0f, 0.5647059f, 1.0f},
},
.diffuse = {
.color = {0.9333334f, 1.0f, 0.5647059f, 1.0f},
},
.specular = {
.color = {0.0f, 0.0f, 0.0f, 1.0f},
},
.shininess = 10.0f,
.reflective = {
.color = {0.0f, 0.0f, 0.0f, 1.0f},
},
.reflectivity = 0.0f,
.transparent = {
.color = {1.0f, 1.0f, 1.0f, 1.0f},
},
.transparency = 1.0f,
.index_of_refraction = 0.0f,
}
};
effect const effect_material__19 = {
.type = effect_type::BLINN,
.blinn = {
.emission = {
.color = {0.0f, 0.0f, 0.0f, 1.0f},
},
.ambient = {
.color = {1.0f, 0.7686275f, 0.5803922f, 1.0f},
},
.diffuse = {
.color = {1.0f, 0.7686275f, 0.5803922f, 1.0f},
},
.specular = {
.color = {0.0f, 0.0f, 0.0f, 1.0f},
},
.shininess = 10.0f,
.reflective = {
.color = {0.0f, 0.0f, 0.0f, 1.0f},
},
.reflectivity = 0.0f,
.transparent = {
.color = {1.0f, 1.0f, 1.0f, 1.0f},
},
.transparency = 1.0f,
.index_of_refraction = 0.0f,
}
};
effect const effect_material__20 = {
.type = effect_type::BLINN,
.blinn = {
.emission = {
.color = {0.0f, 0.0f, 0.0f, 1.0f},
},
.ambient = {
.color = {1.0f, 0.5803922f, 0.5803922f, 1.0f},
},
.diffuse = {
.color = {1.0f, 0.5803922f, 0.5803922f, 1.0f},
},
.specular = {
.color = {0.0f, 0.0f, 0.0f, 1.0f},
},
.shininess = 10.0f,
.reflective = {
.color = {0.0f, 0.0f, 0.0f, 1.0f},
},
.reflectivity = 0.0f,
.transparent = {
.color = {1.0f, 1.0f, 1.0f, 1.0f},
},
.transparency = 1.0f,
.index_of_refraction = 0.0f,
}
};
effect const effect_coloreffectr229g154b215 = {
.type = effect_type::PHONG,
.phong = {
.emission = {
.color = {0.0f, 0.0f, 0.0f, 0.0f},
},
.ambient = {
.color = {0.8980392f, 0.6039216f, 0.8431373f, 1.0f},
},
.diffuse = {
.color = {0.8980392f, 0.6039216f, 0.8431373f, 1.0f},
},
.specular = {
.color = {1.0f, 1.0f, 1.0f, 1.0f},
},
.shininess = 10.0f,
.reflective = {
.color = {0.0f, 0.0f, 0.0f, 1.0f},
},
.reflectivity = 0.0f,
.transparent = {
.color = {1.0f, 1.0f, 1.0f, 1.0f},
},
.transparency = 1.0f,
.index_of_refraction = 0.0f,
}
};
effect const effect_coloreffectr28g149b177 = {
.type = effect_type::PHONG,
.phong = {
.emission = {
.color = {0.0f, 0.0f, 0.0f, 0.0f},
},
.ambient = {
.color = {0.1098039f, 0.5843137f, 0.6941176f, 1.0f},
},
.diffuse = {
.color = {0.1098039f, 0.5843137f, 0.6941176f, 1.0f},
},
.specular = {
.color = {1.0f, 1.0f, 1.0f, 1.0f},
},
.shininess = 10.0f,
.reflective = {
.color = {0.0f, 0.0f, 0.0f, 1.0f},
},
.reflectivity = 0.0f,
.transparent = {
.color = {1.0f, 1.0f, 1.0f, 1.0f},
},
.transparency = 1.0f,
.index_of_refraction = 0.0f,
}
};
material const material_coloreffectr229g154b215_material = {
.effect = &effect_coloreffectr229g154b215,
};
material const material_coloreffectr28g149b177_material = {
.effect = &effect_coloreffectr28g149b177,
};
material const material_material__15_material = {
.effect = &effect_material__15,
};
material const material_material__16_material = {
.effect = &effect_material__16,
};
material const material_material__17_material = {
.effect = &effect_material__17,
};
material const material_material__18_material = {
.effect = &effect_material__18,
};
material const material_material__19_material = {
.effect = &effect_material__19,
};
material const material_material__20_material = {
.effect = &effect_material__20,
};
input_element const input_elements_position_0_3_normal_0_3_texcoord_0_3[] = {
{
.semantic = "POSITION",
.semantic_index = 0,
.format = input_format::FLOAT3,
},
{
.semantic = "NORMAL",
.semantic_index = 0,
.format = input_format::FLOAT3,
},
{
.semantic = "TEXCOORD",
.semantic_index = 0,
.format = input_format::FLOAT3,
},
};
triangles const triangles_geom_cube[] = {
{
.count = 2, // triangles
.index_offset = 0, // indices
.inputs_index = 0, // index into inputs_list
},
{
.count = 2, // triangles
.index_offset = 6, // indices
.inputs_index = 0, // index into inputs_list
},
{
.count = 2, // triangles
.index_offset = 12, // indices
.inputs_index = 0, // index into inputs_list
},
{
.count = 2, // triangles
.index_offset = 18, // indices
.inputs_index = 0, // index into inputs_list
},
{
.count = 2, // triangles
.index_offset = 24, // indices
.inputs_index = 0, // index into inputs_list
},
{
.count = 2, // triangles
.index_offset = 30, // indices
.inputs_index = 0, // index into inputs_list
},
};
geometry const geometry_geom_cube = {
.mesh = {
.triangles = triangles_geom_cube,
.triangles_count = 6,
.vertex_buffer_offset = 0,
.vertex_buffer_size = 864,
.index_buffer_offset = 0,
.index_buffer_size = 144,
}
};
triangles const triangles_geom_cylinder001[] = {
{
.count = 30, // triangles
.index_offset = 0, // indices
.inputs_index = 0, // index into inputs_list
},
};
geometry const geometry_geom_cylinder001 = {
.mesh = {
.triangles = triangles_geom_cylinder001,
.triangles_count = 1,
.vertex_buffer_offset = 864,
.vertex_buffer_size = 1152,
.index_buffer_offset = 144,
.index_buffer_size = 360,
}
};
triangles const triangles_geom_plane001[] = {
{
.count = 2, // triangles
.index_offset = 0, // indices
.inputs_index = 0, // index into inputs_list
},
};
geometry const geometry_geom_plane001 = {
.mesh = {
.triangles = triangles_geom_plane001,
.triangles_count = 1,
.vertex_buffer_offset = 2016,
.vertex_buffer_size = 144,
.index_buffer_offset = 504,
.index_buffer_size = 24,
}
};
geometry const * const geometries[] = {
&geometry_geom_cube,
&geometry_geom_cylinder001,
&geometry_geom_plane001,
};
transform const transforms_node_environmentambientlight[] = {
};
instance_geometry const instance_geometries_node_environmentambientlight[] = {
};
channel const * const node_channels_node_environmentambientlight[] = {};
node const node_node_environmentambientlight = {
.parent_index = -1,
.type = node_type::NODE,
.transforms = transforms_node_environmentambientlight,
.transforms_count = 0,
.instance_geometries = instance_geometries_node_environmentambientlight,
.instance_geometries_count = 0,
.channels = node_channels_node_environmentambientlight,
.channels_count = 0,
};
transform const transforms_node_cube[] = {
{
.type = transform_type::TRANSLATE,
.translate = {10.0f, -1.14258e-07f, 0.0f},
},
};
instance_material const instance_materials_node_cube_0[] = {
{
.element_index = 1, // an index into mesh.triangles
.material = &material_material__15_material,
},
{
.element_index = 0, // an index into mesh.triangles
.material = &material_material__16_material,
},
{
.element_index = 5, // an index into mesh.triangles
.material = &material_material__17_material,
},
{
.element_index = 3, // an index into mesh.triangles
.material = &material_material__18_material,
},
{
.element_index = 2, // an index into mesh.triangles
.material = &material_material__19_material,
},
{
.element_index = 4, // an index into mesh.triangles
.material = &material_material__20_material,
},
};
instance_geometry const instance_geometries_node_cube[] = {
{
.geometry = &geometry_geom_cube,
.instance_materials = instance_materials_node_cube_0,
.instance_materials_count = 6,
},
};
channel const * const node_channels_node_cube[] = {
&node_channel_node_cube_translation_y,
&node_channel_node_cube_translation_x,
};
node const node_node_cube = {
.parent_index = -1,
.type = node_type::NODE,
.transforms = transforms_node_cube,
.transforms_count = 1,
.instance_geometries = instance_geometries_node_cube,
.instance_geometries_count = 1,
.channels = node_channels_node_cube,
.channels_count = 2,
};
transform const transforms_node_cylinder001[] = {
};
instance_material const instance_materials_node_cylinder001_0[] = {
{
.element_index = 0, // an index into mesh.triangles
.material = &material_coloreffectr229g154b215_material,
},
};
instance_geometry const instance_geometries_node_cylinder001[] = {
{
.geometry = &geometry_geom_cylinder001,
.instance_materials = instance_materials_node_cylinder001_0,
.instance_materials_count = 1,
},
};
channel const * const node_channels_node_cylinder001[] = {
};
node const node_node_cylinder001 = {
.parent_index = -1,
.type = node_type::NODE,
.transforms = transforms_node_cylinder001,
.transforms_count = 0,
.instance_geometries = instance_geometries_node_cylinder001,
.instance_geometries_count = 1,
.channels = node_channels_node_cylinder001,
.channels_count = 0,
};
transform const transforms_node_plane001[] = {
{
.type = transform_type::TRANSLATE,
.translate = {0.0f, 0.0f, 0.01f},
},
{
.type = transform_type::ROTATE,
.rotate = {0.0f, 0.0f, -1.0f, -44.99999f},
},
};
instance_material const instance_materials_node_plane001_0[] = {
{
.element_index = 0, // an index into mesh.triangles
.material = &material_coloreffectr28g149b177_material,
},
};
instance_geometry const instance_geometries_node_plane001[] = {
{
.geometry = &geometry_geom_plane001,
.instance_materials = instance_materials_node_plane001_0,
.instance_materials_count = 1,
},
};
channel const * const node_channels_node_plane001[] = {
};
node const node_node_plane001 = {
.parent_index = -1,
.type = node_type::NODE,
.transforms = transforms_node_plane001,
.transforms_count = 2,
.instance_geometries = instance_geometries_node_plane001,
.instance_geometries_count = 1,
.channels = node_channels_node_plane001,
.channels_count = 0,
};
node const * const nodes[] = {
&node_node_environmentambientlight,
&node_node_cube,
&node_node_cylinder001,
&node_node_plane001,
};
inputs const inputs_list[] = {
{
.elements = input_elements_position_0_3_normal_0_3_texcoord_0_3,
.elements_count = 3,
},
};
descriptor const descriptor = {
.nodes = nodes,
.nodes_count = (sizeof (nodes)) / (sizeof (nodes[0])),
.inputs_list = inputs_list,
.inputs_list_count = (sizeof (inputs_list)) / (sizeof (inputs_list[0])),
};
extern collada::descriptor const descriptor;
}

File diff suppressed because one or more lines are too long

View File

@ -83,13 +83,13 @@ namespace collada_scene {
transform.matrix = XMLoadFloat4x4((XMFLOAT4X4 *)&node->transforms[i].matrix);
break;
case transform_type::ROTATE:
transform.rotate = XMLoadFloat4((XMFLOAT4 *)&node->transforms[i].rotate);
transform.vector = XMLoadFloat4((XMFLOAT4 *)&node->transforms[i].rotate);
break;
case transform_type::SCALE:
transform.scale = XMLoadFloat3((XMFLOAT3 *)&node->transforms[i].scale);
transform.vector = XMLoadFloat3((XMFLOAT3*)&node->transforms[i].scale);
break;
case transform_type::TRANSLATE:
transform.translate = XMLoadFloat3((XMFLOAT3*)&node->transforms[i].translate);
transform.vector = XMLoadFloat3((XMFLOAT3*)&node->transforms[i].translate);
break;
default:
assert(false);
@ -271,12 +271,12 @@ namespace collada_scene {
{
switch (transform.type) {
case transform_type::TRANSLATE:
return XMMatrixTranslationFromVector(transform.translate);
return XMMatrixTranslationFromVector(transform.vector);
case transform_type::ROTATE:
return XMMatrixRotationNormal(transform.rotate,
XMConvertToRadians(XMVectorGetW(transform.rotate)));
return XMMatrixRotationNormal(transform.vector,
XMConvertToRadians(XMVectorGetW(transform.vector)));
case transform_type::SCALE:
return XMMatrixScalingFromVector(transform.scale);
return XMMatrixScalingFromVector(transform.vector);
default:
assert(false);
break;
@ -360,17 +360,17 @@ namespace collada_scene {
return -1;
}
static inline float interpolation_value(source const& source, int ix, float t)
static inline float linear_interpolate_iv(source const& source, int frame_ix, float t)
{
float prev = source.float_array[ix];
float next = source.float_array[ix+1];
float prev = source.float_array[(frame_ix+0) * source.stride];
float next = source.float_array[(frame_ix+1) * source.stride];
return (t - prev) / (next - prev);
}
static inline float linear_interpolate(source const& source, int ix, float iv)
static inline float linear_interpolate_value(source const& source, int frame_ix, int parameter_ix, float iv)
{
float prev = source.float_array[ix];
float next = source.float_array[ix+1];
float prev = source.float_array[(frame_ix+0) * source.stride + parameter_ix];
float next = source.float_array[(frame_ix+1) * source.stride + parameter_ix];
return prev + iv * (next - prev);
}
@ -425,7 +425,13 @@ namespace collada_scene {
assert(false);
}
static float bezier_sampler(sampler const * const sampler, int ix, float t)
static inline XMFLOAT2 const * tangent_index(source const& source, int frame_ix, int parameter_ix)
{
int ix = frame_ix * source.stride + parameter_ix * 2;
return (XMFLOAT2 const *)&source.float_array[ix];
}
static float bezier_sampler(sampler const * const sampler, int frame_ix, int parameter_ix, float t)
{
/*
P0 is (INPUT[i] , OUTPUT[i])
@ -433,14 +439,100 @@ namespace collada_scene {
C1 (or T1) is (IN_TANGENT[i+1][0], IN_TANGENT[i+1][1])
P1 is (INPUT[i+1], OUTPUT[i+1])
*/
XMVECTOR p0 = XMVectorSet(sampler->input.float_array[ix], sampler->output.float_array[ix], 0, 0);
XMVECTOR c0 = XMLoadFloat2((XMFLOAT2 *)&sampler->out_tangent.float2_array[ix]);
XMVECTOR c1 = XMLoadFloat2((XMFLOAT2 *)&sampler->in_tangent.float2_array[ix+1]);
XMVECTOR p1 = XMVectorSet(sampler->input.float_array[ix+1], sampler->output.float_array[ix+1], 0, 0);
float frame0_input = sampler->input.float_array[frame_ix+0];
float frame1_input = sampler->input.float_array[frame_ix+1];
float frame0_output = sampler->output.float_array[(frame_ix+0) * sampler->output.stride + parameter_ix];
float frame1_output = sampler->output.float_array[(frame_ix+1) * sampler->output.stride + parameter_ix];
XMVECTOR p0 = XMVectorSet(frame0_input, frame0_output, 0, 0);
XMVECTOR c0 = XMLoadFloat2(tangent_index(sampler->out_tangent, frame_ix + 0, parameter_ix));
XMVECTOR c1 = XMLoadFloat2(tangent_index(sampler->in_tangent, frame_ix + 1, parameter_ix));
XMVECTOR p1 = XMVectorSet(frame1_input, frame1_output, 0, 0);
return bezier_binary_search(p0, c0, c1, p1, t);
}
static void apply_transform_target(transform& transform,
enum target_attribute channel_target_attribute,
float value)
{
switch (transform.type) {
case transform_type::TRANSLATE: __attribute__((fallthrough));
case transform_type::SCALE:
switch (channel_target_attribute) {
case target_attribute::X: transform.vector = XMVectorSetX(transform.vector, value); return;
case target_attribute::Y: transform.vector = XMVectorSetY(transform.vector, value); return;
case target_attribute::Z: transform.vector = XMVectorSetZ(transform.vector, value); return;
default: assert(false);
}
case transform_type::ROTATE:
switch (channel_target_attribute) {
case target_attribute::X: transform.vector = XMVectorSetX(transform.vector, value); return;
case target_attribute::Y: transform.vector = XMVectorSetY(transform.vector, value); return;
case target_attribute::Z: transform.vector = XMVectorSetZ(transform.vector, value); return;
case target_attribute::ANGLE: transform.vector = XMVectorSetW(transform.vector, value); return;
default: assert(false);
}
default:
assert(false);
break;
}
}
static enum target_attribute const rotate_target_attributes[] = {
target_attribute::X,
target_attribute::Y,
target_attribute::Z,
target_attribute::ANGLE,
};
static enum target_attribute const translate_scale_target_attributes[] = {
target_attribute::X,
target_attribute::Y,
target_attribute::Z,
};
static void animate_channel_segment(channel const& channel,
transform& transform,
int frame_ix, float t)
{
enum target_attribute const * target_attributes = &channel.target_attribute;
int target_attributes_count = 1;
if (channel.target_attribute == target_attribute::ALL) {
switch (transform.type) {
case transform_type::TRANSLATE: __attribute__((fallthrough));
case transform_type::SCALE:
target_attributes = translate_scale_target_attributes;
target_attributes_count = 3;
break;
case transform_type::ROTATE:
target_attributes = rotate_target_attributes;
target_attributes_count = 4;
break;
default:
assert(false);
break;
}
}
for (int parameter_ix = 0; parameter_ix < target_attributes_count; parameter_ix++) {
enum collada::interpolation interpolation = channel.source_sampler->interpolation.interpolation_array[frame_ix];
float value;
if (interpolation == interpolation::BEZIER) {
value = bezier_sampler(channel.source_sampler, frame_ix, parameter_ix, t);
} else {
float iv = linear_interpolate_iv(channel.source_sampler->input, frame_ix, t);
value = linear_interpolate_value(channel.source_sampler->output, frame_ix, parameter_ix, iv);
}
apply_transform_target(transform, target_attributes[parameter_ix], value);
}
}
static void animate_node(node const& node, node_instance& node_instance, float t)
{
for (int i = 0; i < node.channels_count; i++) {
@ -448,32 +540,9 @@ namespace collada_scene {
transform& transform = node_instance.transforms[channel.target_transform_index];
int frame_ix = find_frame_ix(channel.source_sampler->input, t);
if (frame_ix < 0)
continue; // animation is missing a key frame
assert(frame_ix >= 0); // animation is missing a key frame
enum collada::interpolation const * const interpolation =
channel.source_sampler->interpolation.interpolation_array;
float value;
if (interpolation[frame_ix] == interpolation::BEZIER) {
value = bezier_sampler(channel.source_sampler, frame_ix, t);
} else {
float iv = interpolation_value(channel.source_sampler->input, frame_ix, t);
value = linear_interpolate(channel.source_sampler->output, frame_ix, iv);
}
switch (transform.type) {
case transform_type::TRANSLATE:
switch (channel.target_attribute) {
case target_attribute::X: transform.translate = XMVectorSetX(transform.translate, value); break;
case target_attribute::Y: transform.translate = XMVectorSetY(transform.translate, value); break;
case target_attribute::Z: transform.translate = XMVectorSetZ(transform.translate, value); break;
default: break;
}
break;
default:
break;
}
animate_channel_segment(channel, transform, frame_ix, t);
}
}

View File

@ -129,7 +129,7 @@ XMFLOAT4 g_vLightColors[2] = {
//
XMVECTOR g_Eye = XMVectorSet(0.0f, -3.0f, 13.0f, 1.0f);
XMVECTOR g_Eye = XMVectorSet(0.0f, -10.0f, 13.0f, 1.0f);
XMVECTOR g_At = XMVectorSet(0.0f, 0.0f, 0.0f, 1.0f);
// collada scene state

File diff suppressed because it is too large Load Diff