internal Texture(BinaryReaderEx br, TPFPlatform platform, byte encoding) { int fileOffset = br.ReadInt32(); int fileSize = br.ReadInt32(); Format = br.ReadByte(); Cubemap = br.ReadBoolean(); Mipmaps = br.ReadByte(); Flags1 = br.AssertByte(0, 1, 2, 3); int nameOffset = 0; if (platform == TPFPlatform.PC) { Header = null; nameOffset = br.ReadInt32(); Flags2 = br.AssertInt32(0, 1); } else if (platform == TPFPlatform.PS3) { Header = new TexHeader(); Header.Width = br.ReadInt16(); Header.Height = br.ReadInt16(); Header.Unk1 = br.ReadInt32(); Header.Unk2 = br.AssertInt32(0, 0xAAE4); nameOffset = br.ReadInt32(); Flags2 = br.AssertInt32(0, 1); } else if (platform == TPFPlatform.PS4 || platform == TPFPlatform.Xbone) { Header = new TexHeader(); Header.Width = br.ReadInt16(); Header.Height = br.ReadInt16(); Header.TextureCount = br.AssertByte(1, 6); br.AssertByte(0); br.AssertByte(0); br.AssertByte(0); Header.Unk2 = br.AssertInt32(0xD); nameOffset = br.ReadInt32(); Flags2 = br.AssertInt32(0, 1); Header.DXGIFormat = br.ReadInt32(); } Bytes = br.GetBytes(fileOffset, fileSize); if (Flags1 == 2 || Flags1 == 3) { Bytes = DCX.Decompress(Bytes); } if (encoding == 1) { Name = br.GetUTF16(nameOffset); } else if (encoding == 0 || encoding == 2) { Name = br.GetShiftJIS(nameOffset); } }
/// <summary> /// Creates an empty TPF configured for DS3. /// </summary> public TPF() { Textures = new List <Texture>(); Platform = TPFPlatform.PC; Encoding = 1; Flag2 = 3; }
public void ConvertPS3ToPC() { if (Platform != TPFPlatform.PS3) { return; } Platform = TPFPlatform.PC; foreach (Texture tex in Textures) { tex.ConsoleToPC(TPFPlatform.PS3); } }
public void ConvertPS4ToPC() { if (Platform != TPFPlatform.PS4) { return; } Platform = TPFPlatform.PC; foreach (Texture tex in Textures) { tex.PS4ToPC(); } }
internal void Write(BinaryWriterEx bw, int index, TPFPlatform platform) { if (platform == TPFPlatform.PC) { DDS dds = new DDS(Bytes); // DDSCAPS2_CUBEMAP Cubemap = (dds.dwCaps2 & 0x200) != 0; Mipmaps = (byte)dds.dwMipMapCount; } bw.ReserveInt32($"FileData{index}"); bw.ReserveInt32($"FileSize{index}"); bw.WriteByte(Format); bw.WriteBoolean(Cubemap); bw.WriteByte(Mipmaps); bw.WriteByte(Flags1); if (platform == TPFPlatform.PC) { bw.ReserveInt32($"FileName{index}"); bw.WriteInt32(Flags2); } else if (platform == TPFPlatform.PS3) { bw.WriteInt16(Header.Width); bw.WriteInt16(Header.Height); bw.WriteInt32(Header.Unk1); bw.WriteInt32(Header.Unk2); bw.ReserveInt32($"FileName{index}"); bw.WriteInt32(Flags2); } else if (platform == TPFPlatform.PS4 || platform == TPFPlatform.Xbone) { bw.WriteInt16(Header.Width); bw.WriteInt16(Header.Height); bw.WriteByte(Header.TextureCount); bw.WriteByte(0); bw.WriteByte(0); bw.WriteByte(0); bw.WriteInt32(Header.Unk2); bw.ReserveInt32($"FileName{index}"); bw.WriteInt32(Flags2); bw.WriteInt32(Header.DXGIFormat); } }
/// <summary> /// Reads TPF data from a BinaryReaderEx. /// </summary> internal override void Read(BinaryReaderEx br) { br.BigEndian = false; br.AssertASCII("TPF\0"); br.BigEndian = br.GetByte(0xC) == 2; int totalFileSize = br.ReadInt32(); int fileCount = br.ReadInt32(); Platform = br.ReadEnum8 <TPFPlatform>(); Flag2 = br.AssertByte(1, 2, 3); Encoding = br.AssertByte(0, 1, 2); br.AssertByte(0); Textures = new List <Texture>(fileCount); for (int i = 0; i < fileCount; i++) { Textures.Add(new Texture(br, Platform, Encoding)); } }
internal void WriteHeader(BinaryWriterEx bw, int index, TPFPlatform platform, byte flag2) { if (platform == TPFPlatform.PC) { DDS dds = new DDS(Bytes); if (dds.dwCaps2.HasFlag(DDS.DDSCAPS2.CUBEMAP)) { Type = TexType.Cubemap; } else if (dds.dwCaps2.HasFlag(DDS.DDSCAPS2.VOLUME)) { Type = TexType.Volume; } else { Type = TexType.Texture; } Mipmaps = (byte)dds.dwMipMapCount; } bw.ReserveUInt32($"FileData{index}"); bw.ReserveInt32($"FileSize{index}"); bw.WriteByte(Format); bw.WriteByte((byte)Type); bw.WriteByte(Mipmaps); bw.WriteByte(Flags1); if (platform != TPFPlatform.PC) { bw.WriteInt16(Header.Width); bw.WriteInt16(Header.Height); if (platform == TPFPlatform.Xbox360) { bw.WriteInt32(0); } else if (platform == TPFPlatform.PS3) { bw.WriteInt32(Header.Unk1); if (flag2 != 0) { bw.WriteInt32(Header.Unk2); } } else if (platform == TPFPlatform.PS4 || platform == TPFPlatform.Xbone) { bw.WriteInt32(Header.TextureCount); bw.WriteInt32(Header.Unk2); } } bw.ReserveUInt32($"FileName{index}"); bw.WriteInt32(FloatStruct == null ? 0 : 1); if (platform == TPFPlatform.PS4 || platform == TPFPlatform.Xbone) { bw.WriteInt32(Header.DXGIFormat); } if (FloatStruct != null) { FloatStruct.Write(bw); } }
internal Texture(BinaryReaderEx br, TPFPlatform platform, byte flag2, byte encoding) { uint fileOffset = br.ReadUInt32(); int fileSize = br.ReadInt32(); Format = br.ReadByte(); Type = br.ReadEnum8 <TexType>(); Mipmaps = br.ReadByte(); Flags1 = br.AssertByte(0, 1, 2, 3); if (platform != TPFPlatform.PC) { Header = new TexHeader(); Header.Width = br.ReadInt16(); Header.Height = br.ReadInt16(); if (platform == TPFPlatform.Xbox360) { br.AssertInt32(0); } else if (platform == TPFPlatform.PS3) { Header.Unk1 = br.ReadInt32(); if (flag2 != 0) { Header.Unk2 = br.AssertInt32(0, 0x69E0, 0xAAE4); } } else if (platform == TPFPlatform.PS4 || platform == TPFPlatform.Xbone) { Header.TextureCount = br.AssertInt32(1, 6); Header.Unk2 = br.AssertInt32(0xD); } } uint nameOffset = br.ReadUInt32(); bool hasFloatStruct = br.AssertInt32(0, 1) == 1; if (platform == TPFPlatform.PS4 || platform == TPFPlatform.Xbone) { Header.DXGIFormat = br.ReadInt32(); } if (hasFloatStruct) { FloatStruct = new FloatStruct(br); } Bytes = br.GetBytes(fileOffset, fileSize); if (Flags1 == 2 || Flags1 == 3) { Bytes = DCX.Decompress(Bytes, out DCX.Type type); if (type != DCX.Type.DCP_EDGE) { throw new NotImplementedException($"TPF compression is expected to be DCP_EDGE, but it was {type}"); } } if (encoding == 1) { Name = br.GetUTF16(nameOffset); } else if (encoding == 0 || encoding == 2) { Name = br.GetShiftJIS(nameOffset); } }
// <summary> // Convert the internal format to PC tpf format // </summary> public void ConsoleToPC(TPFPlatform source) { // Need to create a DDS Header BinaryWriterEx bw = new BinaryWriterEx(false); bw.WriteASCII("DDS "); bw.WriteInt32(124); bw.WriteUInt32(659463); // Flags bw.WriteUInt32((uint)Header.Height); bw.WriteUInt32((uint)Header.Width); bw.WriteUInt32(((uint)Header.Width * (uint)Header.Height) / 2); // Dummy pitch size bw.WriteUInt32(1); // Depth if (source == TPFPlatform.PS3) { // DeS sometimes has mipmap count set to 0 :trashcat: if (Mipmaps == 0) { var dim = Math.Max(Header.Width, Header.Height); while (dim >= 1) { Mipmaps++; dim >>= 1; } } } bw.WriteUInt32(Mipmaps); for (int i = 0; i < 11; i++) { bw.WriteInt32(0); } // Pixel format bw.WriteInt32(32); bw.WriteInt32(4); // Flags (compressed) bool writeExtendedHeader = false; if (Header.DXGIFormat == 71 || Header.DXGIFormat == 72 || (source == TPFPlatform.PS3 && (Format == 0 || Format == 1))) { bw.WriteASCII("DXT1"); } else if (Header.DXGIFormat == 73 || Header.DXGIFormat == 74 || Header.DXGIFormat == 75 || (source == TPFPlatform.PS3 && (Format == 2 || Format == 3))) { bw.WriteASCII("DXT3"); } else if (Header.DXGIFormat == 76 || Header.DXGIFormat == 77 || Header.DXGIFormat == 78 || (source == TPFPlatform.PS3 && (Format == 4 || Format == 5))) { bw.WriteASCII("DXT5"); } else if (Header.DXGIFormat == 79 || Header.DXGIFormat == 80 || Header.DXGIFormat == 81) { bw.WriteASCII("ATI1"); } else if (Header.DXGIFormat == 82 || Header.DXGIFormat == 83 || Header.DXGIFormat == 84) { bw.WriteASCII("ATI2"); } else if (source == TPFPlatform.PS3 && (Format == 9 || Format == 10)) { bw.WriteASCII("DXT1"); Console.WriteLine("ARGB"); } else { bw.WriteASCII("DX10"); writeExtendedHeader = true; } bw.WriteInt32(0); bw.WriteInt32(0); bw.WriteInt32(0); bw.WriteInt32(0); bw.WriteInt32(0); bw.WriteUInt32(0x401008); // Caps if (Cubemap) { bw.WriteUInt32(0xFE00); } else { bw.WriteUInt32(0); } bw.WriteUInt32(0); bw.WriteUInt32(0); bw.WriteUInt32(0); // DX10 extended header if (writeExtendedHeader) { bw.WriteInt32(Header.DXGIFormat); bw.WriteUInt32(3); // 2D texture if (Cubemap) { bw.WriteUInt32(0x4); } else { bw.WriteUInt32(0); } bw.WriteUInt32(1); // Array Size bw.WriteUInt32(0); // Misc } // Next attempt to unswizzle the texture byte[] unswizzled = new byte[Bytes.Length]; for (int i = 0; i < unswizzled.Length; i++) { unswizzled[i] = Bytes[i]; } if (source == TPFPlatform.PS4) { uint blockSize = 16; if (Header.DXGIFormat == 71 || Header.DXGIFormat == 72 || Header.DXGIFormat == 79 || Header.DXGIFormat == 80 || Header.DXGIFormat == 81) { blockSize = 8; } int mipBase = 0; int mipBaseSrc = 0; for (int miplevel = 0; miplevel < Mipmaps; miplevel++) { uint bytesPerLine = Math.Max((uint)Header.Width >> miplevel, 1) * blockSize / 4; int heightBlock = Math.Max((Header.Height / 4) >> miplevel, 1); int widthBlock = Math.Max((Header.Width / 4) >> miplevel, 1); // Convert swizzled to linear strided int index = 0; for (int y = 0; y < heightBlock; y++) { for (int x = 0; x < widthBlock; x++) { int mx = x; int my = y; if (widthBlock > 1 && heightBlock > 1) { MapBlockPosition(x, y, widthBlock, 2, out mx, out my); } if (widthBlock > 2 && heightBlock > 2) { MapBlockPosition(mx, my, widthBlock, 4, out mx, out my); } if (widthBlock > 4 && heightBlock > 4) { MapBlockPosition(mx, my, widthBlock, 8, out mx, out my); } int destinationIndex = (int)blockSize * (my * widthBlock + mx); for (int i = 0; i < blockSize; i++) { unswizzled[mipBase + destinationIndex + i] = Bytes[mipBaseSrc + index]; index += 1; } } } mipBase += index; if (index < 512) { mipBaseSrc += 512; } else { mipBaseSrc += index; } } } // Append the rest of the original texture and update bw.WriteBytes(unswizzled); Bytes = bw.FinishBytes(); }
internal Texture(BinaryReaderEx br, TPFPlatform platform, byte flag2, byte encoding) { uint fileOffset = br.ReadUInt32(); int fileSize = br.ReadInt32(); Format = br.ReadByte(); Type = br.ReadEnum8 <TexType>(); Mipmaps = br.ReadByte(); Flags1 = br.AssertByte(0, 1, 2, 3); uint nameOffset = uint.MaxValue; if (platform == TPFPlatform.PC) { Header = null; nameOffset = br.ReadUInt32(); Flags2 = br.AssertInt32(0, 1); } else { Header = new TexHeader(); Header.Width = br.ReadInt16(); Header.Height = br.ReadInt16(); if (platform == TPFPlatform.Xbox360) { br.AssertInt32(0); nameOffset = br.ReadUInt32(); br.AssertInt32(0); } else if (platform == TPFPlatform.PS3) { Header.Unk1 = br.ReadInt32(); if (flag2 != 0) { Header.Unk2 = br.AssertInt32(0, 0xAAE4); } nameOffset = br.ReadUInt32(); Flags2 = br.AssertInt32(0, 1); if (Flags2 == 1) { Unk20 = br.ReadInt32(); Unk24 = br.ReadInt32(); Unk28 = br.ReadSingle(); } } else if (platform == TPFPlatform.PS4 || platform == TPFPlatform.Xbone) { Header.TextureCount = br.AssertInt32(1, 6); Header.Unk2 = br.AssertInt32(0xD); nameOffset = br.ReadUInt32(); Flags2 = br.AssertInt32(0, 1); Header.DXGIFormat = br.ReadInt32(); } } Bytes = br.GetBytes(fileOffset, fileSize); if (Flags1 == 2 || Flags1 == 3) { Bytes = DCX.Decompress(Bytes); } if (encoding == 1) { Name = br.GetUTF16(nameOffset); } else if (encoding == 0 || encoding == 2) { Name = br.GetShiftJIS(nameOffset); } }