FF7/Playstation battle stage format

From Final Fantasy Inside
< FF7
Jump to navigation Jump to search

Playstation battle stage format

The entire file is compressed using LZS format and is decompressed into the playstation user memory for a battle. The file consists of a header section, metadata, multiple 3D geometry sections for the ground plane and environment, and a texture image in TIM format. All integers short or long are little endian based.


Battle stage header

The header section is a sequence of little endian 32 bit unsigned integers. The first integer (entitled SectionCount) contains the number of pointers offset from the beginning of the file. The remaining integers are SectionCount number of pointers.

Offset
Size
Description
000000
4 bytes long
Number of Sections (N)
000004
N*4 bytes
Array of section offsets from file start
(N+1)*4
8 bytes
Section 0: Metadata flags
...
Varies
Sections 1 to N-2: 3D Geometry (ground plane, sky, environment objects)
...
Varies
Section N-1: Tim image information (8bpp, multiple CLUTs)

Note: Battle stages can also contain animations (e.g. Corel Train Battle - STAGE71), but their data structure is currently unknown. The above structure is valid for stages that do not contain any animations.

Section 0: Metadata

8 bytes containing stage configuration flags.

Offset
Size
Description
000000
3 bytes
Flags (purpose TBD)
000003
1 byte
Type of 3D mesh
000004
4 bytes long
Reserved (always 0)

Mesh Type Values:

Type
Description
Example Fields
0
Mesh with horizontal scrolling parts
Field 47 - Corel Train Battle
1
Normal static mesh
-
2
Mesh with vertical scrolling parts
Field 12 - Shinra Elevators
3
Mesh with lifestream
Field 4E - Final Battle - Sephiroth
4
Mesh with rotating parts
Field 39 - Safer Battle
5
Normal static mesh (same as type 1)
Field 01, 44, 45 - Bizarro Battles

Sections 1 to N-2: 3D Geometry

All geometry sections (including the ground plane at section 1) use the same unified format. This matches the Battle Model Format where polygon data uses explicit PolyCount structures.

Geometry section structure

Offset
Size
Description
000000
4 bytes long
Vertex data size (in bytes)
000004
Vertex data size bytes
Vertex pool for geometry section
...
2 bytes (word)
Number of triangles
...
2 bytes (word)
Texture page (tpage)
...
N * 16 bytes
Textured Triangles if N = 0 these occupy no space
...
2 bytes (word)
Number of quads
...
2 bytes (word)
Texture page (tpage)
...
N * 20 bytes
Textured Quads if N = 0 these occupy no space
...
8 bytes
Unknown/padding. 00's most of the time but STAGE09 has some data here and some unknown bytes immediately after.

Note: The texture page X for the entire section comes from the first PolyCount's tpage field (triangle PolyCount), even when triangle count is 0. Use tpage & 0x0F to extract the texture page X base.

Data structures

typedef struct
{
   uint16  Count;
   uint16  TexPage;
} PolyCount;

typedef struct
{
   int16  X;
   int16  Z;
   int16  Y;
   int16  Unused;
} Vertex;

typedef struct
{
   uint16  A;
   uint16  B;
   uint16  C;
   uint16  D;
} PolyIndices;

typedef struct
{
   uint16       VertexA;
   uint16       VertexB;
   uint16       VertexC;
   uint16       Flags;
   uint8        U0, V0;
   uint16       CLUT;
   uint8        U1, V1;
   uint8        U2, V2;
} TexTriangle;

typedef struct
{
   PolyIndices  Vertices;
   uint8        U0, V0;
   uint16       CLUT;
   uint8        U1, V1;
   uint8        U2, V2;
   uint8        U3, V3;
   uint16       Flags;
} TexQuad;

Vertex Structure

Offset
Size
Description
000000
2 bytes (signed)
X coordinate
000002
2 bytes (signed)
Z coordinate (height/depth, 0 for ground plane)
000004
2 bytes (signed)
Y coordinate
000006
2 bytes (word)
Padding (always 0)

Ground plane vertices typically have Z=0 (flat surface). Typical coordinate range: -6000 to +6000 units.

Textured Triangle Structure (16 bytes)

Offset
Size
Description
000000
6 bytes
3× vertex byte offsets (uint16, divide by 8 for vertex index)
000006
2 bytes (word)
Unknown/flags
000008
1 byte
U0 coordinate
000009
1 byte
V0 coordinate
00000A
2 bytes (word)
CLUT attribute (palette selector)
00000C
1 byte
U1 coordinate
00000D
1 byte
V1 coordinate
00000E
1 byte
U2 coordinate
00000F
1 byte
V2 coordinate

Textured Quad Structure (20 bytes)

Offset
Size
Description
000000
8 bytes
4× vertex byte offsets (uint16, divide by 8 for vertex index)
000008
1 byte
U0 coordinate
000009
1 byte
V0 coordinate
00000A
2 bytes (word)
CLUT attribute (palette selector)
00000C
1 byte
U1 coordinate
00000D
1 byte
V1 coordinate
00000E
1 byte
U2 coordinate
00000F
1 byte
V2 coordinate
000010
1 byte
U3 coordinate
000011
1 byte
V3 coordinate
000012
2 bytes (word)
Flags (typically 0x007F)

Each quad vertex has its own UV coordinates: (U0,V0), (U1,V1), (U2,V2), (U3,V3).

Common section contents

Section
Typical Content
Notes
1
Ground plane
Usually quads only, Z=0
2
Sky dome (upper)
Often triangles
3
Sky ring (middle)
Horizon band
4
Sky ring (lower)
Near-ground atmosphere
5+
Stage objects
Buildings, structures, props

CLUT attribute

Standard PSX CLUT format encoding palette row:

  • Bits 0-5: CLUT X position ÷ 16 (typically 0x14 = 320)
  • Bits 6-14: CLUT Y position (504 + palette_index)
  • Formula: palette_index = ((clut_word >> 6) & 0x1FF) - 504
  • Example: 0x7E14 = palette 0, 0x7E54 = palette 1, 0x7E94 = palette 2

Texture page system

The texture atlas is divided into 128-pixel-wide pages for 8bpp images:

  • Page width: 128 pixels (64 VRAM units)
  • Encoding: Low nibble of PolyCount tpage field
  • Offset calculation: texture_x_offset = (tpage_x - base_tpage_x) × 128
  • Base tpage X = TIM image VRAM X ÷ 64

Example (STAGE00):

  • Ground plane: tpage 6 → offset 0px (left half)
  • Sky sections: tpage 8 → offset 256px (right half)

Section N-1: TIM texture

Standard PlayStation TIM format texture containing all stage textures in an atlas.

Coordinate system

All geometry sections use the same 3D coordinate format (X, Z, Y):

  • X: Left/right
  • Z: Height (stored as negative in PSX format, positive = down; ground plane typically has Z=0)
  • Y: Forward/back

Typical ranges:

  • Ground plane: X, Y from -6000 to +6000, Z=0
  • Sky dome: Large coordinates (~30000) forming a hemisphere

Important: PSX uses positive Z as downward. When rendering in standard 3D systems (positive Y = up), negate the Z coordinate: render_y = -psx_z

Example file analysis

STAGE00 (JP version) (147,820 bytes)

Section
Offset
Size
Content
Texture Page
Palette
0
0x001C
8
Metadata
-
-
1
0x0024
10,836
Ground plane (832 verts, 0 tris, 208 quads)
6 (0-255px)
0
2
0x2A78
3,020
Sky dome (225 verts, 76 tris, 0 quads)
8 (256-511px)
1
3
0x3644
852
Sky ring mid (64 verts, 0 tris, 16 quads)
8 (256-511px)
1
4
0x3998
436
Sky ring low (32 verts, 0 tris, 8 quads)
8 (256-511px)
2
5
0x3B4C
132,640
TIM texture (512×256, 8bpp, 3 palettes)
-
-

STAGE60 (JP version) (226,348 bytes)

Section
Offset
Size
Content
Texture Page
Palette
0
0x0048
8
Metadata
-
-
1
0x0050
7,788
Ground plane (596 verts, 20 tris, 134 quads)
10 (512-639px)
4
2
0x1EBC
3,020
Sky dome (225 verts, 76 tris, 0 quads)
6 (0-127px)
0
3
0x2A88
436
Sky ring (32 verts, 0 tris, 8 quads)
6 (0-127px)
0
4
0x2C3C
852
Sky ring (64 verts, 0 tris, 16 quads)
6 (0-127px)
0
5-15
various
various
Environmental objects
6, 8, 10
0-6
16
0x640C
200,736
TIM texture (768×256, 8bpp, 7+ palettes)
-
-

Note: STAGE60 demonstrates mixed geometry (triangles + quads in same section) and complex texture atlas usage with multiple texture pages and palettes.

Related formats