#pragma once #include "pxl8_math.h" #include "pxl8_types.h" typedef struct demo3d_bsp_edge { u16 vertex[2]; } demo3d_bsp_edge; typedef struct demo3d_bsp_face { u32 first_edge; u32 lightmap_offset; u16 num_edges; u16 plane_id; u16 side; u8 styles[4]; u16 material_id; pxl8_vec3 aabb_min; pxl8_vec3 aabb_max; } demo3d_bsp_face; typedef struct demo3d_bsp_leaf { u8 ambient_level[4]; i32 contents; u16 first_marksurface; i16 maxs[3]; i16 mins[3]; u16 num_marksurfaces; i32 visofs; } demo3d_bsp_leaf; typedef struct demo3d_bsp_model { i32 first_face; i32 headnode[4]; f32 maxs[3]; f32 mins[3]; i32 num_faces; pxl8_vec3 origin; i32 visleafs; } demo3d_bsp_model; typedef struct demo3d_bsp_node { i32 children[2]; u16 first_face; i16 maxs[3]; i16 mins[3]; u16 num_faces; u32 plane_id; } demo3d_bsp_node; typedef struct demo3d_bsp_plane { f32 dist; pxl8_vec3 normal; i32 type; } demo3d_bsp_plane; typedef struct demo3d_bsp_vertex { pxl8_vec3 position; } demo3d_bsp_vertex; typedef struct demo3d_bsp_lightmap { u8 color[3]; u8 height; u32 offset; u8 width; } demo3d_bsp_lightmap; typedef struct demo3d_bsp_lightmap_sample { u8 b; u8 g; u8 r; } demo3d_bsp_lightmap_sample; typedef struct demo3d_bsp_pvs { u8* data; u32 size; } demo3d_bsp_pvs; typedef struct demo3d_bsp_portal { f32 x0, z0; f32 x1, z1; u32 target_leaf; } demo3d_bsp_portal; typedef struct demo3d_bsp_cell_portals { demo3d_bsp_portal portals[4]; u8 num_portals; } demo3d_bsp_cell_portals; typedef struct demo3d_bsp { demo3d_bsp_cell_portals* cell_portals; demo3d_bsp_edge* edges; demo3d_bsp_face* faces; demo3d_bsp_leaf* leafs; u8* lightdata; demo3d_bsp_lightmap* lightmaps; u16* marksurfaces; demo3d_bsp_model* models; demo3d_bsp_node* nodes; demo3d_bsp_plane* planes; i32* surfedges; u32* vertex_lights; demo3d_bsp_vertex* vertices; u8* visdata; f32* heightfield; u32 lightdata_size; u32 num_cell_portals; u32 num_edges; u32 num_faces; u32 num_leafs; u32 num_lightmaps; u32 num_marksurfaces; u32 num_models; u32 num_nodes; u32 num_planes; u32 num_surfedges; u32 num_vertex_lights; u32 num_vertices; u32 num_heightfield; f32 heightfield_ox; f32 heightfield_oz; f32 heightfield_cell_size; u16 heightfield_w; u16 heightfield_h; u32 visdata_size; f32 bounds_min_x; f32 bounds_min_z; f32 bounds_max_x; f32 bounds_max_z; } demo3d_bsp; static inline bool demo3d_bsp_get_edge_vertex(const demo3d_bsp* bsp, i32 surfedge_idx, u32* out_vert_idx) { if (surfedge_idx >= (i32)bsp->num_surfedges) return false; i32 edge_idx = bsp->surfedges[surfedge_idx]; u32 vertex_index; if (edge_idx >= 0) { if ((u32)edge_idx >= bsp->num_edges) return false; vertex_index = 0; } else { edge_idx = -edge_idx; if ((u32)edge_idx >= bsp->num_edges) return false; vertex_index = 1; } *out_vert_idx = bsp->edges[edge_idx].vertex[vertex_index]; return *out_vert_idx < bsp->num_vertices; } static inline u8 demo3d_bsp_vertex_light(const demo3d_bsp* bsp, u32 vert_idx, u8 ambient) { if (!bsp->vertex_lights || vert_idx >= bsp->num_vertex_lights) return 255; u32 packed = bsp->vertex_lights[vert_idx]; u8 direct = (packed >> 24) & 0xFF; u8 ao = (packed >> 16) & 0xFF; f32 combined = (f32)direct + ((f32)ambient / 255.0f) * (f32)ao; return (u8)(combined > 255.0f ? 255.0f : combined); } static inline i32 demo3d_bsp_find_leaf(const demo3d_bsp* bsp, pxl8_vec3 pos) { if (!bsp || bsp->num_nodes == 0) return -1; i32 node_id = 0; while (node_id >= 0) { const demo3d_bsp_node* node = &bsp->nodes[node_id]; const demo3d_bsp_plane* plane = &bsp->planes[node->plane_id]; f32 dist = pxl8_vec3_dot(pos, plane->normal) - plane->dist; node_id = node->children[dist < 0 ? 1 : 0]; } return -(node_id + 1); } #ifdef __cplusplus extern "C" { #endif demo3d_bsp_pvs demo3d_bsp_decompress_pvs(const demo3d_bsp* bsp, i32 leaf); void demo3d_bsp_destroy(demo3d_bsp* bsp); u32 demo3d_bsp_face_count(const demo3d_bsp* bsp); pxl8_vec3 demo3d_bsp_face_normal(const demo3d_bsp* bsp, u32 face_id); void demo3d_bsp_face_set_material(demo3d_bsp* bsp, u32 face_id, u16 material_id); bool demo3d_bsp_is_leaf_visible(const demo3d_bsp* bsp, i32 leaf_from, i32 leaf_to); demo3d_bsp_lightmap demo3d_bsp_lightmap_mapped(u8 width, u8 height, u32 offset); demo3d_bsp_lightmap demo3d_bsp_lightmap_uniform(u8 r, u8 g, u8 b); pxl8_result demo3d_bsp_load(const char* path, demo3d_bsp* bsp); void demo3d_bsp_pvs_destroy(demo3d_bsp_pvs* pvs); bool demo3d_bsp_pvs_is_visible(const demo3d_bsp_pvs* pvs, i32 leaf); u8 demo3d_bsp_light_at(const demo3d_bsp* bsp, f32 x, f32 y, f32 z, u8 ambient); demo3d_bsp_lightmap_sample demo3d_bsp_sample_lightmap(const demo3d_bsp* bsp, u32 face_idx, f32 u, f32 v); #ifdef __cplusplus } #endif