1
0
Fork 0
mirror of https://github.com/zeldaret/oot.git synced 2025-05-10 19:13:42 +00:00

implement more skeleton-related types, cleanups, fixups

This commit is contained in:
Dragorn421 2025-02-05 23:17:05 +01:00
parent f70a07f8cf
commit 66db26a999
No known key found for this signature in database
GPG key ID: 381AEBAF3D429335
18 changed files with 459 additions and 128 deletions

View file

@ -790,7 +790,7 @@ setup: venv
$(MAKE) -C tools
$(PYTHON) tools/decompress_baserom.py $(VERSION)
$(PYTHON) tools/extract_baserom.py $(BASEROM_DIR)/baserom-decompressed.z64 $(EXTRACTED_DIR)/baserom -v $(VERSION)
$(PYTHON) -m tools.assets.extract -j
$(PYTHON) -m tools.assets.extract -j $(EXTRACTED_DIR)/baserom $(EXTRACTED_DIR)
$(PYTHON) tools/extract_incbins.py $(EXTRACTED_DIR)/baserom $(EXTRACTED_DIR)/incbin -v $(VERSION)
$(PYTHON) tools/extract_text.py $(EXTRACTED_DIR)/baserom $(EXTRACTED_DIR)/text -v $(VERSION)
$(PYTHON) tools/extract_audio.py -o $(EXTRACTED_DIR) -v $(VERSION) --read-xml
@ -985,7 +985,7 @@ $(BUILD_DIR)/src/overlays/%_reloc.o: $(BUILD_DIR)/spec
$(AS) $(ASFLAGS) $(@:.o=.s) -o $@
$(BUILD_DIR)/assets/%.inc.c: assets/%.png
false # TODO
false # TODO duplicate extracted/ build rules for git-tracked assets/ too
$(BUILD_DIR)/assets/%.u64.inc.c: $(EXTRACTED_DIR)/assets/%.u64.png
$(PYTHON) tools/assets/build_from_png.py $< $(@:.inc.c=.bin)

View file

@ -13,7 +13,7 @@ typedef struct BowSlingshotStringData {
/* 0x04 */ Vec3f pos;
} BowSlingshotStringData; // size = 0x10
FlexSkeletonHeader* gPlayerSkelHeaders[] = { (void*)&gLinkAdultSkel, (void*)&gLinkChildSkel }; //! FIXME
FlexSkeletonHeader* gPlayerSkelHeaders[] = { &gLinkAdultSkel, &gLinkChildSkel };
s16 sBootData[PLAYER_BOOTS_MAX][17] = {
// PLAYER_BOOTS_KOKIRI

View file

@ -93,7 +93,7 @@ void EnArrow_Init(Actor* thisx, PlayState* play) {
if (this->actor.params <= ARROW_SEED) {
if (this->actor.params <= ARROW_0E) {
SkelAnime_Init(play, &this->skelAnime, (void*)&gArrowSkel, &gArrow2Anim, NULL, NULL, 0);
SkelAnime_Init(play, &this->skelAnime, &gArrowSkel, &gArrow2Anim, NULL, NULL, 0);
}
if (this->actor.params <= ARROW_NORMAL) {

View file

@ -67,7 +67,7 @@ static AnimationHeader** sAnimationHeaders[] = { sEponaAnimHeaders, sHniAnimHead
static f32 sPlaybackSpeeds[] = { 2.0f / 3.0f, 2.0f / 3.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 2.0f / 3.0f, 2.0f / 3.0f };
static SkeletonHeader* sSkeletonHeaders[] = { (void*)&gEponaSkel, (void*)&gHorseIngoSkel };
static SkeletonHeader* sSkeletonHeaders[] = { &gEponaSkel, &gHorseIngoSkel };
ActorProfile En_Horse_Profile = {
/**/ ACTOR_EN_HORSE,

View file

@ -177,7 +177,7 @@ void EnHorseGanon_Init(Actor* thisx, PlayState* play) {
this->actor.focus.pos = this->actor.world.pos;
this->action = 0;
this->actor.focus.pos.y += 70.0f;
Skin_Init(play, &this->skin, (void*)&gHorseGanonSkel, &gHorseGanonIdleAnim);
Skin_Init(play, &this->skin, &gHorseGanonSkel, &gHorseGanonIdleAnim);
this->currentAnimation = 0;
Animation_PlayOnce(&this->skin.skelAnime, sAnimations[0]);

View file

@ -162,7 +162,7 @@ void EnHorseLinkChild_Init(Actor* thisx, PlayState* play) {
this->action = 1;
this->actor.focus.pos = this->actor.world.pos;
this->actor.focus.pos.y += 70.0f;
Skin_Init(play, &this->skin, (void*)&gChildEponaSkel, &gChildEponaGallopingAnim);
Skin_Init(play, &this->skin, &gChildEponaSkel, &gChildEponaGallopingAnim);
this->animationIdx = 0;
Animation_PlayOnce(&this->skin.skelAnime, sAnimations[0]);
Collider_InitCylinder(play, &this->bodyCollider);

View file

@ -226,7 +226,7 @@ void EnHorseNormal_Init(Actor* thisx, PlayState* play) {
return;
}
this->actor.home.rot.z = this->actor.world.rot.z = this->actor.shape.rot.z = 0;
Skin_Init(play, &this->skin, (void*)&gHorseNormalSkel, &gHorseNormalIdleAnim);
Skin_Init(play, &this->skin, &gHorseNormalSkel, &gHorseNormalIdleAnim);
Animation_PlayOnce(&this->skin.skelAnime, sAnimations[this->animationIdx]);
if ((this->actor.world.pos.x == -730.0f && this->actor.world.pos.y == 0.0f &&
this->actor.world.pos.z == -1100.0f) ||
@ -240,7 +240,7 @@ void EnHorseNormal_Init(Actor* thisx, PlayState* play) {
Actor_Kill(&this->actor);
return;
} else {
Skin_Init(play, &this->skin, (void*)&gHorseNormalSkel, &gHorseNormalIdleAnim);
Skin_Init(play, &this->skin, &gHorseNormalSkel, &gHorseNormalIdleAnim);
Animation_PlayOnce(&this->skin.skelAnime, sAnimations[this->animationIdx]);
func_80A6C6B0(this);
return;
@ -248,15 +248,15 @@ void EnHorseNormal_Init(Actor* thisx, PlayState* play) {
} else if (play->sceneId == SCENE_GERUDOS_FORTRESS) {
if (this->actor.world.pos.x == 3707.0f && this->actor.world.pos.y == 1413.0f &&
this->actor.world.pos.z == -665.0f) {
Skin_Init(play, &this->skin, (void*)&gHorseNormalSkel, &gHorseNormalIdleAnim);
Skin_Init(play, &this->skin, &gHorseNormalSkel, &gHorseNormalIdleAnim);
Animation_PlayOnce(&this->skin.skelAnime, sAnimations[this->animationIdx]);
func_80A6C4CC(this);
return;
}
Skin_Init(play, &this->skin, (void*)&gHorseNormalSkel, &gHorseNormalIdleAnim);
Skin_Init(play, &this->skin, &gHorseNormalSkel, &gHorseNormalIdleAnim);
Animation_PlayOnce(&this->skin.skelAnime, sAnimations[this->animationIdx]);
} else {
Skin_Init(play, &this->skin, (void*)&gHorseNormalSkel, &gHorseNormalIdleAnim);
Skin_Init(play, &this->skin, &gHorseNormalSkel, &gHorseNormalIdleAnim);
Animation_PlayOnce(&this->skin.skelAnime, sAnimations[this->animationIdx]);
}
if (PARAMS_GET_NOSHIFT(this->actor.params, 4, 4) == 0x10 && PARAMS_GET_U(this->actor.params, 0, 4) != 0xF) {

View file

@ -158,7 +158,7 @@ void EnHorseZelda_Init(Actor* thisx, PlayState* play) {
this->actor.focus.pos = this->actor.world.pos;
this->action = 0;
this->actor.focus.pos.y += 70.0f;
Skin_Init(play, &this->skin, (void*)&gHorseZeldaSkel, &gHorseZeldaGallopingAnim);
Skin_Init(play, &this->skin, &gHorseZeldaSkel, &gHorseZeldaGallopingAnim);
this->animationIndex = 0;
Animation_PlayOnce(&this->skin.skelAnime, sAnimationHeaders[0]);
Collider_InitCylinder(play, &this->colliderCylinder);

View file

@ -102,7 +102,7 @@ void EnTorch2_Init(Actor* thisx, PlayState* play2) {
this->currentShield = PLAYER_SHIELD_HYLIAN;
this->heldItemAction = this->heldItemId = PLAYER_IA_SWORD_MASTER;
Player_SetModelGroup(this, PLAYER_MODELGROUP_SWORD_AND_SHIELD);
play->playerInit(this, play, (void*)&gDarkLinkSkel); //! FIXME
play->playerInit(this, play, &gDarkLinkSkel);
this->actor.naviEnemyId = NAVI_ENEMY_DARK_LINK;
this->cylinder.base.acFlags = AC_ON | AC_TYPE_PLAYER;
this->meleeWeaponQuads[0].base.atFlags = this->meleeWeaponQuads[1].base.atFlags = AT_ON | AT_TYPE_ENEMY;

View file

@ -80,7 +80,7 @@ void EnfHG_Init(Actor* thisx, PlayState* play2) {
this->actor.speed = 0.0f;
this->actor.focus.pos = this->actor.world.pos;
this->actor.focus.pos.y += 70.0f;
Skin_Init(play, &this->skin, (void*)&gPhantomHorseSkel, &gPhantomHorseRunningAnim);
Skin_Init(play, &this->skin, &gPhantomHorseSkel, &gPhantomHorseRunningAnim);
if (this->actor.params >= GND_FAKE_BOSS) {
EnfHG_SetupApproach(this, play, this->actor.params - GND_FAKE_BOSS);

View file

@ -687,6 +687,8 @@ class File:
h.writelines(headers_includes)
h.write("\n")
if not self._is_resources_sorted:
self.sort_resources()
for resource in self._resources:
if resource.write_c_definition(c):
@ -720,6 +722,14 @@ class File:
+ f"({self.name!r}, data is None={self.data is None}, size={self.size}, {self._resources!r})"
)
def __rich_repr__(self):
yield "name", self.name
yield "data is None", self.data is None
yield "size", self.size
yield "resources", self._resources
__rich_repr__.angular = True
#
# resources
@ -973,7 +983,7 @@ class Resource(abc.ABC):
else "..."
)
),
f"file_name={self.file.name!r}",
f"file.name={self.file.name!r}",
)
)
+ ")"
@ -985,7 +995,7 @@ class Resource(abc.ABC):
f"0x{self.range_start:08X}-"
+ (f"0x{self.range_end:08X}" if self.range_end is not None else "...")
)
yield "file_name", self.file.name
yield "file.name", self.file.name
__rich_repr__.angular = True

View file

@ -303,7 +303,10 @@ class CDataArrayResource(CDataResource):
return super().try_parse_data(memory_context)
def get_c_reference(self, resource_offset: int):
if resource_offset == 0:
return self.symbol_name
else:
raise ValueError
def get_c_expression_length(self, resource_offset: int):
if resource_offset == 0:

View file

@ -899,7 +899,7 @@ class ColorIndexedTexturesManager:
tluts: dict[int, "ColorIndexedTexturesManager.Tlut"]
texs: list["ColorIndexedTexturesManager.Tex"]
def __init__(self) -> None:
def __init__(self, *, HACK_late_SetTextureLUT=False):
self.cur_tlut_mode: G_TT = None
self.cur_tluts_count: int = None
@ -908,6 +908,11 @@ class ColorIndexedTexturesManager:
self.ci_states: list[ColorIndexedTexturesManager.CIState] = []
# Rarely,
# gsDPSetTextureLUT comes after gsDPLoadTextureBlock and gsDPLoadTLUT,
# instead of before
self.HACK_late_SetTextureLUT = HACK_late_SetTextureLUT
def ci_timg(self, timg, fmt: G_IM_FMT, siz: G_IM_SIZ, width, height, pal):
if VERBOSE_ColorIndexedTexturesManager:
print(
@ -920,6 +925,7 @@ class ColorIndexedTexturesManager:
pal,
)
assert fmt == G_IM_FMT.CI
if not self.HACK_late_SetTextureLUT:
assert self.cur_tlut_mode != G_TT.NONE
self.cur_texs.append(
@ -933,6 +939,7 @@ class ColorIndexedTexturesManager:
# HACK idx==-1 may be a libgfxd bug?
assert count == 256
idx = 0
if not self.HACK_late_SetTextureLUT:
assert self.cur_tlut_mode != G_TT.NONE
if self.cur_tluts_count != count:
self.cur_tluts.clear() # TODO ? idk. (at worst it will cause errors)
@ -943,6 +950,7 @@ class ColorIndexedTexturesManager:
if VERBOSE_ColorIndexedTexturesManager:
print("ColorIndexedTexturesManager.tlut_mode", tt)
if self.cur_tlut_mode != tt:
if not self.HACK_late_SetTextureLUT:
self.cur_tluts.clear() # TODO ? idk. (at worst it will cause errors)
self.cur_tlut_mode = tt
@ -1101,7 +1109,10 @@ class DListResource(Resource, can_size_be_unknown=True):
)
return 0
ci_tex_manager = ColorIndexedTexturesManager()
ci_tex_manager = ColorIndexedTexturesManager(
# TODO
HACK_late_SetTextureLUT=(self.name in {"gEponaHeadLimb_0600AC20_DL"})
)
def timg_cb(timg, fmt, siz, width, height, pal):
g_fmt = G_IM_FMT.by_i[fmt]

View file

@ -1,16 +1,12 @@
from __future__ import annotations
import io
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from ..extase.memorymap import MemoryContext
from ..extase import (
File,
ResourceParseWaiting,
)
from ..extase.cdata_resources import (
CDataResource,
CDataArrayResource,
CDataExt_Value,
CDataExt_Struct,
CDataExt_Array,
@ -40,15 +36,38 @@ class StandardLimbResource(CDataResource):
raise ValueError()
class LimbsArrayResource(CDataResource, can_size_be_unknown=True):
class LODLimbResource(CDataResource):
cdata_ext = CDataExt_Struct(
(
("jointPos", cdata_ext_Vec3s),
("child", CDataExt_Value.u8),
("sibling", CDataExt_Value.u8),
("dLists", CDataExt_Array(dlist_resources.cdata_ext_gfx_segmented, 2)),
)
)
def get_c_declaration_base(self):
return f"LodLimb {self.symbol_name}"
def get_c_reference(self, resource_offset: int):
if resource_offset == 0:
return f"&{self.symbol_name}"
else:
raise ValueError()
class LimbsArrayResourceABC(CDataArrayResource):
limb_type: type[CDataResource]
c_limb_type: str
def report_limb_element(resource, memory_context: "MemoryContext", v):
assert isinstance(v, int)
address = v
memory_context.report_resource_at_segmented(
resource,
address,
StandardLimbResource,
lambda file, offset: StandardLimbResource(
resource.limb_type,
lambda file, offset: resource.limb_type(
file, offset, f"{resource.name}_{address:08X}"
),
)
@ -68,51 +87,39 @@ class LimbsArrayResource(CDataResource, can_size_be_unknown=True):
.set_write(write_limb_element)
)
def __init__(self, file: File, range_start: int, name: str):
super().__init__(file, range_start, name)
self.length = None
def try_parse_data(self, memory_context: "MemoryContext"):
if self.length is not None:
self.cdata_ext = CDataExt_Array(self.elem_cdata_ext, self.length)
self.range_end = self.range_start + self.cdata_ext.size
return super().try_parse_data(memory_context)
else:
raise ResourceParseWaiting(waiting_for=["self.length"])
def get_c_declaration_base(self):
return f"void* {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_c_expression_length(self, resource_offset: int):
if resource_offset == 0:
return f"ARRAY_COUNT({self.symbol_name})"
else:
raise ValueError()
return f"{self.c_limb_type}* {self.symbol_name}[]"
class SkeletonNormalResource(CDataResource):
class StandardLimbsArrayResource(LimbsArrayResourceABC):
limb_type = StandardLimbResource
c_limb_type = "StandardLimb"
class LODLimbsArrayResource(LimbsArrayResourceABC):
limb_type = LODLimbResource
c_limb_type = "LodLimb"
class SkeletonResourceABC(CDataResource):
limbs_array_type: type[LimbsArrayResourceABC]
def report_segment(resource, memory_context: "MemoryContext", v):
assert isinstance(v, int)
address = v
resource_limbs = memory_context.report_resource_at_segmented(
resource,
address,
LimbsArrayResource,
lambda file, offset: LimbsArrayResource(
resource.limbs_array_type,
lambda file, offset: resource.limbs_array_type(
file,
offset,
f"{resource.name}_{address:08X}_Limbs",
),
)
resource_limbs.length = resource.get_skeleton_header_cdata_unpacked()[
"limbCount"
]
resource_limbs.set_length(
resource.get_skeleton_header_cdata_unpacked()["limbCount"]
)
def write_segment(
resource, memory_context: "MemoryContext", v, f: io.TextIOBase, line_prefix
@ -162,18 +169,32 @@ class SkeletonNormalResource(CDataResource):
return f"SkeletonHeader {self.symbol_name}"
class SkeletonFlexResource(CDataResource):
cdata_ext = CDataExt_Struct(
class SkeletonNormalResource(SkeletonResourceABC):
limbs_array_type = StandardLimbsArrayResource
class SkeletonNormalLODResource(SkeletonResourceABC):
limbs_array_type = LODLimbsArrayResource
class SkeletonFlexResourceABC(CDataResource):
skeleton_type: type[SkeletonResourceABC]
# For SkeletonResourceABC.report_segment
@property
def limbs_array_type(self):
return self.skeleton_type.limbs_array_type
def __init__(self, file, range_start, name):
self.cdata_ext = CDataExt_Struct(
(
(
"sh",
SkeletonNormalResource.cdata_ext,
), # TODO FIXME this is bad, it ends up using StandardLimb s (or is it fine?)
("sh", self.skeleton_type.cdata_ext),
("dListCount", CDataExt_Value.u8),
("pad9", CDataExt_Value.pad8),
("pad10", CDataExt_Value.pad16),
)
)
super().__init__(file, range_start, name)
def get_skeleton_header_cdata_unpacked(self):
return self.cdata_unpacked["sh"]
@ -186,3 +207,11 @@ class SkeletonFlexResource(CDataResource):
def get_c_declaration_base(self):
return f"FlexSkeletonHeader {self.symbol_name}"
class SkeletonFlexResource(SkeletonFlexResourceABC):
skeleton_type = SkeletonNormalResource
class SkeletonFlexLODResource(SkeletonFlexResourceABC):
skeleton_type = SkeletonNormalLODResource

View file

@ -0,0 +1,244 @@
import io
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,
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}[]"
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}[]"
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, 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_limbTransformations(
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
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}[]"
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, 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(
(
("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()
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, # TODO
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, 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(
(
("jointPos", cdata_ext_Vec3s),
("child", CDataExt_Value.u8),
("sibling", CDataExt_Value.u8),
(
"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 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()
class SkinLimbsArrayResource(skeleton_resources.LimbsArrayResourceABC):
limb_type = SkinLimbResource
c_limb_type = "SkinLimb"
class SkeletonSkinResource(skeleton_resources.SkeletonResourceABC):
limbs_array_type = SkinLimbsArrayResource

View file

@ -1,5 +1,4 @@
import dataclasses
import functools
from pathlib import Path
from pprint import pprint
@ -33,15 +32,16 @@ WRITE_EXTRACT = True
from ..conf import WRITE_HINTS, I_D_OMEGALUL
OOT_VERSION = "gc-eu-mq-dbg"
BASEROM_PATH = Path("extracted") / OOT_VERSION / "baserom"
BUILD_PATH = Path("build") / OOT_VERSION
EXTRACTED_PATH = Path("extracted") / OOT_VERSION
@dataclasses.dataclass
class ExtractionContext:
oot_version: str
version_memctx_base: MemoryContext
baserom_path: Path
build_path: Path
extracted_path: Path
@functools.lru_cache(maxsize=200)
def get_baserom_file_data(baserom_file_name: str):
return memoryview((BASEROM_PATH / baserom_file_name).read_bytes())
def get_baserom_file_data(self, baserom_file_name: str):
return memoryview((self.baserom_path / baserom_file_name).read_bytes())
def create_file_resources(rescoll: ResourcesDescCollection, file: File):
@ -92,7 +92,7 @@ def create_file_resources(rescoll: ResourcesDescCollection, file: File):
def process_pool(
version_memctx_base: MemoryContext, pool_desc: ResourcesDescCollectionsPool
extraction_ctx: ExtractionContext, pool_desc: ResourcesDescCollectionsPool
):
if VERBOSE2:
print("> process_pool")
@ -112,7 +112,7 @@ def process_pool(
for rescoll in pool_desc.collections:
if not isinstance(rescoll.backing_memory, BaseromFileBackingMemory):
raise NotImplementedError(rescoll.backing_memory)
data = get_baserom_file_data(rescoll.backing_memory.name)
data = extraction_ctx.get_baserom_file_data(rescoll.backing_memory.name)
if rescoll.backing_memory.range is not None:
range_start, range_end = rescoll.backing_memory.range
data = data[range_start:range_end]
@ -135,7 +135,7 @@ def process_pool(
# 2) Build a MemoryContext for each File
memctx_base = version_memctx_base.copy()
memctx_base = extraction_ctx.version_memctx_base.copy()
files_by_segment: dict[int, list[File]] = dict()
for rescoll, file in file_by_rescoll.items():
@ -228,31 +228,30 @@ def process_pool(
# 5)
# TODO this looks jank
for rescoll, file in file_by_rescoll.items():
file.set_source_path(Path("assets") / rescoll.out_path)
file.set_resources_paths(
EXTRACTED_PATH,
BUILD_PATH,
extraction_ctx.extracted_path,
extraction_ctx.build_path,
Path("assets") / rescoll.out_path,
)
for file, file_memctx in memctx_by_file.items():
# write to EXTRACTED_PATH
# write to extracted/
if WRITE_EXTRACT:
file.write_resources_extracted(file_memctx)
# "source" refers to the main .c and .h `#include`ing all the extracted resources
if WRITE_SOURCE:
# TODO fill referenced_files properly or something
file.referenced_files = set(memctx_by_file.keys())
file.referenced_files = set(memctx_by_file.keys()) - {file}
file.write_source()
def process_pool_wrapped(version_memctx_base, pd):
def process_pool_wrapped(extraction_ctx, pd):
try:
process_pool(version_memctx_base, pd)
process_pool(extraction_ctx, pd)
except Exception as e:
import traceback
import sys
@ -273,6 +272,16 @@ def main():
from tools import version_config
parser = argparse.ArgumentParser()
parser.add_argument(
"baserom_segments_dir",
type=Path,
help="Directory of uncompressed ROM segments",
)
parser.add_argument(
"output_dir",
type=Path,
help="Output directory to place files in",
)
parser.add_argument("-v", dest="oot_version", default="gc-eu-mq-dbg")
parser.add_argument("-j", dest="use_multiprocessing", action="store_true")
parser.add_argument("-s", dest="single", default=None)
@ -299,6 +308,14 @@ def main():
)
version_memctx_base.set_direct_file(vc.variables["sShadowTex"], file_sShadowTex)
extraction_ctx = ExtractionContext(
args.oot_version,
version_memctx_base,
args.baserom_segments_dir,
Path("build") / args.oot_version,
args.output_dir,
)
z64_resource_handlers.register_resource_handlers()
# TODO extract only when a pool xml was modified since last extract
@ -312,7 +329,7 @@ def main():
if coll.backing_memory.name == args.single:
do_process_pool = True
if do_process_pool:
process_pool(version_memctx_base, pool_desc)
process_pool(extraction_ctx, pool_desc)
any_do_process_pool = True
if any_do_process_pool:
print("OK")
@ -320,7 +337,7 @@ def main():
print("Not found:", args.single)
elif not args.use_multiprocessing: # everything on one process
for pool_desc in pools_desc:
process_pool(version_memctx_base, pool_desc)
process_pool(extraction_ctx, pool_desc)
print("all OK!!!")
else: # multiprocessing
import multiprocessing
@ -328,7 +345,7 @@ def main():
with multiprocessing.Pool() as pool:
pool.starmap(
process_pool_wrapped,
zip([version_memctx_base] * len(pools_desc), pools_desc),
zip([extraction_ctx] * len(pools_desc), pools_desc),
)
print("all OK!?")
except Exception as e:
@ -349,16 +366,3 @@ def main():
else:
print("rich.pretty.pprint(e):")
rich.pretty.pprint(e, indent_guides=False)
# extract_xml(Path("objects/object_ydan_objects"))
# extract_xml(Path("objects/object_fd2")) # TODO xml needs TLUT fixing, see VERBOSE_BEST_EFFORT_TLUT_NO_REAL_USER
# extract_xml(Path("objects/object_am"))
# extract_xml(Path("scenes/indoors/hylia_labo"))
# extract_xml(Path("objects/gameplay_keep"))
# extract_xml(Path("overlays/ovl_En_Jsjutan")) # The only xml with ~~<Symbol>~~ a <File Extract="False"
# extract_xml(Path("overlays/ovl_Magic_Wind")) # SkelCurve
# extract_xml(Path("objects/object_link_child")) # The only xml with <Mtx>
# extract_xml(Path("scenes/dungeons/ddan")) # cutscene test
# extract_xml(Path("scenes/dungeons/ganontikasonogo")) # has a spawn not in the entrance table
pprint(get_baserom_file_data.cache_info())

View file

@ -101,3 +101,8 @@ CAMERA_SETTING_TYPES = {
0x40: "CAM_SET_PIVOT_FROM_SIDE",
0x41: "CAM_SET_NORMAL4",
}
SKIN_LIMB_TYPES = {
4: "SKIN_LIMB_TYPE_ANIMATED",
11: "SKIN_LIMB_TYPE_NORMAL",
}

View file

@ -14,6 +14,7 @@ from .extase.cdata_resources import Vec3sArrayResource, S16ArrayResource
from .extase_oot64 import (
skeleton_resources,
skeleton_skin_resources,
animation_resources,
collision_resources,
dlist_resources,
@ -82,16 +83,13 @@ def register_resource_handlers():
if resource_desc.limb_type == z64resources.LimbType.STANDARD:
pass
elif resource_desc.limb_type == z64resources.LimbType.LOD:
# TODO
if resource_desc.type == z64resources.SkeletonType.NORMAL:
# } SkeletonHeader; // size = 0x8
return BinaryBlobResource(
file, offset, offset + 0x8, resource_desc.symbol_name
return skeleton_resources.SkeletonNormalLODResource(
file, offset, resource_desc.symbol_name
)
elif resource_desc.type == z64resources.SkeletonType.FLEX:
# } FlexSkeletonHeader; // size = 0xC
return BinaryBlobResource(
file, offset, offset + 0xC, resource_desc.symbol_name
return skeleton_resources.SkeletonFlexLODResource(
file, offset, resource_desc.symbol_name
)
else:
raise NotImplementedError(
@ -100,11 +98,9 @@ def register_resource_handlers():
resource_desc.type,
)
elif resource_desc.limb_type == z64resources.LimbType.SKIN:
# TODO
assert resource_desc.type == z64resources.SkeletonType.NORMAL
# } SkeletonHeader; // size = 0x8
return BinaryBlobResource(
file, offset, offset + 0x8, resource_desc.symbol_name
return 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
@ -147,16 +143,15 @@ def register_resource_handlers():
resource_desc.symbol_name,
)
if resource_desc.limb_type == z64resources.LimbType.SKIN:
# } SkinLimb; // size = 0x10
return BinaryBlobResource(
file, offset, offset + 0x10, resource_desc.symbol_name
return skeleton_skin_resources.SkinLimbResource(
file, offset, resource_desc.symbol_name
)
if resource_desc.limb_type == z64resources.LimbType.LOD:
# } LodLimb; // size = 0x10
return BinaryBlobResource(
file, offset, offset + 0x10, resource_desc.symbol_name
return skeleton_resources.LODLimbResource(
file, offset, resource_desc.symbol_name
)
if resource_desc.limb_type == z64resources.LimbType.LEGACY:
# TODO LegacyLimbResource
# } LegacyLimb; // size = 0x20
return BinaryBlobResource(
file, offset, offset + 0x20, resource_desc.symbol_name
@ -171,6 +166,39 @@ def register_resource_handlers():
resource_desc.limb_type,
)
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:
# TODO LegacyLimbsArrayResource
return BinaryBlobResource(
file,
resource_desc.offset,
resource_desc.offset + 4,
resource_desc.symbol_name,
)
else:
raise NotImplementedError("LimbTable of limb type", resource_desc.limb_type)
def animation_resource_handler(
file: File,
resource_desc: z64resources.AnimationResourceDesc,
@ -412,10 +440,7 @@ def register_resource_handlers():
z64resources.LegacyAnimationResourceDesc: get_fixed_size_resource_handler(
0xC
), # TODO
z64resources.LimbTableResourceDesc: get_fixed_size_resource_handler(
# idk, probably an array
4
), # TODO
z64resources.LimbTableResourceDesc: limb_table_handler,
z64resources.CurveAnimationResourceDesc: CurveAnimation_handler,
z64resources.SceneResourceDesc: scene_resource_handler,
z64resources.RoomResourceDesc: room_resource_handler,