Asset Pack File Format Specification
====================================

Extension: .apck
Mime-type: application/asset-pack

All numbers are little-endian and unless noted otherwise, [ULEB128](https://en.wikipedia.org/wiki/LEB128) encoded. File starts
with a fixed size header, followed by the compressed asset directory, and then the asset contents.

Header
------

| Offset | Size | Description                                       |
|-------:|-----:|---------------------------------------------------|
|      0 |    4 | magic `APCK`                                      |
|      4 |    4 | size of the header and the asset directory        |
|      8 |   12 | engine or game specific magic                     |
|     20 |    4 | engine or game version                            |
|     24 |    4 | size of the uncompressed asset directory          |
|     28 |    4 | CRC checksum of the uncompressed asset directory  |
|     32 |   32 | encryption key (must be zero if not used)         |

When encryption is used, then everything except the header is encrypted. The cipher (and therefore the contents of the stored key)
is undefined and engine specific. The `apck` tool comes with a reference AES encryption which stores random bytes here, and needs
another 16 bytes long key in the engine (outside of the Asset Pack's scope) to decrypt the file.

Asset Directory
---------------

It is compressed with RFC1950 deflate, once uncompressed, it has an offset value and two sections:

| Offset | Size | Description                                       |
|-------:|-----:|---------------------------------------------------|
|      0 |    4 | start of directory records                        |
|      4 |    s | string table, zero terminated UTF-8 string list   |
|    4+s |    x | directory records                                 |

The string table contains zero terminated UTF-8 strings, the asset and property names.

Directory records contain multiple directories, each starting with an ULEB128 **Number of entries** in that directory. This is
followed by that many directory entries. Always 64 directories are stored, and if a specific directory is empty, it is encoded
as a single 0 byte. The directory entries are ULEB128 quadlets.

| Number | Description                                       |
|-------:|---------------------------------------------------|
|      0 | asset name                                        |
|      1 | asset offset                                      |
|      2 | asset original size                               |
|      3 | asset compressed size                             |

**Name** is an offset into the asset directory and points into the string table to the start of an UTF-8 string. This is the
name of the asset, same as the file name but without extension. **Offset** is a file offset, relative to the header's end, so
the actual value is offset + header size, and points to the start of the asset within the file. Finally **original size** is
the size of the asset, if compressed size is 0 then that many bytes are stored in the archive. If **compressed size** is not 0,
then original size means the uncompressed size and compressed size many bytes are stored with RFC1950 deflate compression.

Now each directory lists only one kind of asset, and the format of the assets is therefore strict. Conversion must be done when
the archive is created. The directories are as follows, indexed by their order:

### 0 - 31 Translations (locales)

The first 32 directories all contain translateable assets. The name of the first asset in each directory *must be* 2 or 5 bytes,
the ISO-639-1 language code optionally followed by an underscore and a two bytes region code, like "en", "en_US", "ja" or "ja_JP".
The first asset's content is an RFC1950 deflate compressed string pair list. The strings are zero terminated UTF-8 strings,
msgid + msgstr pairs. Two msgids are mandatory, `lang` must be the name of the language as the language's native speakers call
it (so for example it's "Nederlands" and *not* "Dutch"), and msgstr for `title` must be the name of the program (game title).
The rest is application specific.

If there are more assets in these directories, then they all *must* have the same number of assets, and with the same names. These
other assets must be either in OGG [Vorbis](https://xiph.org/vorbis/) format, 44.1 kHz, mono channel with magic `OggS`, and store
localized speech audio; or in [PNG](http://libpng.org/pub/png/) format with magic `\x89PNG` and store images with localized texts
on them. Other formats and number of channels not allowed (due to licensing issues and because [apck.h](../apck.h) has no support
for them).

### 32 Fonts

Stores font assets in [Scalable Screen Font](https://gitlab.com/bztsrc/scalable-font2) format with magic `SFN2` (either vector,
bitmap or pixel map). Other formats not allowed (due to licensing issues and because [apck.h](../apck.h) has no support for them).

### 33 Music

Stores music in OGG [Vorbis](https://xiph.org/vorbis/) format, 44.1 kHz, up to 8 channels with magic `OggS`. Other formats not
allowed (due to licensing issues and because [apck.h](../apck.h) has no support for them). Note: unlike other OGG assets, these
can be stereo, dolby 5.1, 7.1 etc.

### 34 Sound Effects

Stores sounds in OGG [Vorbis](https://xiph.org/vorbis/) format, 44.1 kHz, mono channel with magic `OggS`. Other formats and
number of channels not allowed (due to licensing issues and because [apck.h](../apck.h) has no support for them). It is important
to be mono, because engines should play these with a placement effect.

### 35 Videos

Stores videos in OGV [Theora](https://xiph.org/theora/) format, pixels in planar IYUV420 format with magic `OggS`. If it has
audio, then that must be in OGG Vorbis format, 44100 Hz. Other formats not allowed (due to licensing issues and because
[apck.h](../apck.h) has no support for them).

### 36 Models

Stores 3D models in [Model3D](https://bztsrc.gitlab.io/model3d/) format with magic `3DMO`. Other formats not allowed (due to
licensing issues and because [apck.h](../apck.h) has no support for them).

### 37 Images

Stores image assets in [PNG](http://libpng.org/pub/png/) format with magic `\x89PNG`. Background images that have no sprites
associated with them and have no translateable texts on them.

The image asset by the name `icon` is reserved for the application icon.

### 38 Atlases

Stores image assets in [PNG](http://libpng.org/pub/png/) format with magic `\x89PNG`. Sprite atlases contain packed sprites,
and they have no names just index (because they must use O(1) access).

### 39 Sprites

Sprite assets are compressed with RFC1950 deflate. After uncompression, it has a 4 bytes magic `SPFR` (as in sprite frames) and
a series of ULEB numbers, starting with this three:

| Number | Description                                                        |
|-------:|--------------------------------------------------------------------|
|      0 | loop type (0 - loop, 1 - once, 2 - back&forth, 3 - wang, 4 - wall) |
|      1 | sprite width                                                       |
|      2 | sprite height                                                      |

This is then followed by 8 animation blocks, one for each direction in order South, South-West, West, North-West, North,
North-East, East, South-East. If a certain direction is missing, then that block is a single 0 byte. Otherwise the direction
header is:

| Number | Description                                       |
|-------:|---------------------------------------------------|
|      0 | number of animation frames                        |

Followed by "number of animation frames" records, each with 10 numbers:

| Number | Description                                       |
|-------:|---------------------------------------------------|
|      0 | atlas asset name offset                           |
|      1 | copy method                                       |
|      2 | copy area width                                   |
|      3 | copy area height                                  |
|      4 | copy area source X on image                       |
|      5 | copy area source Y on image                       |
|      6 | copy area destination X on sprite                 |
|      7 | copy area destination Y on sprite                 |
|      8 | duration in centiseconds (100 = 1 sec)            |
|      9 | sound effect asset name offset (or 0 if none)     |

The copy method goes like: 0 - simple copy, 1 - flip vertically, 2 - flip horizontally, 3 - rotate clock-wise, 4 - rotate 180
degrees, 5 - rotate counter clock-wise.

If the loop type is 3 or 4 then only South direction exists. They have special, engine-specific arrangement, so the exact
layout is unspecified.

### 40 Maps

Map assets are compressed with RFC1950 deflate. After uncompression, it has a 4 bytes magic and a series of ULEB numbers. Magic
is `MAP` and `o` for orthogonal (default), `i` for isometric, `v` for vertical hexagonal (pointy top), and `h` for horizontal
hexagonal (flat top). Then map starts with this six numbers:

| Number | Description                                       |
|-------:|---------------------------------------------------|
|      0 | tile width in pixels                              |
|      1 | tile height in pixels                             |
|      2 | map width in tiles                                |
|      3 | map height in tiles                               |
|      4 | number of map layers                              |
|      5 | map properties length                             |

Then properties follow, which are unspecified and entirely engine specific. Optional, properties length could be 0. If the
engine uses tile sets, then the map's tile set id (among other things) can be saved here.

Then for each layer there's a block with the following header:

| Number | Description                                       |
|-------:|---------------------------------------------------|
|      0 | layer type                                        |
|      1 | display type                                      |
|      2 | offset X in pixels                                |
|      3 | offset Y in pixels                                |
|      4 | parallax factor X percentage                      |
|      5 | parallax factor Y percentage                      |
|      6 | movement X in pixels per second                   |
|      7 | movement Y in pixels per second                   |

Display type goes like: 0 - display one time, 1 - repeat vertically, 2 - repeat horizontally, 3 - repeat both ways.

Parallax factor is a percentage, so 100 moves with the camera (just in the opposite direction), 50 means moves half speed
(further away from the viewer), and 200 means double speed (closer to the viewer). 0 is for stationary layers.

Movement is shifted up by 100, so 100 means no time based movement, on X axis 110 means 10 pixels to the right per second, and
90 means 10 pixels to the left per second. On the Y axis 110 is 10 pixels down, 90 is 10 pixels up per second.

**Sprites Layer**

If layer type is 39 (sprites), then an ULEB number comes, the number of records.

| Number | Description                                       |
|-------:|---------------------------------------------------|
|      0 | number of records                                 |

This is followed by that many ULEB triplets:

| Number | Description                                       |
|-------:|---------------------------------------------------|
|      0 | asset name offset                                 |
|      1 | offset X in pixels                                |
|      2 | offset Y in pixels                                |

**Tiles Layer**

If layer type is 40 (map), then layer data is RLE compressed with multiple packets. First comes a packet header byte. If the
most significant bit in this is set, then one ULEB number follows which is repeated (header byte & 0x7f) + 1 times. If the
most significant bit is clear, then (header byte & 0x7f) + 1 ULEB numbers follow, each different map values.

Map values are 32 bit and in general assumed to be sprite asset indeces, however an engine is free to use whatever values it
seems fit. The only restriction is that value of 0 must mean empty tile, transparent; the rest is engine specific.

**Objects and Scripts Layer**

If layer type is 46 or above (objects, scripts, dataX), then an ULEB number comes, followed by that many bytes. The exact
contents are unspecified and engine specific.

| Number | Description                                       |
|-------:|---------------------------------------------------|
|      0 | data bytes length (x)                             |
|      x | that many arbitrary data bytes                    |

**Others**

If layer type is anything else (for example 37 (images)), then a single ULEB number follows:

| Number | Description                                       |
|-------:|---------------------------------------------------|
|      0 | asset name offset                                 |

### 41 - 45 Reserved

Reserved for future use.

### 46 Objects

The format of the object assets is engine specific. Could be plain text, JSON, XML, binary etc. Format is unspecified, only
that each asset should describe some kind of in-game object. Stored compressed with RFC1950 deflate.

### 47 Scripts

The format of the script assets is engine specific. Could be plain text, byte code etc. Stored compressed with RFC1950 deflate.

### 48 - 63 Data Blobs

16 different kind of any assets, specific to the game engine (anything that wasn't covered with the types above). These are
however *not* compressed, so they can potentially big and random access read is possible on them.
