#ifndef W3CS_PACKED_POSITION_H
#define W3CS_PACKED_POSITION_H

#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>

#ifdef __cplusplus
extern "C" {
#endif

/* D3D9 position layouts use at most XYZW. Keeping the bound explicit makes
 * this codec portable to compilers without variable-length arrays. */
#define W3CS_PACKED_POSITION_MAX_AXES 4u
#define W3CS_PACKED_POSITION_BLOCK_VALUES 32u
#define W3CS_PACKED_POSITION_MAX_WIDTH 17u

/* Pack position quanta for opcode 35.
 *
 * `quanta` contains one signed 1/64-unit quantum for every position word.
 * A NULL selection mask means dense mode. Otherwise, one little-endian bit
 * per position word selects the transmitted values. An unselected value is
 * logically zero and resets that axis predictor to zero.
 *
 * Each transmitted quantum must be divisible by 2^drop_bits. The packed
 * value is divided by that scale, predicted from the preceding vertex's
 * value on the same axis, zigzag encoded, and placed in an independent block
 * of at most 32 selected values. A block starts with its minimal bit width
 * (0..17), then LSB-first values with zero padding to the next byte.
 *
 * Pass output=NULL to query the exact output size. On insufficient capacity,
 * the function returns false, writes nothing, and still reports the required
 * size. */
bool w3cs_packed_position_encode(
    const int16_t *quanta,
    uint32_t total_count,
    uint32_t axis_count,
    const uint8_t *selection_mask,
    unsigned drop_bits,
    uint8_t *output,
    size_t output_capacity,
    size_t *output_size);

/* Decode one packed position section. The input can include later opcode-35
 * sections; consumed_size reports only the packed position bytes. `quanta`
 * receives every full-scale 1/64-unit quantum, including zero for sparse
 * unselected positions. The decoder rejects non-canonical widths/padding and
 * any DPCM result outside int16 range after restoring 2^drop_bits. */
bool w3cs_packed_position_decode(
    const uint8_t *input,
    size_t input_size,
    int16_t *quanta,
    uint32_t total_count,
    uint32_t axis_count,
    const uint8_t *selection_mask,
    unsigned drop_bits,
    size_t *consumed_size);

#ifdef __cplusplus
}
#endif

#endif
