#ifndef W3CS_PROTOCOL_H
#define W3CS_PROTOCOL_H

#include <stdint.h>

#define W3CS_VERSION 1u
/* GStreamer's SCTP send path caps one message below 64 KiB including our
 * envelope. A 60 KiB payload leaves headroom and replaces five 12 KiB
 * messages for a typical WC3 frame. */
#define W3CS_MAX_FRAGMENT (60u * 1024u)
#define W3CS_MAX_FRAME (4u * 1024u * 1024u)

enum w3cs_kind {
    W3CS_HELLO = 1,
    W3CS_RESOURCE = 2,
    W3CS_FRAME = 3,
    W3CS_REPAIR = 4,
    W3CS_ACK = 5,
    W3CS_ERROR = 6,
    /* A bundle contains a SHA-256 digest followed by resource records. A
     * reference contains the same digest and the decoded byte count. */
    W3CS_RESOURCE_BUNDLE = 7,
    W3CS_RESOURCE_REFERENCE = 8
};

enum w3cs_flag {
    W3CS_COMPRESSED = 1u,
    W3CS_KEYFRAME = 2u,
    W3CS_LAST = 4u,
    /* A disposable geometry anchor is independently decodable against the
     * reliable recovery epoch. The following short GOP can delta against it. */
    W3CS_GEOMETRY_ANCHOR = 8u
};

enum w3cs_opcode {
    W3CS_OP_FRAME_STATE = 1,
    W3CS_OP_CREATE_BUFFER = 2,
    W3CS_OP_UPDATE_BUFFER = 3,
    W3CS_OP_CREATE_TEXTURE = 4,
    W3CS_OP_UPDATE_TEXTURE = 5,
    W3CS_OP_DESTROY_RESOURCE = 6,
    W3CS_OP_DEFINE_BLOB = 7,
    W3CS_OP_DEFINE_BLOB_DELTA = 8,
    W3CS_OP_DEFINE_BLOB_XOR_MASK = 9,
    W3CS_OP_RESET_BLOB_CACHE = 10,
    W3CS_OP_DEFINE_BLOB_FLOAT16_DELTA = 11,
    /* Texture pixels live in a content-addressed blob. This record binds the
     * stable pixel content to the session-local D3D texture identity. */
    W3CS_OP_UPDATE_TEXTURE_BLOB = 12,
    /* A viewer can attach while the persistent game is between Presents.
     * These markers let the relay discard in-flight updates from the prior
     * viewer and start the new reliable resource epoch at an exact boundary. */
    W3CS_OP_RESOURCE_SNAPSHOT_BEGIN = 13,
    W3CS_OP_RESOURCE_SNAPSHOT_END = 14,
    W3CS_OP_SET_RENDER_STATE = 16,
    W3CS_OP_SET_TRANSFORM = 17,
    W3CS_OP_SET_TEXTURE = 18,
    W3CS_OP_SET_FVF = 19,
    W3CS_OP_SET_STREAM_SOURCE = 20,
    W3CS_OP_SET_INDICES = 21,
    W3CS_OP_SET_MATERIAL = 22,
    W3CS_OP_SET_LIGHT = 23,
    W3CS_OP_LIGHT_ENABLE = 24,
    W3CS_OP_SET_TEXTURE_STAGE_STATE = 25,
    W3CS_OP_SET_SAMPLER_STATE = 26,
    W3CS_OP_SET_VIEWPORT = 27,
    W3CS_OP_SET_SCISSOR = 28,
    W3CS_OP_CLEAR = 29,
    W3CS_OP_SET_CURSOR = 30,
    W3CS_OP_SHOW_CURSOR = 31,
    W3CS_OP_DRAW_PRIMITIVE = 32,
    W3CS_OP_DRAW_INDEXED_PRIMITIVE = 33,
    /* WC3 changes D3DTS_WORLD before most draws. Keep translation as float32
     * and store the other affine components as IEEE binary16. */
    W3CS_OP_SET_WORLD_TRANSFORM_COMPACT = 34
};

#pragma pack(push, 1)
struct w3cs_envelope {
    uint8_t magic[4];
    uint8_t version;
    uint8_t kind;
    uint16_t flags;
    uint32_t session;
    uint32_t sequence;
    uint32_t frame;
    uint16_t fragment_index;
    uint16_t fragment_count;
    uint32_t payload_size;
    uint32_t payload_crc32;
};

struct w3cs_record {
    uint8_t opcode;
    uint8_t flags;
    uint16_t reserved;
    uint32_t payload_size;
};

struct w3cs_create_buffer {
    uint32_t id;
    uint32_t generation;
    uint32_t size;
    uint32_t usage;
    uint32_t format_or_fvf;
    uint32_t pool;
    uint8_t kind;
};

struct w3cs_update_buffer {
    uint32_t id;
    uint32_t generation;
    uint32_t offset;
    uint32_t size;
};

struct w3cs_create_texture {
    uint32_t id;
    uint32_t generation;
    uint32_t width;
    uint32_t height;
    uint32_t levels;
    uint32_t usage;
    uint32_t format;
    uint32_t pool;
};

struct w3cs_update_texture {
    uint32_t id;
    uint32_t generation;
    uint32_t level;
    uint32_t x;
    uint32_t y;
    uint32_t width;
    uint32_t height;
    uint32_t pitch;
    uint32_t format;
    uint32_t size;
};

struct w3cs_update_texture_blob {
    struct w3cs_update_texture texture;
    uint32_t blob_id;
};

struct w3cs_set_cursor {
    uint32_t hot_x;
    uint32_t hot_y;
    uint32_t width;
    uint32_t height;
    uint32_t pitch;
    uint32_t format;
    uint32_t size;
};

struct w3cs_define_blob {
    uint32_t id;
    uint32_t size;
    uint64_t hash_a;
    uint64_t hash_b;
};

struct w3cs_define_blob_delta {
    struct w3cs_define_blob blob;
    uint32_t base_id;
};

struct w3cs_define_blob_float16_delta {
    struct w3cs_define_blob_delta delta;
    uint32_t stride;
    uint32_t fvf;
};
#pragma pack(pop)

#endif
