mirror of
https://github.com/zeldaret/oot.git
synced 2025-05-10 19:13:42 +00:00
469 lines
16 KiB
Python
469 lines
16 KiB
Python
# SPDX-FileCopyrightText: © 2025 ZeldaRET
|
|
# SPDX-License-Identifier: CC0-1.0
|
|
|
|
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,
|
|
room_shape_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:
|
|
return room_shape_resources.RoomShapeNormalResource(
|
|
file,
|
|
resource_desc.offset,
|
|
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
|