Skip to content

Commit 6a2a963

Browse files
authored
patterns: Add pattern and magic for Arma 3 RTM (#478)
* patterns/rtm: Added pattern for Arma 3 plain RTM * magic/arma3: Added plain RTM to magic file * patterns/rtm: Added test file * patterns/rtm: Changed function parameters to refs * patterns/rtm: Replaced RTM test file * patterns/rtm: Added extra description to RTM pattern * pattern/bmtr: Added BMTR pattern, magic and test file
1 parent cee3a5d commit 6a2a963

File tree

6 files changed

+235
-1
lines changed

6 files changed

+235
-1
lines changed

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,9 @@ 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 | | [`patterns/a3_paa.hexpat`](patterns/a3_paa.hexpat) | Arma 3 PAA texture file |
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) |
4042
| Assassin's Creed: Unity | | [`patterns/AC Unity`](patterns/Assassin's Creed: Unity) | Assassin's Creed: Unity archive files -- .forge & .data (compressed and decompressed) -- |
4143
| Bastion | | [`patterns/bastion/*`](https://gitlab.com/EvelynTSMG/imhex-bastion-pats) | Various [Bastion](https://en.wikipedia.org/wiki/Bastion_(video_game)) files |
4244
| BeyondCompare BCSS | | [`patterns/bcss.hexpat`](patterns/bcss.hexpat) | BeyondCompare Snapshot (BCSS) file |

magic/arma3_magic

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,13 @@
1313
>0 leshort 0x1555 RGBA5 format
1414
>0 leshort 0x8888 RGBA8 format
1515
>0 leshort 0x8080 Grayscale format
16+
17+
# Arma 3 RTM animation
18+
0 string RTM_ Arma 3 RTM animation file (plain)
19+
!:mime application/x.a3-rtm
20+
!:ext rtm
21+
22+
# Arma 3 binarized RTM animation
23+
0 string BMTR Arma 3 binarized RTM animation file
24+
!:mime application/x.a3-bmtr
25+
!:ext rtm

patterns/a3_bmtr.hexpat

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
#pragma author MrClock
2+
#pragma description Arma 3 RTM animation format (binarized)
3+
4+
#pragma endian little
5+
6+
#pragma MIME application/x.a3-bmtr
7+
8+
fn get_data_description() {
9+
return "Binarized RTM (BMTR) animation files are the PBO packed versions of plain RTMs.\n Binarized files are optimized for use by the game engine, and they are not editable.\nBone transformations are stored as relative quaternion-vector pairs.\nData blocks are conditionally LZO1X compressed (these are not supported by this pattern).";
10+
};
11+
12+
import std.string;
13+
import std.sys;
14+
import type.float16;
15+
16+
using asciiz = std::string::NullString [[format("formatAsciiz")]];
17+
using half = type::float16 ;
18+
struct s16float {
19+
s16 data;
20+
} [[sealed,static,transform("transforms16float"), format("transforms16float")]];
21+
22+
struct Property {
23+
padding[4];
24+
asciiz name;
25+
float phase;
26+
asciiz value;
27+
} [[format("formatProperty")]];
28+
29+
struct Vector<DataType> {
30+
DataType x [[comment("+Left/-Right")]];
31+
DataType y [[comment("+Up/-Down (UNUSED)")]];
32+
DataType z [[comment("+Forward/-Backward")]];
33+
} [[static]];
34+
35+
struct Quaternion {
36+
s16float x;
37+
s16float y;
38+
s16float z;
39+
s16float w;
40+
} [[static,format("formatQuaternion")]];
41+
42+
struct Transform {
43+
Quaternion orientation;
44+
Vector<half> position [[format("formatVectorHalf")]];
45+
} [[static]];
46+
47+
struct Frame {
48+
u32 count_bones;
49+
bool compressed = count_bones * sizeof(Transform) >= 1024;
50+
if (parent.version > 4) {
51+
u8 lzo_flag;
52+
compressed = lzo_flag > 0;
53+
}
54+
55+
if (compressed) {
56+
std::error("Transformations are LZO compressed and compressed length is unknown");
57+
} else {
58+
Transform transforms[count_bones];
59+
}
60+
};
61+
62+
struct BMTR {
63+
char signature[4];
64+
u32 version;
65+
padding[1];
66+
Vector<float> motion [[format("formatVectorFloat")]];
67+
u32 count_frames;
68+
padding[4];
69+
u32 count_bones;
70+
u32 count_bones_again;
71+
72+
std::assert_warn(count_bones == count_bones_again, "Mismatch between bone counts");
73+
74+
asciiz bones[count_bones];
75+
76+
if (version >= 4) {
77+
padding[4];
78+
u32 count_properties;
79+
Property properties[count_properties];
80+
}
81+
82+
u32 count_phases;
83+
std::assert_warn(count_frames == count_phases, "Frame and phase counts do not match");
84+
85+
bool compressed = count_phases * sizeof(float) >= 1024;
86+
if (version > 4) {
87+
u8 lzo_flag;
88+
compressed = lzo_flag > 0;
89+
}
90+
91+
if (compressed) {
92+
std::error("Phases are LZO compressed and compressed length is unknown");
93+
} else {
94+
float phases[count_phases];
95+
}
96+
97+
Frame frames[count_frames];
98+
};
99+
100+
fn transforms16float(ref s16float value) {
101+
return float(value.data) / 16384;
102+
};
103+
104+
fn formatAsciiz(ref asciiz value) {
105+
return std::format("\"{:s}\"", value);
106+
};
107+
108+
fn formatProperty(ref Property prop) {
109+
return std::format("\"{0:s}\" = \"{1:s}\" @ {2:.4f}", prop.name, prop.value, prop.phase);
110+
};
111+
112+
fn formatVectorHalf(ref Vector<half> vec) {
113+
return std::format(
114+
"[{0}, {1}, {2}]",
115+
type::impl::format_float16(vec.x),
116+
type::impl::format_float16(vec.y),
117+
type::impl::format_float16(vec.z)
118+
);
119+
};
120+
121+
fn formatVectorFloat(ref Vector<float> vec) {
122+
return std::format("[{0:.2f}, {1:.2f}, {2:.2f}]", vec.x, vec.y, vec.z);
123+
};
124+
125+
fn formatQuaternion(ref Quaternion q) {
126+
return std::format("[{0:.2f}, {1:.2f}, {2:.2f}, {3:.2f}]", q.x, q.y, q.z, q.w);
127+
};
128+
129+
BMTR file @ 0x0000;

patterns/a3_rtm.hexpat

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
#pragma author MrClock
2+
#pragma description Arma 3 RTM animation format (plain)
3+
4+
#pragma endian little
5+
6+
#pragma MIME application/x.a3-rtm
7+
8+
fn get_data_description() {
9+
return "Plain RTM animation files are used in animation authoring for Arma 3.\nThey can be created and edited in Object Builder.\nBone transformations are stored as absolute transformation matrices.\nPlain RTMs must be converted to their \"binarized\" versions by an appropriate PBO packing tool for use in game.";
10+
};
11+
12+
import std.mem;
13+
import std.sys;
14+
import std.string;
15+
import std.io;
16+
17+
using lascii = std::string::SizedString<u8> [[format("formatLascii")]];
18+
19+
struct Property {
20+
float phase;
21+
lascii name;
22+
lascii value;
23+
} [[format("formatProperty")]];
24+
25+
struct Bone {
26+
char name[32];
27+
} [[sealed,static,transform("transformBone"),format("formatBone")]];
28+
29+
struct Transform {
30+
Bone bone;
31+
float matrix[12] [[comment("4x4 transformation matrix (with last row omitted)")]];
32+
} [[static,format("formatTransform")]];
33+
34+
struct Frame {
35+
float phase;
36+
Transform transforms[parent.count_bones];
37+
} [[static,format("formatFrame")]];
38+
39+
struct Vector {
40+
float x [[comment("+Left/-Right")]];
41+
float y [[comment("+Up/-Down (UNUSED)")]];
42+
float z [[comment("+Forward/-Backward")]];
43+
} [[static,format("formatVector")]];
44+
45+
struct RTM {
46+
if (std::mem::read_string($, 8) == "RTM_MDAT") {
47+
char properties_signature[8];
48+
padding[4];
49+
u32 count_properties;
50+
Property properties[count_properties];
51+
}
52+
53+
std::assert(std::mem::read_string($, 8) == "RTM_0101", "Missing animation data");
54+
55+
char animation_signature[8];
56+
Vector motion;
57+
u32 count_frames;
58+
u32 count_bones;
59+
Bone bones[count_bones];
60+
Frame frames[count_frames];
61+
62+
std::assert_warn(std::mem::eof(), "Data ended before EOF");
63+
};
64+
65+
fn formatLascii(ref lascii value) {
66+
return std::format("\"{:s}\"", value);
67+
};
68+
69+
fn formatProperty(ref Property prop) {
70+
return std::format("\"{0:s}\" = \"{1:s}\" @ {2:.4f}", prop.name, prop.value, prop.phase);
71+
};
72+
73+
fn transformBone(ref Bone value) {
74+
return std::string::to_string(value.name);
75+
};
76+
77+
fn formatBone(ref Bone value) {
78+
return std::format("\"{0:s}\"", value);
79+
};
80+
81+
fn formatTransform(ref Transform transform) {
82+
return std::format("\"{0:s}\" transform", transform.bone);
83+
};
84+
85+
fn formatFrame(ref Frame frame) {
86+
return std::format("frame @ {0:.4f}", frame.phase);
87+
};
88+
89+
fn formatVector(ref Vector vec) {
90+
return std::format("[{0:.2f}, {1:.2f}, {2:.2f}]", vec.x, vec.y, vec.z);
91+
};
92+
93+
RTM file @ 0x0000;
247 Bytes
Binary file not shown.
849 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)