-
Notifications
You must be signed in to change notification settings - Fork 1
LoadingDraw_C
The class LoadingDraw_C has some bitmap data embedded in the executable. Presumably, this is so the game has something to show before the first BigFile is loaded. These images are RLE-encoded and decode to ARGB. Resources for inspecting the encoded and decoded image data are located at the bottom of this page.
Here's how it looks in-game

The circular throbber does not appear to be embedded.
Tribal Throbber
And in-game

And you can see the bug where the throbber is drawn over the cursor. The background image does not appear to be embedded.
The RLE-encoded data for the splash image can be found at 0x0099673C and is 0x9E48 bytes. The throbber is at 0x009A0584 and is 0xFCC bytes. The bytes can be extracted from the executable using ImHex, and the decoded ARGB data can be viewed with Kuriimu2 Raw Image Viewer. A Python decoding script, input, and output files can be found in LoadingDraw_C.zip if you are interested. The function that does the decoding and a Python script for decoding files are included below.
void __usercall read_data_as_bitmap_data(void *output@<ecx>, int output_size_in_ints@<eax>, unsigned __int8 *input_cursor@<edx>, int bpp)
{
char *output_cursor; // esi
char *output_end; // ebp
int flags_1; // eax
unsigned __int8 *input_cursor_plus_one; // edi
int length_2; // eax
int length_1; // ebx
int flags; // eax
int length; // eax
output_cursor = (char *)output;
output_end = (char *)output + 4 * output_size_in_ints;
if ( (unsigned int)bpp <= 3 )
{
if ( output < output_end )
{
do
{
flags = *input_cursor++;
if ( (flags & 0x80u) == 0 )
{
for ( ; flags; --flags )
{
*output_cursor = input_cursor[2];
output_cursor[1] = input_cursor[1];
output_cursor[2] = *input_cursor;
output_cursor[3] = -1;
output_cursor += 4;
input_cursor += 3;
}
}
else
{
length = flags - 128;
do
{
*output_cursor = input_cursor[2];
output_cursor[1] = input_cursor[1];
output_cursor[2] = *input_cursor;
output_cursor[3] = -1;
output_cursor += 4;
--length;
}
while ( length );
input_cursor += 3;
}
}
while ( output_cursor < output_end );
}
}
else if ( output < output_end )
{
do
{
flags_1 = *input_cursor;
input_cursor_plus_one = input_cursor + 1;
if ( (flags_1 & 0x80u) == 0 )
{
length_1 = 4 * flags_1;
memcpy(output_cursor, input_cursor_plus_one, 4 * flags_1);
output_cursor += length_1;
input_cursor = &input_cursor_plus_one[length_1];
}
else
{
length_2 = flags_1 - 128;
do
{
*(_DWORD *)output_cursor = *(_DWORD *)input_cursor_plus_one;
output_cursor += 4;
--length_2;
}
while ( length_2 );
input_cursor = input_cursor_plus_one + 4;
}
}
while ( output_cursor < output_end );
}
}The Python script from the ZIP is included here for searchability
import argparse
import sys
from pathlib import Path
def read_data_as_bitmap_data(
input_data: bytes, output_size_in_ints: int, bpp: int
) -> bytes:
"""
Decodes RLE-like bitmap data into ARGB output.
:param input_data: compressed input byte stream
:param output_size_in_ints: number of output pixels (32-bit each)
:param bpp: bits per pixel (<=3 uses RGB path, >3 uses ARGB path)
:return: decoded ARGB bytes
"""
output = bytearray(4 * output_size_in_ints)
output_cursor = 0
output_end = 4 * output_size_in_ints
input_cursor = 0
# --- 24-bit input path (RGB -> ARGB) ---
if bpp <= 3:
while output_cursor < output_end:
flags = input_data[input_cursor]
input_cursor += 1
# Literal run
if (flags & 0x80) == 0:
for _ in range(flags):
r = input_data[input_cursor]
g = input_data[input_cursor + 1]
b = input_data[input_cursor + 2]
output[output_cursor : output_cursor + 4] = bytes((b, g, r, 0xFF))
output_cursor += 4
input_cursor += 3
# Repeated run
else:
length = flags - 128
r = input_data[input_cursor]
g = input_data[input_cursor + 1]
b = input_data[input_cursor + 2]
pixel = bytes((b, g, r, 0xFF))
for _ in range(length):
output[output_cursor : output_cursor + 4] = pixel
output_cursor += 4
input_cursor += 3
# --- 32-bit input path (ARGB passthrough) ---
else:
while output_cursor < output_end:
flags = input_data[input_cursor]
input_cursor += 1
# Literal run
if (flags & 0x80) == 0:
length_bytes = 4 * flags
output[output_cursor : output_cursor + length_bytes] = input_data[
input_cursor : input_cursor + length_bytes
]
output_cursor += length_bytes
input_cursor += length_bytes
# Repeated run
else:
length = flags - 128
pixel = input_data[input_cursor : input_cursor + 4]
for _ in range(length):
output[output_cursor : output_cursor + 4] = pixel
output_cursor += 4
input_cursor += 4
return bytes(output)
def main():
parser = argparse.ArgumentParser(
description="Decode RLE-compressed bitmap data into ARGB."
)
parser.add_argument("input_file", type=Path, help="Path to compressed input file")
parser.add_argument(
"output_file", type=Path, help="Path to write decoded ARGB output"
)
parser.add_argument(
"--pixels",
type=lambda x: int(x, 0),
required=True,
help="Number of output pixels (output_size_in_ints)",
)
parser.add_argument(
"--bpp",
type=lambda x: int(x, 0),
required=True,
help="Bits per pixel (<=3 for RGB, >3 for ARGB)",
)
args = parser.parse_args()
try:
input_data = args.input_file.read_bytes()
except OSError as e:
print(f"Failed to read input file: {e}", file=sys.stderr)
sys.exit(1)
output_data = read_data_as_bitmap_data(
input_data=input_data, output_size_in_ints=args.pixels, bpp=args.bpp
)
try:
args.output_file.write_bytes(output_data)
except OSError as e:
print(f"Failed to write output file: {e}", file=sys.stderr)
sys.exit(1)
if __name__ == "__main__":
main()For FMTK Users and Mod Developers
For FMTK Developers
Asobo BigFile Format Specification
Asobo Classes
Animation_Z
Binary_Z
Bitmap_Z
Camera_Z
CollisionVol_Z
Fonts_Z
GameObj_Z
GenWorld_Z
GwRoad_Z
Keyframer*_Z
Light_Z
LightData_Z
Lod_Z
LodData_Z
Material_Z
MaterialAnim_Z
MaterialObj_Z
Mesh_Z
MeshData_Z
Node_Z
Omni_Z
Particles_Z
ParticlesData_Z
RotShape_Z
RotShapeData_Z
Rtc_Z
Skel_Z
Skin_Z
Sound_Z
Spline_Z
SplineGraph_Z
Surface_Z
SurfaceDatas_Z
UserDefine_Z
Warp_Z
World_Z
WorldRef_Z
Asobo File Format Idioms
Asobo CRC32
Asobo LZ Compression
Asobo Arithmetic Coding Compression
Asobo Save Game File Format Specification
Asobo Audio Formats
TotemTech/ToonTech/Zouna/ACE/BSSTech/Opal Timeline
Zouna Modding Resources
Miscellaneous