# SPDX-FileCopyrightText: © 2025 ZeldaRET # SPDX-License-Identifier: CC0-1.0 from typing import TYPE_CHECKING from ..oot64_data.misc_ids import SKIN_LIMB_TYPES if TYPE_CHECKING: from ..extase.memorymap import MemoryContext from ..extase.cdata_resources import ( CDataResource, CDataArrayResource, CDataExt_Value, CDataExt_Struct, CDataExtWriteContext, cdata_ext_Vec3s, ) from . import dlist_resources from . import skeleton_resources class SkinVertexArrayResource(CDataArrayResource): elem_cdata_ext = CDataExt_Struct( ( ("index", CDataExt_Value.u16), ("s", CDataExt_Value.s16), ("t", CDataExt_Value.s16), ("normX", CDataExt_Value.s8), ("normY", CDataExt_Value.s8), ("normZ", CDataExt_Value.s8), ("alpha", CDataExt_Value.u8), ) ) def get_c_declaration_base(self): return f"SkinVertex {self.symbol_name}[]" def get_h_includes(self): return ("skin.h",) class SkinTransformationArrayResource(CDataArrayResource): elem_cdata_ext = CDataExt_Struct( ( ("limbIndex", CDataExt_Value.u8), ("pad1", CDataExt_Value.pad8), ("x", CDataExt_Value.s16), ("y", CDataExt_Value.s16), ("z", CDataExt_Value.s16), ("scale", CDataExt_Value.u8), ("pad9", CDataExt_Value.pad8), ) ) def get_c_declaration_base(self): return f"SkinTransformation {self.symbol_name}[]" def get_h_includes(self): return ("skin.h",) class SkinLimbModifArrayResource(CDataArrayResource): def report_elem(resource, memory_context: "MemoryContext", v): assert isinstance(v, dict) address = v["skinVertices"] assert isinstance(address, int) skin_vertices_res = memory_context.report_resource_at_segmented( resource, address, SkinVertexArrayResource, lambda file, offset: SkinVertexArrayResource( file, offset, f"{resource.name}_{offset:08X}_SkinVertices", ), ) skin_vertices_res.set_length(v["vtxCount"]) address = v["limbTransformations"] assert isinstance(address, int) skin_vertices_res = memory_context.report_resource_at_segmented( resource, address, SkinTransformationArrayResource, lambda file, offset: SkinTransformationArrayResource( file, offset, f"{resource.name}_{offset:08X}_SkinTransforms", ), ) skin_vertices_res.set_length(v["transformCount"]) def write_skinVertices( resource, memory_context: "MemoryContext", v, wctx: CDataExtWriteContext ): assert isinstance(v, int) address = v wctx.f.write(wctx.line_prefix) wctx.f.write(memory_context.get_c_reference_at_segmented(address)) return True def write_limbTransformations( resource, memory_context: "MemoryContext", v, wctx: CDataExtWriteContext ): assert isinstance(v, int) address = v wctx.f.write(wctx.line_prefix) wctx.f.write(memory_context.get_c_reference_at_segmented(address)) return True elem_cdata_ext = CDataExt_Struct( ( ("vtxCount", CDataExt_Value.u16), ("transformCount", CDataExt_Value.u16), ("unk_4", CDataExt_Value.u16), ("pad6", CDataExt_Value.pad16), ( "skinVertices", (CDataExt_Value("I").set_write(write_skinVertices)), ), # SkinVertex* ( "limbTransformations", (CDataExt_Value("I").set_write(write_limbTransformations)), ), # SkinTransformation* ) ).set_report(report_elem) def get_c_declaration_base(self): return f"SkinLimbModif {self.symbol_name}[]" def get_h_includes(self): return ("skin.h",) class SkinAnimatedLimbDataResource(CDataResource): def report_limbModifications(resource, memory_context: "MemoryContext", v): assert isinstance(v, int) address = v skin_vertices_res = memory_context.report_resource_at_segmented( resource, address, SkinLimbModifArrayResource, lambda file, offset: SkinLimbModifArrayResource( file, offset, f"{resource.name}_{offset:08X}_SkinLimbModifs", ), ) skin_vertices_res.set_length(resource.cdata_unpacked["limbModifCount"]) def write_limbModifications( resource, memory_context: "MemoryContext", v, wctx: CDataExtWriteContext ): assert isinstance(v, int) address = v wctx.f.write(wctx.line_prefix) wctx.f.write(memory_context.get_c_reference_at_segmented(address)) return True cdata_ext = CDataExt_Struct( ( ("totalVtxCount", CDataExt_Value.u16), ("limbModifCount", CDataExt_Value.u16), ( "limbModifications", ( CDataExt_Value("I") .set_report(report_limbModifications) .set_write(write_limbModifications) ), ), # SkinLimbModif* ("dlist", dlist_resources.cdata_ext_gfx_segmented), ) ) def get_c_declaration_base(self): return f"SkinAnimatedLimbData {self.symbol_name}" def get_c_reference(self, resource_offset: int): if resource_offset == 0: return f"&{self.symbol_name}" else: raise ValueError() def get_h_includes(self): return ("skin.h",) class SkinLimbResource(CDataResource): def report_segment(resource, memory_context: "MemoryContext", v): assert isinstance(v, int) address = v segmentType = resource.cdata_unpacked["segmentType"] if segmentType == 4: # SKIN_LIMB_TYPE_ANIMATED # segment is SkinAnimatedLimbData* assert address != 0 memory_context.report_resource_at_segmented( resource, address, SkinAnimatedLimbDataResource, lambda file, offset: SkinAnimatedLimbDataResource( file, offset, f"{resource.name}_{address:08X}_SkinAnimatedLimbData" ), ) elif segmentType == 11: # SKIN_LIMB_TYPE_NORMAL # segment is Gfx* assert address != 0 dlist_resources.report_gfx_segmented(resource, memory_context, address) def write_segment( resource, memory_context: "MemoryContext", v, wctx: CDataExtWriteContext ): assert isinstance(v, int) address = v wctx.f.write(wctx.line_prefix) if address == 0: wctx.f.write("NULL") else: wctx.f.write(memory_context.get_c_reference_at_segmented(address)) return True cdata_ext = CDataExt_Struct( ( ("jointPos", cdata_ext_Vec3s), ( "child", CDataExt_Value("B").set_write( skeleton_resources.StandardLimbResource.write_limb_index ), ), ( "sibling", CDataExt_Value("B").set_write( skeleton_resources.StandardLimbResource.write_limb_index ), ), ( "segmentType", CDataExt_Value("i").set_write_str_v( lambda v: SKIN_LIMB_TYPES.get(v, f"{v}") ), ), ( "segment", CDataExt_Value("I").set_report(report_segment).set_write(write_segment), ), ) ) def __init__(self, file, range_start, name): super().__init__(file, range_start, name) self.enum_member_name = f"LIMB_{file.name.upper()}_{range_start:06X}" def set_enum_member_name(self, enum_member_name: str): self.enum_member_name = enum_member_name def get_c_declaration_base(self): return f"SkinLimb {self.symbol_name}" def get_c_reference(self, resource_offset: int): if resource_offset == 0: return f"&{self.symbol_name}" else: raise ValueError() def get_h_includes(self): return ("skin.h",) class SkinLimbsArrayResource(skeleton_resources.LimbsArrayResourceABC): limb_type = SkinLimbResource c_limb_type = "SkinLimb" class SkeletonSkinResource(skeleton_resources.SkeletonResourceABC): limbs_array_type = SkinLimbsArrayResource