diff --git a/tools/assets/extract/extase/cdata_resources.py b/tools/assets/extract/extase/cdata_resources.py index acce03a70b..7cc290425c 100644 --- a/tools/assets/extract/extase/cdata_resources.py +++ b/tools/assets/extract/extase/cdata_resources.py @@ -394,3 +394,11 @@ class S16ArrayResource(CDataResource): return f"ARRAY_COUNT({self.symbol_name})" else: raise ValueError() + +cdata_ext_Vec3f = CDataExt_Struct( + ( + ("x", CDataExt_Value.f32), + ("y", CDataExt_Value.f32), + ("z", CDataExt_Value.f32), + ) +) diff --git a/tools/assets/extract/extase_oot64/skelanime_legacy_resources.py b/tools/assets/extract/extase_oot64/skelanime_legacy_resources.py new file mode 100644 index 0000000000..72c6e42ce4 --- /dev/null +++ b/tools/assets/extract/extase_oot64/skelanime_legacy_resources.py @@ -0,0 +1,206 @@ +import io +from typing import TYPE_CHECKING + +from ..extase import RESOURCE_PARSE_SUCCESS + +if TYPE_CHECKING: + from ..extase.memorymap import MemoryContext + +from ..extase.cdata_resources import ( + CDataResource, + CDataArrayResource, + CDataExt_Struct, + cdata_ext_Vec3f, + cdata_ext_Vec3s, + CDataExt_Value, +) + +from . import animation_resources +from . import dlist_resources +from . import skeleton_resources + + +class LegacyLimbResource(CDataResource): + + def report_limb(resource, memory_context: "MemoryContext", v): + assert isinstance(v, int) + address = v + if address != 0: + memory_context.report_resource_at_segmented( + resource, + address, + LegacyLimbResource, + lambda file, offset: LegacyLimbResource( + file, + offset, + f"{resource.name}_{address:08X}_LegacyLimb", + ), + ) + + def write_limb( + resource, memory_context: "MemoryContext", v, f: io.TextIOBase, line_prefix + ): + assert isinstance(v, int) + address = v + f.write(line_prefix) + if address == 0: + f.write("NULL") + else: + f.write(memory_context.get_c_reference_at_segmented(address)) + return True + + cdata_ext = CDataExt_Struct( + ( + ("dList", dlist_resources.cdata_ext_gfx_segmented), + ("trans", cdata_ext_Vec3f), + ("rot", cdata_ext_Vec3s), + ("pad16", CDataExt_Value.pad16), + ( + "sibling", + CDataExt_Value("I").set_report(report_limb).set_write(write_limb), + ), # LegacyLimb* + ( + "child", + CDataExt_Value("I").set_report(report_limb).set_write(write_limb), + ), # LegacyLimb* + ) + ) + + def get_c_declaration_base(self): + return f"LegacyLimb {self.symbol_name}" + + def get_c_reference(self, resource_offset: int): + if resource_offset == 0: + return f"&{self.symbol_name}" + else: + raise ValueError() + + +class LegacyJointKeyArrayResource(CDataArrayResource): + elem_cdata_ext = CDataExt_Struct( + ( + ("xMax", CDataExt_Value.s16), + ("x", CDataExt_Value.s16), + ("yMax", CDataExt_Value.s16), + ("y", CDataExt_Value.s16), + ("zMax", CDataExt_Value.s16), + ("z", CDataExt_Value.s16), + ) + ) + + def get_c_declaration_base(self): + return f"LegacyJointKey {self.symbol_name}[]" + + def get_c_reference(self, resource_offset: int): + if resource_offset == 0: + return f"{self.symbol_name}" + else: + raise ValueError() + + +class LegacyAnimationResource(CDataResource): + + def write_frameData( + resource, memory_context: "MemoryContext", v, f: io.TextIOBase, line_prefix + ): + assert isinstance(v, int) + address = v + f.write(line_prefix) + f.write(memory_context.get_c_reference_at_segmented(address)) + return True + + def write_jointKey( + resource, memory_context: "MemoryContext", v, f: io.TextIOBase, line_prefix + ): + assert isinstance(v, int) + address = v + f.write(line_prefix) + f.write(memory_context.get_c_reference_at_segmented(address)) + return True + + cdata_ext = CDataExt_Struct( + ( + ("frameCount", CDataExt_Value.s16), + ("limbCount", CDataExt_Value.s16), + ("frameData", CDataExt_Value("I").set_write(write_frameData)), # s16* + ( + "jointKey", + CDataExt_Value("I").set_write(write_jointKey), + ), # LegacyJointKey* + ) + ) + + def try_parse_data(self, memory_context): + super().try_parse_data(memory_context) + + address_frameData = self.cdata_unpacked["frameData"] + assert isinstance(address_frameData, int) + resource_frameData = memory_context.report_resource_at_segmented( + self, + address_frameData, + animation_resources.AnimationFrameDataResource, + lambda file, offset: animation_resources.AnimationFrameDataResource( + file, + offset, + f"{self.name}_{address_frameData:08X}_FrameData", + ), + ) + + address_jointKey = self.cdata_unpacked["jointKey"] + assert isinstance(address_jointKey, int) + resource_jointKey = memory_context.report_resource_at_segmented( + self, + address_jointKey, + LegacyJointKeyArrayResource, + lambda file, offset: LegacyJointKeyArrayResource( + file, + offset, + f"{self.name}_{address_jointKey:08X}_JointKeys", + ), + ) + resource_jointKey.set_length(self.cdata_unpacked["limbCount"] + 1) + + # The length of the frameData array is + # for now assumed to fill the space to the jointKey data, + # at the very least before subtracting the offsets check that + # the offsets belong to the same file + # TODO better idea for computing this data's size + + if not (resource_frameData.file == resource_jointKey.file): + raise NotImplementedError( + "Expected frameData and jointIndices to be in the same file", + self.cdata_unpacked, + resource_frameData.file, + resource_jointKey.file, + ) + + if ( + resource_frameData.range_start + < resource_jointKey.range_start + ): + resource_frameData.length = ( + resource_jointKey.range_start - resource_frameData.range_start + ) // animation_resources.AnimationFrameDataResource.elem_cdata_ext.size + else: + raise NotImplementedError( + "Expected offsets of frameData, jointKey to be in order", + self.cdata_unpacked, + hex(resource_frameData.range_start), + hex(resource_jointKey.range_start), + ) + + return RESOURCE_PARSE_SUCCESS + + def get_c_declaration_base(self): + return f"LegacyAnimationHeader {self.symbol_name}" + + def get_c_reference(self, resource_offset: int): + if resource_offset == 0: + return f"&{self.symbol_name}" + else: + raise ValueError() + + +class LegacyLimbsArrayResource(skeleton_resources.LimbsArrayResourceABC): + limb_type = LegacyLimbResource + c_limb_type = "LegacyLimb" diff --git a/tools/assets/extract/z64_resource_handlers.py b/tools/assets/extract/z64_resource_handlers.py index 335354cb6a..f90e969fda 100644 --- a/tools/assets/extract/z64_resource_handlers.py +++ b/tools/assets/extract/z64_resource_handlers.py @@ -22,6 +22,7 @@ from .extase_oot64 import ( misc_resources, scene_rooms_resources, scene_commands_resource, + skelanime_legacy_resources, ) @@ -55,23 +56,6 @@ class ResourceNeedsPostProcessWithPoolResourcesException(ResourceHandlerExceptio ResourceHandler = Callable[[File, ResourceDesc], Resource] -# Returns a dummy resource_handler that produces a `BinaryBlobResource` of the given size -# This is meant as a "placeholder resource" until a resource is properly implemented -def get_fixed_size_resource_handler(size) -> ResourceHandler: - def resource_handler( - file: File, - resource_desc: ResourceDesc, - ): - return BinaryBlobResource( - file, - resource_desc.offset, - resource_desc.offset + size, - resource_desc.symbol_name, - ) - - return resource_handler - - def register_resource_handlers(): def skeleton_resource_handler( @@ -157,10 +141,8 @@ def register_resource_handlers(): file, offset, resource_desc.symbol_name ) elif resource_desc.limb_type == z64resources.LimbType.LEGACY: - # TODO LegacyLimbResource - # } LegacyLimb; // size = 0x20 - return BinaryBlobResource( - file, offset, offset + 0x20, resource_desc.symbol_name + return skelanime_legacy_resources.LegacyLimbResource( + file, offset, resource_desc.symbol_name ) elif resource_desc.limb_type == z64resources.LimbType.CURVE: res = skelcurve_resources.SkelCurveLimbResource( @@ -200,13 +182,13 @@ def register_resource_handlers(): resource.set_length(resource_desc.count) return resource elif resource_desc.limb_type == z64resources.LimbType.LEGACY: - # TODO LegacyLimbsArrayResource - return BinaryBlobResource( + resource = skelanime_legacy_resources.LegacyLimbsArrayResource( file, resource_desc.offset, - resource_desc.offset + 4, resource_desc.symbol_name, ) + resource.set_length(resource_desc.count) + return resource else: raise NotImplementedError("LimbTable of limb type", resource_desc.limb_type) @@ -430,6 +412,14 @@ def register_resource_handlers(): resource.set_length(resource_desc.num_paths) return resource + def legacy_animation_handler( + file: File, + resource_desc: z64resources.LegacyAnimationResourceDesc, + ): + return skelanime_legacy_resources.LegacyAnimationResource( + file, resource_desc.offset, resource_desc.symbol_name + ) + RESOURCE_HANDLERS.update( { z64resources.SkeletonResourceDesc: skeleton_resource_handler, @@ -446,9 +436,7 @@ def register_resource_handlers(): z64resources.PlayerAnimationResourceDesc: PlayerAnimation_handler, n64resources.BlobResourceDesc: binary_blob_resource_handler, n64resources.MtxResourceDesc: Mtx_handler, - z64resources.LegacyAnimationResourceDesc: get_fixed_size_resource_handler( - 0xC - ), # TODO + z64resources.LegacyAnimationResourceDesc: legacy_animation_handler, z64resources.LimbTableResourceDesc: limb_table_handler, z64resources.CurveAnimationResourceDesc: CurveAnimation_handler, z64resources.SceneResourceDesc: scene_resource_handler,