From 6c0bb1fe12cc7dec9b37a2ecf50d2bca7ce691e1 Mon Sep 17 00:00:00 2001 From: Zack Buhman Date: Tue, 31 Mar 2026 13:03:07 -0500 Subject: [PATCH] collada: use collada::types namespace --- collada/buffer.py | 2 +- collada/cpp_header.py | 36 +++++++++++++++++++----------- collada/generate.py | 2 +- collada/header.py | 39 +++++++++++++++++++++----------- collada/lua_header.py | 6 ++++- collada/main.py | 52 ++++++++++++++++++++++--------------------- collada/parse.py | 14 ++++-------- collada/types.py | 7 ++++-- 8 files changed, 92 insertions(+), 66 deletions(-) diff --git a/collada/buffer.py b/collada/buffer.py index 363a4fd..089bba8 100644 --- a/collada/buffer.py +++ b/collada/buffer.py @@ -8,7 +8,7 @@ from collada import parse from collada import types from collada.util import find_semantics -STD430 = True +STD430 = False def linearize_offset_table(by_offset, p_stride): for offset in range(p_stride): diff --git a/collada/cpp_header.py b/collada/cpp_header.py index 600d1ed..79d8f1f 100644 --- a/collada/cpp_header.py +++ b/collada/cpp_header.py @@ -151,13 +151,17 @@ def render_node_instance_controllers(node_name, items): yield "}," yield "};" -def render_node(node_name, parent_index, type, +def render_node(node_name, + original_node_name, + parent_index, type, transforms_count, instance_geometries_count, instance_controllers_count, instance_lights_count, channels_count): yield f"node const node_{node_name} = {{" + yield f'.name = "{original_node_name}",' + yield "" yield f".parent_index = {parent_index}," yield "" yield f".type = node_type::{type}," @@ -227,9 +231,9 @@ def render_input_elements_list(items): yield "};" def render_descriptor(namespace): - yield f"extern collada::descriptor const descriptor;" + yield f"extern collada::types::descriptor const descriptor;" yield "" - yield "collada::descriptor const descriptor = {" + yield "collada::types::descriptor const descriptor = {" yield ".nodes = nodes," yield ".nodes_count = (sizeof (nodes)) / (sizeof (nodes[0]))," yield "" @@ -239,17 +243,19 @@ def render_descriptor(namespace): yield ".images = images," yield ".images_count = (sizeof (images)) / (sizeof (images[0]))," yield "" - yield f'.position_normal_texture_buffer = L"RES_SCENES_{namespace.upper()}_VTX",' - yield f'.joint_weight_buffer = L"RES_SCENES_{namespace.upper()}_VJW",' - yield f'.index_buffer = L"RES_SCENES_{namespace.upper()}_IDX",' + yield f'.position_normal_texture_buffer = "data/scenes/{namespace}/{namespace}.vtx",' + yield f'.joint_weight_buffer = "data/scenes/{namespace}/{namespace}.vjw",' + yield f'.index_buffer = "data/scenes/{namespace}/{namespace}.idx",' yield "};" def render_prelude(namespace): - yield '#include "collada_types.hpp"' + yield '#include "collada/types.h"' + yield '' + yield f'#include "data/scenes/{namespace}.h"' yield '' yield f'namespace {namespace} {{' yield '' - yield 'using namespace collada;' + yield 'using namespace collada::types;' def render_prologue(): yield "}" @@ -269,7 +275,8 @@ def render_interpolation_array(array_name, names): def render_float_array(array_name, vectors): yield f"float const array_{array_name}[] = {{" for vector in vectors: - yield f"{render_float_tuple(vector)}," + s = ", ".join((f"{float(f)}" for f in vector)) + yield f"{s}," yield "};" def render_source(source_name, field_name, c_type, array_name, count, stride): @@ -295,13 +302,13 @@ def render_channel(target_name, sampler_name, transform_index, target_attribute) def render_light(light_name, light_type, color): yield f"light const light_{light_name} = {{" yield f".type = light_type::{light_type}," - yield f".color = {{ {render_float_tuple(color)} }}," + yield f".color = {render_float_tuple(color)}," yield "};" def render_image(image_id, image_name, resource_name, uri): yield f"// {image_id}" yield f"image const image_{image_name} = {{" - yield f'.resource_name = L"{resource_name}",' + yield f'.uri = "{uri}",' yield "};" def render_library_images(image_names): @@ -318,11 +325,14 @@ def render_inverse_bind_matrices(controller_name, matrices): yield "}," yield "};" -def render_controller(controller_name, geometry_name, vertex_buffer_offset, vertex_buffer_size): +def render_controller(controller_name, geometry_name, bind_shape_matrix, vertex_buffer_offset, vertex_buffer_size): yield f"controller const controller_{controller_name} = {{" yield ".skin = {" yield f".geometry = &geometry_{geometry_name}," yield "" + yield ".bind_shape_matrix = {" + yield from render_matrix(bind_shape_matrix) + yield "}," yield f".inverse_bind_matrices = inverse_bind_matrices_{controller_name}," yield "" yield f".vertex_buffer_offset = {vertex_buffer_offset}," @@ -341,5 +351,5 @@ def render_camera(camera_name, xfov, yfov, znear, zfar, aspect_ratio): def render_hpp(namespace): yield f"namespace {namespace} {{" - yield "extern collada::descriptor const descriptor;" + yield "extern collada::types::descriptor const descriptor;" yield "}" diff --git a/collada/generate.py b/collada/generate.py index 7a6df86..44a9353 100644 --- a/collada/generate.py +++ b/collada/generate.py @@ -1,6 +1,6 @@ import io -line_ending = "\r\n" +line_ending = "\n" def should_autonewline(line): return ( diff --git a/collada/header.py b/collada/header.py index 0708db2..2c3011c 100644 --- a/collada/header.py +++ b/collada/header.py @@ -235,7 +235,10 @@ def shader_to_input_set(channel_to_input_set, shader, op): if type(shader) is types.Constant: return -1 - shader_op = op(shader) + try: + shader_op = op(shader) + except AttributeError: + return -1 if type(shader_op) is types.Color: return -1 @@ -347,7 +350,7 @@ def find_node_index(state, node): if other is node: return other_index -def render_joint_node_indices(state, collada, skin, node_name, controller_name, skeleton_node): +def render_joint_node_indices(state, collada, skin, node_name, controller_name, skeleton_nodes): joint_input, = find_semantics(skin.joints.inputs, "JOINT") joint_source = collada.lookup(joint_input.source, types.SourceCore) stride = joint_source.technique_common.accessor.stride @@ -359,7 +362,13 @@ def render_joint_node_indices(state, collada, skin, node_name, controller_name, def items(): for node_sid in array.names: - joint_node = find_node_by_sid(skeleton_node, node_sid); + joint_node = None + for skeleton_node in skeleton_nodes: + _node = find_node_by_sid(skeleton_node, node_sid) + if _node is not None: + assert joint_node is None + joint_node = _node + assert joint_node is not None, (node_sid, skeleton_node.sid_lookup) joint_node_index = find_node_index(state, joint_node) joint_node_name_id = get_node_name_id(joint_node) @@ -373,9 +382,11 @@ def render_node_instance_controller_joint_node_indices(state, collada, node_name controller_name = sanitize_name(state, controller.id, controller) assert type(controller.control_element) is types.Skin skin = controller.control_element - skeleton_node = collada.lookup(instance_controller.skeleton, types.Node) + skeleton_nodes = [] + for skeleton_id in instance_controller.skeleton: + skeleton_nodes.append(collada.lookup(skeleton_id, types.Node)) - yield from render_joint_node_indices(state, collada, skin, node_name, controller_name, skeleton_node) + yield from render_joint_node_indices(state, collada, skin, node_name, controller_name, skeleton_nodes) def render_node_instance_controllers(state, collada, node_name, instance_controllers): for i, instance_controller in enumerate(instance_controllers): @@ -420,12 +431,14 @@ def render_node(state, collada, node, node_index): instance_lights_count = len(node.instance_lights) channels_count = len(state.node_animation_channels[node.id]) - yield from lang_header.render_node(node_name, parent_index, type, - transforms_count, - instance_geometries_count, - instance_controllers_count, - instance_lights_count, - channels_count) + yield from lang_header.render_node(node_name, + node.name, + parent_index, type, + transforms_count, + instance_geometries_count, + instance_controllers_count, + instance_lights_count, + channels_count) def traverse_node(state, parent_node_index, node): assert parent_node_index < len(state.linearized_nodes) @@ -847,8 +860,8 @@ def render_controller(state, collada, controller): vertex_buffer_size = state.joint_weight_vertex_buffer.tell() - vertex_buffer_offset yield from render_inverse_bind_matrices(collada, skin, controller_name) - - yield from lang_header.render_controller(controller_name, geometry_name, vertex_buffer_offset, vertex_buffer_size) + bind_shape_matrix = matrix_transpose(skin.bind_shape_matrix.values) + yield from lang_header.render_controller(controller_name, geometry_name, bind_shape_matrix, vertex_buffer_offset, vertex_buffer_size) def render_library_controllers(state, collada): for library_controllers in collada.library_controllers: diff --git a/collada/lua_header.py b/collada/lua_header.py index 3bb05be..990a42b 100644 --- a/collada/lua_header.py +++ b/collada/lua_header.py @@ -151,13 +151,17 @@ def render_node_instance_controllers(node_name, items): yield "}," yield "}" -def render_node(node_name, parent_index, type, +def render_node(node_name, + original_node_name, + parent_index, type, transforms_count, instance_geometries_count, instance_controllers_count, instance_lights_count, channels_count): yield f"ns.node_{node_name} = {{" + yield f'name = "{original_node_name}",' + yield "" yield f"parent_index = {parent_index}," yield "" yield f"type = collada_types.node_type.{type}," diff --git a/collada/main.py b/collada/main.py index 36d377b..411a04b 100644 --- a/collada/main.py +++ b/collada/main.py @@ -9,24 +9,24 @@ from collada import lua_header def usage(): name = sys.argv[0] print("usage (source):") - print(f" {name} [input_collada.dae] [output_source.cpp] [output_position_normal_texture.vtx] [output_joint_weight.vjw] [output_index.idx] [output_resource.rc] [output_makefile.mk]") + print(f" {name} [input_collada.dae] [output_source.cpp] [output_position_normal_texture.vtx] [output_joint_weight.vjw] [output_index.idx]") # [output_resource.rc] [output_makefile.mk] print("usage (header):") - print(f" {name} [output_header.hpp]") + print(f" {name} [output_header.h]") sys.exit(1) def parse_namespace(filename): namespace = os.path.splitext(os.path.split(filename)[1])[0] - return namespace + return namespace.replace("-", "_") def render_resource_file(state, namespace, output_vtx, output_vjw, output_idx, f): - f.write(f'RES_SCENES_{namespace.upper()}_VTX RCDATA "{output_vtx}"\r\n'.encode('ascii')) - f.write(f'RES_SCENES_{namespace.upper()}_VJW RCDATA "{output_vjw}"\r\n'.encode('ascii')) - f.write(f'RES_SCENES_{namespace.upper()}_IDX RCDATA "{output_idx}"\r\n'.encode('ascii')) - f.write(b"\r\n") + f.write(f'RES_SCENES_{namespace.upper()}_VTX RCDATA "{output_vtx}"\n'.encode('ascii')) + f.write(f'RES_SCENES_{namespace.upper()}_VJW RCDATA "{output_vjw}"\n'.encode('ascii')) + f.write(f'RES_SCENES_{namespace.upper()}_IDX RCDATA "{output_idx}"\n'.encode('ascii')) + f.write(b"\n") for resource_name, path in state.resource_names.items(): filename = os.path.split(path)[1] filename = os.path.splitext(filename)[0] - f.write(f'{resource_name} RCDATA "image/{filename}.DDS"\r\n'.encode('ascii')) + f.write(f'{resource_name} RCDATA "image/{filename}.DDS"\n'.encode('ascii')) def escape_space(s): def _escape_space(s): @@ -45,12 +45,12 @@ def render_makefile(state, f): escaped = escape_space(path) escaped_dds = os.path.splitext(filename) - f.write(f"IMAGES += image/{filename}.DDS\r\n".encode('ascii')) - f.write(f"image/{filename}.DDS: {escaped}\r\n".encode('ascii')) - f.write(f"\t@mkdir -p image\r\n".encode('ascii')) - f.write('\ttexconv10.exe -f BC1_UNORM -nologo "$<"\r\n'.encode('ascii')) - f.write(f'\tmv "$(<:.{ext[1:]}=.DDS)" "$@"\r\n'.encode('ascii')) - f.write(b"\r\n") + f.write(f"IMAGES += image/{filename}.DDS\n".encode('ascii')) + f.write(f"image/{filename}.DDS: {escaped}\n".encode('ascii')) + f.write(f"\t@mkdir -p image\n".encode('ascii')) + f.write('\ttexconv10.exe -f BC1_UNORM -nologo "$<"\n'.encode('ascii')) + f.write(f'\tmv "$(<:.{ext[1:]}=.DDS)" "$@"\n'.encode('ascii')) + f.write(b"\n") def main(): try: @@ -59,15 +59,15 @@ def main(): output_position_normal_texture = sys.argv[3] output_joint_weight = sys.argv[4] output_index = sys.argv[5] - output_resource = sys.argv[6] - output_makefile = sys.argv[7] + #output_resource = sys.argv[6] + #output_makefile = sys.argv[7] assert input_collada.lower().endswith(".dae") assert output_source.lower().endswith(".cpp") or output_source.lower().endswith(".lua") assert output_position_normal_texture.lower().endswith(".vtx") assert output_joint_weight.lower().endswith(".vjw") assert output_index.lower().endswith(".idx") - assert output_resource.lower().endswith(".rc") - assert output_makefile.lower().endswith(".mk") + #assert output_resource.lower().endswith(".rc") + #assert output_makefile.lower().endswith(".mk") except Exception as e: usage() @@ -84,7 +84,7 @@ def main(): with open(output_source, 'wb') as f: source_buf = out_source.getvalue() - assert "\r\n" in source_buf + assert "\n" in source_buf f.write(source_buf.encode('utf-8')) with open(output_position_normal_texture, 'wb') as f: @@ -96,25 +96,27 @@ def main(): with open(output_joint_weight, 'wb') as f: f.write(state.joint_weight_vertex_buffer.getvalue()) - with open(output_resource, 'wb') as f: - render_resource_file(state, namespace, output_position_normal_texture, output_joint_weight, output_index, f) + #with open(output_resource, 'wb') as f: + # render_resource_file(state, namespace, output_position_normal_texture, output_joint_weight, output_index, f) - with open(output_makefile, 'wb') as f: - render_makefile(state, f) + #with open(output_makefile, 'wb') as f: + # render_makefile(state, f) def main_header(): try: output_header = sys.argv[1] - assert output_header.lower().endswith(".hpp") + assert output_header.lower().endswith(".h") except Exception as e: usage() + header.lang_header = cpp_header + namespace = parse_namespace(output_header) out_header = header.render_all_hpp(namespace) with open(output_header, 'wb') as f: header_buf = out_header.getvalue() - assert "\r\n" in header_buf + assert "\n" in header_buf f.write(header_buf.encode('utf-8')) if __name__ == "__main__": diff --git a/collada/parse.py b/collada/parse.py index 2564e55..ccf86f4 100644 --- a/collada/parse.py +++ b/collada/parse.py @@ -492,7 +492,7 @@ def parse_geometry(lookup, root): geometric_element = parse_mesh(lookup, child) if child.tag == tag("spline"): assert child.tag, False - assert geometric_element is not None + assert geometric_element is not None, root.getchildren() geometry = types.Geometry(id, name, geometric_element) lookup_add(lookup, id, geometry) @@ -614,7 +614,7 @@ def parse_library_images(lookup, root): if child.tag == tag("image"): images.append(parse_image(lookup, child)) - assert len(images) >= 1 + #assert len(images) >= 1 library_images = types.LibraryImages(id, name, images) lookup_add(lookup, id, library_images) @@ -743,7 +743,7 @@ def parse_instance_controller(lookup, sid_lookup, root): name = root.attrib.get("name") url = root.attrib["url"] - skeleton = None + skeleton = [] bind_material = None for child in root.getchildren(): @@ -751,9 +751,8 @@ def parse_instance_controller(lookup, sid_lookup, root): assert bind_material is None bind_material = parse_bind_material(lookup, child) if child.tag == tag("skeleton"): - assert skeleton is None assert len(child.getchildren()) == 0 - skeleton = child.text.strip() + skeleton.append(child.text.strip()) instance_controller = types.InstanceController(sid, name, url, skeleton, bind_material) lookup_add(sid_lookup, sid, instance_controller) @@ -921,11 +920,6 @@ def parse_bind_shape_matrix(lookup, root): values = [float(i) for i in root.text.strip().split()] assert len(values) == 16 - r0 = tuple(values[0:4]) - r1 = tuple(values[4:8]) - r2 = tuple(values[8:12]) - r3 = tuple(values[12:16]) - values = tuple([r0, r1, r2, r3]) return types.BindShapeMatrix(values) def parse_joints(lookup, root): diff --git a/collada/types.py b/collada/types.py index bf5216d..5972972 100644 --- a/collada/types.py +++ b/collada/types.py @@ -418,7 +418,7 @@ class InstanceController: name: Optional[str] url: URI # controller id - skeleton: URI # node id + skeleton: List[URI] # node id bind_material: Optional[BindMaterial] @dataclass(frozen=True) @@ -457,7 +457,10 @@ class LibraryVisualScenes: class BindShapeMatrix: # it is written in row-major order in the COLLADA document for # human readability. - values: Tuple[Float4, Float4, Float4, Float4] + values: Tuple[float, float, float, float, + float, float, float, float, + float, float, float, float, + float, float, float, float] @dataclass(frozen=True) class Joints: