1. Architectural Role & Engine Purpose
The RES (Resource Archive) format serves as the virtual file system (VFS) container for
Project I.G.I., packaging thousands of individual models, textures, animations, scripts, and sound effects
into high-performance contiguous disk archives (e.g., COMMON.RES, LEVEL1.RES).
Innerloop constructed the RES container on top of their proprietary ILFF ("Innerloop File Format") architecture. It features 2,048-byte sector alignment designed specifically to maximize CD-ROM and early HDD read speeds through direct contiguous streaming and zero-overhead memory mapping.
2. Binary File Layout & Memory Map Diagram
The RES archive consists of a 20-byte outer ILFF header, followed by a directory table chunk (DIR )
and a contiguous data chunk (DATA):
3. VFS Streaming & Engine Ingestion Pipeline Diagram
When any engine subsystem requests an asset by path, the VFS resolves the file with O(1) hash complexity and streams the data without temporary disk extraction:
4. Architectural Mechanics & Engine Implementation Details
The RES archive system operates as a lightweight embedded file system with direct memory-mapping characteristics:
- Zero Extraction Overhead: Files are never extracted to temporary folders on the local drive. Instead, the engine maps file offsets directly into memory or streams them into fixed-size DMA ring buffers.
- 2048-Byte Sector Alignment: To achieve peak throughput from CD-ROM optical drives (which read in 2048-byte raw sectors), Innerloop aligned every asset payload boundary to 2KB increments, eliminating drive head repositioning stalls.
- Path Separation: Shared assets reside in
COMMON.RES, while level-specific geometries, scripts, and terrain maps reside inLEVELN.RES, minimizing RAM footprint during transitions.
5. C++ Struct Definitions
#pragma pack(push, 1)
struct IlffResHeader {
char magic[4]; // "ILFF"
uint32_t file_size; // Total file size
char form_type[4]; // "RES "
uint16_t ver_major; // 1
uint16_t ver_minor; // 0
uint32_t reserved;
};
struct ResDirEntry {
uint32_t name_hash; // CRC32 / Innerloop hash
uint32_t data_offset; // Byte offset within DATA chunk
uint32_t uncompressed_sz;// Unpacked size
uint32_t packed_sz; // Size stored in archive
uint32_t flags; // 0=Raw, 1=Compressed
uint32_t debug_name_off; // String table offset
};
static_assert(sizeof(ResDirEntry) == 24, "ResDirEntry must be 24 bytes");
#pragma pack(pop)