1
0
Fork 0
mirror of https://github.com/zeldaret/oot.git synced 2025-05-10 19:13:42 +00:00
oot/tools/assets/extract/z64_resource_handlers.py
2025-02-10 12:02:14 +01:00

467 lines
16 KiB
Python

from typing import Callable
from ..descriptor.base import ResourceDesc
from ..descriptor import n64resources
from ..descriptor import z64resources
from .extase import (
File,
Resource,
BinaryBlobResource,
)
from .extase.cdata_resources import Vec3sArrayResource, S16ArrayResource
from .extase_oot64 import (
skeleton_resources,
skeleton_skin_resources,
animation_resources,
collision_resources,
dlist_resources,
playeranim_resources,
skelcurve_resources,
misc_resources,
scene_rooms_resources,
scene_commands_resource,
skelanime_legacy_resources,
)
#
# resource handlers
#
class ResourceHandlerException(Exception): ...
class ResourceNeedsPostProcessWithPoolResourcesException(ResourceHandlerException):
def __init__(
self,
*args,
resource: Resource,
callback: Callable[[dict[ResourceDesc, Resource]], None],
):
super().__init__(*args)
self.resource = resource
self.callback = callback
def __repr__(self) -> str:
return (
super().__repr__().removesuffix(")")
+ f", resource={self.resource!r}"
+ f", callback={self.callback!r})"
)
ResourceHandler = Callable[[File, ResourceDesc], Resource]
def register_resource_handlers():
def skeleton_resource_handler(
file: File,
resource_desc: z64resources.SkeletonResourceDesc,
):
offset = resource_desc.offset
if resource_desc.limb_type == z64resources.LimbType.STANDARD:
if resource_desc.type == z64resources.SkeletonType.NORMAL:
res = skeleton_resources.SkeletonNormalResource(
file,
offset,
resource_desc.symbol_name,
)
elif resource_desc.type == z64resources.SkeletonType.FLEX:
res = skeleton_resources.SkeletonFlexResource(
file,
offset,
resource_desc.symbol_name,
)
else:
raise NotImplementedError(
"unimplemented SkeletonType",
resource_desc.type,
)
elif resource_desc.limb_type == z64resources.LimbType.LOD:
if resource_desc.type == z64resources.SkeletonType.NORMAL:
res = skeleton_resources.SkeletonNormalLODResource(
file, offset, resource_desc.symbol_name
)
elif resource_desc.type == z64resources.SkeletonType.FLEX:
res = skeleton_resources.SkeletonFlexLODResource(
file, offset, resource_desc.symbol_name
)
else:
raise NotImplementedError(
"LimbType=LOD",
"unimplemented SkeletonType",
resource_desc.type,
)
elif resource_desc.limb_type == z64resources.LimbType.SKIN:
assert resource_desc.type == z64resources.SkeletonType.NORMAL
res = skeleton_skin_resources.SkeletonSkinResource(
file, offset, resource_desc.symbol_name
)
elif resource_desc.limb_type == z64resources.LimbType.CURVE:
assert resource_desc.type == z64resources.SkeletonType.CURVE
res = skelcurve_resources.CurveSkeletonHeaderResource(
file, offset, resource_desc.symbol_name
)
else:
raise NotImplementedError(
"unimplemented Skeleton LimbType",
resource_desc.limb_type,
)
# TODO check is this works for SkeletonSkinResource
# TODO implement for CurveSkeletonHeaderResource
if resource_desc.limb_enum_name is not None:
res.set_enum_name(resource_desc.limb_enum_name)
if resource_desc.limb_enum_none_member_name is not None:
res.set_enum_member_name_none(resource_desc.limb_enum_none_member_name)
if resource_desc.limb_enum_max_member_name is not None:
res.set_enum_member_name_max(resource_desc.limb_enum_max_member_name)
return res
def limb_resource_handler(
file: File,
resource_desc: z64resources.LimbResourceDesc,
):
offset = resource_desc.offset
if resource_desc.limb_type == z64resources.LimbType.STANDARD:
res = skeleton_resources.StandardLimbResource(
file,
offset,
resource_desc.symbol_name,
)
elif resource_desc.limb_type == z64resources.LimbType.SKIN:
res = skeleton_skin_resources.SkinLimbResource(
file, offset, resource_desc.symbol_name
)
elif resource_desc.limb_type == z64resources.LimbType.LOD:
res = skeleton_resources.LODLimbResource(
file, offset, resource_desc.symbol_name
)
elif resource_desc.limb_type == z64resources.LimbType.LEGACY:
return skelanime_legacy_resources.LegacyLimbResource(
file, offset, resource_desc.symbol_name
)
elif resource_desc.limb_type == z64resources.LimbType.CURVE:
res = skelcurve_resources.SkelCurveLimbResource(
file, offset, resource_desc.symbol_name
)
else:
raise NotImplementedError(
"unimplemented LimbType",
resource_desc.limb_type,
)
# TODO check this works for SkinLimbResource
# TODO implement for SkelCurveLimbResource
if resource_desc.limb_enum_member_name is not None:
res.set_enum_member_name(resource_desc.limb_enum_member_name)
return res
def limb_table_handler(
file: File,
resource_desc: z64resources.LimbTableResourceDesc,
):
if resource_desc.limb_type == z64resources.LimbType.STANDARD:
resource = skeleton_resources.StandardLimbsArrayResource(
file, resource_desc.offset, resource_desc.symbol_name
)
resource.set_length(resource_desc.count)
return resource
elif resource_desc.limb_type == z64resources.LimbType.SKIN:
resource = skeleton_skin_resources.SkinLimbsArrayResource(
file, resource_desc.offset, resource_desc.symbol_name
)
resource.set_length(resource_desc.count)
return resource
elif resource_desc.limb_type == z64resources.LimbType.LOD:
resource = skeleton_resources.LODLimbsArrayResource(
file, resource_desc.offset, resource_desc.symbol_name
)
resource.set_length(resource_desc.count)
return resource
elif resource_desc.limb_type == z64resources.LimbType.LEGACY:
resource = skelanime_legacy_resources.LegacyLimbsArrayResource(
file,
resource_desc.offset,
resource_desc.symbol_name,
)
resource.set_length(resource_desc.count)
return resource
else:
raise NotImplementedError("LimbTable of limb type", resource_desc.limb_type)
def animation_resource_handler(
file: File,
resource_desc: z64resources.AnimationResourceDesc,
):
return animation_resources.AnimationResource(
file,
resource_desc.offset,
resource_desc.symbol_name,
)
def collision_resource_handler(
file: File,
resource_desc: z64resources.CollisionResourceDesc,
):
return collision_resources.CollisionResource(
file,
resource_desc.offset,
resource_desc.symbol_name,
)
def dlist_resource_handler(
file: File,
resource_desc: n64resources.DListResourceDesc,
):
res = dlist_resources.DListResource(
file,
resource_desc.offset,
resource_desc.symbol_name,
target_ucode={
n64resources.GfxMicroCode.F3DEX: dlist_resources.Ucode.f3dex,
n64resources.GfxMicroCode.F3DEX2: dlist_resources.Ucode.f3dex2,
}[resource_desc.ucode],
)
res.ignored_raw_pointers |= resource_desc.raw_pointers
return res
def texture_resource_handler(
file: File, resource_desc: n64resources.TextureResourceDesc
):
res = dlist_resources.TextureResource(
file,
resource_desc.offset,
resource_desc.symbol_name,
resource_desc.format.fmt,
resource_desc.format.siz,
resource_desc.width,
resource_desc.height,
)
if "hackmode_ignore_orphaned_tlut" in resource_desc.hack_modes:
res.HACK_ignore_orphaned_tlut = True
return res
def ci_texture_resource_handler(
file: File, resource_desc: n64resources.CITextureResourceDesc
):
if "hackmode_split_tlut" in resource_desc.hack_modes:
# TODO implement SplitTlut="true"
return BinaryBlobResource(
file,
resource_desc.offset,
resource_desc.offset
+ (
resource_desc.format.siz.bpp
* resource_desc.width
* resource_desc.height
// 8
),
resource_desc.symbol_name,
)
resource = dlist_resources.TextureResource(
file,
resource_desc.offset,
resource_desc.symbol_name,
resource_desc.format.fmt,
resource_desc.format.siz,
resource_desc.width,
resource_desc.height,
)
def callback_set_tlut(pool_resources_by_desc):
resource_tlut_desc = resource_desc.tlut
resource_tlut = pool_resources_by_desc[resource_tlut_desc]
resource.set_tlut(resource_tlut)
raise ResourceNeedsPostProcessWithPoolResourcesException(
resource=resource, callback=callback_set_tlut
)
def PlayerAnimationData_handler(
file: File,
resource_desc: z64resources.PlayerAnimationDataResourceDesc,
):
res = playeranim_resources.PlayerAnimationDataResource(
file,
resource_desc.offset,
resource_desc.symbol_name,
)
res.set_frame_count(resource_desc.frame_count)
return res
def PlayerAnimation_handler(
file: File,
resource_desc: z64resources.PlayerAnimationResourceDesc,
):
return playeranim_resources.PlayerAnimationResource(
file,
resource_desc.offset,
resource_desc.symbol_name,
)
def vec3s_array_resource_handler(
file: File,
resource_desc: n64resources.Vec3sArrayResourceDesc,
):
return Vec3sArrayResource(
file,
resource_desc.offset,
resource_desc.symbol_name,
resource_desc.count,
)
def s16_array_resource_handler(
file: File,
resource_desc: n64resources.S16ArrayResourceDesc,
):
return S16ArrayResource(
file,
resource_desc.offset,
resource_desc.symbol_name,
resource_desc.count,
)
def vtx_array_resource_handler(
file: File,
resource_desc: n64resources.VtxArrayResourceDesc,
):
return dlist_resources.VtxArrayResource(
file,
resource_desc.offset,
(
resource_desc.offset
+ (
resource_desc.count
* dlist_resources.VtxArrayResource.element_cdata_ext.size
)
),
resource_desc.symbol_name,
)
def binary_blob_resource_handler(
file: File,
resource_desc: n64resources.BlobResourceDesc,
):
return BinaryBlobResource(
file,
resource_desc.offset,
resource_desc.offset + resource_desc.size,
resource_desc.symbol_name,
)
def CurveAnimation_handler(
file: File,
resource_desc: z64resources.CurveAnimationResourceDesc,
):
# TODO use resource_desc.skeleton
return skelcurve_resources.CurveAnimationHeaderResource(
file, resource_desc.offset, resource_desc.symbol_name
)
def Mtx_handler(
file: File,
resource_desc: n64resources.MtxResourceDesc,
):
return dlist_resources.MtxResource(
file, resource_desc.offset, resource_desc.symbol_name
)
def cutscene_resource_handler(
file: File,
resource_desc: z64resources.CutsceneResourceDesc,
):
return misc_resources.CutsceneResource(
file, resource_desc.offset, resource_desc.symbol_name
)
def scene_resource_handler(
file: File,
resource_desc: z64resources.SceneResourceDesc,
):
return scene_commands_resource.SceneCommandsResource(
file, resource_desc.offset, resource_desc.symbol_name
)
def room_resource_handler(
file: File,
resource_desc: z64resources.RoomResourceDesc,
):
if "hackmode_syotes_room" in resource_desc.hack_modes:
# TODO
return BinaryBlobResource(
file,
resource_desc.offset,
resource_desc.offset + 4,
resource_desc.symbol_name,
)
return scene_commands_resource.SceneCommandsResource(
file, resource_desc.offset, resource_desc.symbol_name
)
def path_list_resource_handler(
file: File,
resource_desc: z64resources.PathListResourceDesc,
):
resource = scene_rooms_resources.PathListResource(
file, resource_desc.offset, resource_desc.symbol_name
)
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,
z64resources.LimbResourceDesc: limb_resource_handler,
z64resources.AnimationResourceDesc: animation_resource_handler,
z64resources.CollisionResourceDesc: collision_resource_handler,
n64resources.DListResourceDesc: dlist_resource_handler,
n64resources.TextureResourceDesc: texture_resource_handler,
n64resources.CITextureResourceDesc: ci_texture_resource_handler,
z64resources.PlayerAnimationDataResourceDesc: PlayerAnimationData_handler,
n64resources.Vec3sArrayResourceDesc: vec3s_array_resource_handler,
n64resources.S16ArrayResourceDesc: s16_array_resource_handler,
n64resources.VtxArrayResourceDesc: vtx_array_resource_handler,
z64resources.PlayerAnimationResourceDesc: PlayerAnimation_handler,
n64resources.BlobResourceDesc: binary_blob_resource_handler,
n64resources.MtxResourceDesc: Mtx_handler,
z64resources.LegacyAnimationResourceDesc: legacy_animation_handler,
z64resources.LimbTableResourceDesc: limb_table_handler,
z64resources.CurveAnimationResourceDesc: CurveAnimation_handler,
z64resources.SceneResourceDesc: scene_resource_handler,
z64resources.RoomResourceDesc: room_resource_handler,
z64resources.PathListResourceDesc: path_list_resource_handler,
z64resources.CutsceneResourceDesc: cutscene_resource_handler,
}
)
RESOURCE_HANDLERS: dict[str, ResourceHandler] = {}
def get_resource_from_desc(
file: File,
resource_desc: ResourceDesc,
) -> Resource:
resource_handler = RESOURCE_HANDLERS.get(type(resource_desc))
if resource_handler is None:
raise Exception("Unknown resource descriptor type", resource_desc)
try:
resource = resource_handler(file, resource_desc)
except ResourceHandlerException:
raise
return resource