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.fxo \
$(BUILD_TYPE)/effect/collada_scene.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) @mkdir -p $(@D)
$(WINDRES) -O coff -I$(BUILD_TYPE)/effect -o $@ $< $(WINDRES) -O coff -I$(BUILD_TYPE)/effect -o $@ $<
@ -67,7 +71,8 @@ OBJS = \
$(BUILD_TYPE)/render_state.obj \ $(BUILD_TYPE)/render_state.obj \
$(BUILD_TYPE)/input.obj \ $(BUILD_TYPE)/input.obj \
$(BUILD_TYPE)/collada.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) $(BUILD_TYPE)/d3d10.exe: $(OBJS)
@mkdir -p $(@D) @mkdir -p $(@D)

View File

@ -475,8 +475,10 @@ def render_input_elements_list(state):
yield "}," yield "},"
yield "};" yield "};"
def render_descriptor(): def render_descriptor(namespace):
yield "descriptor const descriptor = {" yield f"extern collada::descriptor const descriptor;"
yield ""
yield "collada::descriptor const descriptor = {"
yield ".nodes = nodes," yield ".nodes = nodes,"
yield ".nodes_count = (sizeof (nodes)) / (sizeof (nodes[0]))," yield ".nodes_count = (sizeof (nodes)) / (sizeof (nodes[0])),"
yield "" yield ""
@ -494,18 +496,6 @@ def render_animation_children(state, collada, animation_name, animations):
yield "&animation_{animation_name}," yield "&animation_{animation_name},"
yield "};" 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): def render_array(state, collada, accessor, array):
array_name = sanitize_name(state, array.id, array) array_name = sanitize_name(state, array.id, array)
# render the array # render the array
@ -518,30 +508,26 @@ def render_array(state, collada, accessor, array):
assert name in {"BEZIER", "LINEAR"}, name assert name in {"BEZIER", "LINEAR"}, name
yield f"interpolation::{name}," yield f"interpolation::{name},"
yield "};" yield "};"
return "interpolation"
elif type(array) is types.FloatArray: elif type(array) is types.FloatArray:
c_type = array_c_type(accessor) yield f"float const array_{array_name}[] = {{"
yield f"{c_type} const array_{array_name}[] = {{"
it = iter(array.floats) it = iter(array.floats)
for i in range(accessor.count): for i in range(accessor.count):
vector = ", ".join(f"{float(f)}f" for f in islice(it, accessor.stride)) vector = ", ".join(f"{float(f)}f" for f in islice(it, accessor.stride))
if accessor.stride == 1: yield f"{vector},"
yield f"{vector},"
else:
yield f"{{ {vector} }},"
yield "};" yield "};"
else: else:
assert False, type(array) assert False, type(array)
def render_source(state, collada, field_name, source): def render_source(state, collada, field_name, source):
array_name = sanitize_name(state, source.array_element.id, source.array_element) 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) source_name = sanitize_name(state, source.id, source)
#yield f"source const source_{source_name} = {{" #yield f"source const source_{source_name} = {{"
yield f"// {source_name}" yield f"// {source_name}"
yield f".{field_name} = {{" yield f".{field_name} = {{"
yield f".{c_type}_array = array_{array_name}," yield f".{c_type}_array = array_{array_name},"
yield f".count = {source.technique_common.accessor.count}," yield f".count = {source.technique_common.accessor.count},"
yield f".stride = {source.technique_common.accessor.stride},"
yield "}," yield "},"
def render_sampler(state, collada, sampler): def render_sampler(state, collada, sampler):
@ -549,13 +535,32 @@ def render_sampler(state, collada, sampler):
enumerate(["INPUT", "OUTPUT", "IN_TANGENT", "OUT_TANGENT", "INTERPOLATION"])) enumerate(["INPUT", "OUTPUT", "IN_TANGENT", "OUT_TANGENT", "INTERPOLATION"]))
inputs = sorted((input for input in sampler.inputs if input.semantic in order), inputs = sorted((input for input in sampler.inputs if input.semantic in order),
key=lambda input: order[input.semantic]) 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 # render the source arrays first
for input in inputs: for input in inputs:
assert type(input) is types.InputUnshared assert type(input) is types.InputUnshared
source = collada.lookup(input.source, types.SourceCore) source = collada.lookup(input.source, types.SourceCore)
yield from render_array(state, collada, source.technique_common.accessor, source.array_element) yield from render_array(state, collada, source.technique_common.accessor, source.array_element)
# render the sampler
sampler_name = sanitize_name(state, sampler.id, sampler) sampler_name = sanitize_name(state, sampler.id, sampler)
yield f"sampler const sampler_{sampler_name} = {{" yield f"sampler const sampler_{sampler_name} = {{"
for input in inputs: for input in inputs:
@ -565,7 +570,7 @@ def render_sampler(state, collada, sampler):
yield "};" yield "};"
target_attributes = { 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): 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) sampler_name = sanitize_name(state, sampler.id, sampler)
assert '/' in channel.target, channel.target assert '/' in channel.target, channel.target
assert '.' in channel.target, channel.target
assert "(" not in channel.target, channel.target assert "(" not in channel.target, channel.target
node_id, rest = channel.target.split("/") 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 assert target_attribute in target_attributes
node = collada.lookup(f"#{node_id}", types.Node) node = collada.lookup(f"#{node_id}", types.Node)
@ -659,10 +667,20 @@ def render_all(collada, namespace):
# root elements # root elements
render(render_library_visual_scenes(state, collada)) render(render_library_visual_scenes(state, collada))
render(render_input_elements_list(state)) render(render_input_elements_list(state))
render(render_descriptor()) render(render_descriptor(namespace))
render(render_end_of_namespace()) render(render_end_of_namespace())
return state, out 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__": if __name__ == "__main__":
import sys import sys
collada = parse.parse_collada_file(sys.argv[1]) collada = parse.parse_collada_file(sys.argv[1])

View File

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

View File

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

View File

@ -220,12 +220,10 @@ namespace collada {
struct source { struct source {
union { union {
float const * const float_array; 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; enum interpolation const * const interpolation_array;
}; };
int const count; int const count;
int const stride;
}; };
struct sampler { struct sampler {
@ -253,6 +251,7 @@ namespace collada {
X, // first cartesian coordinate X, // first cartesian coordinate
Y, // second cartesian coordinate Y, // second cartesian coordinate
Z, // third cartesian coordinate Z, // third cartesian coordinate
ALL,
}; };
struct channel { struct channel {

View File

@ -1,700 +1,3 @@
#include "collada_types.hpp"
namespace curve_interpolation { namespace curve_interpolation {
extern collada::descriptor const descriptor;
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])),
};
} }

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); transform.matrix = XMLoadFloat4x4((XMFLOAT4X4 *)&node->transforms[i].matrix);
break; break;
case transform_type::ROTATE: case transform_type::ROTATE:
transform.rotate = XMLoadFloat4((XMFLOAT4 *)&node->transforms[i].rotate); transform.vector = XMLoadFloat4((XMFLOAT4 *)&node->transforms[i].rotate);
break; break;
case transform_type::SCALE: case transform_type::SCALE:
transform.scale = XMLoadFloat3((XMFLOAT3 *)&node->transforms[i].scale); transform.vector = XMLoadFloat3((XMFLOAT3*)&node->transforms[i].scale);
break; break;
case transform_type::TRANSLATE: case transform_type::TRANSLATE:
transform.translate = XMLoadFloat3((XMFLOAT3*)&node->transforms[i].translate); transform.vector = XMLoadFloat3((XMFLOAT3*)&node->transforms[i].translate);
break; break;
default: default:
assert(false); assert(false);
@ -271,12 +271,12 @@ namespace collada_scene {
{ {
switch (transform.type) { switch (transform.type) {
case transform_type::TRANSLATE: case transform_type::TRANSLATE:
return XMMatrixTranslationFromVector(transform.translate); return XMMatrixTranslationFromVector(transform.vector);
case transform_type::ROTATE: case transform_type::ROTATE:
return XMMatrixRotationNormal(transform.rotate, return XMMatrixRotationNormal(transform.vector,
XMConvertToRadians(XMVectorGetW(transform.rotate))); XMConvertToRadians(XMVectorGetW(transform.vector)));
case transform_type::SCALE: case transform_type::SCALE:
return XMMatrixScalingFromVector(transform.scale); return XMMatrixScalingFromVector(transform.vector);
default: default:
assert(false); assert(false);
break; break;
@ -360,17 +360,17 @@ namespace collada_scene {
return -1; 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 prev = source.float_array[(frame_ix+0) * source.stride];
float next = source.float_array[ix+1]; float next = source.float_array[(frame_ix+1) * source.stride];
return (t - prev) / (next - prev); 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 prev = source.float_array[(frame_ix+0) * source.stride + parameter_ix];
float next = source.float_array[ix+1]; float next = source.float_array[(frame_ix+1) * source.stride + parameter_ix];
return prev + iv * (next - prev); return prev + iv * (next - prev);
} }
@ -425,7 +425,13 @@ namespace collada_scene {
assert(false); 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]) 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]) C1 (or T1) is (IN_TANGENT[i+1][0], IN_TANGENT[i+1][1])
P1 is (INPUT[i+1], OUTPUT[i+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]); float frame0_input = sampler->input.float_array[frame_ix+0];
XMVECTOR c1 = XMLoadFloat2((XMFLOAT2 *)&sampler->in_tangent.float2_array[ix+1]); float frame1_input = sampler->input.float_array[frame_ix+1];
XMVECTOR p1 = XMVectorSet(sampler->input.float_array[ix+1], sampler->output.float_array[ix+1], 0, 0);
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); 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) static void animate_node(node const& node, node_instance& node_instance, float t)
{ {
for (int i = 0; i < node.channels_count; i++) { 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]; transform& transform = node_instance.transforms[channel.target_transform_index];
int frame_ix = find_frame_ix(channel.source_sampler->input, t); int frame_ix = find_frame_ix(channel.source_sampler->input, t);
if (frame_ix < 0) assert(frame_ix >= 0); // animation is missing a key frame
continue; // animation is missing a key frame
enum collada::interpolation const * const interpolation = animate_channel_segment(channel, transform, frame_ix, t);
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;
}
} }
} }

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); XMVECTOR g_At = XMVectorSet(0.0f, 0.0f, 0.0f, 1.0f);
// collada scene state // collada scene state

File diff suppressed because it is too large Load Diff