-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathACT_Image_File.txt
213 lines (183 loc) · 7.99 KB
/
ACT_Image_File.txt
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
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
ACT Image File
Author: Michael Gaisser (mjgaisser@gmail.com)
Site: https://github.com/MikeG621
Updated: 2023.07.01
=====
The .ACT file is primarily used for backdrops and explosion graphics in TIE95
and XvT/BoP. The ACT format is also used in the XACT LFD Resource, although
this seems to be deprecated in TIE95 in favor of separate *.ACT files.
For the purpose of this document, the use of *.ACT files will be assumed. To
use for XACTs, add the standard LFD header information.
=====
ACT Structure
The following values are used through this and all of my file definitions
unless otherwise specified:
NAME LENGTH DESC
---- ------ ----
BYTE 1 unsigned 8-bit
SHORT 2 signed Int16
INT 4 signed Int32
LONG 8 signed Int64
--
FileHeader
INT[FrameCount] FrameOffsets
Frame[FrameCount] ImageData
Color[GlobalColorCount] GlobalColors
--
struct FileHeader (size 0x34)
{
0x00 INT Length
0x04 INT TotalColorCount
0x08 INT Reserved (0)
0x0C INT GlobalColorJump
0x10 INT FrameOffsetsJump (0x34)
0x14 INT Reserved (0) [In-memory palette jump]
0x18 INT FrameCount
0x1C INT ImageWidth [zero-indexed]
0x20 INT ImageHeight [zero-indexed]
0x24 INT CenterX
0x28 INT CenterY
0x2C INT UseGlobalColors (0 || 0x18)
0x30 INT GlobalColorCount
}
struct Frame
{
0x0000 FrameHeader
0x002C Color[ColorCount]
INT FrameLeft [rel to CENTER_X, likely -]
INT FrameTop [rel to CENTER_Y, likely -]
INT FrameRight [rel to CENTER_X, likely +]
INT FrameTop
Row[FrameHeight]
BYTE EndFrame (0xFF)
}
struct FrameHeader (size 0x2C)
{
0x00 INT FrameLength
0x04 INT FrameColorsJump (0x2C)
0x08 INT ImageDataJump (to FrameLeft)
0x0C INT Reserved (FrameLength) [In-memory palette jump]
0x10 INT FrameWidth
0x14 INT FrameHeight
0x18 LONG Reserved (0)
0x20 INT LengthBitCount
0x24 INT UseFrameColors (0 || 0x18)
0x28 INT ColorCount
}
struct Color (size 0x4)
{
0x00 BYTE Red
0x01 BYTE Green
0x02 BYTE Blue
0x03 BYTE Reserved (0)
}
struct Row
{
OpCode[]
BYTE EndRow (0xFE)
}
struct OpCode
{
BYTE Value
#if (Value==0xFB) (Shift)
SHORT IndexShift
#elseif (Value==0xFC) (Blank)
BYTE NumRepeat
#elseif (Value==0xFD) (Repeat)
BYTE NumRepeat
BYTE ColorIndex
#else (Short)
#endif
}
=====
ACT Structure Details
Yet another graphics format for the X-wing series; I think for TIE95 this is my
7th graphic write-up. This format borrows from some of the other formats, which
makes sense seeing that this came around later. The ACT is capable of holding
multiple images like the ANIM and uses some of the same header info, and the
pixel data is stored much like PANL.
The file iself is broken into a few sections. The first is the FileHeader of a
fixed size. Next is a half section, the jump table, which is really nothing
more than a few INT offsets pointing to each frame. The list is only as long as
it needs to be, so if there's only one image, there's only one offset.
FrameOffset[0] = FrameOffsetsJump
FrameOffset[i] = FrameOffset[i-1] + Frame[i-1].FrameLength
or
&Frame[i] = FrameOffsetsJump + FrameOffset[i]
The remaining section is the Frames, which contain all of the image data.
There is also the possibility of a Global Colors section, although I've never
seen it actually used. Technically speaking, the jump values allow everything
after the FileHeader to be in a jumbled order, so I don't know if the Global
Colors would typically appear before or after the Frames, or how they interact
with the Frame colors when it comes to index usage if they're both used.
-- FileHeader --
To start it off we have the Length value, which for an *.ACT file is just the
filesize, simple enough. TotalColorCount is the sum of ColorCount values from
all frames. The GlobalColorsJump is the offset to that array if used. The
FrameOffsetsJump is a jump to the FrameOffsets and usually FileHeader.Length.
The Reserved value is overwritten in-game, so this is typically left as 0.
FrameCount is one-indexed, nothing fancy there. ImageWidth and ImageHeight
however are zero-indexed, so add 1 to get the true size. The Center values
define the pixel used to "pin" the image at a location. Typically they're just
the Width and Height divided in half. The UseGlobalColors is typically 00 to
denote they're not used, but otherwise would need to be 0x18. That would be
followed by the GlobalColorCount if used, usually zero.
-- Frame --
Frames have a header of their own, starting off with the expected FrameLength
and FrameColorsJump values. Similar to the FileHeader, it is a jump to the
FrameColors and usually FrameHeader.Length. ImageDataJump is the jump value to
the frame extents and the standard value is below.
ImageDataJump = 0x2C + ColorCount * 4
Reserved is again an in-game value, but is typically the FrameLength value
repeated. It's followed by the frame's pixel dimensions, (one-indexed). The
frame can have a size smaller than the entire image.
LengthBitCount is handy value, and the concept was taken from cockpit PANL
image data. This will be explained in detail near the end. Frame colors are
normally used, so that value will be 0x18. ColorCount gives the number of
Colors defined in the Frame. Nothing tricky.
The Color values should be simple enough, each frame contains a palette of
24-bit RGB values. Color[0] is always treated as transparent, so the actual
color is moot.
The FrameLeft and FrameTop values are really there if the frame size is smaller
than the image size, and the image is not intended to be displayed centered.
Usually the values are very close to -(FrameWidth/2) and -(FrameHeight/2).
The FrameRight value just makes up the difference, and Top is repeated for some
reason.
-- Row --
Now we're into the actual pixel data. This is mostly the same as PANL image
compression methods, and where Shift can come to play. But first, the special
OpCode values. The FC (Blank) op code is slightly different from PANL, in that
it only takes one argument, NumRepeat. The ColorIndex value is always zero. FD
(Repeat) however is the same, and requires both NumRepeat and ColorIndex in
that order. FE is still EndRow, and FF is similarly EndFrame.
The pixel data is stored right-to-left, bottom to top, so a FlipXY is required
if you're reading the pixels normally. Idmr.ImageFormat.Act.dll takes this into
account so what you import is what you see in-game.
FB (Shift) is a new op code. It takes one SHORT argument, IndexShift. Although
it's a 16-bit value, in reality the second byte is truncated so it's in effect
a BYTE IndexShift and an unused value that should be zero. This might have
played a part with the Global colors, as I've seen evidence that it was not
limited to 256 colors. The IndexShift value is added to the Index value of all
following Short codes until replaced and the resulting value is used as the
Short's new Index value. Now, this op code technically allows high-Index values
to use the Short codes, but it actually hurts compression for most images, as
this method uses four bytes per operation, when using the Repeat code only
takes up three bytes.
The LengthBitCount value comes into play for all other codes, designated as
Short codes. Unlike PANL which only has two bits for NumRepeat, the BitCount
determines how many bits can be used for that value. A BitCount value of 03
will allow 1-8 pixels while a vlue of 04 will allow 1-16 pixels. Short codes
can only be used for ColorIndex values of (1<<(8-BitCount))-1. If ColorCount is
higher, especially when using 256 colors, then the Repeat code should be used
for all ColorIndex values 0x10 and up for BitCount 04, 0x20 and up for BitCount
03. As mentioned in the previous paragraph, the Shift op code can be used to
extend the Short code's range, but for the sake of filesize compression the
Repeat code is better.
You'll note that in the Row definition, OpCode[] is of an undefined size. This
is the only portion of the file that cannot be determined without iteration,
both the total byte length and number of OpCodes. The true count of each code
is NumRepeat+1 (as NumRepeat is zero-indexed), and the sum of all codes in a
row will equal Frame.Width.
=====
This documentation is distributed under the GNU Free Documentation License
version 1.3 or later