def pack(self) -> bytes: """Pack TPF file to bytes.""" writer = BinaryWriter( big_endian=self.platform in {TPFPlatform.Xbox360, TPFPlatform.PS3}) writer.append(b"TPF\0") writer.reserve("data_size", "i") writer.pack("i", len(self.textures)) writer.pack("b", self.platform) writer.pack("b", self.tpf_flags) writer.pack("b", self.encoding) writer.pad(1) for i, texture in enumerate(self.textures): texture.pack_header(writer, i, self.platform, self.tpf_flags) for i, texture in enumerate(self.textures): texture.pack_name(writer, i, self.encoding) data_start = writer.position for i, texture in enumerate(self.textures): # TKGP notes: padding varies wildly across games, so don't worry about it too much. if len(texture.data) > 0: writer.pad_align(4) texture.pack_data(writer, i) writer.fill("data_size", writer.position - data_start) return writer.finish()
def pack_header(self, writer: BinaryWriter): writer.append(b"BND3") writer.pack("8s", self.signature.encode("ascii")) self.flags.pack(writer, self.bit_big_endian) writer.pack("?", self.big_endian) writer.pack("?", self.bit_big_endian) writer.pad(1) writer.pack("i", len(self._entries)) writer.reserve("file_size", "i") writer.pad(8)
def pack_bnd3(self, writer: BinaryWriter, binder_flags: BinderFlags, bit_big_endian: bool): self.flags.pack(writer, bit_big_endian) writer.pad(3) writer.pack("i", self.compressed_size) writer.reserve("data_offset", "q" if binder_flags.has_long_offsets else "I", obj=self) if binder_flags.has_ids: writer.pack("i", self.id) if binder_flags.has_names: writer.reserve("path_offset", "i", obj=self) if binder_flags.has_compression: writer.pack("i", self.uncompressed_size)
def pack_header(self, writer: BinaryWriter, index: int, platform: TPFPlatform, tpf_flags: int): if platform == TPFPlatform.PC: dds = self.get_dds() if dds.header.caps_2 & DDSCAPS2.CUBEMAP: tex_type = TextureType.Cubemap elif dds.header.caps_2 & DDSCAPS2.VOLUME: tex_type = TextureType.Volume else: tex_type = TextureType.Texture mipmap_count = dds.header.mipmap_count else: tex_type = self.texture_type mipmap_count = self.mipmaps writer.reserve(f"file_data_{index}", "I") writer.reserve(f"file_size_{index}", "i") writer.pack("b", self.format) writer.pack("b", tex_type) writer.pack("b", mipmap_count) writer.pack("b", self.texture_flags) if platform != TPFPlatform.PC: writer.pack("h", self.header.width) writer.pack("h", self.header.height) if platform == TPFPlatform.Xbox360: writer.pad(4) elif platform == TPFPlatform.PS3: writer.pack("i", self.header.unk1) if tpf_flags != 0: writer.pack("i", self.header.unk2) elif platform in {TPFPlatform.PS4, TPFPlatform.XboxOne}: writer.pack("i", self.header.texture_count) writer.pack("i", self.header.unk2) writer.reserve(f"file_name_{index}", "I") writer.pack("i", 0 if self.float_struct is None else 1) if platform in {TPFPlatform.PS4, TPFPlatform.XboxOne}: writer.pack("i", self.header.dxgi_format) if self.float_struct: self.float_struct.pack(writer)
def pack_header(self, writer: BinaryWriter): writer.append(b"BHF4") writer.pack("?", self.unknown1) writer.pack("?", self.unknown2) writer.pad(3) writer.pack("?", self.big_endian) writer.pack("?", not self.bit_big_endian) # note reversal writer.pad(1) writer.pack("i", len(self._entries)) writer.pack("q", 0x40) # header size writer.pack("8s", self.signature.encode("ascii")) writer.pack("q", self.flags.get_bnd_entry_header_size()) writer.reserve("data_offset", "q") writer.pack("?", self.unicode) self.flags.pack(writer, self.bit_big_endian) writer.pack("B", self.hash_table_type) writer.pad(5) if self.hash_table_type == 4: writer.reserve("hash_table_offset", "q") else: writer.pad(8)