Asset Pack API
==============

Unpacker (apck.h)
-----------------

To use the unpacker library, include [apck.h](../apck.h) and in exactly one of your source files, also define `APCK_IMPLEMENTATION`
and create a context variable. No other headers nor libraries required, all decoders are already included.

```c
#define APCK_IMPLEMENTATION
#include <apck.h>

apck_t ctx;
```

### Initialization

Then to initialize, do

```c
int apck_init(apck_t *ctx, char *engine, uint32_t version, apck_initcb_t initcb, apck_readcb_t readcb);
```

Here `engine` is an engine or game specific magic up to 12 ASCII characters or NULL if you don't care, and `version` is the
biggest supported engine version or 0 if you don't care. To handle encrypted archives, you must also provide two hooks, otherwise
those can be NULL too. Returns 0 on success, error code otherwise.

```c
typedef void* (*apck_initcb_t)(uint8_t *enckey);
typedef int (*apck_readcb_t)(void *enc, uint64_t offs, uint8_t *buf, uint64_t size);
```

The `initcb` hook receives the 32 bytes long encryption key from the archive and allocates and generates an encryption context
from that key. This encrption context is fully opaque to Asset Packer. Then the second hook, `readcb` receives this encryption
context, and should decrypt `buf` and return 0 on success, error code otherwise. It receives `offs` too because encryption might
be position dependent, and also the buffer is padded due to cyclic block ciphers, but `size` does not include this padding.

### Loading Archives

```c
int apck_load(apck_t *ctx, char *fn);
```

After the context is initialized, you can load one or more archives into it. This will not load the entire archive, it will just
merge its Asset Directory with the context's Global Asset Directory, so it is fast. Returns 0 on success, error code otherwise.

You can load unencrypted and encrypted archives as well into the same context, even with different keys, but not with different
ciphers.

### Localization

```c
int apck_setlocale(apck_t *ctx, char *locale);
```

This selects one of the loaded locales. You can call this any time, it is possible to change locales on-the-fly. This not only
influences localized strings, but also selects localized voices and images. `locale` is an ISO-639-1 language code optionally
followed by an underscore and a two bytes region code, like "en", "en_US", "ja" or "ja_JP". Returns 0 on success, error code
otherwise.

```c
char *apck_msgstr(apck_t *ctx, char *msgid);
```

Looks up and returns a localized string. Uses fast O(log2) binary search. Do not free the returned buffer, it's cached within
the context. If translation not found, returns the original string.

```c
uint32_t *apck_text(apck_t *ctx, char *msgid, uint32_t color, int fontstyle, int fontsize, int *w, int *h);
```

Looks up and returns a localized string rendered to a pixel buffer using a previously selected font. See below for more details.

### Retrieving Assets

**IMPORTANT**: asset decoding and buffer caching is automatic. *NEVER* free the buffers returned by these functions (with one
notable exception being `apck_text()`), use `apck_release()` on one asset or `apck_free()` on the context instead.

```c
uint8_t *apck_asset(apck_t *ctx, int type, char *name, uint64_t *size);
```

Returns any arbitrary asset. You should only use this with assets that have no specialized retrievers, because this returns
raw undecoded data. The `type` argument is one of the `APCK_OBJECT`, `APCK_SCRIPT`, and `APCK_DATA01` to `APCK_DATA16`,
and `name` is the name of the asset. The lookup is very fast, uses O(log2) binary search, and the asset's contents are cached,
meaning subsequent calls with the same name return instantly.

```c
int apck_font(apck_t *ctx, char *name);
```

Retrieves a font asset and sets it in the context for further use. Returns 0 on success, error code otherwise.

```c
uint32_t *apck_text(apck_t *ctx, char *msgid, uint32_t color, int fontstyle, int fontsize, int *w, int *h);
```

Returns a newly allocated pixel buffer with localized string rendered on it as if it were a normal image asset in the archive
(under `locales/xx_XX/something.png`). The desired font must be set with `apck_font()` before calling. `fontstyle` can be
`APCK_REGULAR`, or an OR'd value of `APCK_BOLD`, `APCK_ITALIC`, `APCK_UNDERLINE` and `APCK_STRIKETHROUGH`. The `fontsize` must
be between 8 and 192 pixels. This is much more sophisticated than a baked pixel font, as it supports the entire 0 .. 0x10FFFFF
UNICODE range and is capable of handling ligatures and kerning as well.

**IMPORTANT**: unlike all the other retrievers, this returns an uncached, every time newly allocated buffer. So caching
dynamically these is up to you and you *MUST* call `free()` on the returned pixel buffer when you're done using it.

```c
uint32_t *apck_image(apck_t *ctx, int type, char *name, int *w, int *h);
```

Returns decoded image data, that is, RGBA pixel buffer of `w` \* `h` pixels. Here `type` can be either `APCK_IMAGE`, `APCK_ATLAS`.
For images, a localized pixel buffer might be returned. Atlases are generated, so their names go like "0001" to "9999".

```c
int16_t *apck_audio(apck_t *ctx, int type, char *name, int *numsamples, int *channels);
```

Returns decoded audio data, that is, `numsamples` PCM samples, signed 16-bit and interleaved if `channels` is greater than 1 (the
number of samples is the total number regardless to the number of channels). `type` can be either `APCK_SFX` or `APCK_BGM`. For
sound effects, a localized voice might be returned.

```c
apck_sprite_t *apck_sprite(apck_t *ctx, char *name);
```

Returns a decoded sprite frame list. See `apck_sprite_pose()` below on how to blit to a pixel buffer.

```c
m3d_t *apck_model(apck_t *ctx, char *name);
```
Returns a decoded 3D model. No getters nor any special treatment, you can simply traverse directly the
[m3d_t struct](https://gitlab.com/bztsrc/model3d/-/blob/master/docs/usage.md#traversing-the-in-memory-model-struct) to get
vertices, EBO/VBO lists, PBR-compliant materials, etc.; and you can call `m3d_pose()` to pose your models.

```c
apck_map_t *apck_map(apck_t *ctx, char *name);
```

Returns a decoded map. Map has various attributes and may have multiple layers.
- `type` is one of `APCK_ORTHOGONAL`, `APCK_ISOMETRIC`, `APCK_VERTHEX` (pointy top hexagonal), `APCK_HORIZHEX` (flat top hexagonal).
- `tilew` and `tileh` is the tile size in pixels.
- `w` and `h` is the map size in tiles.
- `l` is the number of layers.
- `properties` is an engine specific data structure of `proplen` size, optional.
- `layers[]` this array holds the layer data, has `l` elements.

For each layer, you have the following attributes:
- `type` either `APCK_MAP` (tile data), `APCK_OBJECT` / `APCK_SCRIPT` (engine specific data), `APCK_IMAGE` (background parallax
  image) or `APCK_MODEL` (voxel terrain).
- `disptype` is the display type, bit 0: repeat horizontally on X axis, bit 1: repeat vertically on Y axis.
- `offX` and `offY` are display offsets in pixels.
- `parX` and `parY` the parallax effect in percentage: 100 means same as camera, 50 half speed (further away from the viewer),
  200 double speed (closer to viewer).
- `movX` and `movY` time based parallax in pixels per second. This is signed so all four direction supported, from -100 to +100.
- `size` is the size of the layer data.
- `data[]` is the actual layer data.

Layer data for `APCK_MAP` type is `map.w` \* `map.h` uint32_t engine specific values. For `APCK_OBJECT` and above, the whole
data structure is entirely engine specific, could be anything. For all the other types, it's an UTF-8 asset name.

### Reading Arbitrary Parts of the Archive

These are low level functions, you probably won't need them, use one of the retrievers above instead. These are just documented
here in case someone needs to integrate Asset Pack with some kind of pull API.

```c
uint8_t *apck_readbuf(apck_t *ctx, uint32_t archive, uint64_t offs, uint64_t size);
```

This function reads in raw, but unencrypted data from the archive into a newly allocated buffer. All ciphers must support this
variant as long as `offs` is a start of an asset (see `ctx->files[type][index].archive`, `ctx->files[type][index].offs` and
`ctx->files[type][index].size`). It does not uncompress nor decode the data, but it does decrypt it.

```c
uint64_t apck_read(apck_t *ctx, uint32_t archive, uint64_t offs, uint8_t *buf, uint64_t size);
```

Reads in raw, but unencrypted data from the archive into an existing buffer. It does not do padding and expected to be called
with non-asset start `offs` too, so not all ciphers support this (the cipher must be position aware and must not use padding).
It does not uncompress nor decode the data, but it does decrypt it. This is the most likely needed for a pull API; and image,
audio, video assets and custom blobs are never compressed to allow random access reads. Returns the number of bytes read.

### Freeing Memory

```c
int apck_release(apck_t *ctx, int type, char *name);
```
Release the internal cache for one particular asset. Use this when you know that you don't need an asset any more and you want
to free up its memory.

```c
int apck_free(apck_t *ctx);
```
Free all internal caches and buffers on the context. Use this when you're finished with assets alltogether.

### Sprites

You can also dynamically construct sprites from your code.

```c
apck_sprite_t *apck_sprite_new(int type, int w, int h);
```

Creates a new sprite. The animation `type` can be `APCK_ANIM_LOOP`, `APCK_ANIM_ONCE`, `APCK_ANIM_BF` (back and forth).

```c
int apck_sprite_frame(apck_sprite_t *sprite, int dir, int atlas, int m, int w, int h, int sx, int sy, int dx, int dy,
    int dur, char *sfx);
```

Adds a new frame to the sprite. There are 8 possible directions, starting from South and going clock-wise. So `dir` direction
can be `APCK_DIR_S`, `APCK_DIR_SW`, `APCK_DIR_W`, `APCK_DIR_NW`, `APCK_DIR_N`, `APCK_DIR_NE`, `APCK_DIR_E`, `APCK_DIR_SE`. The
`atlas` parameter selects an asset from the `APCK_ATLAS` directory with an index (because that's O(1)). Method `m` could be
`APCK_M_COPY`, `APCK_M_FLIPV`, `APCK_M_FLIPH`, `APCK_M_ROT90`, `APCK_M_ROT180`, `APCK_M_ROT270` and specifies how the area is
copied from the atlas into the frame. The copy area is of `w` \* `h` size, taken at `sx`, `sy` from atlas, and placed at `dx`,
`dy` on the frame. Duration can be set in `dur` in centiseconds (like in GIF, 100 = 1 sec). If `sfx` is NULL, then there should
be no sound effect associated with this frame, otherwise an UTF-8 asset name.

```c
void apck_sprite_pose(apck_t *ctx, apck_sprite_t *sprite, int dir, int frame, uint32_t *buf, int x, int y, int w, int h, int p);
```

This function blits the requested sprite pose on an arbitrary pixel buffer `buf`, which is `w` \* `h` pixels in size, has `p`
bytes in a line (pitch). The `sprite` must be further specified with `dir` direction (see above) and a `frame` number, which
rolls over at the number of actual frames. If the frame is found on an atlas which wasn't loaded before, then it gets loaded.

```c
int apck_sprite_free(apck_sprite_t *sprite);
```

Frees a sprites from memory with all of its directions and animation frames.

### Maps

You can also dynamically construct maps from your code.

```c
apck_map_t *apck_map_new(int type, int tilew, int tileh, int w, int h, int proplen, uint8_t *properties);
```

Creates a new map. For valid values and explanation of arguments see `apck_map()` above.

```c
apck_map_layer_t *apck_map_layer(apck_map_t *map, int type, uint32_t datasize, void *data);
```

Allocates a new layer to the map. If `type` is `APCK_MAP`, then `datasize` and `data` not used, layer data is created as `w` \* `h`
tiles. If `type` is `APCK_SPRITE`, then `datasize` is the number of sprite records and `data` not used, if `type` is `APCK_OBJECT`
or above, then `datasize` bytes of `data` is added verbatim, and for any other types `datasize` is not used and `data` should point
to a zero terminated UTF-8 asset name. There are more layer attributes which you can use, see `apck_map()` above.

```c
int apck_map_free(apck_map_t *map);
```

Frees a map with all of its layers.

Packer (apck_pack.h)
--------------------

To use the packer library, include [apck_pack.h](../apck_pack.h) and in exactly one of your source files, also define
`APCK_PACK_IMPLEMENTATION` and create a context variable. This will also include `apck.h` because it needs the file structures,
and requires `png.h` and `vorbis/vorbisenc.h`; also link your program with those libraries. Alternatively you can include
`stb_image_write.h` instead, or you can specify your own implementations with the `APCK_PACK_PNG` and `APCK_PACK_OGG` macros.

```c
/* important to include these as well */
#include <png.h>
#include <vorbis/vorbisenc.h>

#define APCK_PACK_IMPLEMENTATION
#include <apck_pack.h>

apck_pack_t ctx;
```

### Initialization

Then to initialize, do

```c
void *f = apck_fileopenw("input.apck");
int apck_pack_init(apck_pack_t *ctx, void *f, char *engine, uint32_t version);
```

First you have to open a file for writing and pass its handler. Then `engine` is an engine or game specific magic, up to 12 ASCII
characters. `Version` is the engine's or game's version. Returns 0 on success, error code otherwise.

```c
int apck_pack_encrypt(apck_pack_t *ctx, uint32_t pad, uint8_t *enckey, apck_initcb_t initcb, apck_writecb_t writecb);
```

If you want to create an encrypted archive, you must provide a 32 bytes long encryption key in `enckey` and two hooks. Depending on
the cipher you choose, contents might also need padding, you can set this in `pad` (for example AES requires 16 bytes padding).

```c
typedef void* (*apck_initcb_t)(uint8_t *enckey);
typedef uint64_t (*apck_writecb_t)(void *enc, void *f, uint64_t offs, const uint8_t *buf, uint64_t size);
```

The `initcb` hook is exactly the same as with unpack, and `writecb` should encrypt the data in `buf` and write that to `f` to
offset `offs` and return the actual number of bytes written. The buffer `size` does not include the padding, however it is assumed
that size rounded up to that padding number bytes is written to the archive.

### Adding Assets

```c
int apck_pack_asset(apck_pack_t *ctx, int type, char *name, void *buf, uint64_t size, int w, int h);
```
Adds an asset by `name` with buffer `buf` of `size` bytes to the directory `type`, which can be `APCK_LOCALE`, `APCK_FONT`,
`APCK_BGM`, `APCK_SFX`, `APCK_VIDEO`, `APCK_MODEL`, `APCK_IMAGE`, `APCK_ATLAS`, `APCK_SPRITE`, `APCK_MAP`, `APCK_OBJECT`,
`APCK_SCRIPT`, and `APCK_DATA01` to `APCK_DATA16`. For pixel buffers, the `w` and `h` parameters must be set too. For audio, WAV
is expected with a 44 bytes long header, 44.1 kHz, and save `APCK_BGM` mono channel. Note that this function requires memory
buffers, as it does serialization and encoding on its own, and therefore a call to this could take some time to return.

```c
int apck_pack_add(apck_pack_t *ctx, int type, char *name, uint8_t *buf, uint64_t size);
```

Adds a raw serialized and encoded buffer to the archive. Do not use this directly unless you know what you're doing. Use the
`apck_pack_asset()` function instead.

### Finishing

```c
int apck_pack_flush(apck_pack_t *ctx);
apck_fileclose(f);
```

When there are no more assets to be added, a call must be made to `apck_pack_flush()`. This will write out data to the file and
free internal buffers. Afterwards the file handle can be closed.
