#pragma once

#define RGFW_IMPLEMENTATION
#include "../external/rgfw/RGFW.h"

#include "assets.h"

constexpr u64 FRAME_OVERLAP = 2;

typedef enum Pipeline_e
{
	PIPELINE_PBR,
	//PIPELINE_GUI,
	PIPELINE_MAX,
} Pipeline;

typedef enum PBRPropType_e
{
	PPT_NONE = 0x0000,
	PPT_ALBEDO_VALUE = 0x0001,
	PPT_AMBIENT_VALUE = 0x0002,
	PPT_SPECULAR_VALUE = 0x0004,
	PPT_ALBEDO_TEX = 0x0008,
	PPT_AMBIENT_TEX = 0x0010,
	PPT_SPECULAR_TEX = 0x0020,
} PBRPropType;

typedef struct PipelineCreateInfo
{
	char *vertex_shader;
	char *fragment_shader;
} PipelineCreateInfo;

typedef unsigned int VertexBuffer;
typedef unsigned int IndexBuffer;
typedef unsigned int PipelineHandle;
typedef unsigned int ShaderHandle;
typedef unsigned int VertexArray;
typedef unsigned int UBO;

typedef struct rIndexedBuffer
{
	i64 icount, ioffset;
	u32 vao, buffer;
} rIndexedBuffer;

typedef struct rMesh
{
	apMatProps 	  values;
	apMatTextures textures;
	uintptr				idx_offset;
	u64						length;
	u32 					type;
} rMesh;

ArrayType(rMesh);

typedef struct rModel
{
	rIndexedBuffer buffer;
	rMeshArray meshes;
	u32Array   textures;
} rModel;

typedef struct Renderer
{
	RGFW_window 	 *window;
	PipelineHandle pipelines[PIPELINE_MAX];
	rModel 				 models[MODEL_ASSET_MAX];
	u32						 mat_buf;
	Arena 				 *perm_arena;
	Arena					 *frame_arenas[FRAME_OVERLAP];
} Renderer;

// ::Init::Decl::

static b32 Init(Renderer *renderer);
static void InitModels(Renderer *renderer);
static PipelineHandle CreatePipeline();
static VertexBuffer CreateVertexBuffer();
static IndexBuffer CreateIndexBuffer();
static VertexArray CreateVertexArray();
static ShaderHandle CreateShader(int type);
static PipelineHandle BuildPipeline(PipelineCreateInfo *create_info);
static UBO CreateUBO(rawptr data, u32 size);
static b32 BuildShader(ShaderHandle *handle,  char *asset);

// ::Draw::Decl::

static void DrawIndexedBuffer(rIndexedBuffer *buffer);
static void rDrawModel(Renderer *renderer, rModel *model);

// ::Buffers::Decl::

static rIndexedBuffer rLoadModel(char *asset);
static rIndexedBuffer CreateIndexedBuffer(rawptr vert_data, u32 vcount, rawptr idx_data, u32 icount);
static void SetVertexAttrib(u32 vao, u32 idx, u32 count, i32 type, b32 normalized, u32 offset);
static u32 rCreateBuffer(rawptr data, u32 size);

// ::Textures::Decl::

static u32 CreateTexture(rawptr data, u32 width, u32 height, u32 channels);

// ::Draw::Decl::

static void DrawMeshBuffer(rIndexedBuffer *mesh);

// ::Debug::Decl::

void DebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, GLchar const* message, void const* user_param);

