Repository navigation
Expand file tree
/
Copy patha3_paa.hexpat
More file actions
141 lines (118 loc) · 3.42 KB
/
Copy patha3_paa.hexpat
File metadata and controls
141 lines (118 loc) · 3.42 KB
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
#pragma author MrClock
#pragma description Arma 3 PAA image format
#pragma endian little
#pragma MIME image/x.a3-paa
fn get_data_description() {
return "PAA texture files are the proprietary image format used for textures in Arma 3.\nSimilar to most other formats used in game engines, the PAA stores not only a single resolution, but a series of precomputed mipmaps.\nPAA supports multiple pixel encoding formats, such as DXT1, DXT5, RGBA5551, grayscale, and others. Mipmap data in DXT encoded files is optionally compressed with the LZO1X algorithm. All other types are unconditionally LZSS compressed.";
};
import type.color;
import std.mem;
import std.sys;
struct Color<auto alpha> {
u8 b;
u8 g;
u8 r;
if (alpha) u8 a;
} [[sealed, format("type::impl::format_color"), color(std::format("{0:02X}{1:02X}{2:02X}", r, g, b))]];
using BGR8 = Color<false>;
using BGRA8 = Color<true>;
enum PixelFormat: u16 {
DXT1 = 0xFF01,
DXT2 = 0xFF02,
DXT3 = 0xFF03,
DXT4 = 0xFF04,
DXT5 = 0xFF05,
RGBA4 = 0x4444,
RGBA5 = 0x1555,
RGBA8 = 0x8888,
GRAY = 0x8080
};
enum AlphaMode: u32 {
NONE = 0,
INTERPOLATED = 1,
BINARY = 2
};
enum Swizzle: u8 {
ALPHA = 0,
RED = 1,
GREEN = 2,
BLUE = 3,
INVERTED_ALPHA = 4,
INVERTED_RED = 5,
INVERTED_GREEN = 6,
INVERTED_BLUE = 7,
BLANK_WHITE = 8,
BLANK_BLACK = 9
};
enum Compression: u8 {
NONE = 0,
LZO1X = 1,
LZSS = 2
};
struct Tagg {
char signature[8];
u32 length;
match (signature) {
("GGATCGVA"): BGRA8 color;
("GGATCXAM"): BGRA8 color;
("GGATGALF"): AlphaMode alpha;
("GGATSFFO"): u32 offsets[16];
("GGATZIWS"): Swizzle copies[4];
(_): u8 data[length];
}
} [[format("format_tagg_name")]];
struct Palette {
u16 length;
BGR8 colors[length];
};
struct Mipmap {
u16 width_and_lzo [[format("format_width_lzo")]];
u16 height;
u16 width = width_and_lzo;
Compression compression = Compression::NONE;
if ((u32(parent.format) & 0xFF00) == 0xFF00) {
width = width_and_lzo & 0x7FFF;
compression = width_and_lzo & 0x8000 ? Compression::LZO1X : Compression::NONE;
} else {
compression = Compression::LZSS;
}
if (width == 0 && height == 0) {
break;
}
u24 size;
match (compression) {
(Compression::NONE): u8 encoded_data[size];
(Compression::LZO1X): u8 lzo_compressed_data[size];
(Compression::LZSS): u8 lzss_compressed_data[size];
}
} [[format("format_resolution")]];
struct PAA {
PixelFormat format;
Tagg taggs[while(std::mem::read_string($, 4) == "GGAT")];
Palette palette;
Mipmap mipmaps[while(true)];
u16 EOF;
std::assert_warn(EOF == 0, "Invalid EOF sentinel");
};
fn format_resolution(ref auto mip) {
return std::format("{0:d} x {1:d}", mip.width, mip.height);
};
fn format_width_lzo(u16 value) {
u16 width = value & 0x7FFF;
if (value & 0x8000) {
return std::format("{0:d} (+LZO flag)", width);
} else {
return std::format("{0:d}", width);
}
};
fn format_tagg_name(Tagg data) {
match (data.signature) {
("GGATCGVA"): return "Average color";
("GGATCXAM"): return "Max color";
("GGATGALF"): return "Alpha flag";
("GGATZIWS"): return "Swizzle";
("GGATSFFO"): return "Mipmap offsets";
(_): return "Unknown";
}
};
PAA file @ 0x0000;