#ifndef RENDER_D3D11_H
#define RENDER_D3D11_H

#define COBJMACROS
#include <d3d11.h>
#include <dxgi1_3.h>
#include <d3dcompiler.h>
#include <dxgidebug.h>

#pragma comment(lib, "user32")
#pragma comment(lib, "dxguid")
#pragma comment(lib, "dxgi")
#pragma comment(lib, "d3d11")
#pragma comment(lib, "d3dcompiler")

/////////////////////////////////
//~ Metadata types. Ryan uses metadesk to generate tables, but I hardcode it for now. 
// TODO(anton): Use metaprogramming to generate what is necessary here.

typedef struct R_D3D11_CmdGlobalKindInfo R_D3D11_CmdGlobalKindInfo;
struct R_D3D11_CmdGlobalKindInfo 
{
  U64 size;
};

typedef enum R_D3D11_CmdGlobalKind
{
  R_D3D11_CmdGlobalKind_Nil,
  R_D3D11_CmdGlobalKind_Rect2D,
  R_D3D11_CmdGlobalKind_Grid,
  R_D3D11_CmdGlobalKind_COUNT
}
R_D3D11_CmdGlobalKind;

typedef struct R_D3D11_ShaderPairKindInfo R_D3D11_ShaderPairKindInfo;
struct R_D3D11_ShaderPairKindInfo
{
  String8 name;
  String8 shader_blob; //String8 shader_blob;
  D3D11_INPUT_ELEMENT_DESC *element_description;
  U64 element_description_count;
};

typedef enum R_D3D11_ShaderPairKind
{
  R_D3D11_ShaderPairKind_Nil,
  R_D3D11_ShaderPairKind_Rect2D,
  R_D3D11_ShaderPairKind_Grid,
  R_D3D11_ShaderPairKind_COUNT
}
R_D3D11_ShaderPairKind;


/////////////////////////////////
//~ Pipeline data types
typedef struct R_D3D11_CmdGlobals_Rect2D R_D3D11_CmdGlobals_Rect2D;
struct R_D3D11_CmdGlobals_Rect2D 
{
  Vec2_F32 viewport_size;
  Vec2_F32 albedo_t2d_size;
  Vec3_F32 transform[3];
  Vec2_F32 _16byte_padding0_;
};



/////////////////////////////////
//~ Resource types

typedef struct R_D3D11_Tex2D R_D3D11_Tex2D;
struct R_D3D11_Tex2D
{
  ID3D11Texture2D *texture;
  ID3D11ShaderResourceView *view;
  Vec2_S32 size;
  R_Tex2DFormat format;
  R_Tex2DKind kind;
};

typedef struct R_D3D11_Buffer R_D3D11_Buffer;
struct R_D3D11_Buffer
{
  ID3D11Buffer *obj;
  U64 size;
};

/////////////////////////////////
//~ Main state bundle
typedef struct R_D3D11_State R_D3D11_State;
struct R_D3D11_State
{
  Arena *arena;

  //- Base d3d11 objects
  ID3D11Device *base_device;
  ID3D11DeviceContext *base_device_context;
  IDXGIDevice *dxgi_device;
  IDXGIAdapter *dxgi_adapter;
  IDXGIFactory2 *dxgi_factory2;
  ID3D11RasterizerState *rasterizer_state;
  ID3D11BlendState *main_blend_state;
  ID3D11DepthStencilState *depth_stencil_state;
  ID3D11SamplerState *nearest_sampler;
  ID3D11SamplerState *linear_sampler;

  //- Global buffers
  // NOTE(anton): We have an extra space for the nil buffer, which is how it will work with nil structs etc.
  // That's "wasting" a bit of space, but with huge benefits in terms of codepaths and error handling.
  // Nil is a valid state that does nothing.
  ID3D11Buffer *cmd_global_buffer_table[R_D3D11_CmdGlobalKind_COUNT];

  //- Shader tables
  ID3D11InputLayout *input_layout_table[R_D3D11_ShaderPairKind_COUNT];
  ID3D11VertexShader *vs_table[R_D3D11_ShaderPairKind_COUNT];
  ID3D11PixelShader *ps_table[R_D3D11_ShaderPairKind_COUNT];
  
  // Scratch buffers
  ID3D11Buffer *scratch_buffer_64kb;
  ID3D11Buffer *scratch_buffer_8mb;
};

typedef struct R_D3D11_WindowEquip R_D3D11_WindowEquip;
struct R_D3D11_WindowEquip 
{
  IDXGISwapChain1 *swapchain;
  ID3D11Texture2D *framebuffer;
  ID3D11RenderTargetView *framebuffer_rtv;

  Vec2_S64 last_resolution;
};

/////////////////////////////////
//~ D3D11 Functions
r_function R_Handle R_D3D11_handle_from_window_equip(R_D3D11_WindowEquip *equip);
r_function R_D3D11_WindowEquip *R_D3D11_window_equip_from_handle(R_Handle handle);
r_function R_Handle R_D3D11_handle_from_tex2d(R_D3D11_Tex2D texture);
#endif /* RENDER_D3D11_H */
