#pragma once

#include "pxl8_atlas.h"
#include "pxl8_colormap.h"
#include "pxl8_gfx.h"
#include "pxl8_gfx3d.h"
#include "pxl8_lightmap.h"
#include "pxl8_math.h"
#include "pxl8_mesh.h"
#include "pxl8_palette.h"
#include "pxl8_types.h"

#ifdef __cplusplus
extern "C" {
#endif

typedef struct pxl8_cpu_backend pxl8_cpu_backend;
typedef struct pxl8_cpu_render_target pxl8_cpu_render_target;

typedef struct pxl8_cpu_render_target_desc {
    u32 width;
    u32 height;
    bool with_depth;
    bool with_lighting;
} pxl8_cpu_render_target_desc;

pxl8_cpu_backend* pxl8_cpu_create(u32 width, u32 height);
void pxl8_cpu_destroy(pxl8_cpu_backend* cpu);

void pxl8_cpu_begin_frame(pxl8_cpu_backend* cpu, const pxl8_3d_frame* frame);
void pxl8_cpu_end_frame(pxl8_cpu_backend* cpu);

void pxl8_cpu_clear(pxl8_cpu_backend* cpu, u8 color);
void pxl8_cpu_clear_depth(pxl8_cpu_backend* cpu);

void pxl8_cpu_set_colormap(pxl8_cpu_backend* cpu, const pxl8_colormap* cm);
void pxl8_cpu_set_palette(pxl8_cpu_backend* cpu, const u32* palette);
void pxl8_cpu_set_palette_cube(pxl8_cpu_backend* cpu, const pxl8_palette_cube* cube);

u32 pxl8_cpu_add_lightmap(pxl8_cpu_backend* cpu, pxl8_lightmap* lm);
pxl8_lightmap* pxl8_cpu_get_lightmap(pxl8_cpu_backend* cpu, u32 id);

void pxl8_cpu_draw_pixel(pxl8_cpu_backend* cpu, i32 x, i32 y, u8 color);
u8 pxl8_cpu_get_pixel(pxl8_cpu_backend* cpu, i32 x, i32 y);
void pxl8_cpu_draw_line_2d(pxl8_cpu_backend* cpu, i32 x0, i32 y0, i32 x1, i32 y1, u8 color);
void pxl8_cpu_draw_rect(pxl8_cpu_backend* cpu, i32 x, i32 y, i32 w, i32 h, u8 color);
void pxl8_cpu_draw_rect_fill(pxl8_cpu_backend* cpu, i32 x, i32 y, i32 w, i32 h, u8 color);
void pxl8_cpu_draw_circle(pxl8_cpu_backend* cpu, i32 cx, i32 cy, i32 radius, u8 color);
void pxl8_cpu_draw_circle_fill(pxl8_cpu_backend* cpu, i32 cx, i32 cy, i32 radius, u8 color);
void pxl8_cpu_draw_line_3d(pxl8_cpu_backend* cpu, pxl8_vec3 v0, pxl8_vec3 v1, u8 color);

void pxl8_cpu_draw_mesh(
    pxl8_cpu_backend* cpu,
    const pxl8_mesh* mesh,
    const pxl8_mat4* model,
    const pxl8_gfx_material* material,
    const pxl8_atlas* textures
);

void pxl8_cpu_draw_mesh_wireframe(
    pxl8_cpu_backend* cpu,
    const pxl8_mesh* mesh,
    pxl8_mat4 model,
    u8 color
);

u8* pxl8_cpu_get_framebuffer(pxl8_cpu_backend* cpu);
u32* pxl8_cpu_get_output(pxl8_cpu_backend* cpu);
u32 pxl8_cpu_get_height(const pxl8_cpu_backend* cpu);
u32 pxl8_cpu_get_width(const pxl8_cpu_backend* cpu);

void pxl8_cpu_render_glows(
    pxl8_cpu_backend* cpu,
    const pxl8_glow_source* glows,
    u32 glow_count
);

void pxl8_cpu_resolve(pxl8_cpu_backend* cpu);

pxl8_cpu_render_target* pxl8_cpu_create_render_target(const pxl8_cpu_render_target_desc* desc);
void pxl8_cpu_destroy_render_target(pxl8_cpu_render_target* target);

pxl8_cpu_render_target* pxl8_cpu_get_target(pxl8_cpu_backend* cpu);
void pxl8_cpu_set_target(pxl8_cpu_backend* cpu, pxl8_cpu_render_target* target);

void pxl8_cpu_blit(pxl8_cpu_backend* cpu, pxl8_cpu_render_target* src, i32 x, i32 y, u8 transparent_idx);

bool pxl8_cpu_push_target(pxl8_cpu_backend* cpu);
void pxl8_cpu_pop_target(pxl8_cpu_backend* cpu);
u32 pxl8_cpu_get_target_depth(const pxl8_cpu_backend* cpu);

u8* pxl8_cpu_render_target_get_framebuffer(pxl8_cpu_render_target* target);
u32 pxl8_cpu_render_target_get_height(const pxl8_cpu_render_target* target);
u32 pxl8_cpu_render_target_get_width(const pxl8_cpu_render_target* target);
u32* pxl8_cpu_render_target_get_light_accum(pxl8_cpu_render_target* target);

#ifdef __cplusplus
}
#endif
