diff options
Diffstat (limited to 'tools/assets/descriptor/n64resources.py')
| -rw-r--r-- | tools/assets/descriptor/n64resources.py | 77 |
1 files changed, 62 insertions, 15 deletions
diff --git a/tools/assets/descriptor/n64resources.py b/tools/assets/descriptor/n64resources.py index b88c69f4b..8430084aa 100644 --- a/tools/assets/descriptor/n64resources.py +++ b/tools/assets/descriptor/n64resources.py @@ -3,6 +3,7 @@ import dataclasses import enum +from typing import Optional from xml.etree.ElementTree import Element from ..n64 import G_IM_FMT, G_IM_SIZ @@ -13,6 +14,7 @@ from .base import ( ResourcesDescCollectionsPool, ResourceHandlerNeedsPass2Exception, BaseromFileBackingMemory, + ResourceHasNoSizeError, ) from . import xml_errors @@ -24,18 +26,29 @@ class GfxMicroCode(enum.Enum): @dataclasses.dataclass(eq=False) class DListResourceDesc(ResourceDesc): + length: Optional[int] ucode: GfxMicroCode raw_pointers: set[int] = dataclasses.field(default_factory=set) """Pointers in the dlist that are fine to keep raw ("in hex") instead of using symbols""" + def get_size(self): + if self.length is None: + raise ResourceHasNoSizeError() + return self.length * 8 + def handler_DList(symbol_name, offset, collection, reselem: Element): - xml_errors.check_attrib(reselem, {"Name", "Offset"}, {"Ucode", "RawPointers"}) + xml_errors.check_attrib( + reselem, {"Name"}, {"Offset", "Length", "Ucode", "RawPointers"} + ) + length = None + if "Length" in reselem.attrib: + length = int(reselem.attrib["Length"]) if "Ucode" in reselem.attrib: ucode = GfxMicroCode[reselem.attrib["Ucode"].upper()] else: ucode = GfxMicroCode.F3DEX2 - res = DListResourceDesc(symbol_name, offset, collection, reselem, ucode) + res = DListResourceDesc(symbol_name, offset, collection, reselem, length, ucode) raw_pointers_str = reselem.attrib.get("RawPointers") if raw_pointers_str: for rp_str in raw_pointers_str.split(","): @@ -47,9 +60,12 @@ def handler_DList(symbol_name, offset, collection, reselem: Element): class BlobResourceDesc(ResourceDesc): size: int + def get_size(self) -> int: + return self.size + def handler_Blob(symbol_name, offset, collection, reselem: Element): - xml_errors.check_attrib(reselem, {"Name", "Offset", "Size"}) + xml_errors.check_attrib(reselem, {"Name", "Size"}, {"Offset"}) size = int(reselem.attrib["Size"], 16) return BlobResourceDesc(symbol_name, offset, collection, reselem, size) @@ -60,7 +76,7 @@ class MtxResourceDesc(ResourceDesc): def handler_Mtx(symbol_name, offset, collection, reselem: Element): - xml_errors.check_attrib(reselem, {"Name", "Offset"}) + xml_errors.check_attrib(reselem, {"Name"}, {"Offset"}) return MtxResourceDesc(symbol_name, offset, collection, reselem) @@ -78,9 +94,12 @@ class Vec3sArrayResourceDesc(ResourceDesc): class VtxArrayResourceDesc(ResourceDesc): count: int + def get_size(self): + return self.count * 0x10 + def handler_Array(symbol_name, offset, collection, reselem: Element): - xml_errors.check_attrib(reselem, {"Name", "Offset", "Count"}) + xml_errors.check_attrib(reselem, {"Name", "Count"}, {"Offset"}) count = int(reselem.attrib["Count"]) assert len(reselem) == 1, "Expected exactly one child of Array node" array_elem = reselem[0] @@ -121,6 +140,9 @@ class TextureResourceDesc(ResourceDesc): width: int height: int + def get_size(self): + return self.width * self.height * self.format.siz.bpp // 8 + @dataclasses.dataclass(eq=False) class CITextureResourceDesc(TextureResourceDesc): @@ -132,10 +154,12 @@ def handler_Texture( ): xml_errors.check_attrib( reselem, - {"Name", "Offset", "Format", "Width", "Height"}, + {"Name", "Format", "Width", "Height"}, # TODO remove SplitTlut { + "Offset", "SplitTlut", + "Tlut", "TlutOffset", "ExternalTlut", "ExternalTlutOffset", @@ -156,15 +180,39 @@ def handler_Texture( res.hack_modes.add("hackmode_split_tlut_false") assert ( - "TlutOffset" in reselem.attrib or "ExternalTlutOffset" in reselem.attrib - ), f"CI texture {symbol_name} is missing a tlut offset" + "Tlut" in reselem.attrib + or "TlutOffset" in reselem.attrib + or "ExternalTlutOffset" in reselem.attrib + ), f"CI texture {symbol_name} is missing tlut information" + + if "Tlut" in reselem.attrib: + xml_errors.check_attrib( + reselem, + {"Name", "Format", "Width", "Height", "Tlut"}, + # TODO remove SplitTlut + {"Offset", "SplitTlut", "HackMode"}, + ) + tlut_name = reselem.attrib["Tlut"] + + def pass2_callback(pool: ResourcesDescCollectionsPool): + matching_tlut_resources = [ + res for res in collection.resources if res.symbol_name == tlut_name + ] + assert len(matching_tlut_resources) == 1, ( + f"Found {len(matching_tlut_resources)} resources named " + f"{tlut_name} instead of exactly one" + ) + assert isinstance( + matching_tlut_resources[0], TextureResourceDesc + ), matching_tlut_resources[0] + res.tlut = matching_tlut_resources[0] - if "TlutOffset" in reselem.attrib: + elif "TlutOffset" in reselem.attrib: xml_errors.check_attrib( reselem, - {"Name", "Offset", "Format", "Width", "Height", "TlutOffset"}, + {"Name", "Format", "Width", "Height", "TlutOffset"}, # TODO remove SplitTlut - {"SplitTlut", "HackMode"}, + {"Offset", "SplitTlut", "HackMode"}, ) tlut_offset = int(reselem.attrib["TlutOffset"], 16) @@ -186,7 +234,6 @@ def handler_Texture( reselem, { "Name", - "Offset", "Format", "Width", "Height", @@ -194,7 +241,7 @@ def handler_Texture( "ExternalTlutOffset", }, # TODO remove SplitTlut - {"SplitTlut", "HackMode"}, + {"Offset", "SplitTlut", "HackMode"}, ) external_tlut_file = reselem.attrib["ExternalTlut"] external_tlut_offset = int(reselem.attrib["ExternalTlutOffset"], 16) @@ -222,8 +269,8 @@ def handler_Texture( else: xml_errors.check_attrib( reselem, - {"Name", "Offset", "Format", "Width", "Height"}, - {"HackMode"}, + {"Name", "Format", "Width", "Height"}, + {"Offset", "HackMode"}, ) res = TextureResourceDesc( symbol_name, offset, collection, reselem, format, width, height |
