#ifndef QUICKMAKE_PLATFORM_H
#define QUICKMAKE_PLATFORM_H

#define assert(expression) if (!(expression)) { *(int *)0 = 0; }

// TODO(ebuchholz): figure out how to organize includes a little better
#include "quickmake_math.h"

#define CONSOLE_COLOR_WHITE 0x000f
#define CONSOLE_COLOR_RED (0x0004 | 0x0008)
#define CONSOLE_COLOR_GREEN (0x0002 | 0x0008)
#define CONSOLE_COLOR_BLUE (0x0001 | 0x0008)
#define CONSOLE_COLOR_YELLOW (0x0004 | 0x0002 | 0x0008)
#define CONSOLE_COLOR_CYAN (0x0002 | 0x0001 | 0x0008)
#define CONSOLE_COLOR_MAGENTA (0x0004 | 0x0001 | 0x0008)

struct memory_arena {
    void *base;
    unsigned int size;
    unsigned int capacity;
};

// asset loading
enum asset_type {
    ASSET_TYPE_OBJ,
    ASSET_TYPE_BMP,
    ASSET_TYPE_ATLAS_TEXTURE,
    ASSET_TYPE_ATLAS_DATA,
    ASSET_TYPE_ANIMATION_DATA,
    ASSET_TYPE_QMM,
    ASSET_TYPE_WAV,
    ASSET_TYPE_MIDI,
    ASSET_TYPE_DATA
};

struct asset_pack_data {
    void *assetData;
    int numFiles;
    int currentIndex;

    void *cursor;
    asset_type lastAssetType;
    bool needPlatformLoad;
    bool complete;
};

// Makes it easier to wrap up in WebIDL
// NOTE(ebuchholz): emscripten+idl can't handle pointers to primitives, so these have to be void
// pointers
struct float_mesh_attribute {
    void *values;
    int count;
};

struct int_mesh_attribute {
    void *values;
    int count;
};

struct loaded_mesh_asset {
    unsigned int id;
    float_mesh_attribute positions;
    float_mesh_attribute texCoords;
    float_mesh_attribute normals;
    int_mesh_attribute indices;
};

struct loaded_animated_mesh_asset {
    int key;
    float_mesh_attribute positions;
    float_mesh_attribute texCoords;
    float_mesh_attribute normals;
    // TODO(ebuchholz): multiple bone indices per vertex + weights
    float_mesh_attribute boneIndices;
    float_mesh_attribute boneWeights;
    int_mesh_attribute indices;
};

struct loaded_texture_asset {
    unsigned int id;
    int width;
    int height;
    void *pixels; // unsigned int, but void for compatibility with webidl
};

// same as texture asset, combine?
struct loaded_atlas_asset {
    int key;
    int width;
    int height;
    void *pixels; // unsigned int, but void for compatibility with webidl
};

enum render_command_type {
    RENDER_COMMAND_MODEL,
    RENDER_COMMAND_GENERATE_MESH,
    RENDER_COMMAND_DYNAMIC_MODEL,
    RENDER_COMMAND_ANIMATED_MODEL,
    RENDER_COMMAND_LINES,
    RENDER_COMMAND_SPRITE,
    RENDER_COMMAND_SPRITE_LIST,
    RENDER_COMMAND_SET_CAMERA,
    RENDER_COMMAND_BACKGROUND_VISUALIZATION
};

struct render_command_header{
    render_command_type type;
};

struct render_command_model {
    unsigned int meshID;
    unsigned int textureID;
    matrix4x4 modelMatrix;
};

struct render_command_dynamic_model {
    unsigned int meshID;
    unsigned int textureID;
    matrix4x4 modelMatrix;
};

// TODO(ebuchholz): bone matrices
struct render_command_animated_model {
    matrix4x4 modelMatrix;
    matrix4x4 *boneMatrices;
    int animatedMeshKey;
    unsigned int textureID;
    int numBones;
};

// TODO(ebuchholz): merge with loaded_mesh_asset?
struct render_command_generate_mesh {
    unsigned int id;
    float_mesh_attribute positions;
    float_mesh_attribute texCoords;
    float_mesh_attribute normals;
    int_mesh_attribute indices;
};

struct render_command_lines {
    line *lines;
    int numLines;
};

struct render_command_sprite {
    unsigned int textureID;
    float x;
    float y;
    float width;
    float height;
};

struct render_sprite {
    vector2 pos[4];
    vector2 texCoord[4];
    vector4 color[4];
    unsigned int textureID;
};

struct render_command_sprite_list {
    render_sprite *sprites;
    int numSprites;
};

struct render_command_set_camera {
    matrix4x4 viewMatrix;
    matrix4x4 projMatrix;
};

struct render_command_background_visualization {
    float t;
};

struct render_command_list {
    int windowWidth;
    int windowHeight;
    memory_arena memory;
};

struct input_key {
    bool down;
    bool justPressed;
};

// based on xbox 360 controller/xinput
struct game_controller_input {
    bool connected;

    input_key dPadUp;
    input_key dPadDown;
    input_key dPadLeft;
    input_key dPadRight;

    input_key start;
    input_key back;

    input_key leftStick;
    input_key rightStick;

    input_key leftBumper;
    input_key rightBumper;

    input_key aButton;
    input_key bButton;
    input_key xButton;
    input_key yButton;

    float leftTrigger;
    input_key leftTriggerButton;
    float rightTrigger;
    input_key rightTriggerButton;

    float leftStickX;
    float leftStickY;
    float rightStickX;
    float rightStickY;

    input_key leftStickUp;
    input_key leftStickDown;
    input_key leftStickLeft;
    input_key leftStickRight;

    input_key rightStickUp;
    input_key rightStickDown;
    input_key rightStickLeft;
    input_key rightStickRight;
};

struct game_input {
    input_key upKey;
    input_key downKey;
    input_key leftKey;
    input_key rightKey;

    input_key actionKey;
    input_key enterKey;

    bool backspaceDown;

    char typedText[10];
    int numTypedChars;

    game_controller_input controllers[4];

    bool pointerDown;
    bool pointerJustDown;
    int pointerX;
    int pointerY;

    bool pointer2Down;
    bool pointer2JustDown;
    int pointer2X;
    int pointer2Y;
};

struct sound_sample {
    float value;
};

struct platform_options {
    int audioSampleRate;
};

struct platform_triggers {
    bool triggerFileWindow;
    bool triggerFileSave;
    void *fileToSaveData;
    unsigned int fileToSaveSize;
};

struct game_sound_output {
    int samplesPerSecond;
    int sampleCount;
    sound_sample *samples;
};

struct game_window {
    int width;
    int height;
    char *buffer;
    char *colors;
};

struct game_memory {
    void *memory;
    unsigned int memoryCapacity;
    void *tempMemory;
    unsigned int tempMemoryCapacity;
};

#endif
