1. Architectural Role & Engine Purpose
The SPR (Sprite File) format powers 2D animated visual elements in Project I.G.I. 1, including weapon muzzle flashes, explosion bursts, bullet impact sparks, water splashes, blood splatters, and tactical HUD overlays (ammo counters, crosshairs, binoculars).
Sprites in IGI 1 are screen-aligned or view-oriented billboard elements. The format packs multiple animation frames into a single stream with per-frame pivot offsets, allowing arbitrary rotational and translational anchoring relative to 3D weapon muzzles or world-space impact points.
2. Binary File Layout & Memory Map Diagram
An SPR file consists of a header with frame counts and bounding dimensions, followed by a frame offset directory, and the sequential frame data payloads:
3. Engine Pipeline & Sprite Rendering Flow Diagram
Sprites are updated by the particle and FX subsystem each tick and rendered as camera-facing quads in Direct3D 7:
4. Architectural Mechanics & Engine Implementation Details
Innerloop designed the sprite engine for extreme lightweight instantiation:
- Sub-Pixel Hotspot Pivots: Each frame specifies an explicit
hotspot_xandhotspot_yorigin. For muzzle flashes, the hotspot is positioned exactly at the weapon barrel tip, ensuring that orientation changes don't cause sprite detachment. - Additive vs Alpha Blend: Sprites support multiple blending modes encoded in the frame header. Explosion fireballs and muzzle flashes use additive blending (
ONE, ONE), while smoke puffs and blood use linear alpha blending (SRC_ALPHA, INV_SRC_ALPHA). - Dynamic Memory Pooling: Active sprite instances share read-only memory pointers to the loaded SPR buffer in RAM, avoiding duplicate memory copies.
5. C++ Struct Definitions
#pragma pack(push, 1)
struct SprHeader {
uint16_t magic; // Sprite magic identifier
uint16_t version; // Format version
uint16_t frame_count; // Total number of animation frames
uint16_t fps; // Playback framerate
uint16_t max_width; // Maximum frame width
uint16_t max_height; // Maximum frame height
uint32_t flags; // Blending and format flags
};
struct SprFrameDesc {
uint16_t width; // Frame width in pixels
uint16_t height; // Frame height in pixels
int16_t hotspot_x; // Anchor X offset relative to center
int16_t hotspot_y; // Anchor Y offset relative to center
uint32_t data_offset; // Byte offset to pixel payload
uint32_t blend_mode; // 0=Alpha, 1=Additive, 2=ColorKey
};
static_assert(sizeof(SprHeader) == 16, "SprHeader must be 16 bytes");
#pragma pack(pop)