def pack_mesh_matrix_strings( mesh_matrixlist: List[Tuple[int, ...]], pack_as_16bit: bool, big_endian: bool) -> Tuple[bytes, Dict[Tuple, int]]: matrixlist_bytearray = bytearray() matrixlist_index = {} for matrixlist in mesh_matrixlist: matrixlist_index[matrixlist] = len(matrixlist_bytearray) if pack_as_16bit: c_uint16.pack(big_endian, value=len(matrixlist), append_to=matrixlist_bytearray) FixedSizeArrayUnpacker(c_uint16, len(matrixlist)).pack( big_endian=big_endian, value=matrixlist, append_to=matrixlist_bytearray) if not matrixlist: # Add a padding byte in case? c_uint16.pack(big_endian, value=0, append_to=matrixlist_bytearray) else: matrixlist_bytearray += bytes([len(matrixlist)] + list(matrixlist)) return bytes(matrixlist_bytearray), matrixlist_index
def Vec3Unpacker_of(float_type: BaseUnpacker[float]): return ValueAdaptor[mathutils.Vector, List[float]](mathutils.Vector, FixedSizeArrayUnpacker(float_type, 3), lambda arr: mathutils.Vector( (arr[0], arr[1], arr[2])), lambda vec: [vec[0], vec[1], vec[2]])
def read_bytestring(start_byte: int, length: int): if (not mesh_matrix_bytestrings) or (length == 0): return [] unpack_type = c_uint16 if bytestrings_are_16bit else c_uint8 #len_bytes = length * unpack_type.sizeof() actual_len, offset = unpack_type.unpack(self.file_is_big_endian, mesh_matrix_bytestrings, offset=start_byte) if actual_len != length: actual_bytes = mesh_matrix_bytestrings[start_byte:start_byte + actual_len * unpack_type.sizeof()] actual_bytes = [f"{x:02x}" for x in actual_bytes] self.error.fatal( f"Bytestring length mismatch: expected {length}, got {actual_len}. bytes: {actual_bytes}" ) print(start_byte, actual_len, (start_byte + (actual_len + 1) * unpack_type.sizeof())) # data_start = start_byte + 1 # data_end = data_start + len_bytes # data = mesh_matrix_bytestrings[data_start:data_end] # if bytestrings_are_16bit: # # TODO: are 16bit strings always big-endian? # data, _ = FixedSizeArrayUnpacker(c_uint16, length).unpack(True, data, 0) # return data # else: # return [int(bone_idx_byte) for bone_idx_byte in data] data, _ = FixedSizeArrayUnpacker(unpack_type, length).unpack( self.file_is_big_endian, mesh_matrix_bytestrings, offset=offset) return data
from dataclasses import dataclass from typing import List, Optional from yk_gmd_blender.structurelib.base import StructureUnpacker, FixedSizeArrayUnpacker from yk_gmd_blender.structurelib.primitives import * short_arr_6 = FixedSizeArrayUnpacker(c_uint16, 6) bs = bytes([0, 0, 0, 1, 0, 2, 0, 3, 0, 4, 0, 5]) print(short_arr_6.unpack(big_endian=True, data=bs, offset=0)) print(short_arr_6.unpack(big_endian=False, data=bs, offset=0)) @dataclass(frozen=True) class TestStructure: top_int: int bottom_float: float array: List[int] TestStructureUnpacker = StructureUnpacker(TestStructure, fields=[("top_int", c_uint32), ("bottom_float", c_float32), ("array", short_arr_6)]) structure_bytes = bytes( [0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 3, 0, 4, 0, 5]) struct, _ = TestStructureUnpacker.unpack(big_endian=True, data=structure_bytes, offset=0)
from dataclasses import dataclass from typing import List from yk_gmd_blender.structurelib.base import StructureUnpacker, FixedSizeArrayUnpacker from yk_gmd_blender.structurelib.primitives import c_float32, c_uint32 @dataclass(frozen=True) class Unk12Struct: data: List[float] Unk12Struct_Unpack = StructureUnpacker( Unk12Struct, fields=[ ("data", FixedSizeArrayUnpacker(c_float32, 32)) ] ) @dataclass(frozen=True) class Unk14Struct: data: List[int] Unk14Struct_Unpack = StructureUnpacker( Unk14Struct, fields=[ ("data", FixedSizeArrayUnpacker(c_uint32, 32)) ] )
def extract(self, unpack: BaseUnpacker[T], big_endian: bool, data: bytes) -> List[T]: return FixedSizeArrayUnpacker(unpack, self.sized_ptr.size).unpack( big_endian, data, self.sized_ptr.ptr)[0]
from dataclasses import dataclass from typing import List from yk_gmd_blender.structurelib.base import StructureUnpacker, FixedSizeArrayUnpacker from yk_gmd_blender.structurelib.primitives import * from yk_gmd_blender.yk_gmd.v2.structure.common.material_base import MaterialBaseStruct @dataclass(frozen=True) class MaterialStruct_YK1(MaterialBaseStruct): diffuse: List[int] opacity: int specular: List[int] unk1: List[int] unk2: List[int] padding: int = 0 # These are best guesses, we don't have a textdump of this like we do for Kenzan MaterialStruct_YK1_Unpack = StructureUnpacker( MaterialStruct_YK1, fields=[("unk1", FixedSizeArrayUnpacker(c_uint8, 4)), ("specular", FixedSizeArrayUnpacker(c_uint8, 3)), ("padding", c_uint8), ("diffuse", FixedSizeArrayUnpacker(c_uint8, 3)), ("opacity", c_uint8), ("unk2", FixedSizeArrayUnpacker(c_uint8, 4))])
import mathutils from yk_gmd_blender.structurelib.base import FixedSizeArrayUnpacker, ValueAdaptor, BaseUnpacker from yk_gmd_blender.structurelib.primitives import c_float32, List def Vec3Unpacker_of(float_type: BaseUnpacker[float]): return ValueAdaptor[mathutils.Vector, List[float]](mathutils.Vector, FixedSizeArrayUnpacker(float_type, 3), lambda arr: mathutils.Vector( (arr[0], arr[1], arr[2])), lambda vec: [vec[0], vec[1], vec[2]]) Vec3Unpacker = Vec3Unpacker_of(c_float32) def Vec4Unpacker_of(float_type: BaseUnpacker[float]): return ValueAdaptor[mathutils.Vector, List[float]]( mathutils.Vector, FixedSizeArrayUnpacker(float_type, 4), lambda arr: mathutils.Vector((arr[0], arr[1], arr[2], arr[3])), lambda vec: [vec[0], vec[1], vec[2], vec[3]]) Vec4Unpacker = Vec4Unpacker_of(c_float32) QuatUnpacker = ValueAdaptor[mathutils.Quaternion, List[float]]( mathutils.Quaternion, FixedSizeArrayUnpacker(c_float32, 4), lambda arr: mathutils.Quaternion((arr[3], arr[0], arr[1], arr[2])), lambda quat: [quat.x, quat.y, quat.z, quat.w])
("mesh_indices_count", c_uint32), ("texture_init_count", c_uint32), # These may not actually be a single flag block - but they all have data that we don't understand #("unk1_always_1", c_uint16), #("unk2_always_0", c_uint16), ("flags", c_uint64), #("unk3_always_0", c_uint16), # This may be part of the flags block - it may be other flags left unused in Kiwami ("texture_diffuse", TextureIndexStruct_Dragon_Unpack), ("texture_multi", TextureIndexStruct_Dragon_Unpack), ("texture_normal", TextureIndexStruct_Dragon_Unpack), ("texture_rd", TextureIndexStruct_Dragon_Unpack), ("texture_unk1", TextureIndexStruct_Dragon_Unpack), ("texture_rt", TextureIndexStruct_Dragon_Unpack), ("texture_ts", TextureIndexStruct_Dragon_Unpack), ("texture_refl", TextureIndexStruct_Dragon_Unpack), # diffuse # multi # normal # rd # rm? # rt # ts # refl? ("extra_properties", FixedSizeArrayUnpacker(c_float32, 16)) ] )
from yk_gmd_blender.structurelib.primitives import * from yk_gmd_blender.yk_gmd.v2.structure.common.material_base import MaterialBaseStruct @dataclass(frozen=True) class MaterialStruct_Kenzan(MaterialBaseStruct): diffuse: List[int] opacity: float specular: List[int] ambient: List[int] emissive: float power: float intensity: float padding: int MaterialStruct_Kenzan_Unpack = StructureUnpacker( MaterialStruct_Kenzan, fields=[ # TODO: These two are probs wrong ("power", c_float16), ("intensity", c_float16), ("diffuse", FixedSizeArrayUnpacker(c_uint8, 3)), ("padding", c_uint8), ("specular", FixedSizeArrayUnpacker(c_uint8, 3)), ("opacity", c_unorm8), ("ambient", FixedSizeArrayUnpacker(c_uint8, 3)), ("emissive", c_unorm8) ])
from typing import List import mathutils from yk_gmd_blender.structurelib.base import ValueAdaptor, FixedSizeArrayUnpacker from yk_gmd_blender.structurelib.primitives import c_float32 MatrixUnpacker = ValueAdaptor( mathutils.Matrix, FixedSizeArrayUnpacker(c_float32, 16), # The array is column-major, but the matrix constructor takes rows # Solution - pass the columns in as rows, and then transpose lambda arr: mathutils.Matrix( (arr[0:4], arr[4:8], arr[8:12], arr[12:16])).transposed(), # Column-major = each column concatenated lambda matrix: list(matrix.col[0]) + list(matrix.col[1]) + list(matrix.col[ 2]) + list(matrix.col[3]))
from dataclasses import dataclass from enum import Enum from typing import Optional, Tuple, List, Sized, Callable, Iterable from mathutils import Vector from yk_gmd_blender.structurelib.base import StructureUnpacker, BasePrimitive, FixedSizeArrayUnpacker, ValueAdaptor, \ BaseUnpacker from yk_gmd_blender.structurelib.primitives import c_float32, c_float16, c_unorm8, c_uint8, RangeConverterPrimitive from yk_gmd_blender.yk_gmd.v2.errors.error_reporter import ErrorReporter from yk_gmd_blender.yk_gmd.v2.structure.common.vector import Vec3Unpacker, Vec4Unpacker, Vec3Unpacker_of, \ Vec4Unpacker_of # TODO: Rename to HLSL-style (ubyte4, float2, float3, float4, half2 etc.) class VecStorage(Enum): Vec4Fixed = 1 Vec2Full = 2 Vec3Full = 3 Vec4Full = 4 Vec2Half = 5 Vec3Half = 6 Vec4Half = 7 @staticmethod def component_count(val: 'VecStorage'): if val in [ VecStorage.Vec4Half, VecStorage.Vec4Fixed, VecStorage.Vec4Full ]: return 4 elif val in [VecStorage.Vec3Half, VecStorage.Vec3Full]: return 3 else: return 2
unk12: ArrayPointerStruct[Unk12Struct] # Material properties unk13: ArrayPointerStruct[ int] # List of root node indices - those without parents unk14: ArrayPointerStruct[Unk14Struct] # Material properties flags: List[int] GMDHeader_YK1_Unpack = StructureUnpacker( GMDHeader_YK1, fields=[ ("node_arr", ArrayPointerStruct_Unpack), ("obj_arr", ArrayPointerStruct_Unpack), ("mesh_arr", ArrayPointerStruct_Unpack), ("attribute_arr", ArrayPointerStruct_Unpack), ("material_arr", ArrayPointerStruct_Unpack), ("matrix_arr", ArrayPointerStruct_Unpack), ("vertex_buffer_arr", ArrayPointerStruct_Unpack), ("vertex_data", SizedPointerStruct_Unpack), ("texture_arr", ArrayPointerStruct_Unpack), ("shader_arr", ArrayPointerStruct_Unpack), ("node_name_arr", ArrayPointerStruct_Unpack), ("index_data", ArrayPointerStruct_Unpack), ("object_drawlist_bytes", SizedPointerStruct_Unpack), ("mesh_matrixlist_bytes", SizedPointerStruct_Unpack), ("overall_bounds", BoundsData_YK1_Unpack), ("unk12", ArrayPointerStruct_Unpack), ("unk13", ArrayPointerStruct_Unpack), ("unk14", ArrayPointerStruct_Unpack), ("flags", FixedSizeArrayUnpacker(c_uint32, 6)), ], base_class_unpackers={GMDHeaderStruct: GMDHeaderStruct_Unpack})