diff --git a/collada/header.py b/collada/header.py index aabaa49..3d0ddbb 100644 --- a/collada/header.py +++ b/collada/header.py @@ -61,7 +61,11 @@ class State: # effect_textures_by_texcoord: (effect_id, channel): [sampler_sid] effect_textures_by_texcoord: Dict[Tuple[str, str], list] - def __init__(self): + # input_filename + input_filename: str + relative_path: bool + + def __init__(self, input_filename): self.vertex_buffer = BytesIO() self.index_buffer = BytesIO() self.joints_weights_vertex_buffer = BytesIO() @@ -76,6 +80,8 @@ class State: self.image_indices = {} self.resource_names = {} self.effect_textures_by_texcoord = defaultdict(list) + self.input_filename = input_filename + self.relative_path = False def _sanitize(name): return name.replace(' ', '_').replace('-', '_').replace('.', '_').replace('/', '_') @@ -228,7 +234,7 @@ def render_node_transforms(state, collada, node_name, transformation_elements): yield "}," elif type(transform) is types.Matrix: yield ".type = transform_type::MATRIX," - yield f".matrix = {render_float_tuple(matrix_transpose(transform.matrix))}," + yield f".matrix = {render_float_tuple(matrix_transpose(transform.values))}," elif type(transform) is types.Rotate: yield ".type = transform_type::ROTATE," yield f".rotate = {render_float_tuple(transform.rotate)}," @@ -507,7 +513,7 @@ def render_library_visual_scenes(state, collada): for node_index, node in enumerate(state.linearized_nodes): node_name_id = get_node_name_id(node) node_name = sanitize_name(state, node_name_id, node) - yield f"&node_{node_name}," + yield f"&node_{node_name}, // {node_index}" yield "};" def render_header(namespace): @@ -852,9 +858,11 @@ def render_library_lights(state, collada): def image_resource_name(state, uri): uri = unquote(uri) - prefix = "file:///" - assert uri.startswith(prefix), uri - path = uri[len(prefix):] + file_prefix = "file:///" + path = uri[len(file_prefix):] if uri.startswith(file_prefix) else uri + if not os.path.isabs(path) and not os.path.exists(path): + path = os.path.join(os.path.dirname(state.input_filename), path) + state.relative_path = True assert os.path.exists(path), path image_extensions = {".png", ".jpg", ".bmp", ".jpeg", ".tiff"} assert os.path.splitext(path)[1].lower() in image_extensions, path @@ -959,14 +967,38 @@ def render_controller(state, collada, controller): yield "};" def render_library_controllers(state, collada): - for library_controller in collada.library_controllers: - for controller in library_controller.controllers: + for library_controllers in collada.library_controllers: + for controller in library_controllers.controllers: yield from render_controller(state, collada, controller) -def render_all(collada, namespace): - state = State() +def render_camera(state, collada, camera): + camera_name = sanitize_name(state, camera.id, camera) + perspective = camera.optics.technique_common.projection_type + assert type(perspective) is types.Perspective + def nf(f): + if f is None: + return float(0) + else: + return f + + yield f"camera const camera_{camera_name} = {{" + yield f".xfov = {nf(perspective.xfov)}f," + yield f".yfov = {nf(perspective.yfov)}f," + yield f".znear = {nf(perspective.znear)}f," + yield f".zfar = {nf(perspective.zfar)}f," + yield f".aspect_ratio = {nf(perspective.aspect_ratio)}f," + yield "};" + +def render_library_cameras(state, collada): + for library_cameras in collada.library_cameras: + for camera in library_cameras.cameras: + yield from render_camera(state, collada, camera) + +def render_all(collada, namespace, input_filename): + state = State(input_filename) render, out = renderer() render(render_header(namespace)) + render(render_library_cameras(state, collada)) render(render_library_lights(state, collada)) render(render_library_animations(state, collada)) render(render_library_images(state, collada)) @@ -996,5 +1028,5 @@ if __name__ == "__main__": import sys collada = parse.parse_collada_file(sys.argv[1]) - state, out = render_all(collada, "test") + state, out = render_all(collada, "test", "./test.DAE") print(out.getvalue()) diff --git a/collada/main.py b/collada/main.py index f2fcdfe..efca245 100644 --- a/collada/main.py +++ b/collada/main.py @@ -65,7 +65,7 @@ def main(): collada = parse.parse_collada_file(input_collada) namespace = parse_namespace(input_collada) - state, out_source = header.render_all(collada, namespace) + state, out_source = header.render_all(collada, namespace, input_collada) with open(output_source, 'wb') as f: source_buf = out_source.getvalue() diff --git a/collada/parse.py b/collada/parse.py index e3b70c6..2564e55 100644 --- a/collada/parse.py +++ b/collada/parse.py @@ -649,12 +649,7 @@ def parse_matrix(lookup, sid_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]) - - matrix = types.Matrix(sid, tuple([r0, r1, r2, r3])) + matrix = types.Matrix(sid, values) lookup_add(sid_lookup, sid, matrix) return matrix @@ -1022,6 +1017,85 @@ def parse_library_controllers(lookup, root): lookup_add(lookup, id, library_controllers) return library_controllers +def parse_perspective(lookup, root): + xfov = None + yfov = None + znear = None + zfar = None + aspect_ratio = None + for child in root.getchildren(): + assert len(child.getchildren()) == 0 + if child.tag == tag("xfov"): + assert xfov is None + xfov = float(child.text.strip()) + if child.tag == tag("yfov"): + assert yfov is None + yfov = float(child.text.strip()) + if child.tag == tag("znear"): + assert znear is None + znear = float(child.text.strip()) + if child.tag == tag("zfar"): + assert zfar is None + zfar = float(child.text.strip()) + if child.tag == tag("aspect_ratio"): + assert aspect_ratio is None + aspect_ratio = float(child.text.strip()) + perspective = types.Perspective(xfov, yfov, znear, zfar, aspect_ratio) + return perspective + +def parse_technique_common_optics(lookup, root): + projection_type = None + for child in root.getchildren(): + if child.tag == tag("perspective"): + assert projection_type is None + projection_type = parse_perspective(lookup, child) + if child.tag == tag("orthographic"): + assert projection_type is None + assert False, child.tag + assert projection_type is not None + optics = types.TechniqueCommon_Optics(projection_type) + return optics + +def parse_optics(lookup, root): + technique_common = None + for child in root.getchildren(): + if child.tag == tag("technique_common"): + assert technique_common is None + technique_common = parse_technique_common_optics(lookup, child) + assert technique_common is not None + optics = types.Optics(technique_common) + return optics + +def parse_camera(lookup, root): + id = root.attrib.get("id") + name = root.attrib.get("name") + + optics = None + for child in root.getchildren(): + if child.tag == tag("optics"): + assert optics is None + optics = parse_optics(lookup, child) + + assert optics is not None + camera = types.Camera(id, name, optics) + lookup_add(lookup, id, camera) + return camera + +def parse_library_cameras(lookup, root): + id = root.attrib.get("id") + name = root.attrib.get("name") + + cameras = [] + for child in root.getchildren(): + if child.tag == tag("camera"): + cameras.append(parse_camera(lookup, child)) + + assert len(cameras) >= 1 + + library_cameras = types.LibraryCameras(id, name, cameras) + lookup_add(lookup, id, library_cameras) + return library_cameras + def parse_collada(tree): root = tree.getroot() assert root.tag == tag("COLLADA") @@ -1030,6 +1104,8 @@ def parse_collada(tree): lookup = {} for child in root.getchildren(): + if child.tag == tag("library_cameras"): + collada.library_cameras.append(parse_library_cameras(lookup, child)) if child.tag == tag("library_animations"): collada.library_animations.append(parse_library_animations(lookup, child)) if child.tag == tag("library_controllers"): diff --git a/collada/types.py b/collada/types.py index d53d9b4..bf5216d 100644 --- a/collada/types.py +++ b/collada/types.py @@ -519,8 +519,39 @@ class LibraryAnimations: animations: List[Animation] # 1 or more +@dataclass(frozen=True) +class Perspective: + xfov: float + yfov: float + znear: float + zfar: float + aspect_ratio: float + +@dataclass(frozen=True) +class TechniqueCommon_Optics: + projection_type: Union[Perspective] + +@dataclass(frozen=True) +class Optics: + technique_common: TechniqueCommon_Optics + +@dataclass(frozen=True) +class Camera: + id: Optional[ID] + name: Optional[str] + + optics: Optics + +@dataclass(frozen=True) +class LibraryCameras: + id: Optional[ID] + name: Optional[str] + + cameras: List[Camera] # 1 or more + @dataclass class Collada: + library_cameras: List[LibraryCameras] library_animations: List[LibraryAnimations] library_controllers: List[LibraryControllers] library_effects: List[LibraryEffects] @@ -533,6 +564,7 @@ class Collada: _lookup: dict = field(repr=False) def __init__(self): + self.library_cameras = [] self.library_animations = [] self.library_controllers = [] self.library_effects = [] diff --git a/include/collada_types.hpp b/include/collada_types.hpp index 85db681..20f1c2f 100644 --- a/include/collada_types.hpp +++ b/include/collada_types.hpp @@ -349,6 +349,14 @@ namespace collada { }; */ + struct camera { + float xfov; + float yfov; + float znear; + float zfar; + float aspect_ratio; + }; + ////////////////////////////////////////////////////////////////////// // scene ////////////////////////////////////////////////////////////////////// diff --git a/src/scenes/curve_interpolation/curve_interpolation.cpp b/src/scenes/curve_interpolation/curve_interpolation.cpp index 957950c..351be58 100644 --- a/src/scenes/curve_interpolation/curve_interpolation.cpp +++ b/src/scenes/curve_interpolation/curve_interpolation.cpp @@ -543,15 +543,15 @@ float const array_node_bone002_rotationz_angle_input_array[] = { }; float const array_node_bone002_rotationz_angle_output_array[] = { - 180.0f + 180.0f, - 230.0f + 180.0f, - 180.0f + 180.0f, - 130.0f + 180.0f, - 180.0f + 180.0f, - 230.0f + 180.0f, - 180.0f + 180.0f, - 130.0f + 180.0f, - 180.0f + 180.0f, + 180.0f, + 230.0f, + 180.0f, + 130.0f, + 180.0f, + 230.0f, + 180.0f, + 130.0f, + 180.0f, }; float const array_node_bone002_rotationz_angle_intangent_array[] = { @@ -1660,6 +1660,15 @@ instance_material const instance_geometry_instance_materials_node_cube_0[] = { .diffuse = { .input_set = -1 }, .specular = { .input_set = -1 }, }, + { + .element_index = 5, // an index into mesh.triangles + .material = &material_material__17_material, + + .emission = { .input_set = -1 }, + .ambient = { .input_set = -1 }, + .diffuse = { .input_set = -1 }, + .specular = { .input_set = -1 }, + }, { .element_index = 0, // an index into mesh.triangles .material = &material_material__16_material, @@ -1678,15 +1687,6 @@ instance_material const instance_geometry_instance_materials_node_cube_0[] = { .diffuse = { .input_set = -1 }, .specular = { .input_set = -1 }, }, - { - .element_index = 5, // an index into mesh.triangles - .material = &material_material__17_material, - - .emission = { .input_set = -1 }, - .ambient = { .input_set = -1 }, - .diffuse = { .input_set = -1 }, - .specular = { .input_set = -1 }, - }, { .element_index = 2, // an index into mesh.triangles .material = &material_material__19_material, @@ -2044,8 +2044,8 @@ instance_light const instance_lights_node_light[] = { }; channel const * const node_channels_node_light[] = { - &node_channel_node_light_translation_y, &node_channel_node_light_translation_x, + &node_channel_node_light_translation_y, }; node const node_node_light = { @@ -2139,15 +2139,6 @@ int const joint_node_indices_node_box001_geom_box001_skin1[] = { }; instance_material const instance_controller_instance_materials_node_box001_0[] = { - { - .element_index = 0, // an index into mesh.triangles - .material = &material_material__14_material, - - .emission = { .input_set = -1 }, - .ambient = { .input_set = -1 }, - .diffuse = { .input_set = -1 }, - .specular = { .input_set = -1 }, - }, { .element_index = 1, // an index into mesh.triangles .material = &material_material__13_material, @@ -2166,6 +2157,15 @@ instance_material const instance_controller_instance_materials_node_box001_0[] = .diffuse = { .input_set = -1 }, .specular = { .input_set = -1 }, }, + { + .element_index = 0, // an index into mesh.triangles + .material = &material_material__14_material, + + .emission = { .input_set = -1 }, + .ambient = { .input_set = -1 }, + .diffuse = { .input_set = -1 }, + .specular = { .input_set = -1 }, + }, { .element_index = 3, // an index into mesh.triangles .material = &material_material__16_1_material, @@ -2328,17 +2328,17 @@ node const node_node_bone002 = { }; node const * const nodes[] = { - &node_node_environmentambientlight, - &node_node_cube, - &node_node_torus, - &node_node_cylinder, - &node_node_plane, - &node_node_geosphere, - &node_node_light, - &node_node_lightindicator, - &node_node_box001, - &node_node_bone001, - &node_node_bone002, + &node_node_environmentambientlight, // 0 + &node_node_cube, // 1 + &node_node_torus, // 2 + &node_node_cylinder, // 3 + &node_node_plane, // 4 + &node_node_geosphere, // 5 + &node_node_light, // 6 + &node_node_lightindicator, // 7 + &node_node_box001, // 8 + &node_node_bone001, // 9 + &node_node_bone002, // 10 }; inputs const inputs_list[] = {