-
Notifications
You must be signed in to change notification settings - Fork 5
/
PTLG.cs
171 lines (138 loc) · 5.54 KB
/
PTLG.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
using AuroraLib.Common;
namespace AuroraLib.Texture.Formats
{
// base on https://github.com/KillzXGaming/Switch-Toolbox/blob/12dfbaadafb1ebcd2e07d239361039a8d05df3f7/File_Format_Library/FileFormats/NLG/MarioStrikers/StrikersRLT.cs
public class PTLG : JUTTexture, IMagicIdentify, IFileAccess
{
public bool CanRead => true;
public bool CanWrite => false;
public string Magic => magic;
private const string magic = "PTLG";
public PTLG()
{ }
public PTLG(Stream stream) : base(stream)
{
}
public PTLG(string filepath) : base(filepath)
{
}
public bool IsMatch(Stream stream, in string extension = "")
=> stream.MatchString(magic) || (extension == string.Empty && stream.At(0x10, s => s.MatchString(magic)));
protected override void Read(Stream stream)
{
if (!stream.MatchString(magic))
{
stream.Seek(0x10, SeekOrigin.Begin);
if (!stream.MatchString(magic))
throw new InvalidIdentifierException(Magic);
}
uint numTextures = stream.ReadUInt32(Endian.Big);
uint hash = stream.ReadUInt32(Endian.Big); // GC 0 Wii != 0
uint padding = stream.ReadUInt32(Endian.Big);
uint Off = stream.ReadUInt32(Endian.Big);
PTLGType type = Off == 0 ? PTLGType.GC : hash == 0 ? PTLGType.GCCompact : PTLGType.Wii;
if (Off == 0)
stream.Seek(12, SeekOrigin.Current);
else
stream.Seek(-4, SeekOrigin.Current);
Entry[] Entrys = stream.For((int)numTextures, s => s.Read<Entry>(Endian.Big));
long startPos = stream.Position;
for (int i = 0; i < numTextures; i++)
{
stream.Seek(startPos + Entrys[i].ImageOffset, SeekOrigin.Begin);
if (ReadTexture(stream, Entrys[i].SectionSize, out TexEntry current, Entrys[i].Flag))
{
Add(current);
}
}
}
public static bool ReadTexture(Stream stream, uint size, out TexEntry texture, uint flag = 0)
{
long endPos = stream.Position + size;
uint Images = stream.ReadUInt32(Endian.Big);
if (Images > 0x10)
{
//1313621792 "NLG " Font Description file
//1600939625 "_lfi" maybe a pallete or other game data?
//2142000 TPL
if (Images == 2142000)
{
List<TexEntry> entries = new();
TPL.ProcessStream(stream, stream.Position - 4, entries);
texture = entries.First();
return true;
}
texture = null;
return false;
}
uint Format0 = stream.ReadUInt32(Endian.Big); //RGB5A3 1 CMPR 2 RGBA32 3 C8 8
byte Format1 = (byte)stream.ReadByte(); //5 RGBA32 8
PTLGImageFormat PTLGFormat = (PTLGImageFormat)stream.ReadByte();
byte Format3 = (byte)stream.ReadByte(); //5 RGBA32 8
byte Format4 = (byte)stream.ReadByte(); //CMPR 0 RGB5A3 3 RGBA32 8 C8 0 || 1 || 4
GXImageFormat Format = (GXImageFormat)Enum.Parse(typeof(GXImageFormat), PTLGFormat.ToString());
ReadOnlySpan<byte> Palette = ReadOnlySpan<byte>.Empty;
ushort ImageWidth, ImageHeight;
uint Collors = 0;
ImageWidth = stream.ReadUInt16(Endian.Big);
if (ImageWidth == 0)
{
ImageWidth = stream.ReadUInt16(Endian.Big);
ImageHeight = stream.ReadUInt16(Endian.Big);
ushort pad1 = stream.ReadUInt16(Endian.Big);
Collors = stream.ReadUInt32(Endian.Big);
}
else
{
ImageHeight = stream.ReadUInt16(Endian.Big);
}
if (Collors != 0)
{
Format = GXImageFormat.C8;
Palette = stream.At(endPos - Collors * 2, SeekOrigin.Begin, s => s.Read((int)Collors * 2));
}
//The image files are aligned from end.
int imageSize = Format.GetCalculatedTotalDataSize(ImageWidth, ImageHeight, (int)Images - 1);
stream.Seek(endPos - Collors * 2 - imageSize, SeekOrigin.Begin);
texture = new(stream, Palette, Format, GXPaletteFormat.RGB5A3, (int)Collors, ImageWidth, ImageHeight, (int)Images - 1)
{
LODBias = 0,
MagnificationFilter = GXFilterMode.Nearest,
MinificationFilter = GXFilterMode.Nearest,
WrapS = GXWrapMode.CLAMP,
WrapT = GXWrapMode.CLAMP,
EnableEdgeLOD = false,
MinLOD = 0,
MaxLOD = Images - 1
};
return true;
}
protected override void Write(Stream stream)
{
throw new NotImplementedException();
}
public enum PTLGImageFormat : byte
{
I4 = 0x02,
I8 = 0x03,
IA4 = 0x04,
RGB5A3 = 0x05, // or C8
CMPR = 0x06,
RGB565 = 0x07,
RGBA32 = 0x08
}
public struct Entry
{
public uint Hash;
public uint ImageOffset;
public uint SectionSize;
public uint Flag; //0 or 12
}
public enum PTLGType
{
Wii,
GC,
GCCompact
}
}
}