Skip to content

Commit 525f3ad

Browse files
authored
patterns/magic: Add more Arma 3 files (#479)
* patterns/texheaders: Added pattern for Arma 3 texHeaders.bin * magic/arma3: Added texHeaders.bin magic * patterns/texheaders: Added test file * patterns/paa: Small improvements Added extra data description, and better indication of internally compressed data mipmap data. * patterns/a3: Moved Arma 3 patterns into common folder * patterns/a3: Added pattern for MLOD P3D * patterns/a3: Added pattern for RAP * magic/arma3: Added P3D and RAP to magic file * patterns/a3: Added test files for P3D and RAP * patterns/a3: Small correction to type names in TexHeaders format
1 parent 27480b1 commit 525f3ad

File tree

11 files changed

+565
-7
lines changed

11 files changed

+565
-7
lines changed

README.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,12 @@ Everything will immediately show up in ImHex's Content Store and gets bundled wi
3636
| ARC | | [`patterns/arc.hexpat`](patterns/arc.hexpat) | Minecraft Legacy Console Edition ARC files |
3737
| ARIA2 | | [`patterns/aria2.hexpat`](patterns/aria2.hexpat) | ARIA2 Download Manager Control files |
3838
| ARM VTOR | | [`patterns/arm_cm_vtor.hexpat`](patterns/arm_cm_vtor.hexpat) | ARM Cortex M Vector Table Layout |
39-
| Arma 3 PAA | `image/x.a3-paa` | [`patterns/a3_paa.hexpat`](patterns/a3_paa.hexpat) | Arma 3 PAA texture file |
40-
| Arma 3 RTM | `application/x.a3-rtm` | [`patterns/a3_rtm.hexpat`](patterns/a3_rtm.hexpat) | Arma 3 RTM animation file (plain) |
41-
| Arma 3 RTM (binarized) | `application/x.a3-bmtr` | [`patterns/a3_bmtr.hexpat`](patterns/a3_bmtr.hexpat) | Arma 3 RTM animation file (binarized) |
39+
| Arma 3 config | `application/x.a3-rap` | [`patterns/a3/a3_rap.hexpat`](patterns/a3/a3_rap.hexpat) | Arma 3 binary/rapified config |
40+
| Arma 3 P3D (MLOD) | `model/x.a3-p3d-mlod` | [`patterns/a3/a3_p3d_mlod.hexpat`](patterns/a3/a3_p3d_mlod.hexpat) | Arma 3 P3D model file (MLOD) |
41+
| Arma 3 PAA | `image/x.a3-paa` | [`patterns/a3/a3_paa.hexpat`](patterns/a3/a3_paa.hexpat) | Arma 3 PAA texture file |
42+
| Arma 3 RTM | `application/x.a3-rtm` | [`patterns/a3/a3_rtm.hexpat`](patterns/a3/a3_rtm.hexpat) | Arma 3 RTM animation file (plain) |
43+
| Arma 3 RTM (binarized) | `application/x.a3-bmtr` | [`patterns/a3/a3_bmtr.hexpat`](patterns/a3/a3_bmtr.hexpat) | Arma 3 RTM animation file (binarized) |
44+
| Arma 3 texHeaders.bin | `application/x.a3-texheaders` | [`patterns/a3/a3_texheaders.hexpat`](patterns/a3/a3_texheaders.hexpat) | Arma 3 texture index file |
4245
| Assassin's Creed: Unity | | [`patterns/AC Unity`](patterns/Assassin's Creed: Unity) | Assassin's Creed: Unity archive files -- .forge & .data (compressed and decompressed) -- |
4346
| Bastion | | [`patterns/bastion/*`](https://gitlab.com/EvelynTSMG/imhex-bastion-pats) | Various [Bastion](https://en.wikipedia.org/wiki/Bastion_(video_game)) files |
4447
| BeyondCompare BCSS | | [`patterns/bcss.hexpat`](patterns/bcss.hexpat) | BeyondCompare Snapshot (BCSS) file |

magic/arma3_magic

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,22 @@
2020
!:ext rtm
2121

2222
# Arma 3 binarized RTM animation
23-
0 string BMTR Arma 3 binarized RTM animation file
23+
0 string BMTR Arma 3 RTM animation file (binarized)
2424
!:mime application/x.a3-bmtr
2525
!:ext rtm
26+
27+
# Arma 3 texture index
28+
0 string 0DHT Arma 3 texture index file
29+
!:mime application/x.a3-texheaders
30+
!:ext bin
31+
32+
# Arma 3 MLOD P3D model
33+
0 string MLOD Arma 3 P3D model file (MLOD)
34+
!:mime model/x.a3-p3d-mlod
35+
!:ext p3d
36+
>0x0c string P3DM P3DM LOD type
37+
38+
# Arma 3 binarized config
39+
0x01 string raP Arma 3 binary configuration file
40+
!:mime application/x.a3-rap
41+
!:ext bin

patterns/a3/a3_p3d_mlod.hexpat

Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
#pragma author MrClock
2+
#pragma description Arma 3 P3D model format (MLOD)
3+
4+
#pragma endian little
5+
6+
#pragma MIME model/x.a3-p3d-mlod
7+
8+
fn get_data_description() {
9+
return "MLOD type P3D files are used for authoring 3D models for Arma 3.\nThese files can be carated in and edited in the Object Builder application.\nAll data is stored uncompressed for ease of editing.\nDuring the PBO packing process they are further \"binarized\" into ODOL type P3D files, that are optimized for use by the game engine. (These are no longer editable, the conversion is irreversible.)\n\nP3D model files can by quite large, so by default only the 1st LOD is processed by this pattern. Processing of all LODs can be enabled in the pattern settings.";
10+
};
11+
12+
import std.string;
13+
import std.core;
14+
15+
bool process_all_lods in;
16+
17+
using asciiz = std::string::NullString;
18+
19+
enum FaceType: u32 {
20+
TRIANGLE = 3,
21+
QUAD = 4
22+
};
23+
24+
struct Vector {
25+
float x;
26+
float y;
27+
float z;
28+
} [[static,format("formatVector")]];
29+
30+
struct UV {
31+
float u;
32+
float v;
33+
} [[static,format("formatUV")]];
34+
35+
enum SurfaceFitting: u8 {
36+
NORMAL = 0,
37+
ON_SURFACE = 1,
38+
ABOVE_SURFACE = 2,
39+
UNDER_SURFACE = 4,
40+
KEEP_HEIGHT = 8
41+
};
42+
43+
enum Lighting: u8 {
44+
NORMAL = 0,
45+
SHINING = 1,
46+
SHADOWED = 2,
47+
FULL_LIT = 4,
48+
HALF_LIT = 8
49+
};
50+
51+
enum DecalMode: u8 {
52+
NORMAL = 0,
53+
DECAL = 1,
54+
RADIO12 = 2
55+
};
56+
57+
enum Fog: u8 {
58+
NORMAL = 0,
59+
NONE = 1,
60+
SKY = 2
61+
};
62+
63+
enum NormalCalculation: u8 {
64+
FACE_AREA = 0,
65+
HIDDE_VERTEX = 1,
66+
FIXED = 2,
67+
FACE_ANLGE = 4
68+
};
69+
70+
bitfield VertexFlags {
71+
padding : 5;
72+
NormalCalculation normals : 3;
73+
u8 user;
74+
padding : 2;
75+
Fog fog : 2;
76+
padding : 2;
77+
DecalMode decal : 2;
78+
Lighting lighting : 4;
79+
SurfaceFitting surface : 4;
80+
} [[bitfield_order(std::core::BitfieldOrder::MostToLeastSignificant, 32)]];
81+
82+
struct Vertex {
83+
Vector position;
84+
VertexFlags flags;
85+
}[[static,format("formatVertex")]];
86+
87+
struct FacePoint {
88+
u32 vertex_index;
89+
u32 normal_index;
90+
UV uv;
91+
} [[static]];
92+
93+
enum ZBiasFlag: u8 {
94+
NONE = 0,
95+
LOW = 1,
96+
MIDDLE = 2,
97+
HIGH = 3
98+
};
99+
100+
bitfield FaceFlags {
101+
user : 7;
102+
disable_texture_merging : 1;
103+
padding : 2;
104+
flat_lighting : 1;
105+
reversed_face : 1;
106+
padding : 10;
107+
ZBiasFlag zbias : 2;
108+
position : 1;
109+
padding : 1;
110+
double_sided_face : 1;
111+
disable_shadow : 1;
112+
padding : 4;
113+
} [[bitfield_order(std::core::BitfieldOrder::MostToLeastSignificant, 32)]];
114+
115+
struct Face {
116+
FaceType type;
117+
FacePoint points[4];
118+
FaceFlags flags;
119+
asciiz texture;
120+
asciiz material;
121+
} [[format("formatFace")]];
122+
123+
struct Edge {
124+
u32 vertex_1;
125+
u32 vertex_2;
126+
} [[sealed,static,format("formatEdge")]];
127+
128+
struct Property {
129+
char name[64] [[transform("std::string::to_string")]];
130+
char value[64] [[transform("std::string::to_string")]];
131+
} [[static,sealed,format("formatProperty")]];
132+
133+
struct Tagg {
134+
bool active;
135+
asciiz name;
136+
u32 length;
137+
138+
if (name == "#EndOfFile#") {
139+
break;
140+
}
141+
142+
match (name) {
143+
("#SharpEdges#"): Edge edges[length/8];
144+
("#Property#"): Property property;
145+
("#Mass#"): float masses[parent.count_verticies];
146+
("#UVSet#"): {
147+
u32 channel;
148+
UV coordinates[(length - 4) / 8];
149+
}
150+
(_): if (std::string::starts_with(name, "#") && std::string::ends_with(name, "#")) {
151+
u8 unknown_data[length];
152+
} else {
153+
u8 vertex_weights[parent.count_verticies];
154+
u8 face_weights[parent.count_faces];
155+
}
156+
}
157+
} [[format("formatTagg")]];
158+
159+
struct P3dmLod {
160+
char signature[4];
161+
u32 version_major;
162+
u32 version_minor;
163+
u32 count_verticies;
164+
u32 count_normals;
165+
u32 count_faces;
166+
u32; // Unknown data (might be unused model flags)
167+
Vertex verticies[count_verticies];
168+
Vector normals[count_normals];
169+
Face faces[count_faces];
170+
char tagg_signature[4];
171+
Tagg taggs[while(true)];
172+
float resolution;
173+
} [[format("formatP3dmLod")]];
174+
175+
struct P3D {
176+
char signature[4];
177+
u32 version;
178+
u32 count_lods;
179+
if (!process_all_lods) {
180+
P3dmLod lod_0;
181+
} else {
182+
P3dmLod lods[count_lods];
183+
}
184+
};
185+
186+
fn formatVector(ref Vector pos) {
187+
return std::format("[{0:.3f}, {1:.3f}, {1:.3f}]", pos.x, pos.y, pos.z);
188+
};
189+
190+
fn formatUV(ref UV pos) {
191+
return std::format("[{0:.3f}, {1:.3f}]", pos.u, pos.v);
192+
};
193+
194+
fn formatVertex(ref Vertex vert) {
195+
return formatVector(vert.position);
196+
};
197+
198+
fn formatFace(ref Face face) {
199+
return face.type == FaceType::TRIANGLE ? "triangle" : "quad";
200+
};
201+
202+
fn formatEdge(ref Edge edge) {
203+
return std::format("{0:d} <-> {1:d}", edge.vertex_1, edge.vertex_2);
204+
};
205+
206+
fn formatProperty(ref Property prop) {
207+
return std::format("\"{0:s}\" = \"{1:s}\"", prop.name, prop.value);
208+
};
209+
210+
fn formatTagg(ref Tagg tagg) {
211+
if (std::core::has_member(tagg, "vertex_weights")) {
212+
return std::format("\"{0:s}\" selection", tagg.name);
213+
} else {
214+
return std::format("\"{0:s}\"", tagg.name);
215+
}
216+
};
217+
218+
fn formatP3dmLod(ref P3dmLod lod) {
219+
return std::format("Resolution: {0}", lod.resolution);
220+
};
221+
222+
P3D file @ 0x0000;
Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@
55

66
#pragma MIME image/x.a3-paa
77

8+
fn get_data_description() {
9+
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.";
10+
};
11+
812
import type.color;
913
import std.mem;
1014
import std.sys;
@@ -50,6 +54,12 @@ enum Swizzle: u8 {
5054
BLANK_BLACK = 9
5155
};
5256

57+
enum Compression: u8 {
58+
NONE = 0,
59+
LZO1X = 1,
60+
LZSS = 2
61+
};
62+
5363
struct Tagg {
5464
char signature[8];
5565
u32 length;
@@ -73,14 +83,25 @@ struct Mipmap {
7383
u16 width_and_lzo [[format("format_width_lzo")]];
7484
u16 height;
7585

76-
u16 width = width_and_lzo & 0x7FFF;
86+
u16 width = width_and_lzo;
87+
Compression compression = Compression::NONE;
88+
if ((u32(parent.format) & 0xFF00) == 0xFF00) {
89+
width = width_and_lzo & 0x7FFF;
90+
compression = width_and_lzo & 0x8000 ? Compression::LZO1X : Compression::NONE;
91+
} else {
92+
compression = Compression::LZSS;
93+
}
7794

7895
if (width == 0 && height == 0) {
7996
break;
8097
}
8198

8299
u24 size;
83-
u8 data[size];
100+
match (compression) {
101+
(Compression::NONE): u8 encoded_data[size];
102+
(Compression::LZO1X): u8 lzo_compressed_data[size];
103+
(Compression::LZSS): u8 lzss_compressed_data[size];
104+
}
84105
} [[format("format_resolution")]];
85106

86107
struct PAA {
@@ -100,7 +121,7 @@ fn format_resolution(ref auto mip) {
100121
fn format_width_lzo(u16 value) {
101122
u16 width = value & 0x7FFF;
102123
if (value & 0x8000) {
103-
return std::format("{0:d} (+LZO)", width);
124+
return std::format("{0:d} (+LZO flag)", width);
104125
} else {
105126
return std::format("{0:d}", width);
106127
}

0 commit comments

Comments
 (0)