From b8cea38d9f43230a96be66d68f3aeecaeb8546e3 Mon Sep 17 00:00:00 2001 From: Zack Buhman Date: Mon, 26 Jan 2026 13:21:12 -0600 Subject: [PATCH] collada_scene: basic scene rendering --- Makefile | 6 +- collada/buffer.py | 6 - collada/header.py | 63 +- collada/main.py | 21 +- include/collada_scene.hpp | 25 + include/collada_types.hpp | 16 +- include/scenes/curve_interpolation.hpp | 529 +++++++ main.rc | 6 +- .../curve_interpolation.DAE | 1238 +++++++++++------ .../curve_interpolation.idx | Bin 0 -> 528 bytes .../curve_interpolation.max | Bin 204800 -> 249856 bytes .../curve_interpolation.vtx | Bin 0 -> 2160 bytes src/collada.cpp | 25 +- src/collada_scene.cpp | 285 ++++ src/effect/collada_scene.fx | 67 + src/main.cpp | 16 +- 16 files changed, 1811 insertions(+), 492 deletions(-) create mode 100644 include/collada_scene.hpp create mode 100644 include/scenes/curve_interpolation.hpp create mode 100644 models/curve_interpolation/curve_interpolation.idx create mode 100644 models/curve_interpolation/curve_interpolation.vtx create mode 100644 src/collada_scene.cpp create mode 100644 src/effect/collada_scene.fx diff --git a/Makefile b/Makefile index 9aafe07..1b1b4f1 100644 --- a/Makefile +++ b/Makefile @@ -47,7 +47,8 @@ SHADERS = \ $(BUILD_TYPE)/effect/volume.fxo \ $(BUILD_TYPE)/effect/bloom.fxo \ $(BUILD_TYPE)/effect/static.fxo \ - $(BUILD_TYPE)/effect/collada.fxo + $(BUILD_TYPE)/effect/collada.fxo \ + $(BUILD_TYPE)/effect/collada_scene.fxo $(BUILD_TYPE)/%.res: %.rc $(SHADERS) @mkdir -p $(@D) @@ -65,7 +66,8 @@ OBJS = \ $(BUILD_TYPE)/print.obj \ $(BUILD_TYPE)/render_state.obj \ $(BUILD_TYPE)/input.obj \ - $(BUILD_TYPE)/collada.obj + $(BUILD_TYPE)/collada.obj \ + $(BUILD_TYPE)/collada_scene.obj $(BUILD_TYPE)/d3d10.exe: $(OBJS) @mkdir -p $(@D) diff --git a/collada/buffer.py b/collada/buffer.py index 117866a..5f21969 100644 --- a/collada/buffer.py +++ b/collada/buffer.py @@ -42,13 +42,7 @@ def mesh_vertex_index_buffer_triangles(collada, mesh, triangles): p_stride = max_offset + 1 offset_table, used_offsets = build_offset_table(collada, triangles, p_stride) -from prettyprinter import pprint, install_extras -install_extras(include=["dataclasses"]) - -@dataclass class MeshVertexIndexBufferState: - index_buffer: List[int] - def __init__(self): self.index_buffer = [] # a list of integers self.vertex_buffer = [] # a list of floats diff --git a/collada/header.py b/collada/header.py index 4a305ac..db1062c 100644 --- a/collada/header.py +++ b/collada/header.py @@ -18,7 +18,8 @@ install_extras(include=["dataclasses"]) class State: # arbitrary binary data, including vertex buffers and index # buffers - buf: BytesIO + vertex_buffer: BytesIO + index_buffer: BytesIO # geometry__indices: # keys: collada id @@ -40,7 +41,8 @@ class State: emitted_input_elements_arrays: Dict[str, tuple] def __init__(self): - self.buf = BytesIO() + self.vertex_buffer = BytesIO() + self.index_buffer = BytesIO() self.geometry__indices = {} self.geometry__vertex_index_tables = {} self.node_names = {} @@ -109,9 +111,9 @@ def render_input_elements(state, collada, geometry_name, offset_tables): key = tuple(offset_table_key(offset_table)) key_name = input_elements_key_name(key) if key_name in state.emitted_input_elements_arrays: - assert state.emitted_input_elements_arrays[key_name] == key + assert state.emitted_input_elements_arrays[key_name][1] == key continue - state.emitted_input_elements_arrays[key_name] = key + state.emitted_input_elements_arrays[key_name] = (i, key) yield f"input_element const input_elements_{key_name}[] = {{" for semantic, semantic_index, stride in key: @@ -131,14 +133,12 @@ def render_triangles(state, collada, geometry_name, primitive_elements, mesh_buf key = tuple(offset_table_key(mesh_buffer_state.offset_tables[i])) key_name = input_elements_key_name(key) + index, _ = state.emitted_input_elements_arrays[key_name] yield "{" yield f".count = {triangles.count}, // triangles" yield f".index_offset = {mesh_buffer_state.index_buffer_offsets[i]}, // indices" - yield ".inputs = {" - yield f".elements = input_elements_{key_name}," - yield f".elements_count = {len(key)}," - yield "}" + yield f".inputs_index = {index}, // index into inputs_list" yield "}," yield "};" @@ -149,13 +149,13 @@ def render_geometry(state, collada, geometry): assert type(mesh) is types.Mesh mesh_buffer_state = buffer.mesh_vertex_index_buffer(collada, mesh) - vertex_buffer_offset = state.buf.tell() - renderbin(state.buf, mesh_buffer_state.vertex_buffer, float) - vertex_buffer_size = state.buf.tell() - vertex_buffer_offset + vertex_buffer_offset = state.vertex_buffer.tell() + renderbin(state.vertex_buffer, mesh_buffer_state.vertex_buffer, float) + vertex_buffer_size = state.vertex_buffer.tell() - vertex_buffer_offset - index_buffer_offset = state.buf.tell() - renderbin(state.buf, mesh_buffer_state.index_buffer, int) - index_buffer_size = state.buf.tell() - index_buffer_offset + index_buffer_offset = state.index_buffer.tell() + renderbin(state.index_buffer, mesh_buffer_state.index_buffer, int) + index_buffer_size = state.index_buffer.tell() - index_buffer_offset yield from render_triangles(state, collada, geometry_name, mesh.primitive_elements, mesh_buffer_state) @@ -328,12 +328,13 @@ def render_library_visual_scenes(state, collada): yield f"&node_{node_name}," yield "};" -def render_header(): +def render_header(namespace): yield '#include "collada_types.hpp"' yield '' + yield f'namespace {namespace} {{' + yield '' yield 'using namespace collada;' - def render_opt_color(field_name, color): yield f".color = {render_float_tuple(color.value)}," @@ -424,14 +425,38 @@ def render_library_materials(state, collada): yield f".effect = &effect_{effect_name}," yield "};" -def render_all(collada): +def render_input_elements_list(state): + yield "inputs const inputs_list[] = {" + for key_name, (index, key) in state.emitted_input_elements_arrays.items(): + yield "{" + yield f".elements = input_elements_{key_name}," + yield f".elements_count = {len(key)}," + yield "}," + yield "};" + +def render_descriptor(): + yield "descriptor const descriptor = {" + yield ".nodes = nodes," + yield ".nodes_count = (sizeof (nodes)) / (sizeof (nodes[0]))," + yield "" + yield ".inputs_list = inputs_list," + yield ".inputs_list_count = (sizeof (inputs_list)) / (sizeof (inputs_list[0]))," + yield "};" + +def render_end_of_namespace(): + yield "}" + +def render_all(collada, namespace): state = State() render, out = renderer() - render(render_header()) + render(render_header(namespace)) render(render_library_effects(state, collada)) render(render_library_materials(state, collada)) render(render_library_geometries(state, collada)) render(render_library_visual_scenes(state, collada)) + render(render_input_elements_list(state)) + render(render_descriptor()) + render(render_end_of_namespace()) return state, out if __name__ == "__main__": @@ -442,5 +467,5 @@ if __name__ == "__main__": #assert type(skin) is types.Skin #foo = render_inverse_bind_matrix(collada, skin) - state, out = render_all(collada) + state, out = render_all(collada, "test") print(out.getvalue()) diff --git a/collada/main.py b/collada/main.py index 99da452..fd95b5e 100644 --- a/collada/main.py +++ b/collada/main.py @@ -1,4 +1,5 @@ import sys +from os import path from collada import parse from collada import header @@ -6,30 +7,36 @@ from collada import header def usage(): name = sys.argv[0] print("usage:") - print(f" {name} [input_collada.dae] [output_header.hpp] [output_binary.bin]") + print(f" {name} [input_collada.dae] [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_binary = sys.argv[3] + output_vertex = sys.argv[3] + output_index = sys.argv[4] assert input_collada.lower().endswith(".dae") assert output_header.lower().endswith(".hpp") - assert output_binary.lower().endswith(".bin") - except: + assert output_vertex.lower().endswith(".vtx") + assert output_index.lower().endswith(".idx") + except Exception as e: usage() collada = parse.parse_collada_file(input_collada) - state, out = header.render_all(collada) + namespace = path.splitext(path.split(input_collada)[1])[0] + state, out = header.render_all(collada, namespace) with open(output_header, 'wb') as f: header_buf = out.getvalue() assert "\r\n" in header_buf f.write(header_buf.encode('utf-8')) - with open(output_binary, 'wb') as f: - f.write(state.buf.getvalue()) + with open(output_vertex, 'wb') as f: + f.write(state.vertex_buffer.getvalue()) + + with open(output_index, 'wb') as f: + f.write(state.index_buffer.getvalue()) if __name__ == "__main__": main() diff --git a/include/collada_scene.hpp b/include/collada_scene.hpp new file mode 100644 index 0000000..96961f4 --- /dev/null +++ b/include/collada_scene.hpp @@ -0,0 +1,25 @@ +#pragma once + +#include "collada_types.hpp" + +namespace collada_scene { + + struct scene_state { + const UINT numBuffers = 1; // FIXME + const UINT strides[1] = {3 * 3 * 4}; // FIXME + const UINT offsets[1] = {0}; // FIXME + + ID3D10Buffer * pVertexBuffers[1] = {}; // FIXME + ID3D10Buffer * pIndexBuffer = NULL; + + ID3D10InputLayout ** pVertexLayouts = NULL; + + HRESULT load_vertex_buffer(LPCWSTR name); + HRESULT load_index_buffer(LPCWSTR name); + HRESULT load_layout(int inputs_index, collada::inputs const& inputs); + HRESULT load_layouts(collada::descriptor const& descriptor); + }; + + HRESULT LoadScene(collada::descriptor const& descriptor, scene_state& state); + void Render(collada::descriptor const& descriptor, scene_state const& state); +} diff --git a/include/collada_types.hpp b/include/collada_types.hpp index fe6c71c..02cd981 100644 --- a/include/collada_types.hpp +++ b/include/collada_types.hpp @@ -56,8 +56,13 @@ namespace collada { ////////////////////////////////////////////////////////////////////// enum class input_format { + FLOAT1, + FLOAT2, FLOAT3, FLOAT4, + INT1, + INT2, + INT3, INT4, }; @@ -76,7 +81,7 @@ namespace collada { struct triangles { int const count; int const index_offset; - inputs const inputs; + int const inputs_index; }; struct mesh { @@ -138,7 +143,6 @@ namespace collada { NODE, }; - struct color_or_texture { union { float4 color; @@ -236,4 +240,12 @@ namespace collada { node const * const nodes; int const nodes_count; }; + + struct descriptor { + node const * const * const nodes; + int const nodes_count; + + inputs const * inputs_list; + int const inputs_list_count; + }; } diff --git a/include/scenes/curve_interpolation.hpp b/include/scenes/curve_interpolation.hpp new file mode 100644 index 0000000..3e3f34d --- /dev/null +++ b/include/scenes/curve_interpolation.hpp @@ -0,0 +1,529 @@ +#include "collada_types.hpp" + +namespace curve_interpolation { + +using namespace collada; + +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[] = { +}; + +node const node_node_environmentambientlight = { + .type = node_type::NODE, + + .transforms = transforms_node_environmentambientlight, + .transforms_count = 0, + + .instance_geometries = instance_geometries_node_environmentambientlight, + .instance_geometries_count = 0, +}; + +transform const transforms_node_cube[] = { + { + .type = transform_type::TRANSLATE, + .translate = {10.0f, 0.0f, 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 = 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 = 0, // an index into mesh.triangles + .material = &material_material__16_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, + }, +}; + +node const node_node_cube = { + .type = node_type::NODE, + + .transforms = transforms_node_cube, + .transforms_count = 1, + + .instance_geometries = instance_geometries_node_cube, + .instance_geometries_count = 1, +}; + +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, + }, +}; + +node const node_node_cylinder001 = { + .type = node_type::NODE, + + .transforms = transforms_node_cylinder001, + .transforms_count = 0, + + .instance_geometries = instance_geometries_node_cylinder001, + .instance_geometries_count = 1, +}; + +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, + }, +}; + +node const node_node_plane001 = { + .type = node_type::NODE, + + .transforms = transforms_node_plane001, + .transforms_count = 2, + + .instance_geometries = instance_geometries_node_plane001, + .instance_geometries_count = 1, +}; + +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])), +}; + +} diff --git a/main.rc b/main.rc index 32888a1..18746d6 100644 --- a/main.rc +++ b/main.rc @@ -7,4 +7,8 @@ RES_PERLIN RCDATA "texture/perlin.data" RES_ROBOT_PLAYER RCDATA "models/robot_player/robot_player.data" RES_FONT_TERMINUS_6X12 RCDATA "font/terminus_128x64_6x12.data" -RES_COLLADA_FXO RCDATA "collada.fxo" \ No newline at end of file +RES_COLLADA_FXO RCDATA "collada.fxo" + +RES_COLLADA_SCENE_FXO RCDATA "collada_scene.fxo" +RES_MODELS_CURVE_INTERPOLATION_VTX RCDATA "models/curve_interpolation/curve_interpolation.vtx" +RES_MODELS_CURVE_INTERPOLATION_IDX RCDATA "models/curve_interpolation/curve_interpolation.idx" diff --git a/models/curve_interpolation/curve_interpolation.DAE b/models/curve_interpolation/curve_interpolation.DAE index c3b7b21..eeb1d4f 100755 --- a/models/curve_interpolation/curve_interpolation.DAE +++ b/models/curve_interpolation/curve_interpolation.DAE @@ -1,448 +1,792 @@ - - - - - bilbo - OpenCOLLADA for 3ds Max; Version: 1.6; Revision: 68 - file:///C:/cygwin/home/bilbo/d3d10/models/curve_interpolation/curve_interpolation.max - - 2026-01-24T21:02:20 - 2026-01-24T21:02:20 - - Z_UP - - - - - - - - 0.1019608 0.6941176 0.1019608 1 - - - 0.1019608 0.6941176 0.1019608 1 - - - 1 1 1 1 - - - 10 - - - 0 0 0 1 - - - 1 1 1 1 - - - 1 - - - - - - - - - - - 0.8980392 0.6039216 0.8431373 1 - - - 0.8980392 0.6039216 0.8431373 1 - - - 1 1 1 1 - - - 10 - - - 0 0 0 1 - - - 1 1 1 1 - - - 1 - - - - - - - - - - - 0.1098039 0.5843137 0.6941176 1 - - - 0.1098039 0.5843137 0.6941176 1 - - - 1 1 1 1 - - - 10 - - - 0 0 0 1 - - - 1 1 1 1 - - - 1 - - - - - - - - - - - - - - - - - - - - - - -0.5 -0.5 0 0.5 -0.5 0 -0.5 0.5 0 0.5 0.5 0 -0.5 -0.5 1 0.5 -0.5 1 -0.5 0.5 1 0.5 0.5 1 - - - - - - - - - - 0 0 -1 0 0 -1 0 0 -1 0 0 -1 0 0 1 0 0 1 0 0 1 0 0 1 0 -1 0 0 -1 0 0 -1 0 0 -1 0 1 0 0 1 0 0 1 0 0 1 0 0 0 1 0 0 1 0 0 1 0 0 1 0 -1 0 0 -1 0 0 -1 0 0 -1 0 0 - - - - - - - - - - 0 0 0 1 0 0 0 1 0 1 1 0 0 0 0 1 0 0 0 1 0 1 1 0 0 0 0 1 0 0 0 1 0 1 1 0 - - - - - - - - - - - - - - - -

0 0 9 2 1 11 3 2 10 3 2 10 1 3 8 0 0 9 4 4 8 5 5 9 7 6 11 7 6 11 6 7 10 4 4 8 0 8 4 1 9 5 5 10 7 5 10 7 4 11 6 0 8 4 1 12 0 3 13 1 7 14 3 7 14 3 5 15 2 1 12 0 3 16 4 2 17 5 6 18 7 6 18 7 7 19 6 3 16 4 2 20 0 0 21 1 4 22 3 4 22 3 6 23 2 2 20 0

-
-
- - - - 1 - 1 - 1 - 1 - 1 - 1 - 1 - - - -
- - - - 10 0 0 9.807853 1.950903 0 9.238795 3.826834 0 8.314696 5.555702 0 7.071068 7.071068 0 5.555702 8.314696 0 3.826834 9.238795 0 1.950904 9.807853 0 7.54979e-7 10 0 -1.950902 9.807853 0 -3.826833 9.238796 0 -5.555702 8.314696 0 -7.071068 7.071068 0 -8.314696 5.555702 0 -9.238796 3.826833 0 -9.807854 1.950901 0 -10 -3.25841e-6 0 -9.807852 -1.950907 0 -9.238793 -3.826839 0 -8.314693 -5.555707 0 -7.071063 -7.071073 0 -5.555696 -8.3147 0 -3.826827 -9.238798 0 -1.950894 -9.807855 0 9.65599e-6 -10 0 1.950913 -9.807851 0 3.826845 -9.238791 0 5.555712 -8.31469 0 7.071077 -7.071059 0 8.314704 -5.555691 0 9.238801 -3.826821 0 9.807856 -1.950888 0 - - - - - - - - - - 0 0 1 0 0 1 0 0 1 0 0 0.9999999 0 0 1 0 0 0.9999999 0 0 1 0 0 0.9999999 0 0 1 0 0 1 0 0 0.9999999 0 0 1 0 0 1 0 0 1 0 0 1 0 0 0.9999999 0 0 1 0 0 0.9999999 0 0 1 0 0 0.9999999 0 0 0.9999999 0 0 0.9999999 0 0 1 0 0 0.9999999 0 0 1 0 0 1 0 0 0.9999999 0 0 1 0 0 1 0 0 0.9999999 0 0 0.9999999 0 0 1 - - - - - - - - - - 0.5975444 0.9903928 -0.25 0.691341 0.9619401 -0.25 0.7777845 0.9157352 -0.25 0.8535529 0.8535539 -0.25 0.9157345 0.7777857 -0.25 0.9619396 0.6913422 -0.25 0.9903926 0.5975457 -0.25 1 0.5000005 -0.25 0.9903927 0.4024553 -0.25 0.9619399 0.3086587 -0.25 0.915735 0.2222152 -0.25 0.8535537 0.1464469 -0.25 0.7777854 0.08426532 -0.25 0.6913419 0.03806034 -0.25 0.5975454 0.009607404 -0.25 0.5000002 0 -0.25 0.402455 0.009607315 -0.25 0.3086584 0.03806019 -0.25 0.2222149 0.08426517 -0.25 0.1464466 0.1464466 -0.25 0.08426517 0.2222149 -0.25 0.03806019 0.3086583 -0.25 0.009607345 0.4024549 -0.25 0 0.5 -0.25 0.009607345 0.5975451 -0.25 0.03806022 0.6913417 -0.25 0.08426517 0.7777851 -0.25 0.1464466 0.8535534 -0.25 0.2222148 0.9157348 -0.25 0.3086582 0.9619398 -0.25 0.4024548 0.9903927 -0.25 0.5 1 -0.25 - - - - - - - - - - - - - - - -

0 0 31 1 1 30 2 2 29 2 2 29 3 3 28 4 4 27 0 0 31 2 2 29 4 4 27 4 4 27 5 5 26 6 6 25 6 6 25 7 7 24 8 8 23 4 4 27 6 6 25 8 8 23 0 0 31 4 4 27 8 8 23 8 8 23 9 9 22 10 10 21 10 10 21 11 11 20 12 12 19 8 8 23 10 10 21 12 12 19 12 12 19 13 13 18 14 14 17 14 14 17 15 15 16 16 16 15 12 12 19 14 14 17 16 16 15 8 8 23 12 12 19 16 16 15 0 0 31 8 8 23 16 16 15 16 16 15 17 17 14 18 18 13 18 18 13 19 19 12 20 20 11 16 16 15 18 18 13 20 20 11 20 20 11 21 21 10 22 22 9 22 22 9 23 23 8 24 24 7 20 20 11 22 22 9 24 24 7 16 16 15 20 20 11 24 24 7 0 0 31 16 16 15 24 24 7 24 24 7 25 25 6 26 26 5 26 26 5 27 27 4 28 28 3 24 24 7 26 26 5 28 28 3 0 0 31 24 24 7 28 28 3 28 28 3 29 29 2 30 30 1 0 0 31 28 28 3 30 30 1 31 31 0 0 0 31 30 30 1

-
-
-
- - - - -7.071065 -7.071065 0 7.071065 -7.071065 0 -7.071065 7.071065 0 7.071065 7.071065 0 - - - - - - - - - - 0 0 1 0 0 0.9999999 0 0 0.9999999 0 0 1 - - - - - - - - - - 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 1 0 1 1 0 - - - - - - - - - - - - - - - -

2 0 6 0 1 4 3 2 7 1 3 5 3 2 7 0 1 4

-
-
- - - - 14.14213 - 14.14213 - 1 - 1 - 1 - 1 - 1 - - - -
-
- - - - - 0 0 0 - - - - - - - - - - - 10 0 0 - - - - - - - - - - 1 - 1 - 1 - 1 - - - - - - - - - - - - - - 1 - 1 - 1 - 1 - - - - - 0 0 0.01 - 0 0 -1 -44.99999 - - - - - - - - - - 1 - 1 - 1 - 1 - - - - - - - - - 0 1.666667 3.333333 5 - - - - - - - - 10 -10 10 -10 - - - - - - - - -0.3332306 10 1.111167 -10 2.778333 10 4.4445 -9.219337 - - - - - - - - - 0.5555 10 2.222167 -10 3.888333 10 4.000208 -8.594958 - - - - - - - - - BEZIER BEZIER BEZIER BEZIER - - - - - - - - -0.8333334 0.8333334 2.5 4.166667 - - - - - - - - -10.05776 10.05852 -9.941484 10.05852 - - - - - - - - -1.166264 -10.05776 0.2778334 10.05852 1.9445 -9.941484 3.611667 10.05852 - - - - - - - - - -0.2783333 -10.05776 1.388833 10.05852 3.0555 -9.941484 4.499598 10.05852 - - - - - - - - - BEZIER BEZIER BEZIER BEZIER - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + bilbo + OpenCOLLADA for 3ds Max; Version: 1.6; Revision: 68 + file:///C:/cygwin/home/bilbo/d3d10/models/curve_interpolation/curve_interpolation.max + + 2026-01-25T13:40:01 + 2026-01-25T13:40:01 + + Z_UP + + + + + + + + 0 0 0 1 + + + 0.6705883 0.5843138 1 1 + + + 0.6705883 0.5843138 1 1 + + + 0 0 0 1 + + + 10 + + + 0 0 0 1 + + + 1 1 1 1 + + + 1 + + + + + + + + 0 + 0 + 0 + 1.5 + 1 + 0 + 0 + 0 + 3 + + + 1 + 1 + 0 + 0 + 0 + 0 + 0.1 + + + + + + + + + + 0 0 0 1 + + + 0.5803922 1 0.9647059 1 + + + 0.5803922 1 0.9647059 1 + + + 0 0 0 1 + + + 10 + + + 0 0 0 1 + + + 1 1 1 1 + + + 1 + + + + + + + + 0 + 0 + 0 + 1.5 + 1 + 0 + 0 + 0 + 3 + + + 1 + 1 + 0 + 0 + 0 + 0 + 0.1 + + + + + + + + + + 0 0 0 1 + + + 0.6509804 1 0.5803922 1 + + + 0.6509804 1 0.5803922 1 + + + 0 0 0 1 + + + 10 + + + 0 0 0 1 + + + 1 1 1 1 + + + 1 + + + + + + + + 0 + 0 + 0 + 1.5 + 1 + 0 + 0 + 0 + 3 + + + 1 + 1 + 0 + 0 + 0 + 0 + 0.1 + + + + + + + + + + 0 0 0 1 + + + 0.9333334 1 0.5647059 1 + + + 0.9333334 1 0.5647059 1 + + + 0 0 0 1 + + + 10 + + + 0 0 0 1 + + + 1 1 1 1 + + + 1 + + + + + + + + 0 + 0 + 0 + 1.5 + 1 + 0 + 0 + 0 + 3 + + + 1 + 1 + 0 + 0 + 0 + 0 + 0.1 + + + + + + + + + + 0 0 0 1 + + + 1 0.7686275 0.5803922 1 + + + 1 0.7686275 0.5803922 1 + + + 0 0 0 1 + + + 10 + + + 0 0 0 1 + + + 1 1 1 1 + + + 1 + + + + + + + + 0 + 0 + 0 + 1.5 + 1 + 0 + 0 + 0 + 3 + + + 1 + 1 + 0 + 0 + 0 + 0 + 0.1 + + + + + + + + + + 0 0 0 1 + + + 1 0.5803922 0.5803922 1 + + + 1 0.5803922 0.5803922 1 + + + 0 0 0 1 + + + 10 + + + 0 0 0 1 + + + 1 1 1 1 + + + 1 + + + + + + + + 0 + 0 + 0 + 1.5 + 1 + 0 + 0 + 0 + 3 + + + 1 + 1 + 0 + 0 + 0 + 0 + 0.1 + + + + + + + + + + 0.8980392 0.6039216 0.8431373 1 + + + 0.8980392 0.6039216 0.8431373 1 + + + 1 1 1 1 + + + 10 + + + 0 0 0 1 + + + 1 1 1 1 + + + 1 + + + + + + + + + + + 0.1098039 0.5843137 0.6941176 1 + + + 0.1098039 0.5843137 0.6941176 1 + + + 1 1 1 1 + + + 10 + + + 0 0 0 1 + + + 1 1 1 1 + + + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -0.5 -0.5 0 0.5 -0.5 0 -0.5 0.5 0 0.5 0.5 0 -0.5 -0.5 1 0.5 -0.5 1 -0.5 0.5 1 0.5 0.5 1 + + + + + + + + + + 0 0 -1 0 0 -1 0 0 -1 0 0 -1 0 0 1 0 0 1 0 0 1 0 0 1 0 -1 0 0 -1 0 0 -1 0 0 -1 0 1 0 0 1 0 0 1 0 0 1 0 0 0 1 0 0 1 0 0 1 0 0 1 0 -1 0 0 -1 0 0 -1 0 0 -1 0 0 + + + + + + + + + + 1 0 0 0 0 0 1 1 0 0 1 0 0 0 0 1 0 0 0 1 0 1 1 0 0 0 0 1 0 0 0 1 0 1 1 0 0 0 0 1 0 0 0 1 0 1 1 0 0 0 0 1 0 0 0 1 0 1 1 0 0 0 0 1 0 0 0 1 0 1 1 0 + + + + + + + + + + + + + + + +

0 0 0 2 1 2 3 2 3 3 2 3 1 3 1 0 0 0

+
+ + + + +

4 4 4 5 5 5 7 6 7 7 6 7 6 7 6 4 4 4

+
+ + + + +

0 8 8 1 9 9 5 10 11 5 10 11 4 11 10 0 8 8

+
+ + + + +

1 12 12 3 13 13 7 14 15 7 14 15 5 15 14 1 12 12

+
+ + + + +

3 16 16 2 17 17 6 18 19 6 18 19 7 19 18 3 16 16

+
+ + + + +

2 20 20 0 21 21 4 22 23 4 22 23 6 23 22 2 20 20

+
+
+
+ + + + 10 0 0 9.807853 1.950903 0 9.238795 3.826834 0 8.314696 5.555702 0 7.071068 7.071068 0 5.555702 8.314696 0 3.826834 9.238795 0 1.950904 9.807853 0 7.54979e-7 10 0 -1.950902 9.807853 0 -3.826833 9.238796 0 -5.555702 8.314696 0 -7.071068 7.071068 0 -8.314696 5.555702 0 -9.238796 3.826833 0 -9.807854 1.950901 0 -10 -3.25841e-6 0 -9.807852 -1.950907 0 -9.238793 -3.826839 0 -8.314693 -5.555707 0 -7.071063 -7.071073 0 -5.555696 -8.3147 0 -3.826827 -9.238798 0 -1.950894 -9.807855 0 9.65599e-6 -10 0 1.950913 -9.807851 0 3.826845 -9.238791 0 5.555712 -8.31469 0 7.071077 -7.071059 0 8.314704 -5.555691 0 9.238801 -3.826821 0 9.807856 -1.950888 0 + + + + + + + + + + 0 0 1 0 0 1 0 0 1 0 0 0.9999999 0 0 1 0 0 0.9999999 0 0 1 0 0 0.9999999 0 0 1 0 0 1 0 0 0.9999999 0 0 1 0 0 1 0 0 1 0 0 1 0 0 0.9999999 0 0 1 0 0 0.9999999 0 0 1 0 0 0.9999999 0 0 0.9999999 0 0 0.9999999 0 0 1 0 0 0.9999999 0 0 1 0 0 1 0 0 0.9999999 0 0 1 0 0 1 0 0 0.9999999 0 0 0.9999999 0 0 1 + + + + + + + + + + 0.5975444 0.9903928 -0.25 0.691341 0.9619401 -0.25 0.7777845 0.9157352 -0.25 0.8535529 0.8535539 -0.25 0.9157345 0.7777857 -0.25 0.9619396 0.6913422 -0.25 0.9903926 0.5975457 -0.25 1 0.5000005 -0.25 0.9903927 0.4024553 -0.25 0.9619399 0.3086587 -0.25 0.915735 0.2222152 -0.25 0.8535537 0.1464469 -0.25 0.7777854 0.08426532 -0.25 0.6913419 0.03806034 -0.25 0.5975454 0.009607404 -0.25 0.5000002 0 -0.25 0.402455 0.009607315 -0.25 0.3086584 0.03806019 -0.25 0.2222149 0.08426517 -0.25 0.1464466 0.1464466 -0.25 0.08426517 0.2222149 -0.25 0.03806019 0.3086583 -0.25 0.009607345 0.4024549 -0.25 0 0.5 -0.25 0.009607345 0.5975451 -0.25 0.03806022 0.6913417 -0.25 0.08426517 0.7777851 -0.25 0.1464466 0.8535534 -0.25 0.2222148 0.9157348 -0.25 0.3086582 0.9619398 -0.25 0.4024548 0.9903927 -0.25 0.5 1 -0.25 + + + + + + + + + + + + + + + +

0 0 31 1 1 30 2 2 29 2 2 29 3 3 28 4 4 27 0 0 31 2 2 29 4 4 27 4 4 27 5 5 26 6 6 25 6 6 25 7 7 24 8 8 23 4 4 27 6 6 25 8 8 23 0 0 31 4 4 27 8 8 23 8 8 23 9 9 22 10 10 21 10 10 21 11 11 20 12 12 19 8 8 23 10 10 21 12 12 19 12 12 19 13 13 18 14 14 17 14 14 17 15 15 16 16 16 15 12 12 19 14 14 17 16 16 15 8 8 23 12 12 19 16 16 15 0 0 31 8 8 23 16 16 15 16 16 15 17 17 14 18 18 13 18 18 13 19 19 12 20 20 11 16 16 15 18 18 13 20 20 11 20 20 11 21 21 10 22 22 9 22 22 9 23 23 8 24 24 7 20 20 11 22 22 9 24 24 7 16 16 15 20 20 11 24 24 7 0 0 31 16 16 15 24 24 7 24 24 7 25 25 6 26 26 5 26 26 5 27 27 4 28 28 3 24 24 7 26 26 5 28 28 3 0 0 31 24 24 7 28 28 3 28 28 3 29 29 2 30 30 1 0 0 31 28 28 3 30 30 1 31 31 0 0 0 31 30 30 1

+
+
+
+ + + + -7.071065 -7.071065 0 7.071065 -7.071065 0 -7.071065 7.071065 0 7.071065 7.071065 0 + + + + + + + + + + 0 0 1 0 0 0.9999999 0 0 0.9999999 0 0 1 + + + + + + + + + + 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 1 0 1 1 0 + + + + + + + + + + + + + + + +

2 0 6 0 1 4 3 2 7 1 3 5 3 2 7 0 1 4

+
+
+ + + + 14.14213 + 14.14213 + 1 + 1 + 1 + 1 + 1 + + + +
+
+ + + + + 0 0 0 + + + + + + + + + + + 10 0 0 + + + + + + + + + + + + + + + 1 + 1 + 1 + 1 + + + + + + + + + + + + + + 1 + 1 + 1 + 1 + + + + + 0 0 0.01 + 0 0 -1 -44.99999 + + + + + + + + + + 1 + 1 + 1 + 1 + + + + + + + + + 0 1.666667 3.333333 5 + + + + + + + + 10 -10 10 -10 + + + + + + + + -0.3332306 10 1.111167 -10 2.778333 10 4.4445 -9.219337 + + + + + + + + + 0.5555 10 2.222167 -10 3.888333 10 4.000208 -8.594958 + + + + + + + + + BEZIER BEZIER BEZIER BEZIER + + + + + + + + -0.8333334 0.8333334 2.5 4.166667 + + + + + + + + -10.05776 10.05852 -9.941484 10.05852 + + + + + + + + -1.166264 -10.05776 0.2778334 10.05852 1.9445 -9.941484 3.611667 10.05852 + + + + + + + + + -0.2783333 -10.05776 1.388833 10.05852 3.0555 -9.941484 4.499598 10.05852 + + + + + + + + + BEZIER BEZIER BEZIER BEZIER + + + + + + + + + + + + + + + + + + + + + + + + + + +
\ No newline at end of file diff --git a/models/curve_interpolation/curve_interpolation.idx b/models/curve_interpolation/curve_interpolation.idx new file mode 100644 index 0000000000000000000000000000000000000000..f1f1a855c6087d076e0b3f3c16ce03c06f4c405c GIT binary patch literal 528 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 literal 204800 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%0DfF&aDf+la?V3(>(?x*lCcGN6Rkn;@hf!2d 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 diff --git a/models/curve_interpolation/curve_interpolation.vtx b/models/curve_interpolation/curve_interpolation.vtx new file mode 100644 index 0000000000000000000000000000000000000000..76208f7089caa7f2277c5754f7c36c12e2877696 GIT binary patch literal 2160 zcmZ{kKWG#|6vh|Ak-J6<5e>P7(?X0O#6pZ{?sf?zAR=OUO(Y_SU?Cm>1<4Vuf>`*c z5X2N#k`x9phY)UW5h0Bhf`x4)O^gPg$>=$zmPt6SXE2CvYjHhfWV=x()i_5_bTQRq!&b7H6h{VK$2hj#=!Dq} z*OK?huuI#KFXPb7ViFC-*qGJf+{TOs_Of%!@O2yW)Lu!9fNo^i(KMsSW*rP;I-Z(S zBizZPbjh$w(^@uW>dIhJEcT&}jp?TybDiDJ?UVZ?W6?1&jj#=6xj_ji3LU!1vZnBI?jg3oI;UlV-)M*dm(WiV-& zt$Z#xzr2uQ{%%cG#_nAzKe=|*FoUBjKD(>av$3~)Yr1L}YEVlv)ERm>Km4sYW*Fwe zoHWCH3ah=t?|u&&<|JxjZJMD@=}O<}Mti?u-o7|<-1A(ItaqMa4mUcXtHZsh^8g;v z!%u6qR?*3adwIxb5+0F3T`jjR>aebJ@Q4h&Y5mV1dPD{qk?S*cs6j0<$R$EfzOJ3j zP3D4}$h6msQOP-X=KPp7p*Aw`CfYq$U37K2k~>##Zb0V(Jkktxmf-QY==30;@9;=7 z%x4*AH6Z!?L0wgNq#5e`z?q+wx(>mgQ|K-;g>UDm_%i~Hu0k$ynWy*$C&cF^BN!+&M4i^9H%Rmizt-ck2~Aa`Tx(O%w9pID%ZzeV2*n@jVl!r5Wy}=hSd@VkY*Q NtS~M8o;?d2`v +#include +#include + +#include "directxmath/directxmath.h" + +#include "print.hpp" +#include "collada_scene.hpp" + +extern ID3D10Device * g_pd3dDevice; +extern XMMATRIX g_View; +extern XMMATRIX g_Projection; + +namespace collada_scene { + using namespace collada; + + ID3D10Effect * g_pEffect = NULL; + ID3D10EffectTechnique * g_pTechniqueBlinn = NULL; + + ID3D10EffectMatrixVariable * g_pWorldVariable = NULL; + ID3D10EffectMatrixVariable * g_pViewVariable = NULL; + ID3D10EffectMatrixVariable * g_pProjectionVariable = NULL; + + static inline DXGI_FORMAT dxgi_format(input_format format) + { + switch (format) { + case input_format::FLOAT1: return DXGI_FORMAT_R32_FLOAT; + case input_format::FLOAT2: return DXGI_FORMAT_R32G32_FLOAT; + case input_format::FLOAT3: return DXGI_FORMAT_R32G32B32_FLOAT; + case input_format::FLOAT4: return DXGI_FORMAT_R32G32B32A32_FLOAT; + default: + assert(false); + } + } + + static inline int format_size(input_format format) + { + switch (format) { + case input_format::FLOAT1: return 1 * 4; + case input_format::FLOAT2: return 2 * 4; + case input_format::FLOAT3: return 3 * 4; + case input_format::FLOAT4: return 4 * 4; + default: + assert(false); + } + } + + HRESULT scene_state::load_vertex_buffer(LPCWSTR name) + { + HRESULT hr; + HRSRC hRes = FindResource(NULL, name, RT_RCDATA); + if (hRes == NULL) { + printW(L"FindResource %s\n", name); + return E_FAIL; + } + DWORD dwResSize = SizeofResource(NULL, hRes); + void * pData = LockResource(LoadResource(NULL, hRes)); + + D3D10_BUFFER_DESC bd; + D3D10_SUBRESOURCE_DATA initData; + + bd.Usage = D3D10_USAGE_IMMUTABLE; + bd.ByteWidth = dwResSize; + bd.BindFlags = D3D10_BIND_VERTEX_BUFFER; + bd.CPUAccessFlags = 0; + bd.MiscFlags = 0; + initData.pSysMem = pData; + hr = g_pd3dDevice->CreateBuffer(&bd, &initData, &pVertexBuffers[0]); + if (FAILED(hr)) { + print("CreateBuffer: D3D10_BIND_VERTEX_BUFFER\n"); + return hr; + } + + return S_OK; + } + + HRESULT scene_state::load_index_buffer(LPCWSTR name) + { + HRESULT hr; + HRSRC hRes = FindResource(NULL, name, RT_RCDATA); + if (hRes == NULL) { + printW(L"FindResource %s\n", name); + return E_FAIL; + } + DWORD dwResSize = SizeofResource(NULL, hRes); + void * pData = LockResource(LoadResource(NULL, hRes)); + + D3D10_BUFFER_DESC bd; + D3D10_SUBRESOURCE_DATA initData; + + bd.Usage = D3D10_USAGE_IMMUTABLE; + bd.ByteWidth = dwResSize; + bd.BindFlags = D3D10_BIND_VERTEX_BUFFER; + bd.CPUAccessFlags = 0; + bd.MiscFlags = 0; + initData.pSysMem = pData; + hr = g_pd3dDevice->CreateBuffer(&bd, &initData, &pIndexBuffer); + if (FAILED(hr)) { + print("CreateBuffer: D3D10_BIND_VERTEX_BUFFER\n"); + return hr; + } + + return S_OK; + } + + HRESULT scene_state::load_layout(int inputs_index, inputs const& inputs) + { + HRESULT hr; + + D3D10_INPUT_ELEMENT_DESC layout[inputs.elements_count]; + + int byte_offset = 0; + for (int i = 0; i < inputs.elements_count; i++) { + layout[i].SemanticName = inputs.elements[i].semantic; + layout[i].SemanticIndex = inputs.elements[i].semantic_index; + layout[i].Format = dxgi_format(inputs.elements[i].format); + layout[i].InputSlot = 0; + layout[i].AlignedByteOffset = byte_offset; + layout[i].InputSlotClass = D3D10_INPUT_PER_VERTEX_DATA; + layout[i].InstanceDataStepRate = 0; + + byte_offset += format_size(inputs.elements[i].format); + } + + D3D10_PASS_DESC passDesc; + g_pTechniqueBlinn->GetPassByIndex(0)->GetDesc(&passDesc); + + hr = g_pd3dDevice->CreateInputLayout(layout, inputs.elements_count, + passDesc.pIAInputSignature, + passDesc.IAInputSignatureSize, + &pVertexLayouts[inputs_index]); + if (FAILED(hr)) { + print("CreateInputLayout\n"); + return hr; + } + + return S_OK; + } + + template + T New(int elements) + { + return (T)malloc((sizeof (T)) * elements); + } + + HRESULT scene_state::load_layouts(descriptor const& descriptor) + { + HRESULT hr; + + //this->pVertexLayouts = new ID3D10InputLayout *[descriptor.inputs_list_count]; + this->pVertexLayouts = New(descriptor.inputs_list_count); + + for (int i = 0; i < descriptor.inputs_list_count; i++) { + hr = load_layout(i, descriptor.inputs_list[i]); + if (FAILED(hr)) + return hr; + } + + return S_OK; + } + + HRESULT LoadEffect() + { + HRESULT hr; + HRSRC hRes = FindResource(NULL, L"RES_COLLADA_SCENE_FXO", RT_RCDATA); + if (hRes == NULL) { + print("FindResource RES_COLLADA_SCENE_FXO\n"); + return E_FAIL; + } + DWORD dwResSize = SizeofResource(NULL, hRes); + HGLOBAL hData = LoadResource(NULL, hRes); + void * pData = LockResource(hData); + hr = D3D10CreateEffectFromMemory(pData, + dwResSize, + 0, + g_pd3dDevice, + NULL, + &g_pEffect + ); + if (FAILED(hr)) { + print("D3D10CreateEffectFromMemory\n"); + return hr; + } + + g_pTechniqueBlinn = g_pEffect->GetTechniqueByName("Blinn"); + + g_pWorldVariable = g_pEffect->GetVariableByName("World")->AsMatrix(); + g_pViewVariable = g_pEffect->GetVariableByName("View")->AsMatrix(); + g_pProjectionVariable = g_pEffect->GetVariableByName("Projection")->AsMatrix(); + + return S_OK; + } + + HRESULT LoadScene(descriptor const& descriptor, scene_state& state) + { + HRESULT hr; + + // effects/techniques + hr = LoadEffect(); + if (FAILED(hr)) + return E_FAIL; + + // layouts + hr = state.load_layouts(descriptor); + if (FAILED(hr)) + return E_FAIL; + + hr = state.load_vertex_buffer(L"RES_MODELS_CURVE_INTERPOLATION_VTX"); + if (FAILED(hr)) + return E_FAIL; + + hr = state.load_index_buffer(L"RES_MODELS_CURVE_INTERPOLATION_IDX"); + if (FAILED(hr)) + return E_FAIL; + + return S_OK; + } + + static inline XMMATRIX transform_matrix(transform const& transform) + { + switch (transform.type) { + case transform_type::TRANSLATE: + return XMMatrixTranslationFromVector(XMLoadFloat3((XMFLOAT3 *)&transform.translate.x)); + case transform_type::ROTATE: + return XMMatrixRotationNormal(XMLoadFloat3((XMFLOAT3 *)&transform.rotate.x), + XMConvertToRadians(transform.rotate.w)); + case transform_type::SCALE: + return XMMatrixScalingFromVector(XMLoadFloat3((XMFLOAT3 *)&transform.scale.x)); + default: + assert(false); + break; + } + } + + void RenderGeometries(scene_state const& state, + instance_geometry const * const instance_geometries, + int const instance_geometries_count) + { + for (int i = 0; i < instance_geometries_count; i++) { + instance_geometry const &instance_geometry = instance_geometries[i]; + + mesh const& mesh = instance_geometry.geometry->mesh; + + UINT strides[1] = { 3 * 3 * 4 }; + UINT offsets[1] = { (UINT)mesh.vertex_buffer_offset }; + g_pd3dDevice->IASetVertexBuffers(0, state.numBuffers, state.pVertexBuffers, strides, offsets); + g_pd3dDevice->IASetIndexBuffer(state.pIndexBuffer, DXGI_FORMAT_R32_UINT, mesh.index_buffer_offset); + + D3D10_TECHNIQUE_DESC techDesc; + g_pTechniqueBlinn->GetDesc(&techDesc); + + for (int j = 0; j < mesh.triangles_count; j++) { + triangles const& triangles = mesh.triangles[j]; + + g_pTechniqueBlinn->GetPassByIndex(0)->Apply(0); + g_pd3dDevice->IASetInputLayout(state.pVertexLayouts[triangles.inputs_index]); + g_pd3dDevice->DrawIndexed(triangles.count * 3, triangles.index_offset, 0); + } + } + } + + void Render(descriptor const& descriptor, scene_state const& state) + { + g_pViewVariable->SetMatrix((float *)&g_View); + g_pProjectionVariable->SetMatrix((float *)&g_Projection); + + g_pd3dDevice->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + + for (int i = 0; i < descriptor.nodes_count; i++) { + node const& node = *descriptor.nodes[i]; + if (node.type != node_type::NODE) + continue; + + XMMATRIX World = XMMatrixIdentity(); + // build the world transform + for (int j = 0; j < node.transforms_count; j++) { + transform const& transform = node.transforms[j]; + World = transform_matrix(transform) * World; + } + g_pWorldVariable->SetMatrix((float *)&World); + + RenderGeometries(state, node.instance_geometries, node.instance_geometries_count); + } + } +} diff --git a/src/effect/collada_scene.fx b/src/effect/collada_scene.fx new file mode 100644 index 0000000..8c8cbe0 --- /dev/null +++ b/src/effect/collada_scene.fx @@ -0,0 +1,67 @@ +cbuffer cbEveryFrame +{ + matrix View; + matrix Projection; +}; + +cbuffer cbMultiplePerFrame +{ + matrix World; +}; + +struct VS_INPUT +{ + float3 Pos : POSITION; + float3 Norm : NORMAL; + float2 Tex : TEXCOORD0; +}; + +struct PS_INPUT +{ + float4 Pos : SV_POSITION; + float3 Norm : NORMAL; + float2 Tex : TEXCOORD0; +}; + +PS_INPUT VS(VS_INPUT input) +{ + PS_INPUT output; + + output.Pos = mul(float4(input.Pos, 1), World); + output.Pos = mul(output.Pos, View); + output.Pos = mul(output.Pos, Projection); + + output.Norm = mul(input.Norm, (float3x3)World); + output.Tex = input.Tex; + + return output; +} + +float4 PS(PS_INPUT input) : SV_Target +{ + //return float4(input.Normal * 0.5 + 0.5, 1); + return float4(input.Tex.xy, 0, 1); +} + +BlendState DisableBlending +{ + BlendEnable[0] = FALSE; +}; + +DepthStencilState EnableDepth +{ + DepthEnable = TRUE; + DepthWriteMask = ALL; +}; + +technique10 Blinn +{ + pass P0 + { + SetVertexShader(CompileShader(vs_4_0, VS())); + SetGeometryShader(NULL); + SetPixelShader(CompileShader(ps_4_0, PS())); + SetBlendState(DisableBlending, float4(0.0, 0.0, 0.0, 0.0), 0xffffffff); + SetDepthStencilState(EnableDepth, 0); + } +} diff --git a/src/main.cpp b/src/main.cpp index f0f8d45..ad5a2da 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -18,6 +18,9 @@ #include "cube.hpp" #include "collada.hpp" +#include "collada_scene.hpp" + +#include "scenes/curve_interpolation.hpp" HINSTANCE g_hInstance = NULL; HWND g_hWnd = NULL; @@ -129,6 +132,10 @@ XMFLOAT4 g_vLightColors[2] = { XMVECTOR g_Eye = XMVectorSet(0.0f, -30.0f, 15.0f, 1.0f); XMVECTOR g_At = XMVectorSet(0.0f, 0.0f, 15.0f, 1.0f); +// collada scene state + +collada_scene::scene_state g_SceneState; + // forward declarations HRESULT InitWindow(HINSTANCE hInstance, int nCmdShow); @@ -197,6 +204,11 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLi return 0; } + if (FAILED(collada_scene::LoadScene(curve_interpolation::descriptor, g_SceneState))) { + print("collada::LoadScene\n"); + return 0; + } + InitializeNodeInstances(); if (FAILED(InitInput(hInstance))) { @@ -1827,7 +1839,9 @@ void Render(float t, float dt) RenderFont(dt); - collada::Render(t); + //collada::Render(t); + + collada_scene::Render(curve_interpolation::descriptor, g_SceneState); // present g_pSwapChain->Present(0, 0);