From b4cd67d748c497d5c92da480a5336d3cdb9a32dc Mon Sep 17 00:00:00 2001 From: Lila <87947656+Lilaa3@users.noreply.github.com> Date: Mon, 22 Apr 2024 17:19:27 +0100 Subject: [PATCH] assumed bone count --- fast64_internal/sm64/animation/classes.py | 13 +++- fast64_internal/sm64/animation/importing.py | 73 +++++++++++++++----- fast64_internal/sm64/animation/operators.py | 37 +++++----- fast64_internal/sm64/animation/properties.py | 43 ++++++++---- 4 files changed, 116 insertions(+), 50 deletions(-) diff --git a/fast64_internal/sm64/animation/classes.py b/fast64_internal/sm64/animation/classes.py index 6de6c8f74..3ea5ef9bc 100644 --- a/fast64_internal/sm64/animation/classes.py +++ b/fast64_internal/sm64/animation/classes.py @@ -235,7 +235,12 @@ def to_binary( # 0x18 return data - def read_binary(self, header_reader: RomReading, is_dma: bool = False): + def read_binary( + self, + header_reader: RomReading, + is_dma: bool = False, + assumed_bone_count: int | None = None, + ): self.reference = header_reader.address self.flags = header_reader.read_value(2, signed=False) # /*0x00*/ s16 flags; self.trans_divisor = header_reader.read_value(2) # /*0x02*/ s16 animYTransDivisor; @@ -243,7 +248,9 @@ def read_binary(self, header_reader: RomReading, is_dma: bool = False): self.loop_start = header_reader.read_value(2) # /*0x06*/ s16 loopStart; self.loop_end = header_reader.read_value(2) # /*0x08*/ s16 loopEnd; # Unused in engine but makes it easy to read animation data - self.bone_count = header_reader.read_value(2) # /*0x0A*/ s16 unusedBoneCount; + # /*0x0A*/ s16 unusedBoneCount; + bone_count = header_reader.read_value(2) + self.bone_count = bone_count if bone_count is not None else assumed_bone_count # /*0x0C*/ const s16 *values; # /*0x10*/ const u16 *index; @@ -499,7 +506,7 @@ def to_binary(self, is_dma: bool = False, start_address: int = 0): if anim_header.data: ptrs.extend([start_address + len(data) + 12, start_address + len(data) + 16]) indice_offset = indice_tables_offset + sum( -len(indice_table.data) * 2 for indice_table in indice_tables[: data_set.index(anim_header.data)] + len(indice_table.data) * 2 for indice_table in indice_tables[: data_set.index(anim_header.data)] ) data.extend( anim_header.to_binary( diff --git a/fast64_internal/sm64/animation/importing.py b/fast64_internal/sm64/animation/importing.py index eca245e6e..6c4a2e692 100644 --- a/fast64_internal/sm64/animation/importing.py +++ b/fast64_internal/sm64/animation/importing.py @@ -13,7 +13,15 @@ from ..sm64_constants import insertableBinaryTypes from .utility import RomReading, get_anim_pose_bones, sm64_to_radian -from .classes import SM64_DMATable, DMATableEntrie, SM64_Anim, SM64_AnimData, SM64_AnimHeader, SM64_AnimPair, SM64_AnimTable +from .classes import ( + SM64_DMATable, + DMATableEntrie, + SM64_Anim, + SM64_AnimData, + SM64_AnimHeader, + SM64_AnimPair, + SM64_AnimTable, +) from .c_parser import CParser, EnumIndexedValue, Initialization @@ -238,24 +246,25 @@ def import_binary_header( header_reader: RomReading, is_dma: bool, animations: dict[str, SM64_Anim], + assumed_bone_count: int | None = None, ): print(f"Reading binary header at address {hex(header_reader.address)}") header = SM64_AnimHeader() - header.read_binary(header_reader, is_dma) + header.read_binary(header_reader=header_reader, is_dma=is_dma, assumed_bone_count=assumed_bone_count) data_key = f"{header.indice_reference}-{header.values_reference}" if data_key in animations: anim = animations[data_key] else: anim = SM64_Anim() - # if header.indice_reference < len(data) and header.values_reference < len(data): + # TODO: if header.indice_reference < len(data) and header.values_reference < len(data): if True: anim.data = SM64_AnimData() anim.data.read_binary( - header_reader.branch(header.indice_reference), - header_reader.branch(header.values_reference), - header.bone_count, - ) # Add suport for using the bone ocunt in the selected armature + indices_reader=header_reader.branch(header.indice_reference), + values_reader=header_reader.branch(header.values_reference), + bone_count=header.bone_count, + ) animations[data_key] = anim header.header_variant = len(anim.headers) @@ -268,7 +277,8 @@ def import_binary_dma_animation( dma_table_reader: RomReading, animations: dict[str, SM64_Anim], table: SM64_AnimTable, - table_index: int|None = None, + table_index: int | None = None, + assumed_bone_count: int | None = None, ) -> SM64_AnimHeader | None: dma_table = SM64_DMATable() dma_table.read_binary(dma_table_reader) @@ -277,12 +287,22 @@ def import_binary_dma_animation( raise PluginError(f"Index {table_index} outside of defined table ({len(dma_table.entries)} entries).") entrie: DMATableEntrie = dma_table.entries[table_index] - header = import_binary_header(dma_table_reader.branch(entrie.address), True, animations) + header = import_binary_header( + header_reader=dma_table_reader.branch(entrie.address), + is_dma=True, + animations=animations, + assumed_bone_count=assumed_bone_count, + ) table.elements.append(header) return header else: for entrie in dma_table.entries: - header = import_binary_header(dma_table_reader.branch(entrie.address), True, animations) + header = import_binary_header( + header_reader=dma_table_reader.branch(entrie.address), + is_dma=True, + animations=animations, + assumed_bone_count=assumed_bone_count, + ) table.elements.append(header) @@ -291,7 +311,8 @@ def import_binary_table( animations: dict[str, SM64_Anim], table: SM64_AnimTable, ignore_null: bool, - table_index: int|None = None, + table_index: int | None = None, + assumed_bone_count: int | None = None, ): for i in range(255): ptr = table_reader.read_ptr() @@ -302,7 +323,12 @@ def import_binary_table( is_correct_index = i == table_index if table_index is None or is_correct_index: - header = import_binary_header(table_reader.branch(ptr), False, animations) + header = import_binary_header( + header_reader=table_reader.branch(ptr), + is_dma=False, + animations=animations, + assumed_bone_count=assumed_bone_count, + ) table.elements.append(header) if table_index is not None and is_correct_index: @@ -315,9 +341,10 @@ def import_binary_animations( data_reader: RomReading, import_type: str, animations: dict[str, SM64_Anim], - table: SM64_AnimTable, - table_index: int|None = None, + table_index: int | None = None, ignore_null: bool = False, + assumed_bone_count: int | None = None, + table: SM64_AnimTable = SM64_AnimTable(), ): if import_type == "Table": import_binary_table( @@ -326,6 +353,7 @@ def import_binary_animations( table=table, table_index=table_index, ignore_null=ignore_null, + assumed_bone_count=assumed_bone_count, ) elif import_type == "DMA": import_binary_dma_animation( @@ -333,9 +361,15 @@ def import_binary_animations( animations=animations, table=table, table_index=table_index, + assumed_bone_count=assumed_bone_count, ) elif import_type == "Animation": - import_binary_header(data_reader, False, animations) + import_binary_header( + header_reader=data_reader, + is_dma=False, + animations=animations, + assumed_bone_count=assumed_bone_count, + ) else: raise PluginError("Unimplemented binary import type.") @@ -345,6 +379,7 @@ def import_insertable_binary_animations( animations: dict[str, SM64_Anim], table_index: int = 0, ignore_null: bool = False, + assumed_bone_count: int | None = None, table: SM64_AnimTable = SM64_AnimTable(), ): data_type_num = insertable_data_reader.read_value(4, signed=False) @@ -367,7 +402,12 @@ def import_insertable_binary_animations( data_type = next(key for key, value in insertableBinaryTypes.items() if value == data_type_num) if data_type == "Animation": - import_binary_header(data_reader, False, animations) + import_binary_header( + header_reader=data_reader, + is_dma=False, + animations=animations, + assumed_bone_count=assumed_bone_count, + ) elif data_type == "Animation Table": import_binary_table( table_reader=data_reader, @@ -375,6 +415,7 @@ def import_insertable_binary_animations( table=table, table_index=table_index, ignore_null=ignore_null, + assumed_bone_count=assumed_bone_count, ) else: raise PluginError(f'Wrong animation data type "{data_type}".') diff --git a/fast64_internal/sm64/animation/operators.py b/fast64_internal/sm64/animation/operators.py index cd197a019..60e358f6b 100644 --- a/fast64_internal/sm64/animation/operators.py +++ b/fast64_internal/sm64/animation/operators.py @@ -44,11 +44,7 @@ update_table_file, write_anim_header, ) -from .utility import ( - animation_operator_checks, - eval_num_from_str, - get_action, -) +from .utility import animation_operator_checks, eval_num_from_str, get_action, get_anim_pose_bones from .constants import marioAnimationNames from typing import TYPE_CHECKING @@ -452,9 +448,9 @@ def execute_operator(self, context: Context): table_props.update_table, ) elif sm64_props.export_type == "Insertable Binary": - #data, ptrs = animation.to_binary(export_props.is_binary_dma, 0) - #path = abspath(export_props.insertable_path) - #writeInsertableFile(path, 2, ptrs, 0, data) + # data, ptrs = animation.to_binary(export_props.is_binary_dma, 0) + # path = abspath(export_props.insertable_path) + # writeInsertableFile(path, 2, ptrs, 0, data) pass else: raise PluginError(f"Unimplemented export type ({sm64_props.export_type})") @@ -546,6 +542,8 @@ def execute_operator(self, context): import_props: SM64_AnimImportProps = sm64_props.anim_import table_props: SM64_AnimTableProps = export_props.table + armature_obj: Object = context.selected_objects[0] + animations: dict[str, SM64_Anim] = {} table = SM64_AnimTable() @@ -560,6 +558,9 @@ def execute_operator(self, context): else: rom_data, segment_data = None, None + anim_bones = get_anim_pose_bones(armature_obj) + assumed_bone_count = len(anim_bones) if import_props.assume_bone_count else None + if import_props.import_type == "Binary": address = eval_num_from_str( import_props.dma_table_address if import_props.binary_import_type == "DMA" else import_props.address @@ -567,29 +568,33 @@ def execute_operator(self, context): if import_props.binary_import_type != "DMA" and import_props.is_segmented_address: address = decodeSegmentedAddr(address.to_bytes(4, "big"), segment_data) import_binary_animations( - data_reader=RomReading(data=rom_data, start_address=address, rom_data=rom_data, segment_data=segment_data), + data_reader=RomReading( + data=rom_data, start_address=address, rom_data=rom_data, segment_data=segment_data + ), import_type=import_props.binary_import_type, animations=animations, table_index=None if import_props.read_entire_table else import_props.mario_or_table_index, ignore_null=import_props.ignore_null, table=table, + assumed_bone_count=assumed_bone_count, ) elif import_props.import_type == "Insertable Binary": - insertable_path = abspath(import_props.insertable_path) - filepath_checks(insertable_path) + path = abspath(import_props.path) + filepath_checks(path) - with open(insertable_path, "rb") as insertable_file: + with open(path, "rb") as insertable_file: import_insertable_binary_animations( insertable_data_reader=RomReading(insertable_file.read(), 0, None, rom_data, segment_data), animations=animations, table=table, table_index=None if import_props.read_entire_table else import_props.mario_or_table_index, ignore_null=import_props.ignore_null, + assumed_bone_count=assumed_bone_count, ) elif import_props.import_type == "C": - c_path = abspath(import_props.c_path) - path_checks(c_path) - import_c_animations(c_path, animations, table) + path = abspath(import_props.path) + path_checks(path) + import_c_animations(path, animations, table) for data in animations.values(): animation_import_to_blender( @@ -600,7 +605,7 @@ def execute_operator(self, context): import_props.remove_name_footer, import_props.use_custom_name, ) - sm64_props.anim_export.table.from_anim_table_class(table) + table_props.from_anim_table_class(table) self.report({"INFO"}, "Success!") return {"FINISHED"} diff --git a/fast64_internal/sm64/animation/properties.py b/fast64_internal/sm64/animation/properties.py index ae0b30a9a..68309c944 100644 --- a/fast64_internal/sm64/animation/properties.py +++ b/fast64_internal/sm64/animation/properties.py @@ -419,7 +419,9 @@ def to_data_class( file_name: str = "anim_00.inc.c", ): data = SM64_AnimData() - pairs = get_animation_pairs(blender_to_sm64_scale, action.fast64.sm64.get_max_frame(action), action, armature_obj, quick_read) + pairs = get_animation_pairs( + blender_to_sm64_scale, action.fast64.sm64.get_max_frame(action), action, armature_obj, quick_read + ) data_name: str = toAlnum(f"anim_{action.name}") values_reference = f"{data_name}_values" indice_reference = f"{data_name}_indices" @@ -1229,6 +1231,11 @@ class SM64_AnimImportProps(PropertyGroup): default="Animation", ) + assume_bone_count: BoolProperty( + name="Assume Bone Count", + description="When enabled, the selected armature's bone count will be used instead of the header's, " + "as old fast64 binary exports did no export this value", + ) address: StringProperty(name="Address", default="0600FC48") is_segmented_address: BoolProperty(name="Is Segmented Address") level: EnumProperty(items=level_enums, name="Level", default="IC") @@ -1242,10 +1249,15 @@ class SM64_AnimImportProps(PropertyGroup): dma_table_address: StringProperty(name="DMA Table Address", default="0x4EC000") mario_animation: IntProperty(name="Selected Preset Mario Animation") - c_path: StringProperty( + insertable_read_from_rom: BoolProperty( + name="Read From Import ROM", + description="When enabled, the importer will read from the import ROM given a non defined address", + ) + + path: StringProperty( name="Path", subtype="FILE_PATH", - default="U:/home/user/sm64/assets/anims/", + default="anims/", ) remove_name_footer: BoolProperty( name="Remove Name Footers", @@ -1257,12 +1269,6 @@ class SM64_AnimImportProps(PropertyGroup): default=False, ) - insertable_path: StringProperty(name="Path", subtype="FILE_PATH") - insertable_read_from_rom: BoolProperty( - name="Read From Import ROM", - description="When enabled, the importer will read from the import ROM given a non defined address", - ) - @property def mario_or_table_index(self): return ( @@ -1273,8 +1279,7 @@ def mario_or_table_index(self): def draw_c(self, layout: UILayout): col = layout.column() - prop_split(col, self, "c_path", "Path") - path_ui_warnings(col, abspath(self.c_path)) + col.prop(self, "remove_name_footer") col.prop(self, "use_custom_name") @@ -1307,9 +1312,8 @@ def draw_binary(self, layout: UILayout): def draw_insertable_binary(self, layout: UILayout): col = layout.column() - prop_split(col, self, "insertable_path", "Path") - path_ui_warnings(col, abspath(self.insertable_path)) - col.label(text="Type will be read from the data type of the files", icon="INFO") + + col.label(text="Type will be read from the data type of the files") col.separator() read_from_rom_box = col.box().column() @@ -1329,6 +1333,12 @@ def draw_insertable_binary(self, layout: UILayout): def draw_props(self, layout: UILayout, binary_col_enabled: bool = True): col = layout.column() prop_split(col, self, "import_type", "Type") + col.separator() + + if self.import_type in {"C", "Insertable Binary"}: + prop_split(col, self, "path", "Path") + col.label(text="Folders and individual files are supported as the path", icon="INFO") + path_ui_warnings(col, abspath(self.path)) if self.import_type == "C": self.draw_c(col) @@ -1339,9 +1349,12 @@ def draw_props(self, layout: UILayout, binary_col_enabled: bool = True): elif self.import_type == "Insertable Binary": self.draw_insertable_binary(col) + if self.import_type in {"Binary", "Insertable Binary"}: + col.prop(self, "assume_bone_count") + col.separator() col.operator(SM64_ImportAnim.bl_idname, icon="IMPORT") - if self.import_type not in {"Binary", "C"}: + if self.import_type in {"Binary", "C"}: col.operator(SM64_ImportAllMarioAnims.bl_idname, icon="IMPORT")