YAPF/yapf.h
Claude a226b06368
YAPF 2: texture container with GPU blocks, wide samples and streaming
Adds format version 2 alongside version 1 (still written for plain 8-bit
images, so existing readers keep working). Full specification in
docs/FORMAT.md.

- GPU block payloads: BC1-BC7, BC6H, ETC2/EAC, ASTC 4x4-12x12, in tiles
  of 16x16 blocks. Built-in BC1/BC3/BC4/BC5/BC7/BC6H encoders and
  BC1-BC7 decoders (BC6H/BC7 bit-exact with a reference decoder).
- Lossless 16-bit, half and float pixels as byte planes over the 8-bit
  coder; order-preserving float mapping, transforms at sample width.
- Cubemaps, cube arrays, texture arrays, volumes, animation frames.
- Channel meanings, normal convention, linear mask, primaries/transfer,
  mip filter and coverage-preserving mips (yapf_tex_build_mips).
- Small mips stored first, file size in the header, surface/tile tables:
  decode from a file prefix and single tiles (virtual texturing).
- yapf-sum checksums on header, tables and every tile; needs bits so
  decoders refuse cleanly what they cannot read.
- Optional entropy stage: per-surface Huffman code books with a
  neighbourhood context (~10% smaller photos) and per-lane packing of
  GPU blocks (~3x smaller on disk); planes decoded interleaved.
- Notes: author, licence, source, tool, ICC and application tags.
- CLI: --format, --entropy, --coverage, --normal, --map, colour options,
  16-bit/HDR input, pack cube/array/volume/anim, info, verify, export.
- Tests for all of the above, including fuzzing; v1 API reads 8-bit v2.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DVrVthWN8GsmgHGUhhsCYm
2026-10-10 21:57:14 +00:00

615 lines
33 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* yapf.h — Yet Another Picture Format
* Public API and format specification.
*
* Copyright 2026 Nexoniarz
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* -------------------------------------------------------------------------
*
* YAPF — lossless, GPU-ready image format.
*
* Designed for single-core decode speed. Everything is byte aligned:
* no bit reader, no entropy coder, no context model. Per row the decoder
* dispatches one filter; per 8 samples it reads a 4-bit control code and
* exactly w bytes of payload, unpacked with one 64-bit load and shifts.
* The encoder does the hard work (filter search, colour transform choice,
* optimal control codes); the decoder only follows instructions.
*
* 1. Per tile: YCoCg-R or subtract-green colour transform, 8-bit modular
* 2. Per band of 8 rows: one of 12 row filters
* 3. Residuals in groups of 8, each group at its bit width (0–8);
* 4-bit control codes, with codes that repeat the previous width
* 4. Independent 64×64 tiles with a size table → random access and
* optional parallel decode
*
* The file carries GPU metadata (format hint, mip levels, flags) so a
* loader can upload the decoded buffer straight to a texture without any
* additional transcoding step.
*
* Two versions exist. Version 1 (below) is a single 8-bit 2D image with
* optional mips. Version 2 is the texture container: GPU block payloads
* (BCn / ETC2 / ASTC), 16-bit and float samples, cubemaps, arrays and
* volumes, channel meanings, per-tile checksums, optional entropy-coded
* planes, notes (metadata) and animation frames. Its complete
* specification is docs/FORMAT.md; a summary follows the v1 spec.
*
* =========================================================================
* FILE FORMAT (version 1)
* =========================================================================
*
* All multi-byte integers are little-endian. All arithmetic on samples
* is mod 256.
*
* ┌─────────────────────────────────────────────────────────────────────┐
* │ HEADER — 20 bytes │
* ├────────┬──────┬────────────────────────────────────────────────────┤
* │ Offset │ Size │ Field │
* ├────────┼──────┼────────────────────────────────────────────────────┤
* │ 0x00 │ 4 │ Magic: "YAPF" │
* │ 0x04 │ 1 │ Version: 1 │
* │ 0x05 │ 1 │ Channels: 1 gray / 2 gray+A / 3 RGB / 4 RGBA │
* │ 0x06 │ 1 │ GPU format hint (YAPF_GPU_* constant) │
* │ 0x07 │ 1 │ Mip levels (1 = base only, max 16) │
* │ 0x08 │ 1 │ Flags (see YAPF_FLAG_* bitmask) │
* │ 0x09 │ 3 │ Reserved (write 0, ignore on read) │
* │ 0x0C │ 4 │ Base width (uint32, pixels) │
* │ 0x10 │ 4 │ Base height (uint32, pixels) │
* └────────┴──────┴────────────────────────────────────────────────────┘
*
* ┌─────────────────────────────────────────────────────────────────────┐
* │ MIP INDEX — 8 bytes × mip_levels, immediately after header │
* ├────────┬──────┬────────────────────────────────────────────────────┤
* │ +0 │ 4 │ Byte offset of mip data from start of file (uint32) │
* │ +4 │ 4 │ Byte size of mip data (uint32) │
* └────────┴──────┴────────────────────────────────────────────────────┘
* Mip m has size max(1, width >> m) × max(1, height >> m).
*
* ┌─────────────────────────────────────────────────────────────────────┐
* │ MIP LEVEL DATA │
* ├─────────────────────────────────────────────────────────────────────┤
* │ Pixels are divided into 64×64 tiles in row-major order; the last │
* │ column / row of tiles may be smaller (no padding). │
* │ │
* │ uint32 tile_size[tile_count] byte size of each tile │
* │ tile data, back to back │
* │ │
* │ TILE │
* │ 1 byte header │
* │ 0x80 stored: tile_w × tile_h × channels raw bytes │
* │ follow, interleaved, in the original channel order │
* │ otherwise coded: │
* │ bits 0–3 bit c set = plane c is constant (only bits below │
* │ the channel count may be set) │
* │ bit 4 colour transform: 0 = YCoCg-R, 1 = subtract-green │
* │ (RGB / RGBA only; must be 0 for gray) │
* │ bits 5–7 must be 0 │
* │ coded tiles then hold one value byte per constant plane, and a │
* │ plane payload per other plane, both in plane order. The tile │
* │ must end exactly where its last payload ends. │
* │ │
* │ PLANES │
* │ gray / gray+A: the channels as stored. │
* │ RGB(A), YCoCg-R (>> is an arithmetic shift of the value as int8):│
* │ planes Y, Co, Cg (+ A) │
* │ forward: o = R − B; t = B + (o >> 1); q = G − t; │
* │ Y = t + (q >> 1); Co = o + 128; Cg = q + 128 │
* │ inverse: o = Co − 128; q = Cg − 128; t = Y − (q >> 1); │
* │ G = q + t; B = t − (o >> 1); R = B + o │
* │ RGB(A), subtract-green: │
* │ planes G, R − G + 128, B − G + 128 (+ A) │
* │ │
* │ PLANE PAYLOAD │
* │ filter[ceil(tile_h / 8)] one byte per band of 8 rows. │
* │ L / A / D / AR = left, above, above-left, above-right sample; │
* │ samples outside the tile read as 0, except that AR in the │
* │ last column reads as A. │
* │ 0 Left pred = L │
* │ 1 Gradient pred = L + A − D │
* │ 2 Up-right pred = AR │
* │ 3 Up-average pred = (A + AR) >> 1 (not mod 256) │
* │ 16 + k−1 Up k pred = sample k rows above, k = 1..8 │
* │ control nibbles, low nibble of each byte first, covering │
* │ exactly ceil(tile_w × tile_h / 8) groups of 8 consecutive │
* │ residuals in raster order: │
* │ 0–8 one group of width w │
* │ 9–15 2, 3, 4, 8, 16, 32 or 64 groups at the width of │
* │ the last 0–8 code in this plane (0 if none yet) │
* │ an odd nibble count is padded with a zero high nibble │
* │ group data: w bytes per group, the 8 values packed little- │
* │ endian, value i in bits [i·w, i·w + w) │
* │ Residual r = (sample − pred) mod 256 is stored folded: │
* │ v = (r << 1) ^ (r >> 7) (0, −1, 1, −2, … → 0, 1, 2, 3, …) │
* │ The last group is padded with zero values. │
* └─────────────────────────────────────────────────────────────────────┘
*
* GPU FORMAT HINTS (YAPF_GPU_* values for the gpu_format field)
* ──────────────────────────────────────────────────────────────
* 0x00 RGBA8 GL_RGBA8 / VK_FORMAT_R8G8B8A8_UNORM
* 0x01 RGB8 GL_RGB8 / VK_FORMAT_R8G8B8_UNORM
* 0x02 RG8 GL_RG8 / VK_FORMAT_R8G8_UNORM
* 0x03 R8 GL_R8 / VK_FORMAT_R8_UNORM
* 0x04 SRGB8_A8 GL_SRGB8_ALPHA8
* 0x05 SRGB8 GL_SRGB8
*
* FLAGS (YAPF_FLAG_* bitmask for the flags field)
* ─────────────────────────────────────────────────
* bit 0 PREMULT_ALPHA alpha is premultiplied into RGB
* bit 1 SRGB pixels are in sRGB gamma (informational only)
* bit 2 COVERAGE (v2) mips keep alpha-test coverage at alpha_ref
*
* =========================================================================
* FILE FORMAT (version 2) — summary; the full text is docs/FORMAT.md
* =========================================================================
*
* HEADER (64 bytes)
* 0x00 "YAPF" 0x04 version 2 0x05 channels 0x06 format
* 0x07 mips 0x08 flags 0x09 payload 0x0A sample 0x0B shape
* 0x0C width u32 0x10 height u32 0x14 depth u32
* 0x18 layers u16 0x1A frames u16 0x1C needs u32
* 0x20 channel map[4] 0x24 linear mask 0x25 normal 0x26 primaries
* 0x27 transfer 0x28 mip filter 0x29 alpha ref 0x2A loop count u16
* 0x2C notes size u32 0x30 file size u64
* 0x38 tables check u32 (yapf-sum of bytes [0x40, data start))
* 0x3C header check u32 (yapf-sum of bytes [0, 0x3C))
* SURFACE TABLE 16 bytes per surface: offset u64, size u32,
* tile-table check u32. Surface s of (frame, layer,
* face, mip) is ((frame·layers + layer)·faces + face)·mips + mip
* FRAME TABLE u32 duration in µs per frame (only when frames > 1)
* NOTES tag[4], length u32, bytes — repeated
* SURFACE DATA smallest mips first, so a file prefix is a complete
* low-resolution texture. Per surface: u32 book size,
* code book (Huffman tables by slot and context, only
* with entropy coding), tile table (size u32 with bit 31 =
* packed, yapf-sum u32 per tile), then the tiles. Pixel
* tiles are the v1 tiles plus byte planes for wide samples
* and entropy-coded planes; block tiles hold 16 × 16 GPU
* blocks, raw or packed lane by lane.
* NEEDS a decoder must refuse a file with a needs bit it does
* not implement; everything else may be ignored safely.
*/
#ifndef YAPF_H
#define YAPF_H
#include <stdint.h>
#include <stddef.h>
/* ── GPU format hints ────────────────────────────────────────────────── */
#define YAPF_GPU_RGBA8 0x00
#define YAPF_GPU_RGB8 0x01
#define YAPF_GPU_RG8 0x02
#define YAPF_GPU_R8 0x03
#define YAPF_GPU_SRGB8_A8 0x04
#define YAPF_GPU_SRGB8 0x05
/* v2 pixel hints for wide samples */
#define YAPF_GPU_RGBA16 0x06
#define YAPF_GPU_RGB16 0x07
#define YAPF_GPU_RG16 0x08
#define YAPF_GPU_R16 0x09
#define YAPF_GPU_RGBA16F 0x0A
#define YAPF_GPU_RGB16F 0x0B
#define YAPF_GPU_RG16F 0x0C
#define YAPF_GPU_R16F 0x0D
#define YAPF_GPU_RGBA32F 0x0E
#define YAPF_GPU_RGB32F 0x0F
#define YAPF_GPU_RG32F 0x10
#define YAPF_GPU_R32F 0x11
/* v2 GPU block formats (payload = YAPF_PAYLOAD_BLOCKS). The sRGB flag
* selects the _SRGB variant where the API has one. */
#define YAPF_GPU_BC1 0x40 /* RGB(A1), 8 bytes per 4×4 */
#define YAPF_GPU_BC2 0x41 /* RGBA, explicit 4-bit alpha */
#define YAPF_GPU_BC3 0x42 /* RGBA */
#define YAPF_GPU_BC4 0x43 /* R */
#define YAPF_GPU_BC4_SNORM 0x44
#define YAPF_GPU_BC5 0x45 /* RG (normal maps) */
#define YAPF_GPU_BC5_SNORM 0x46
#define YAPF_GPU_BC6H 0x47 /* RGB half float, unsigned */
#define YAPF_GPU_BC6H_SF 0x48 /* RGB half float, signed */
#define YAPF_GPU_BC7 0x49 /* RGB(A) */
#define YAPF_GPU_ETC2_RGB8 0x50
#define YAPF_GPU_ETC2_RGB8A1 0x51
#define YAPF_GPU_ETC2_RGBA8 0x52
#define YAPF_GPU_EAC_R11 0x53
#define YAPF_GPU_EAC_R11_SNORM 0x54
#define YAPF_GPU_EAC_RG11 0x55
#define YAPF_GPU_EAC_RG11_SNORM 0x56
#define YAPF_GPU_ASTC_4x4 0x60 /* ASTC: 0x60 + footprint index */
#define YAPF_GPU_ASTC_5x4 0x61
#define YAPF_GPU_ASTC_5x5 0x62
#define YAPF_GPU_ASTC_6x5 0x63
#define YAPF_GPU_ASTC_6x6 0x64
#define YAPF_GPU_ASTC_8x5 0x65
#define YAPF_GPU_ASTC_8x6 0x66
#define YAPF_GPU_ASTC_8x8 0x67
#define YAPF_GPU_ASTC_10x5 0x68
#define YAPF_GPU_ASTC_10x6 0x69
#define YAPF_GPU_ASTC_10x8 0x6A
#define YAPF_GPU_ASTC_10x10 0x6B
#define YAPF_GPU_ASTC_12x10 0x6C
#define YAPF_GPU_ASTC_12x12 0x6D
/* ── Flags ───────────────────────────────────────────────────────────── */
#define YAPF_FLAG_PREMULT_ALPHA 0x01
#define YAPF_FLAG_SRGB 0x02
#define YAPF_FLAG_COVERAGE 0x04 /* v2: mips preserve alpha-test coverage */
/* ── Channel constants ───────────────────────────────────────────────── */
#define YAPF_CHANNELS_GRAY 1
#define YAPF_CHANNELS_GRAY_ALPHA 2
#define YAPF_CHANNELS_RGB 3
#define YAPF_CHANNELS_RGBA 4
/* ── Return codes ────────────────────────────────────────────────────── */
#define YAPF_OK 0
#define YAPF_ERR_INVALID -1
#define YAPF_ERR_IO -2
#define YAPF_ERR_OOM -3
#define YAPF_ERR_CORRUPT -4
#define YAPF_ERR_UNSUPPORTED -5 /* valid file, feature this decoder lacks */
#define YAPF_ERR_CHECKSUM -6 /* a yapf-sum does not match */
#define YAPF_ERR_TRUNCATED -7 /* data lies beyond the bytes available yet */
/* ── Limits ──────────────────────────────────────────────────────────── */
#define YAPF_MAX_DIM 65535u
#define YAPF_MAX_MIPS 16u
#define YAPF_TILE_SIZE 64u
#define YAPF_BLOCK_TILE 16u /* v2 block tiles: 16 × 16 GPU blocks */
/* ── Image descriptor ────────────────────────────────────────────────── */
typedef struct {
uint32_t width;
uint32_t height;
uint8_t channels; /* 1–4 */
uint8_t gpu_format; /* YAPF_GPU_* */
uint8_t flags; /* YAPF_FLAG_* bitmask */
uint8_t mip_levels; /* number of mip levels stored (1 = base only) */
uint8_t *pixels; /* base-level pixels, malloc-owned */
uint8_t **mips; /* mips[0]=base alias, mips[1..mip_levels-1] owned */
} yapf_image_t;
/* ── Version 2: texture description ──────────────────────────────────── */
/* payload */
#define YAPF_PAYLOAD_PIXELS 0 /* lossless YAPF tiles */
#define YAPF_PAYLOAD_BLOCKS 1 /* GPU blocks, uploaded as they are */
/* sample: how one channel value is stored (pixel payload); for block
* payloads, the type of the decoded texels (U8, or F16 for BC6H) */
#define YAPF_SAMPLE_U8 0
#define YAPF_SAMPLE_U16 1
#define YAPF_SAMPLE_F16 2 /* IEEE half, as uint16_t bits */
#define YAPF_SAMPLE_F32 3
/* shape */
#define YAPF_SHAPE_2D 0
#define YAPF_SHAPE_CUBE 1 /* 6 faces: +X −X +Y −Y +Z −Z; with layers
> 1 a cube array */
#define YAPF_SHAPE_VOLUME 2 /* depth slices; mips halve depth too */
/* needs: features a decoder must implement to read the file */
#define YAPF_NEED_WIDE 0x01 /* sample other than U8 (pixel payload) */
#define YAPF_NEED_BLOCKS 0x02 /* GPU block payload */
#define YAPF_NEED_ENTROPY 0x04 /* code books: entropy planes, packed blocks */
#define YAPF_NEED_LAYOUT 0x08 /* cube, volume or layers > 1 */
#define YAPF_NEED_FRAMES 0x10 /* frames > 1 */
#define YAPF_NEED_ALL 0x1F /* everything this library implements */
/* channel meanings (channel_map[c]); 0 = default for the channel count */
#define YAPF_CH_DEFAULT 0
#define YAPF_CH_RED 1
#define YAPF_CH_GREEN 2
#define YAPF_CH_BLUE 3
#define YAPF_CH_ALPHA 4
#define YAPF_CH_LUMA 5
#define YAPF_CH_NORMAL_X 6
#define YAPF_CH_NORMAL_Y 7
#define YAPF_CH_NORMAL_Z 8
#define YAPF_CH_ROUGHNESS 9
#define YAPF_CH_GLOSS 10 /* smoothness = 1 − roughness */
#define YAPF_CH_METALNESS 11
#define YAPF_CH_OCCLUSION 12 /* ambient occlusion */
#define YAPF_CH_HEIGHT 13
#define YAPF_CH_SPECULAR 14
#define YAPF_CH_EMISSIVE 15
#define YAPF_CH_OPACITY 16 /* alpha-test / cut-out mask */
#define YAPF_CH_MASK 17 /* generic mask */
#define YAPF_CH_CAVITY 18
#define YAPF_CH_THICKNESS 19
#define YAPF_CH_ID 20 /* material or object id */
#define YAPF_CH_UNUSED 255
/* normal: bits 0–1 convention, bits 2–3 encoding */
#define YAPF_NORMAL_NONE 0x00
#define YAPF_NORMAL_GL 0x01 /* +Y up (OpenGL, Blender, Unity) */
#define YAPF_NORMAL_DX 0x02 /* −Y (DirectX, Unreal) */
#define YAPF_NORMAL_XYZ 0x00
#define YAPF_NORMAL_XY 0x04 /* Z = sqrt(1 − x² − y²) is reconstructed */
#define YAPF_NORMAL_OCT 0x08 /* octahedral */
/* primaries / transfer (0 = unspecified: the sRGB flag decides) */
#define YAPF_PRIMARIES_UNSPECIFIED 0
#define YAPF_PRIMARIES_BT709 1 /* = sRGB */
#define YAPF_PRIMARIES_DISPLAY_P3 2
#define YAPF_PRIMARIES_BT2020 3
#define YAPF_PRIMARIES_ACES_AP0 4
#define YAPF_PRIMARIES_ACES_AP1 5 /* ACEScg */
#define YAPF_PRIMARIES_ADOBE_RGB 6
#define YAPF_TRANSFER_UNSPECIFIED 0
#define YAPF_TRANSFER_SRGB 1
#define YAPF_TRANSFER_LINEAR 2
#define YAPF_TRANSFER_GAMMA22 3
#define YAPF_TRANSFER_PQ 4 /* SMPTE ST 2084 */
#define YAPF_TRANSFER_HLG 5
#define YAPF_TRANSFER_BT1886 6 /* gamma 2.4 */
/* mip filter (bits 0–6) | YAPF_MIP_LINEAR_LIGHT */
#define YAPF_MIP_UNKNOWN 0
#define YAPF_MIP_BOX 1
#define YAPF_MIP_TENT 2
#define YAPF_MIP_KAISER 3
#define YAPF_MIP_LANCZOS 4
#define YAPF_MIP_MITCHELL 5
#define YAPF_MIP_AUTHORED 6 /* made by hand / by an external tool */
#define YAPF_MIP_LINEAR_LIGHT 0x80 /* sRGB channels were filtered in linear light */
/* load flags */
#define YAPF_LOAD_TRUST 0x01 /* skip checksum verification */
/* encode flags */
#define YAPF_ENC_ENTROPY 0x01 /* allow entropy-coded planes and packed
blocks where they are smaller: ~10 %
smaller photos, ~3× smaller GPU blocks
on disk; slower to decode */
/* A note (metadata entry). Well-known tags: "AUTH" author, "LICN"
* licence, "SRCE" source, "TOOL" creating tool, "TITL" title, "DESC"
* description, "DATE" ISO 8601 date (all UTF-8 text); "ICCP" ICC profile;
* "ORNT" orientation (1 byte); "DPI " 2 × u32 milli-dots per inch;
* "CLL " 2 × u16 max content / max frame-average light level (cd/m²).
* Tags that start with a lowercase letter belong to applications. */
typedef struct {
char tag[4];
uint32_t size;
uint8_t *data;
} yapf_note_t;
/*
* A version 2 texture. Surfaces are numbered
* s = ((frame × layers + layer) × faces + face) × mip_levels + mip
* (faces = 6 for cubes, else 1) and data[s] holds the whole surface:
* pixels: width_m × height_m × depth_m × channels samples, rows top to
* bottom, slices in order; samples in the native byte order
* (uint8_t, uint16_t, half bits as uint16_t, float);
* blocks: ceil(width_m / bw) × ceil(height_m / bh) blocks per slice,
* row-major — exactly what glCompressedTexImage / Vulkan take.
* width_m = max(1, width >> m), likewise height and (volumes) depth.
*/
typedef struct {
uint32_t width, height, depth; /* depth: volumes only, else 1 */
uint16_t layers; /* array layers, >= 1 */
uint16_t frames; /* animation frames, >= 1 */
uint8_t shape; /* YAPF_SHAPE_* */
uint8_t mip_levels; /* 1–16 */
uint8_t payload; /* YAPF_PAYLOAD_* */
uint8_t format; /* YAPF_GPU_*: block format, or hint */
uint8_t sample; /* YAPF_SAMPLE_* */
uint8_t channels; /* 1–4 */
uint8_t flags; /* YAPF_FLAG_* */
uint8_t channel_map[4]; /* YAPF_CH_* per channel */
uint8_t linear_mask; /* bit c: channel c is linear even in
an sRGB image (e.g. alpha, masks) */
uint8_t normal; /* YAPF_NORMAL_* */
uint8_t primaries, transfer; /* YAPF_PRIMARIES_*, YAPF_TRANSFER_* */
uint8_t mip_filter; /* YAPF_MIP_* */
uint8_t alpha_ref; /* coverage reference (with COVERAGE) */
uint16_t loop_count; /* animation loops, 0 = forever */
uint32_t *frame_us; /* frames durations in µs, or NULL */
uint32_t note_count;
yapf_note_t *notes;
void **data; /* one pointer per surface */
void *internal_; /* library use: file tables, ownership */
} yapf_texture_t;
/* ── Public API ──────────────────────────────────────────────────────── */
#ifdef __cplusplus
extern "C" {
#endif
/*
* yapf_load — decode a .yapf file.
* Returns NULL on any failure (bad magic, truncated data, OOM, I/O error).
* The returned image must be released with yapf_free().
*/
yapf_image_t *yapf_load(const char *filename);
/*
* yapf_load_memory — decode a .yapf file already in memory (e.g. from a
* game archive). Same ownership and failure rules as yapf_load().
*/
yapf_image_t *yapf_load_memory(const void *buffer, size_t size);
/*
* yapf_load_mt / yapf_load_memory_mt — same as above, but decode tiles on
* up to `threads` threads (0 = one per CPU core). Output is identical.
* Without thread support (YAPF_NO_THREADS, or an unknown platform) these
* decode on the calling thread.
*/
yapf_image_t *yapf_load_mt(const char *filename, int threads);
yapf_image_t *yapf_load_memory_mt(const void *buffer, size_t size, int threads);
/*
* yapf_save — encode an image to disk.
* img->mip_levels controls how many levels are written; set to 1 to write
* only the base level. img->mips may be NULL when mip_levels == 1.
* Returns YAPF_OK or a negative YAPF_ERR_* code.
*/
int yapf_save(const char *filename, const yapf_image_t *img);
/*
* yapf_encode — encode an image into memory.
* On success *out_data points to *out_size bytes of a complete .yapf file;
* release it with yapf_free_buffer(). Same rules and return codes as
* yapf_save() (no YAPF_ERR_IO).
*/
int yapf_encode(const yapf_image_t *img, void **out_data, size_t *out_size);
/* yapf_free_buffer — release memory returned by yapf_encode(). NULL-safe. */
void yapf_free_buffer(void *data);
/*
* yapf_free — release all memory owned by an image returned by yapf_load().
* NULL-safe.
*/
void yapf_free(yapf_image_t *img);
/*
* The v1 functions above also read version 2 files that hold 8-bit pixels
* of a 2D, cube or array texture: they return frame 0, layer 0, face 0
* with all its mips. yapf_save / yapf_encode always write version 1.
*/
/* ── Version 2: textures ─────────────────────────────────────────────── */
/*
* yapf_tex_create — a library-owned texture with the description of
* `desc` (every field up to loop_count; notes, frame times and data are
* not copied) and zeroed storage for every surface. frame_us is
* allocated (zeroed) when frames > 1. NULL on invalid description / OOM.
*/
yapf_texture_t *yapf_tex_create(const yapf_texture_t *desc);
/* yapf_tex_free — release a texture made by the library. NULL-safe. */
void yapf_tex_free(yapf_texture_t *tex);
/* Surface helpers. */
uint32_t yapf_tex_faces(const yapf_texture_t *tex); /* 6 or 1 */
uint32_t yapf_tex_surface_count(const yapf_texture_t *tex);
uint32_t yapf_tex_surface(const yapf_texture_t *tex, uint32_t frame,
uint32_t layer, uint32_t face, uint32_t mip);
void yapf_tex_mip_size(const yapf_texture_t *tex, uint32_t mip,
uint32_t *w, uint32_t *h, uint32_t *d);
size_t yapf_tex_surface_bytes(const yapf_texture_t *tex, uint32_t mip);
size_t yapf_sample_bytes(uint8_t sample); /* 1, 2 or 4 */
/* Notes: add (library-owned textures only; data is copied) and find. */
int yapf_tex_add_note(yapf_texture_t *tex, const char tag[4],
const void *data, uint32_t size);
const yapf_note_t *yapf_tex_find_note(const yapf_texture_t *tex, const char tag[4]);
/*
* yapf_tex_encode / yapf_tex_save — write a version 2 file. `flags` is
* YAPF_ENC_*. Works on library-owned and caller-built textures alike
* (nothing is taken over). Returns YAPF_OK or a YAPF_ERR_* code.
*/
int yapf_tex_encode(const yapf_texture_t *tex, int flags,
void **out_data, size_t *out_size);
int yapf_tex_save(const char *filename, const yapf_texture_t *tex, int flags);
/*
* yapf_tex_load / yapf_tex_load_memory — read a version 1 or 2 file and
* decode every surface on up to `threads` threads (0 = one per core).
* `flags` is YAPF_LOAD_*. On failure NULL is returned and *err (if not
* NULL) receives the YAPF_ERR_* reason.
*/
yapf_texture_t *yapf_tex_load(const char *filename, int flags, int threads, int *err);
yapf_texture_t *yapf_tex_load_memory(const void *buffer, size_t size,
int flags, int threads, int *err);
/*
* Streaming and partial decoding.
*
* yapf_tex_open — read only the header, tables and notes. `avail` may be
* less than the whole file (a download in progress): it must cover the
* front matter, else YAPF_ERR_TRUNCATED. All data[] pointers are NULL.
*
* yapf_tex_stream_bytes — how many leading bytes of the file hold every
* surface of mip `first_mip` and smaller (the file stores small mips
* first, so these are a usable texture on their own).
*
* yapf_tex_decode_surface — decode surface s into tex->data[s]
* (allocated). `buffer`/`avail` is the file or a prefix of it; returns
* YAPF_ERR_TRUNCATED when the surface is not in it yet.
*
* yapf_tex_tile_grid / yapf_tex_decode_tile — virtual texturing: the
* surfaces of mip m are cut into tiles (64 × 64 pixels, or 16 × 16
* blocks), tx across, ty down, per slice. decode_tile writes one tile
* into `out`, rows `stride` bytes apart, and reports its pixel rectangle.
*/
yapf_texture_t *yapf_tex_open(const void *buffer, size_t avail, int flags, int *err);
uint64_t yapf_tex_stream_bytes(const yapf_texture_t *tex, uint32_t first_mip);
int yapf_tex_decode_surface(yapf_texture_t *tex, const void *buffer, size_t avail,
uint32_t surface, int threads);
void yapf_tex_tile_grid(const yapf_texture_t *tex, uint32_t mip,
uint32_t *tiles_x, uint32_t *tiles_y);
int yapf_tex_decode_tile(const yapf_texture_t *tex, const void *buffer, size_t avail,
uint32_t surface, uint32_t tx, uint32_t ty, uint32_t slice,
void *out, size_t stride,
uint32_t *x, uint32_t *y, uint32_t *w, uint32_t *h);
/*
* yapf_tex_build_mips — replace the mips of a library-owned pixel texture
* with a chain made from mip 0: `levels` levels (0 = down to 1 × 1).
* 2 × 2 (× 2 for volumes) box filter; sRGB channels are averaged in
* linear light. alpha_ref > 0 rescales alpha on every mip so the share
* of texels above alpha_ref stays that of mip 0 (fences and foliage do
* not thin out); it sets YAPF_FLAG_COVERAGE. Records the filter used.
*/
int yapf_tex_build_mips(yapf_texture_t *tex, uint32_t levels, uint8_t alpha_ref);
/* ── GPU blocks ──────────────────────────────────────────────────────── */
/* Block footprint and size of a YAPF_GPU_* block format; 0 if not one. */
int yapf_block_info(uint8_t format, uint32_t *block_w, uint32_t *block_h,
uint32_t *block_bytes);
/*
* yapf_tex_compress — a new library-owned texture holding `src` (pixel
* payload) as GPU blocks. Built-in encoders: BC1, BC3, BC4, BC5, BC7 and
* BC6H (unsigned). LDR formats take 8-bit pixels; BC6H takes 16-bit,
* half or float pixels. For other formats bring blocks from your own
* encoder: a payload = BLOCKS texture with data[] filled.
*/
int yapf_tex_compress(const yapf_texture_t *src, uint8_t format,
yapf_texture_t **out);
/*
* yapf_blocks_decode — decode a w × h image of BC1–BC7 blocks (previews,
* tools). LDR formats write RGBA8 (BC4 / BC5: R / RG, then 0, 255;
* snorm values shifted by +128); BC6H writes RGB half floats. Returns
* YAPF_ERR_UNSUPPORTED for ETC2 / EAC / ASTC.
*/
int yapf_blocks_decode(uint8_t format, const void *blocks, uint32_t w, uint32_t h,
void *out);
/* yapf-sum, the checksum used by version 2 files. */
uint32_t yapf_checksum(const void *data, size_t size);
/* Half float conversion helpers. */
uint16_t yapf_float_to_half(float f);
float yapf_half_to_float(uint16_t h);
#ifdef __cplusplus
}
#endif
#endif /* YAPF_H */