#ifndef TWN_DEFERRED_COMMANDS_H
#define TWN_DEFERRED_COMMANDS_H

#include "twn_types.h"
#include "twn_gpu_texture_c.h"
#include "twn_textures_c.h"

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


typedef enum {
    PIPELINE_NO,
    PIPELINE_SPACE,
    PIPELINE_2D,
} Pipeline;


typedef struct {
    size_t offset;
    uint32_t type;
    uint32_t stride;
    uint32_t buffer;
    uint8_t arity; /* leave at 0 to signal pointer as unused */
} AttributeArrayPointer;


/* allows us to have generic way to issue draws as well as */
/* deferring new draw calls while previous frame is still being drawn */
typedef struct {
    AttributeArrayPointer vertices;
    AttributeArrayPointer texcoords;

    bool constant_colored;
    union {
        AttributeArrayPointer colors;        
        Color color;
    };

    bool textured, texture_repeat, uses_gpu_key;
    TextureKey texture_key;
    GPUTexture gpu_texture;

    uint32_t element_buffer;
    uint32_t element_count;
    uint32_t range_start, range_end;

    /* could be either `element_count` with supplied `element_buffer`, or this, but not both */
    uint32_t primitive_count;

    double depth_range_low, depth_range_high;
} DeferredCommandDraw;


typedef struct {
    char *paths;
} DeferredCommandDrawSkybox;


typedef struct {
    Color color;
    bool clear_color;
    bool clear_depth;
    bool clear_stencil;
} DeferredCommandClear;


typedef struct {
    Pipeline pipeline;
} DeferredCommandUsePipeline;


typedef struct {
    TextureMode mode;
} DeferredCommandUseTextureMode;


typedef struct {
    double low, high;
} DeferredCommandDepthRange;


typedef struct {
    float start, end, density;
    Color color;
} DeferredCommandApplyFog;


typedef struct {
    enum DeferredCommandType {
        DEFERRED_COMMAND_TYPE_DRAW,
        DEFERRED_COMMAND_TYPE_DRAW_SKYBOX,
        DEFERRED_COMMAND_TYPE_CLEAR,
        DEFERRED_COMMAND_TYPE_USE_PIPIELINE,
        DEFERRED_COMMAND_TYPE_USE_TEXTURE_MODE,
        DEFERRED_COMMAND_TYPE_DEPTH_RANGE,
        DEFERRED_COMMAND_TYPE_APPLY_FOG,
        DEFERRED_COMMAND_TYPE_POP_FOG,
    } type;

    union {
        DeferredCommandDraw draw;
        DeferredCommandDrawSkybox draw_skybox;
        DeferredCommandClear clear;
        DeferredCommandUsePipeline use_pipeline;
        DeferredCommandUseTextureMode use_texture_mode;
        DeferredCommandDepthRange depth_range;
        DeferredCommandApplyFog apply_fog;
    };
} DeferredCommand;


extern DeferredCommand *deferred_commands;

#endif
