Difference between revisions of "Maps/Mesh"

From Final Fantasy Hacktics Wiki
Jump to navigation Jump to search
Line 43: Line 43:
 
| 0xac || Animated mesh 8
 
| 0xac || Animated mesh 8
 
|-
 
|-
| 0xb0 || Polygon visibility angles
+
| 0xb0 || Polygon Render Properties
 
|}
 
|}
  
 
Notice that this table skips some pointers. The omitted pointers are 0 in every mesh file: they never point at anything.
 
Notice that this table skips some pointers. The omitted pointers are 0 in every mesh file: they never point at anything.
 
  
 
==Primary mesh==
 
==Primary mesh==

Revision as of 18:34, 11 March 2024

The structure of a mesh file consists of a header of 196 bytes followed by a series of chunks of different kinds of data.

Header

The header serves as a table of contents for the data chunks. It is a series of 32-bit unsigned little-endian integers, each of which is either 0 (meaning that a given chunk is not present in the file) or an intra-file pointer to the byte where the chunk begins. Here's a table of what each pointer points to.

address of pointer type of chunk it points to
0x40 Primary mesh
0x44 Texture palettes (color)
0x4c Unknown (this pointer is only non-zero in MAP000.5)
0x64 Light colors and positions, background gradient colors
0x68 Terrain (tile heights, slopes, and surface types)
0x6c Texture animation instructions
0x70 Palette animation instructions
0x7c Texture palettes (grayscale)
0x8c Mesh animation instructions
0x90 Animated mesh 1
0x94 Animated mesh 2
0x98 Animated mesh 3
0x9c Animated mesh 4
0xa0 Animated mesh 5
0xa4 Animated mesh 6
0xa8 Animated mesh 7
0xac Animated mesh 8
0xb0 Polygon Render Properties

Notice that this table skips some pointers. The omitted pointers are 0 in every mesh file: they never point at anything.

Primary mesh

This chunk contains most of the polygons that make up the map. It contains XYZ coordinates for each vertex, normal vectors for each vertex, UV coordinates for each vertex, and the ID of the palette to use for each polygon's texture.

The polygons are divided into four groups: Textured triangles, textured quadrilaterals, untextured triangles, and untextured quadrilaterals. The untextured polygons are always black. They're used mostly around the edges of the map to make the map look like a solid cross-section.


Header

The mesh chunk begins with a header of 4 16-bit unsigned integers specifying how many of each type of polygon the mesh contains:

Mesh header
Width (bits) Data type Purpose Maximum Value
16 uint Number of textured triangles (N) 512
16 uint Number of textured quadrilaterals (P) 768
16 uint Number of untextured triangles (Q) 64
16 uint Number of untextured quadrilaterals (R) 256


XYZ coordinates

The next block of data consists of N sets of 3 XYZ coordinates (one XYZ coordinate for each of the triangle's points):

Triangle XYZ coordinates
Width (bits) Data type Purpose
16 int Point A, X coordinate
16 int Point A, Y coordinate
16 int Point A, Z coordinate
16 int Point B, X coordinate
16 int Point B, Y coordinate
16 int Point B, Z coordinate
16 int Point C, X coordinate
16 int Point C, Y coordinate
16 int Point C, Z coordinate


Then P sets of 4 XYZ coordinates:

Quadrilateral XYZ coordinates
Width (bits) Data type Purpose
16 int Point A, X coordinate
16 int Point A, Y coordinate
16 int Point A, Z coordinate
16 int Point B, X coordinate
16 int Point B, Y coordinate
16 int Point B, Z coordinate
16 int Point C, X coordinate
16 int Point C, Y coordinate
16 int Point C, Z coordinate
16 int Point D, X coordinate
16 int Point D, Y coordinate
16 int Point D, Z coordinate


Then Q sets of 3 XYZ coordinates (same format as triangles, above), then R sets of 4 XYZ coordinate (same format as quadrilaterals, above).


Normal vectors

Next come the normal vectors, which follow the same pattern. Instead of being integers, however, the values are stored as fixed-point numbers. They have a sign bit, then a 3-bit whole part and a 12-bit fractional part. This sounds complicated, but basically it just means you read them as signed 16-bit integers, then convert them to floating-point numbers and divide by 4096.0.

Also, there are no normal vectors for the untextured polygons, since those are always completely black.

First, there are N sets of 3 normal vectors:

Triangle normal vectors
Width (bits) Data type Purpose
16 fixed 1,3,12 Point A, nomal vector X
16 fixed 1,3,12 Point A, nomal vector Y
16 fixed 1,3,12 Point A, nomal vector Z
16 fixed 1,3,12 Point B, nomal vector X
16 fixed 1,3,12 Point B, nomal vector Y
16 fixed 1,3,12 Point B, nomal vector Z
16 fixed 1,3,12 Point C, nomal vector X
16 fixed 1,3,12 Point C, nomal vector Y
16 fixed 1,3,12 Point C, nomal vector Z


Then P sets of 4 normal vectors:

Quadrilateral normal vectors
Width (bits) Data type Purpose
16 fixed 1,3,12 Point A, nomal vector X
16 fixed 1,3,12 Point A, nomal vector Y
16 fixed 1,3,12 Point A, nomal vector Z
16 fixed 1,3,12 Point B, nomal vector X
16 fixed 1,3,12 Point B, nomal vector Y
16 fixed 1,3,12 Point B, nomal vector Z
16 fixed 1,3,12 Point C, nomal vector X
16 fixed 1,3,12 Point C, nomal vector Y
16 fixed 1,3,12 Point C, nomal vector Z
16 fixed 1,3,12 Point D, nomal vector X
16 fixed 1,3,12 Point D, nomal vector Y
16 fixed 1,3,12 Point D, nomal vector Z


Polygon texture data

This block of data is a little bit different. It has UV coordinates for each point on the textured polygons, but it also has a texture page number and palette number for the polygon as a whole. The texture page number is multiplied by 256 and then added to the V coordinate for each point on the polygon. This is because the UV coordinates are stored as bytes, but the textures are 256x1024 pixels, so effectively there are 4 texture pages. The palette number indicates which palette to apply to the polygon's texture while rendering it.

There are N triangles:

Triangle texture data
Width (bits) Data type Purpose
8 uint Point A, U coordinate
8 uint Point A, V coordinate
8 uint Palette number
8 N/A Padding/unknown
8 uint Point B, U coordinate
8 uint Point B, V coordinate
4 N/A Padding/unknown
2 N/A Unknown, but a value of 3 works and other values only sometimes work
2 uint Page number
8 N/A Padding/unknown
8 uint Point C, U coordinate
8 uint Point C, V coordinate


Followed by P quadrilaterals:

Quadrilateral texture data
Width (bits) Data type Purpose
8 uint Point A, U coordinate
8 uint Point A, V coordinate
8 uint Palette number
8 N/A Padding/unknown
8 uint Point B, U coordinate
8 uint Point B, V coordinate
4 N/A Padding/unknown
2 N/A Unknown, but a value of 3 works and other values only sometimes work
2 uint Page number
8 N/A Padding/unknown
8 uint Point C, U coordinate
8 uint Point C, V coordinate
8 uint Point D, U coordinate
8 uint Point D, V coordinate

Unknown Untextured Polygon Data

After the polygon texture data, there's a block of data whose purpose I don't understand. Its length is equal to 4 * Q + 4 * R.

Polygon tile locations

Next comes a block that assigns a terrain coordinate to each textured polygon. Its length is equal to 2 * N + 2 * P. This data is used when the game highlights all the tiles you can move to: It looks here to figure out which polygons to turn blue.

Textured polygon terrain coordinate data
Width (bits) Data type Purpose
7 uint Z coordinate
1 N/A Height Level
8 uint X coordinate

Sometimes, there are 2 bytes of unknown data or padding at the end of this block.

Texture palettes (color)

A set of 16 palettes, each containing 16 colors. Each color in the palette is 16 bits in little endian format.

  8B B1 => B1 8B
  
  1000 1011 1011 0001
  ABBB BBGG GGGR RRRR
Color
Width (bits) Data type Purpose
1 uint Alpha
5 uint Blue
5 uint Green
5 uint Red

If R == G == B == A == 0, then the color is transparent.

Light colors and positions, background gradient colors

Each map can have 3 directional lights and ambient light. The lighting data is stored like this:

Directional light colors
Width (bits) Data type Purpose
16 fixed 1,3,12 Light 1, red
16 fixed 1,3,12 Light 2, red
16 fixed 1,3,12 Light 3, red
16 fixed 1,3,12 Light 1, green
16 fixed 1,3,12 Light 2, green
16 fixed 1,3,12 Light 3, green
16 fixed 1,3,12 Light 1, blue
16 fixed 1,3,12 Light 2, blue
16 fixed 1,3,12 Light 3, blue


Directional light positions
Width (bits) Data type Purpose
16 int Light 1, X coordinate
16 int Light 1, Y coordinate
16 int Light 1, Z coordinate
16 int Light 2, X coordinate
16 int Light 2, Y coordinate
16 int Light 2, Z coordinate
16 int Light 3, X coordinate
16 int Light 3, Y coordinate
16 int Light 3, Z coordinate


Ambient light colors
Width (bits) Data type Purpose
8 uint Red
8 uint Green
8 uint Blue


This is immediately followed by the background gradient colors:

Background gradient colors
Width (bits) Data type Purpose
8 uint Top color, red
8 uint Top color, green
8 uint Top color, blue
8 uint Bottom color, red
8 uint Bottom color, green
8 uint Bottom color, blue


Sometimes, there are 3 bytes of unknown data or padding at the end of this chunk.


Terrain

This chunk contains data about the height, depth, slope, and surface type (grass, water, stone, etc) of each tile, as well as flags for whether you can walk on a tile or select it with the cursor.


Header

There is a two-byte header indicating the size of the X and Z dimensions of the map, in tiles. The product of X and Z must be <= 256.

Terrain header
Width (bits) Data type Purpose
8 uint Number of tiles of terrain, X dimension
8 uint Number of tiles of terrain, Z dimension


Main Block

The main block of the terrain data is divided into 2 levels. For a map with a bridge, for instance, the bridge might be on level 0 and the water below it on level 1. Each terrain level contains Z rows of X tile definitions, which look like this:

Terratin tile
Width (bits) Data type Purpose
2 N/A unknown/padding
6 uint Surface type (grass, water, stone, etc.)
8 N/A unknown/padding
8 uint Height (For sloped tiles, the height of the bottom of the slope)
3 uint Depth
5 uint Slope height (For sloped tiles, the difference between the height at the top and the height at the bottom)
8 uint Slope types
14 N/A unknown/padding
1 uint Can't walk on this tile
1 uint Can't move cursor to this tile
8 uint Controls which angles the camera will auto-rotate to when a unit enters this tile.
  • 0: Northwest Top
  • 1: Southwest Top
  • 2: Southeast Top
  • 3: Northeast Top
  • 4: Northwest Bottom
  • 5: Southwest Bottom
  • 6: Southeast Bottom
  • 7: Northeast Bottom


These tile definitions are 8 bytes long. Each terrain level always has room for 256 tiles (i.e. each one is always 256 * 8 bytes long), even if the map doesn't use them all. In other words, the terrain chunk, including its header, is always 2 + 256 * 8 * 2 bytes long, no matter how big the map is. If the map is small, there will be a lot of padding.

Slope types
Value Meaning
0x00 Flat
0x85 Incline N
0x52 Incline E
0x25 Incline S
0x58 Incline W
0x41 Convex NE
0x11 Convex SE
0x14 Convex SW
0x44 Convex NW
0x96 Concave NE
0x66 Concave SE
0x69 Concave SW
0x99 Concave NW


Sometimes, there are 2 bytes of unknown data or padding at the end of this chunk.

Texture animation instructions

There are 32 rows of x14 (20) Bytes, with each row defining a Texture Animation.

Each animation has a Canvas position and size. Animations will play within this canvas space.

Texture animation instruction
Width (bits) Data type Purpose
8 uint Canvas X coordinate and Texture Page.

Multiply uint value by 4. The Texture Page is defined by how many times the X value loops past 256.

For example, a Hex value of x82 would be a uint of 130. Multiplied by 4, it becomes 520. Subtract 256 to get 264. Subract 256 again to get 8. This value would be Texture Page 2, X coordinate 8.

8 N/A Unknown, seems to only work if this value is set to x03
8 uint Canvas Y coordinate.
8 uint Unknown
8 uint Width of the Canvas. This value is multiplied by 4. For example, a width of x05 will be 20 pixels wide.
8 uint Unknown
8 uint Height of the Canvas.
8 uint Unknown
8 uint First Frame X coordinate. Follows the same rules as the Canvas X coordinate.
8 N/A Unknown, seems to only work if this value is set to x03
8 uint First Frame Y coordinate.
8 uint Unknown
8 uint Unknown
8 uint Unknown
8 N/A Animation Technique. This can be one of four values:

x01: An indefinitely looping forward playing animation

x02: An indefinitely looping forward-then-reverse playing animation

x05: A forward playing animation that plays once when the UseFieldObject script command is called

x15: A reverse playing animation that plays once when the UseFieldObject script command is called

8 uint The number of frames in the animation
8 N/A Unknown
8 uint Frame Duration (in 1/30ths of a second)
8 N/A Unknown + 8 N/A Unknown


If the second byte is set to x00 and the third and fourth bytes are set to xE0 x01, then this uses a different format.

The format is as follows:

Palette animation instruction
Width (bits) Data type Purpose
4 uint The Palette Id that will be animated
4 N/A Unknown
8 N/A Unknown, seems to only work if this value is set to x00
8 N/A Unknown, seems to only work if this value is set to xE0
8 N/A Unknown, seems to only work if this value is set to x01
32 N/A Unknown
8 N/A The Palette Animation's Starting Index in the Palette Animations data set.
40 N/A Unknown
8 uint Unknown, seems to only work if this value is set to x03
8 uint The number of frames in the animation
8 N/A Unknown
8 uint Frame Duration (in 1/30ths of a second)
16 N/A Unknown

Palette animation instructions

This section defines Palette Animation Frames. It is a fixed length of 16 sets of 32 bytes each. Each set of 32 bytes is a frame of palette animation and is structured identically to the other Texture Palette data.


Animation details (Palette Index, number of frames, etc) are defined in the Texture Animation data.

Texture palettes (grayscale)

This is a grayscale version of the main palette. It is used when highlighting polygons with the red movement and blue action squares.

Mesh animation instructions

I partly understand this section. More info coming later.


Animated Meshes 1-8

Each of these chunks is very similar to the primary mesh chunk.


Polygon Render Properties

This chunk defines properties for polygons on how they should render. Included are whether the polygon is lit or unlit, and whether it's visible from each of eight camera viewing angles. This data is used to remove obstructions like walls from the the camera's view, and also to avoid drawing certain polygons that are unnecessary because they're covered up by other polygons anyway.

This chunk is always 4096 bytes long. It consists of 5 blocks:

  1. A block of unknown data 896 bytes long
  2. 1024 bytes for 512 textured triangles
  3. 1536 bytes for 768 textured quads
  4. 128 bytes for 64 untextured triangles
  5. 512 bytes for 256 untextured quads

The length of each block is always the same, regardless of the number of polygons the mesh actually contains. This means that there's a lot of padding for meshes with low polygon counts. It also means there's an upper limit on the number of polygons allowed in a mesh.

Bytes are read as Little Endian format (swap the high byte with the low byte).

bit:

  • 0: Polygon is Unlit (appears as pure texture color with no lighting applied)
  • 1: Unknown
  • 2: Southwest
  • 3: Northwest
  • 4: Northeast
  • 5: Southeast
  • 6: South Southwest
  • 7: West Southwest
  • 8: West Northwest
  • 9: North Northwest
  • 10: North Northeast
  • 11: East Northeast
  • 12: East Southeast
  • 13: South Southeast
  • 14: Unknown
  • 15: Unknown