#pragma once

#include "pxl8_gfx.h"
#include "pxl8_math.h"
#include "pxl8_mesh.h"
#include "pxl8_types.h"

typedef struct pxl8_bsp_edge {
    u16 vertex[2];
} pxl8_bsp_edge;

typedef struct pxl8_bsp_face {
    u32 first_edge;
    u32 lightmap_offset;
    u16 num_edges;
    u16 plane_id;
    u16 side;

    u8 styles[4];
    u16 texinfo_id;

    pxl8_vec3 aabb_min;
    pxl8_vec3 aabb_max;
} pxl8_bsp_face;

typedef struct pxl8_bsp_leaf {
    u8 ambient_level[4];
    i32 contents;

    u16 first_marksurface;
    i16 maxs[3];
    i16 mins[3];
    u16 num_marksurfaces;

    i32 visofs;
} pxl8_bsp_leaf;

typedef struct pxl8_bsp_model {
    i32 first_face;
    i32 headnode[4];
    f32 maxs[3];
    f32 mins[3];
    i32 num_faces;

    pxl8_vec3 origin;
    i32 visleafs;
} pxl8_bsp_model;

typedef struct pxl8_bsp_node {
    i32 children[2];

    u16 first_face;
    i16 maxs[3];
    i16 mins[3];
    u16 num_faces;

    u32 plane_id;
} pxl8_bsp_node;

typedef struct pxl8_bsp_plane {
    f32 dist;
    pxl8_vec3 normal;
    i32 type;
} pxl8_bsp_plane;

typedef struct pxl8_bsp_texinfo {
    u32 miptex;
    char name[16];

    f32 u_offset;
    pxl8_vec3 u_axis;

    f32 v_offset;
    pxl8_vec3 v_axis;
} pxl8_bsp_texinfo;

typedef struct pxl8_bsp_vertex {
    pxl8_vec3 position;
} pxl8_bsp_vertex;

typedef struct pxl8_bsp_lightmap {
    u8 color[3];
    u8 height;
    u32 offset;
    u8 width;
} pxl8_bsp_lightmap;

typedef struct pxl8_bsp_lightmap_sample {
    u8 b;
    u8 g;
    u8 r;
} pxl8_bsp_lightmap_sample;

typedef struct pxl8_bsp_material_batch {
    u16* face_indices;
    u32 face_count;
    u8 material_id;
    pxl8_mesh* mesh;
} pxl8_bsp_material_batch;

typedef struct pxl8_bsp_pvs {
    u8* data;
    u32 size;
} pxl8_bsp_pvs;

typedef struct pxl8_bsp {
    pxl8_bsp_edge* edges;
    pxl8_bsp_face* faces;
    pxl8_bsp_leaf* leafs;
    u8* lightdata;
    pxl8_bsp_lightmap* lightmaps;
    u16* marksurfaces;
    pxl8_bsp_material_batch* material_batches;
    pxl8_bsp_model* models;
    pxl8_bsp_node* nodes;
    pxl8_bsp_plane* planes;
    i32* surfedges;
    pxl8_bsp_texinfo* texinfo;
    u32* vertex_lights;
    pxl8_bsp_vertex* vertices;
    u8* visdata;

    u32 lightdata_size;
    u32 num_edges;
    u32 num_faces;
    u32 num_leafs;
    u32 num_lightmaps;
    u32 num_marksurfaces;
    u32 num_material_batches;
    u32 num_models;
    u32 num_nodes;
    u32 num_planes;
    u32 num_surfedges;
    u32 num_texinfo;
    u32 num_vertex_lights;
    u32 num_vertices;
    u32 visdata_size;
} pxl8_bsp;

#ifdef __cplusplus
extern "C" {
#endif

pxl8_result pxl8_bsp_load(const char* path, pxl8_bsp* bsp);
void pxl8_bsp_destroy(pxl8_bsp* bsp);

i32 pxl8_bsp_find_leaf(const pxl8_bsp* bsp, pxl8_vec3 pos);
bool pxl8_bsp_is_leaf_visible(const pxl8_bsp* bsp, i32 leaf_from, i32 leaf_to);

pxl8_bsp_pvs pxl8_bsp_decompress_pvs(const pxl8_bsp* bsp, i32 leaf);
void pxl8_bsp_pvs_destroy(pxl8_bsp_pvs* pvs);
bool pxl8_bsp_pvs_is_visible(const pxl8_bsp_pvs* pvs, i32 leaf);

pxl8_bsp_lightmap pxl8_bsp_lightmap_uniform(u8 r, u8 g, u8 b);
pxl8_bsp_lightmap pxl8_bsp_lightmap_mapped(u8 width, u8 height, u32 offset);
pxl8_bsp_lightmap_sample pxl8_bsp_sample_lightmap(const pxl8_bsp* bsp, u32 face_idx, f32 u, f32 v);

void pxl8_bsp_render_face(pxl8_gfx* gfx, const pxl8_bsp* bsp, u32 face_id, u32 texture_id);
void pxl8_bsp_render_textured(pxl8_gfx* gfx, const pxl8_bsp* bsp, pxl8_vec3 camera_pos);
void pxl8_bsp_render_wireframe(pxl8_gfx* gfx, const pxl8_bsp* bsp, pxl8_vec3 camera_pos, u32 color);

#ifdef __cplusplus
}
#endif
