in-progress map things...
This commit is contained in:
parent
cfe7501fe2
commit
3c54e379d4
10 changed files with 753 additions and 14 deletions
|
|
@ -1,4 +1,5 @@
|
||||||
(local pxl8 (require :pxl8))
|
(local pxl8 (require :pxl8))
|
||||||
|
(local bsp_world (require :mod.bsp_world))
|
||||||
(local cube3d (require :mod.cube3d))
|
(local cube3d (require :mod.cube3d))
|
||||||
|
|
||||||
(var time 0)
|
(var time 0)
|
||||||
|
|
@ -16,11 +17,13 @@
|
||||||
(var logo-sprite nil)
|
(var logo-sprite nil)
|
||||||
|
|
||||||
(global init (fn []
|
(global init (fn []
|
||||||
|
(bsp_world.init)
|
||||||
(pxl8.load_palette "res/sprites/pxl8_logo.ase")
|
(pxl8.load_palette "res/sprites/pxl8_logo.ase")
|
||||||
(set logo-sprite (pxl8.load_sprite "res/sprites/pxl8_logo.ase"))
|
(set logo-sprite (pxl8.load_sprite "res/sprites/pxl8_logo.ase"))
|
||||||
(set particles (pxl8.particles_new 1000))))
|
(set particles (pxl8.particles_new 1000))))
|
||||||
|
|
||||||
(global update (fn [dt]
|
(global update (fn [dt]
|
||||||
|
(bsp_world.update dt)
|
||||||
(set time (+ time dt))
|
(set time (+ time dt))
|
||||||
|
|
||||||
(when (pxl8.key_pressed "1")
|
(when (pxl8.key_pressed "1")
|
||||||
|
|
@ -46,6 +49,8 @@
|
||||||
(set use-nes-palette (not use-nes-palette))
|
(set use-nes-palette (not use-nes-palette))
|
||||||
(local palette-path (if use-nes-palette "res/palettes/nes.ase" "res/sprites/pxl8_logo.ase"))
|
(local palette-path (if use-nes-palette "res/palettes/nes.ase" "res/sprites/pxl8_logo.ase"))
|
||||||
(pxl8.load_palette palette-path))
|
(pxl8.load_palette palette-path))
|
||||||
|
(when (pxl8.key_pressed "0")
|
||||||
|
(set current-effect 0))
|
||||||
|
|
||||||
(case current-effect
|
(case current-effect
|
||||||
1 (do
|
1 (do
|
||||||
|
|
@ -63,6 +68,8 @@
|
||||||
|
|
||||||
(global frame (fn []
|
(global frame (fn []
|
||||||
(case current-effect
|
(case current-effect
|
||||||
|
0 (bsp_world.frame)
|
||||||
|
|
||||||
1 (do
|
1 (do
|
||||||
(pxl8.clr 0)
|
(pxl8.clr 0)
|
||||||
(when logo-sprite
|
(when logo-sprite
|
||||||
|
|
|
||||||
53
demo/mod/bsp_world.fnl
Normal file
53
demo/mod/bsp_world.fnl
Normal file
|
|
@ -0,0 +1,53 @@
|
||||||
|
(local pxl8 (require :pxl8))
|
||||||
|
|
||||||
|
(var camera-angle 0)
|
||||||
|
(local camera-height 0)
|
||||||
|
(local camera-distance 300)
|
||||||
|
(var fps 0)
|
||||||
|
(var world nil)
|
||||||
|
|
||||||
|
(fn init []
|
||||||
|
(set world (pxl8.world_new))
|
||||||
|
(let [result (pxl8.world_load world "res/maps/test.bsp")]
|
||||||
|
(if (< result 0)
|
||||||
|
(pxl8.error (.. "Failed to load test.bsp - result: " result))
|
||||||
|
(pxl8.info "Loaded world successfully!"))))
|
||||||
|
|
||||||
|
(fn update [dt]
|
||||||
|
(when (> dt 0)
|
||||||
|
(set fps (math.floor (/ 1.0 dt))))
|
||||||
|
(when (pxl8.world_is_loaded world)
|
||||||
|
(set camera-angle (+ camera-angle (* dt 0.5)))))
|
||||||
|
|
||||||
|
(fn frame []
|
||||||
|
(pxl8.clr 0)
|
||||||
|
(pxl8.text (.. "FPS: " fps) 10 40 14)
|
||||||
|
|
||||||
|
(if (pxl8.world_is_loaded world)
|
||||||
|
(let [cam-x (* camera-distance (math.cos camera-angle))
|
||||||
|
cam-z (* camera-distance (math.sin camera-angle))]
|
||||||
|
|
||||||
|
(pxl8.text (.. "Camera: " (string.format "%.0f" cam-x) ","
|
||||||
|
(string.format "%.0f" camera-height) ","
|
||||||
|
(string.format "%.0f" cam-z)) 10 55 12)
|
||||||
|
|
||||||
|
(pxl8.clear_zbuffer)
|
||||||
|
(pxl8.set_backface_culling true)
|
||||||
|
(pxl8.set_wireframe true)
|
||||||
|
|
||||||
|
(let [aspect (/ (pxl8.get_width) (pxl8.get_height))
|
||||||
|
fov 1.047]
|
||||||
|
(pxl8.set_projection (pxl8.mat4_perspective fov aspect 1.0 4096.0)))
|
||||||
|
|
||||||
|
(pxl8.set_view (pxl8.mat4_lookat
|
||||||
|
[cam-x camera-height cam-z]
|
||||||
|
[0 0 0]
|
||||||
|
[0 1 0]))
|
||||||
|
|
||||||
|
(pxl8.set_model (pxl8.mat4_identity))
|
||||||
|
|
||||||
|
(pxl8.world_render world [cam-x camera-height cam-z]))))
|
||||||
|
|
||||||
|
{:init init
|
||||||
|
:update update
|
||||||
|
:frame frame}
|
||||||
|
|
@ -20,7 +20,6 @@
|
||||||
(var cam-pitch -0.2)
|
(var cam-pitch -0.2)
|
||||||
(var show-debug-ui false)
|
(var show-debug-ui false)
|
||||||
(var fps 0)
|
(var fps 0)
|
||||||
(var fps-timer 0)
|
|
||||||
(var fps-accumulator 0)
|
(var fps-accumulator 0)
|
||||||
(var fps-frame-count 0)
|
(var fps-frame-count 0)
|
||||||
|
|
||||||
|
|
@ -174,7 +173,7 @@
|
||||||
(pxl8.set_projection (pxl8.mat4_perspective fov aspect 0.1 100.0))))
|
(pxl8.set_projection (pxl8.mat4_perspective fov aspect 0.1 100.0))))
|
||||||
|
|
||||||
(let [target-x (* (math.sin cam-yaw) (math.cos cam-pitch))
|
(let [target-x (* (math.sin cam-yaw) (math.cos cam-pitch))
|
||||||
target-y (* (math.sin cam-pitch))
|
target-y (math.sin cam-pitch)
|
||||||
target-z (* (- (math.cos cam-yaw)) (math.cos cam-pitch))
|
target-z (* (- (math.cos cam-yaw)) (math.cos cam-pitch))
|
||||||
look-x (+ cam-x target-x)
|
look-x (+ cam-x target-x)
|
||||||
look-y (+ cam-y target-y)
|
look-y (+ cam-y target-y)
|
||||||
|
|
@ -229,5 +228,5 @@
|
||||||
(when use-texture (init-texture)))
|
(when use-texture (init-texture)))
|
||||||
(when (not= new-state.affine nil) (set affine new-state.affine))))
|
(when (not= new-state.affine nil) (set affine new-state.affine))))
|
||||||
|
|
||||||
{: update
|
{:update update
|
||||||
: frame}
|
:frame frame}
|
||||||
|
|
|
||||||
2
pxl8.sh
2
pxl8.sh
|
|
@ -384,6 +384,7 @@ case "$COMMAND" in
|
||||||
src/pxl8.c
|
src/pxl8.c
|
||||||
src/pxl8_ase.c
|
src/pxl8_ase.c
|
||||||
src/pxl8_blit.c
|
src/pxl8_blit.c
|
||||||
|
src/pxl8_bsp.c
|
||||||
src/pxl8_cart.c
|
src/pxl8_cart.c
|
||||||
src/pxl8_font.c
|
src/pxl8_font.c
|
||||||
src/pxl8_gfx.c
|
src/pxl8_gfx.c
|
||||||
|
|
@ -394,6 +395,7 @@ case "$COMMAND" in
|
||||||
src/pxl8_tilesheet.c
|
src/pxl8_tilesheet.c
|
||||||
src/pxl8_ui.c
|
src/pxl8_ui.c
|
||||||
src/pxl8_vfx.c
|
src/pxl8_vfx.c
|
||||||
|
src/pxl8_world.c
|
||||||
"
|
"
|
||||||
|
|
||||||
LUAJIT_LIB="lib/luajit/src/libluajit.a"
|
LUAJIT_LIB="lib/luajit/src/libluajit.a"
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,6 @@ local gfx = _pxl8_gfx
|
||||||
local input = _pxl8_input
|
local input = _pxl8_input
|
||||||
local ui = _pxl8_ui
|
local ui = _pxl8_ui
|
||||||
|
|
||||||
-- pxl8 lua api
|
|
||||||
--
|
|
||||||
local pxl8 = {}
|
local pxl8 = {}
|
||||||
|
|
||||||
function pxl8.clr(color)
|
function pxl8.clr(color)
|
||||||
|
|
@ -86,7 +84,6 @@ function pxl8.upload_atlas()
|
||||||
C.pxl8_gfx_upload_atlas(gfx)
|
C.pxl8_gfx_upload_atlas(gfx)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- log
|
|
||||||
function pxl8.info(msg)
|
function pxl8.info(msg)
|
||||||
C.pxl8_lua_info(msg)
|
C.pxl8_lua_info(msg)
|
||||||
end
|
end
|
||||||
|
|
@ -419,4 +416,29 @@ function pxl8.ui_window_set_open(title, open)
|
||||||
C.pxl8_ui_window_set_open(ui, title, open)
|
C.pxl8_ui_window_set_open(ui, title, open)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function pxl8.world_new()
|
||||||
|
return C.pxl8_world_create()
|
||||||
|
end
|
||||||
|
|
||||||
|
function pxl8.world_destroy(world)
|
||||||
|
C.pxl8_world_destroy(world)
|
||||||
|
end
|
||||||
|
|
||||||
|
function pxl8.world_load(world, filepath)
|
||||||
|
return C.pxl8_world_load(world, filepath)
|
||||||
|
end
|
||||||
|
|
||||||
|
function pxl8.world_render(world, camera_pos)
|
||||||
|
local vec = ffi.new("pxl8_vec3", {x = camera_pos[1], y = camera_pos[2], z = camera_pos[3]})
|
||||||
|
C.pxl8_world_render(world, gfx, vec)
|
||||||
|
end
|
||||||
|
|
||||||
|
function pxl8.world_unload(world)
|
||||||
|
C.pxl8_world_unload(world)
|
||||||
|
end
|
||||||
|
|
||||||
|
function pxl8.world_is_loaded(world)
|
||||||
|
return C.pxl8_world_is_loaded(world)
|
||||||
|
end
|
||||||
|
|
||||||
return pxl8
|
return pxl8
|
||||||
|
|
|
||||||
419
src/pxl8_bsp.c
Normal file
419
src/pxl8_bsp.c
Normal file
|
|
@ -0,0 +1,419 @@
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <SDL3/SDL.h>
|
||||||
|
|
||||||
|
#include "pxl8_bsp.h"
|
||||||
|
#include "pxl8_gfx.h"
|
||||||
|
#include "pxl8_macros.h"
|
||||||
|
|
||||||
|
#define BSP_VERSION 29
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
CHUNK_ENTITIES = 0,
|
||||||
|
CHUNK_PLANES = 1,
|
||||||
|
CHUNK_TEXTURES = 2,
|
||||||
|
CHUNK_VERTICES = 3,
|
||||||
|
CHUNK_VISIBILITY = 4,
|
||||||
|
CHUNK_NODES = 5,
|
||||||
|
CHUNK_TEXINFO = 6,
|
||||||
|
CHUNK_FACES = 7,
|
||||||
|
CHUNK_LIGHTING = 8,
|
||||||
|
CHUNK_CLIPNODES = 9,
|
||||||
|
CHUNK_LEAFS = 10,
|
||||||
|
CHUNK_MARKSURFACES = 11,
|
||||||
|
CHUNK_EDGES = 12,
|
||||||
|
CHUNK_SURFEDGES = 13,
|
||||||
|
CHUNK_MODELS = 14,
|
||||||
|
CHUNK_COUNT = 15
|
||||||
|
} pxl8_bsp_chunk_type;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
u32 offset;
|
||||||
|
u32 size;
|
||||||
|
} pxl8_bsp_chunk;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
u32 version;
|
||||||
|
pxl8_bsp_chunk chunks[CHUNK_COUNT];
|
||||||
|
} pxl8_bsp_header;
|
||||||
|
|
||||||
|
static u16 read_u16(const u8* data) {
|
||||||
|
return (u16)data[0] | ((u16)data[1] << 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
static u32 read_u32(const u8* data) {
|
||||||
|
return (u32)data[0] | ((u32)data[1] << 8) | ((u32)data[2] << 16) | ((u32)data[3] << 24);
|
||||||
|
}
|
||||||
|
|
||||||
|
static i16 read_i16(const u8* data) {
|
||||||
|
return (i16)read_u16(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static i32 read_i32(const u8* data) {
|
||||||
|
return (i32)read_u32(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static f32 read_f32(const u8* data) {
|
||||||
|
u32 val = read_u32(data);
|
||||||
|
f32 result;
|
||||||
|
memcpy(&result, &val, sizeof(f32));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
pxl8_result pxl8_bsp_load(const char* path, pxl8_bsp* bsp) {
|
||||||
|
if (!path || !bsp) return PXL8_ERROR_INVALID_ARGUMENT;
|
||||||
|
|
||||||
|
memset(bsp, 0, sizeof(*bsp));
|
||||||
|
|
||||||
|
size_t file_size;
|
||||||
|
u8* file_data = (u8*)SDL_LoadFile(path, &file_size);
|
||||||
|
if (!file_data) {
|
||||||
|
pxl8_error("Failed to load BSP file: %s", path);
|
||||||
|
return PXL8_ERROR_FILE_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file_size < sizeof(pxl8_bsp_header)) {
|
||||||
|
pxl8_error("BSP file too small: %s", path);
|
||||||
|
SDL_free(file_data);
|
||||||
|
return PXL8_ERROR_INVALID_FORMAT;
|
||||||
|
}
|
||||||
|
|
||||||
|
pxl8_bsp_header header;
|
||||||
|
header.version = read_u32(file_data);
|
||||||
|
|
||||||
|
if (header.version != BSP_VERSION) {
|
||||||
|
pxl8_error("Invalid BSP version: %u (expected %d)", header.version, BSP_VERSION);
|
||||||
|
SDL_free(file_data);
|
||||||
|
return PXL8_ERROR_INVALID_FORMAT;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i32 i = 0; i < CHUNK_COUNT; i++) {
|
||||||
|
header.chunks[i].offset = read_u32(file_data + 4 + i * 8);
|
||||||
|
header.chunks[i].size = read_u32(file_data + 4 + i * 8 + 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
pxl8_bsp_chunk* vertices_chunk = &header.chunks[CHUNK_VERTICES];
|
||||||
|
bsp->num_vertices = vertices_chunk->size / 12;
|
||||||
|
if (bsp->num_vertices > 0) {
|
||||||
|
bsp->vertices = (pxl8_bsp_vertex*)SDL_calloc(bsp->num_vertices, sizeof(pxl8_bsp_vertex));
|
||||||
|
const u8* data = file_data + vertices_chunk->offset;
|
||||||
|
for (u32 i = 0; i < bsp->num_vertices; i++) {
|
||||||
|
bsp->vertices[i].position.x = read_f32(data + i * 12);
|
||||||
|
bsp->vertices[i].position.y = read_f32(data + i * 12 + 4);
|
||||||
|
bsp->vertices[i].position.z = read_f32(data + i * 12 + 8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pxl8_bsp_chunk* edges_chunk = &header.chunks[CHUNK_EDGES];
|
||||||
|
bsp->num_edges = edges_chunk->size / 4;
|
||||||
|
if (bsp->num_edges > 0) {
|
||||||
|
bsp->edges = (pxl8_bsp_edge*)SDL_calloc(bsp->num_edges, sizeof(pxl8_bsp_edge));
|
||||||
|
const u8* data = file_data + edges_chunk->offset;
|
||||||
|
for (u32 i = 0; i < bsp->num_edges; i++) {
|
||||||
|
bsp->edges[i].vertex[0] = read_u16(data + i * 4);
|
||||||
|
bsp->edges[i].vertex[1] = read_u16(data + i * 4 + 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pxl8_bsp_chunk* surfedges_chunk = &header.chunks[CHUNK_SURFEDGES];
|
||||||
|
bsp->num_surfedges = surfedges_chunk->size / 4;
|
||||||
|
if (bsp->num_surfedges > 0) {
|
||||||
|
bsp->surfedges = (i32*)SDL_calloc(bsp->num_surfedges, sizeof(i32));
|
||||||
|
const u8* data = file_data + surfedges_chunk->offset;
|
||||||
|
for (u32 i = 0; i < bsp->num_surfedges; i++) {
|
||||||
|
bsp->surfedges[i] = read_i32(data + i * 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pxl8_bsp_chunk* planes_chunk = &header.chunks[CHUNK_PLANES];
|
||||||
|
bsp->num_planes = planes_chunk->size / 20;
|
||||||
|
if (bsp->num_planes > 0) {
|
||||||
|
bsp->planes = (pxl8_bsp_plane*)SDL_calloc(bsp->num_planes, sizeof(pxl8_bsp_plane));
|
||||||
|
const u8* data = file_data + planes_chunk->offset;
|
||||||
|
for (u32 i = 0; i < bsp->num_planes; i++) {
|
||||||
|
bsp->planes[i].normal.x = read_f32(data + i * 20);
|
||||||
|
bsp->planes[i].normal.y = read_f32(data + i * 20 + 4);
|
||||||
|
bsp->planes[i].normal.z = read_f32(data + i * 20 + 8);
|
||||||
|
bsp->planes[i].dist = read_f32(data + i * 20 + 12);
|
||||||
|
bsp->planes[i].type = read_i32(data + i * 20 + 16);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pxl8_bsp_chunk* texinfo_chunk = &header.chunks[CHUNK_TEXINFO];
|
||||||
|
bsp->num_texinfo = texinfo_chunk->size / 40;
|
||||||
|
if (bsp->num_texinfo > 0) {
|
||||||
|
bsp->texinfo = (pxl8_bsp_texinfo*)SDL_calloc(bsp->num_texinfo, sizeof(pxl8_bsp_texinfo));
|
||||||
|
const u8* data = file_data + texinfo_chunk->offset;
|
||||||
|
for (u32 i = 0; i < bsp->num_texinfo; i++) {
|
||||||
|
bsp->texinfo[i].u_axis.x = read_f32(data + i * 40);
|
||||||
|
bsp->texinfo[i].u_axis.y = read_f32(data + i * 40 + 4);
|
||||||
|
bsp->texinfo[i].u_axis.z = read_f32(data + i * 40 + 8);
|
||||||
|
bsp->texinfo[i].u_offset = read_f32(data + i * 40 + 12);
|
||||||
|
bsp->texinfo[i].v_axis.x = read_f32(data + i * 40 + 16);
|
||||||
|
bsp->texinfo[i].v_axis.y = read_f32(data + i * 40 + 20);
|
||||||
|
bsp->texinfo[i].v_axis.z = read_f32(data + i * 40 + 24);
|
||||||
|
bsp->texinfo[i].v_offset = read_f32(data + i * 40 + 28);
|
||||||
|
bsp->texinfo[i].miptex = read_u32(data + i * 40 + 32);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pxl8_bsp_chunk* faces_chunk = &header.chunks[CHUNK_FACES];
|
||||||
|
bsp->num_faces = faces_chunk->size / 20;
|
||||||
|
if (bsp->num_faces > 0) {
|
||||||
|
bsp->faces = (pxl8_bsp_face*)SDL_calloc(bsp->num_faces, sizeof(pxl8_bsp_face));
|
||||||
|
const u8* data = file_data + faces_chunk->offset;
|
||||||
|
for (u32 i = 0; i < bsp->num_faces; i++) {
|
||||||
|
bsp->faces[i].plane_id = read_u16(data + i * 20);
|
||||||
|
bsp->faces[i].side = read_u16(data + i * 20 + 2);
|
||||||
|
bsp->faces[i].first_edge = read_u32(data + i * 20 + 4);
|
||||||
|
bsp->faces[i].num_edges = read_u16(data + i * 20 + 8);
|
||||||
|
bsp->faces[i].texinfo_id = read_u16(data + i * 20 + 10);
|
||||||
|
bsp->faces[i].styles[0] = data[i * 20 + 12];
|
||||||
|
bsp->faces[i].styles[1] = data[i * 20 + 13];
|
||||||
|
bsp->faces[i].styles[2] = data[i * 20 + 14];
|
||||||
|
bsp->faces[i].styles[3] = data[i * 20 + 15];
|
||||||
|
bsp->faces[i].lightmap_offset = read_u32(data + i * 20 + 16);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pxl8_bsp_chunk* nodes_chunk = &header.chunks[CHUNK_NODES];
|
||||||
|
bsp->num_nodes = nodes_chunk->size / 24;
|
||||||
|
if (bsp->num_nodes > 0) {
|
||||||
|
bsp->nodes = (pxl8_bsp_node*)SDL_calloc(bsp->num_nodes, sizeof(pxl8_bsp_node));
|
||||||
|
const u8* data = file_data + nodes_chunk->offset;
|
||||||
|
for (u32 i = 0; i < bsp->num_nodes; i++) {
|
||||||
|
bsp->nodes[i].plane_id = read_u32(data + i * 24);
|
||||||
|
bsp->nodes[i].children[0] = read_i16(data + i * 24 + 4);
|
||||||
|
bsp->nodes[i].children[1] = read_i16(data + i * 24 + 6);
|
||||||
|
bsp->nodes[i].mins[0] = read_i16(data + i * 24 + 8);
|
||||||
|
bsp->nodes[i].mins[1] = read_i16(data + i * 24 + 10);
|
||||||
|
bsp->nodes[i].mins[2] = read_i16(data + i * 24 + 12);
|
||||||
|
bsp->nodes[i].maxs[0] = read_i16(data + i * 24 + 14);
|
||||||
|
bsp->nodes[i].maxs[1] = read_i16(data + i * 24 + 16);
|
||||||
|
bsp->nodes[i].maxs[2] = read_i16(data + i * 24 + 18);
|
||||||
|
bsp->nodes[i].first_face = read_u16(data + i * 24 + 20);
|
||||||
|
bsp->nodes[i].num_faces = read_u16(data + i * 24 + 22);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pxl8_bsp_chunk* leafs_chunk = &header.chunks[CHUNK_LEAFS];
|
||||||
|
bsp->num_leafs = leafs_chunk->size / 28;
|
||||||
|
if (bsp->num_leafs > 0) {
|
||||||
|
bsp->leafs = (pxl8_bsp_leaf*)SDL_calloc(bsp->num_leafs, sizeof(pxl8_bsp_leaf));
|
||||||
|
const u8* data = file_data + leafs_chunk->offset;
|
||||||
|
for (u32 i = 0; i < bsp->num_leafs; i++) {
|
||||||
|
bsp->leafs[i].contents = read_i32(data + i * 28);
|
||||||
|
bsp->leafs[i].visofs = read_i32(data + i * 28 + 4);
|
||||||
|
bsp->leafs[i].mins[0] = read_i16(data + i * 28 + 8);
|
||||||
|
bsp->leafs[i].mins[1] = read_i16(data + i * 28 + 10);
|
||||||
|
bsp->leafs[i].mins[2] = read_i16(data + i * 28 + 12);
|
||||||
|
bsp->leafs[i].maxs[0] = read_i16(data + i * 28 + 14);
|
||||||
|
bsp->leafs[i].maxs[1] = read_i16(data + i * 28 + 16);
|
||||||
|
bsp->leafs[i].maxs[2] = read_i16(data + i * 28 + 18);
|
||||||
|
bsp->leafs[i].first_marksurface = read_u16(data + i * 28 + 20);
|
||||||
|
bsp->leafs[i].num_marksurfaces = read_u16(data + i * 28 + 22);
|
||||||
|
bsp->leafs[i].ambient_level[0] = data[i * 28 + 24];
|
||||||
|
bsp->leafs[i].ambient_level[1] = data[i * 28 + 25];
|
||||||
|
bsp->leafs[i].ambient_level[2] = data[i * 28 + 26];
|
||||||
|
bsp->leafs[i].ambient_level[3] = data[i * 28 + 27];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pxl8_bsp_chunk* marksurfaces_chunk = &header.chunks[CHUNK_MARKSURFACES];
|
||||||
|
bsp->num_marksurfaces = marksurfaces_chunk->size / 2;
|
||||||
|
if (bsp->num_marksurfaces > 0) {
|
||||||
|
bsp->marksurfaces = (u16*)SDL_calloc(bsp->num_marksurfaces, sizeof(u16));
|
||||||
|
const u8* data = file_data + marksurfaces_chunk->offset;
|
||||||
|
for (u32 i = 0; i < bsp->num_marksurfaces; i++) {
|
||||||
|
bsp->marksurfaces[i] = read_u16(data + i * 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pxl8_bsp_chunk* models_chunk = &header.chunks[CHUNK_MODELS];
|
||||||
|
bsp->num_models = models_chunk->size / 64;
|
||||||
|
if (bsp->num_models > 0) {
|
||||||
|
bsp->models = (pxl8_bsp_model*)SDL_calloc(bsp->num_models, sizeof(pxl8_bsp_model));
|
||||||
|
const u8* data = file_data + models_chunk->offset;
|
||||||
|
for (u32 i = 0; i < bsp->num_models; i++) {
|
||||||
|
bsp->models[i].mins[0] = read_f32(data + i * 64);
|
||||||
|
bsp->models[i].mins[1] = read_f32(data + i * 64 + 4);
|
||||||
|
bsp->models[i].mins[2] = read_f32(data + i * 64 + 8);
|
||||||
|
bsp->models[i].maxs[0] = read_f32(data + i * 64 + 12);
|
||||||
|
bsp->models[i].maxs[1] = read_f32(data + i * 64 + 16);
|
||||||
|
bsp->models[i].maxs[2] = read_f32(data + i * 64 + 20);
|
||||||
|
bsp->models[i].origin.x = read_f32(data + i * 64 + 24);
|
||||||
|
bsp->models[i].origin.y = read_f32(data + i * 64 + 28);
|
||||||
|
bsp->models[i].origin.z = read_f32(data + i * 64 + 32);
|
||||||
|
bsp->models[i].headnode[0] = read_i32(data + i * 64 + 36);
|
||||||
|
bsp->models[i].headnode[1] = read_i32(data + i * 64 + 40);
|
||||||
|
bsp->models[i].headnode[2] = read_i32(data + i * 64 + 44);
|
||||||
|
bsp->models[i].headnode[3] = read_i32(data + i * 64 + 48);
|
||||||
|
bsp->models[i].visleafs = read_i32(data + i * 64 + 52);
|
||||||
|
bsp->models[i].first_face = read_i32(data + i * 64 + 56);
|
||||||
|
bsp->models[i].num_faces = read_i32(data + i * 64 + 60);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pxl8_bsp_chunk* vis_chunk = &header.chunks[CHUNK_VISIBILITY];
|
||||||
|
bsp->visdata_size = vis_chunk->size;
|
||||||
|
if (bsp->visdata_size > 0) {
|
||||||
|
bsp->visdata = (u8*)SDL_malloc(bsp->visdata_size);
|
||||||
|
memcpy(bsp->visdata, file_data + vis_chunk->offset, bsp->visdata_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
pxl8_bsp_chunk* light_chunk = &header.chunks[CHUNK_LIGHTING];
|
||||||
|
bsp->lightdata_size = light_chunk->size;
|
||||||
|
if (bsp->lightdata_size > 0) {
|
||||||
|
bsp->lightdata = (u8*)SDL_malloc(bsp->lightdata_size);
|
||||||
|
memcpy(bsp->lightdata, file_data + light_chunk->offset, bsp->lightdata_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_free(file_data);
|
||||||
|
|
||||||
|
pxl8_debug("Loaded BSP: %u verts, %u faces, %u nodes, %u leafs",
|
||||||
|
bsp->num_vertices, bsp->num_faces, bsp->num_nodes, bsp->num_leafs);
|
||||||
|
|
||||||
|
return PXL8_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pxl8_bsp_destroy(pxl8_bsp* bsp) {
|
||||||
|
if (!bsp) return;
|
||||||
|
|
||||||
|
SDL_free(bsp->edges);
|
||||||
|
SDL_free(bsp->faces);
|
||||||
|
SDL_free(bsp->leafs);
|
||||||
|
SDL_free(bsp->lightdata);
|
||||||
|
SDL_free(bsp->marksurfaces);
|
||||||
|
SDL_free(bsp->models);
|
||||||
|
SDL_free(bsp->nodes);
|
||||||
|
SDL_free(bsp->planes);
|
||||||
|
SDL_free(bsp->surfedges);
|
||||||
|
SDL_free(bsp->texinfo);
|
||||||
|
SDL_free(bsp->vertices);
|
||||||
|
SDL_free(bsp->visdata);
|
||||||
|
|
||||||
|
memset(bsp, 0, sizeof(*bsp));
|
||||||
|
}
|
||||||
|
|
||||||
|
i32 pxl8_bsp_find_leaf(const pxl8_bsp* bsp, pxl8_vec3 pos) {
|
||||||
|
if (!bsp || bsp->num_nodes == 0) return -1;
|
||||||
|
|
||||||
|
i32 node_id = 0;
|
||||||
|
|
||||||
|
while (node_id >= 0) {
|
||||||
|
const pxl8_bsp_node* node = &bsp->nodes[node_id];
|
||||||
|
const pxl8_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);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool pxl8_bsp_is_leaf_visible(const pxl8_bsp* bsp, i32 leaf_from, i32 leaf_to) {
|
||||||
|
if (!bsp || !bsp->visdata || leaf_from < 0 || leaf_to < 0) return true;
|
||||||
|
if ((u32)leaf_from >= bsp->num_leafs || (u32)leaf_to >= bsp->num_leafs) return true;
|
||||||
|
|
||||||
|
i32 visofs = bsp->leafs[leaf_from].visofs;
|
||||||
|
if (visofs < 0) return true;
|
||||||
|
|
||||||
|
i32 byte_idx = leaf_to >> 3;
|
||||||
|
i32 bit_idx = leaf_to & 7;
|
||||||
|
|
||||||
|
if ((u32)visofs + byte_idx >= bsp->visdata_size) return true;
|
||||||
|
|
||||||
|
return (bsp->visdata[visofs + byte_idx] & (1 << bit_idx)) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pxl8_bsp_render_face(pxl8_gfx* gfx, const pxl8_bsp* bsp, u32 face_id, u32 color) {
|
||||||
|
if (!gfx || !bsp || face_id >= bsp->num_faces) return;
|
||||||
|
|
||||||
|
const pxl8_bsp_face* face = &bsp->faces[face_id];
|
||||||
|
if (face->num_edges < 3) return;
|
||||||
|
|
||||||
|
pxl8_vec3 verts[64];
|
||||||
|
u32 num_verts = 0;
|
||||||
|
|
||||||
|
for (u32 i = 0; i < face->num_edges && num_verts < 64; i++) {
|
||||||
|
i32 surfedge_idx = face->first_edge + i;
|
||||||
|
if (surfedge_idx >= (i32)bsp->num_surfedges) continue;
|
||||||
|
|
||||||
|
i32 edge_idx = bsp->surfedges[surfedge_idx];
|
||||||
|
u32 vert_idx;
|
||||||
|
|
||||||
|
if (edge_idx >= 0) {
|
||||||
|
if ((u32)edge_idx >= bsp->num_edges) continue;
|
||||||
|
vert_idx = bsp->edges[edge_idx].vertex[0];
|
||||||
|
} else {
|
||||||
|
edge_idx = -edge_idx;
|
||||||
|
if ((u32)edge_idx >= bsp->num_edges) continue;
|
||||||
|
vert_idx = bsp->edges[edge_idx].vertex[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vert_idx >= bsp->num_vertices) continue;
|
||||||
|
verts[num_verts++] = bsp->vertices[vert_idx].position;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (num_verts < 3) return;
|
||||||
|
|
||||||
|
for (u32 i = 1; i < num_verts - 1; i++) {
|
||||||
|
pxl8_3d_draw_triangle_raw(gfx, verts[0], verts[i], verts[i + 1], color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void pxl8_bsp_render_wireframe(
|
||||||
|
pxl8_gfx* gfx,
|
||||||
|
const pxl8_bsp* bsp,
|
||||||
|
pxl8_vec3 camera_pos,
|
||||||
|
u32 color
|
||||||
|
) {
|
||||||
|
if (!gfx || !bsp) return;
|
||||||
|
|
||||||
|
i32 camera_leaf = pxl8_bsp_find_leaf(bsp, camera_pos);
|
||||||
|
|
||||||
|
for (u32 leaf_id = 0; leaf_id < bsp->num_leafs; leaf_id++) {
|
||||||
|
if (camera_leaf >= 0 && !pxl8_bsp_is_leaf_visible(bsp, camera_leaf, leaf_id)) continue;
|
||||||
|
|
||||||
|
const pxl8_bsp_leaf* leaf = &bsp->leafs[leaf_id];
|
||||||
|
|
||||||
|
for (u32 i = 0; i < leaf->num_marksurfaces; i++) {
|
||||||
|
u32 surf_idx = leaf->first_marksurface + i;
|
||||||
|
if (surf_idx >= bsp->num_marksurfaces) continue;
|
||||||
|
|
||||||
|
u32 face_id = bsp->marksurfaces[surf_idx];
|
||||||
|
if (face_id >= bsp->num_faces) continue;
|
||||||
|
|
||||||
|
const pxl8_bsp_face* face = &bsp->faces[face_id];
|
||||||
|
|
||||||
|
for (u32 e = 0; e < face->num_edges; e++) {
|
||||||
|
i32 surfedge_idx = face->first_edge + e;
|
||||||
|
i32 next_surfedge_idx = face->first_edge + ((e + 1) % face->num_edges);
|
||||||
|
|
||||||
|
if (surfedge_idx >= (i32)bsp->num_surfedges ||
|
||||||
|
next_surfedge_idx >= (i32)bsp->num_surfedges) continue;
|
||||||
|
|
||||||
|
i32 edge_idx = bsp->surfedges[surfedge_idx];
|
||||||
|
u32 v0_idx, v1_idx;
|
||||||
|
|
||||||
|
if (edge_idx >= 0) {
|
||||||
|
if ((u32)edge_idx >= bsp->num_edges) continue;
|
||||||
|
v0_idx = bsp->edges[edge_idx].vertex[0];
|
||||||
|
v1_idx = bsp->edges[edge_idx].vertex[1];
|
||||||
|
} else {
|
||||||
|
edge_idx = -edge_idx;
|
||||||
|
if ((u32)edge_idx >= bsp->num_edges) continue;
|
||||||
|
v0_idx = bsp->edges[edge_idx].vertex[1];
|
||||||
|
v1_idx = bsp->edges[edge_idx].vertex[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (v0_idx >= bsp->num_vertices || v1_idx >= bsp->num_vertices) continue;
|
||||||
|
|
||||||
|
pxl8_vec3 p0 = bsp->vertices[v0_idx].position;
|
||||||
|
pxl8_vec3 p1 = bsp->vertices[v1_idx].position;
|
||||||
|
|
||||||
|
pxl8_3d_draw_line_3d(gfx, p0, p1, color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
130
src/pxl8_bsp.h
Normal file
130
src/pxl8_bsp.h
Normal file
|
|
@ -0,0 +1,130 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "pxl8_gfx.h"
|
||||||
|
#include "pxl8_math.h"
|
||||||
|
#include "pxl8_types.h"
|
||||||
|
|
||||||
|
typedef struct pxl8_bsp_vertex {
|
||||||
|
pxl8_vec3 position;
|
||||||
|
} pxl8_bsp_vertex;
|
||||||
|
|
||||||
|
typedef struct pxl8_bsp_edge {
|
||||||
|
u16 vertex[2];
|
||||||
|
} pxl8_bsp_edge;
|
||||||
|
|
||||||
|
typedef struct pxl8_bsp_plane {
|
||||||
|
f32 dist;
|
||||||
|
pxl8_vec3 normal;
|
||||||
|
i32 type;
|
||||||
|
} pxl8_bsp_plane;
|
||||||
|
|
||||||
|
typedef struct pxl8_bsp_texinfo {
|
||||||
|
u32 miptex;
|
||||||
|
|
||||||
|
f32 u_offset;
|
||||||
|
pxl8_vec3 u_axis;
|
||||||
|
|
||||||
|
f32 v_offset;
|
||||||
|
pxl8_vec3 v_axis;
|
||||||
|
} pxl8_bsp_texinfo;
|
||||||
|
|
||||||
|
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_bsp_face;
|
||||||
|
|
||||||
|
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_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 {
|
||||||
|
pxl8_bsp_edge* edges;
|
||||||
|
pxl8_bsp_face* faces;
|
||||||
|
pxl8_bsp_leaf* leafs;
|
||||||
|
u8* lightdata;
|
||||||
|
u16* marksurfaces;
|
||||||
|
pxl8_bsp_model* models;
|
||||||
|
pxl8_bsp_node* nodes;
|
||||||
|
pxl8_bsp_plane* planes;
|
||||||
|
i32* surfedges;
|
||||||
|
pxl8_bsp_texinfo* texinfo;
|
||||||
|
pxl8_bsp_vertex* vertices;
|
||||||
|
u8* visdata;
|
||||||
|
|
||||||
|
u32 lightdata_size;
|
||||||
|
u32 num_edges;
|
||||||
|
u32 num_faces;
|
||||||
|
u32 num_leafs;
|
||||||
|
u32 num_marksurfaces;
|
||||||
|
u32 num_models;
|
||||||
|
u32 num_nodes;
|
||||||
|
u32 num_planes;
|
||||||
|
u32 num_surfedges;
|
||||||
|
u32 num_texinfo;
|
||||||
|
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);
|
||||||
|
|
||||||
|
void pxl8_bsp_render_face(
|
||||||
|
pxl8_gfx* gfx,
|
||||||
|
const pxl8_bsp* bsp,
|
||||||
|
u32 face_id,
|
||||||
|
u32 color
|
||||||
|
);
|
||||||
|
|
||||||
|
void pxl8_bsp_render_wireframe(
|
||||||
|
pxl8_gfx* gfx,
|
||||||
|
const pxl8_bsp* bsp,
|
||||||
|
pxl8_vec3 camera_pos,
|
||||||
|
u32 color
|
||||||
|
);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
@ -158,6 +158,14 @@ static const char* pxl8_ffi_cdefs =
|
||||||
"pxl8_mat4 pxl8_mat4_scale(float x, float y, float z);\n"
|
"pxl8_mat4 pxl8_mat4_scale(float x, float y, float z);\n"
|
||||||
"pxl8_mat4 pxl8_mat4_translate(float x, float y, float z);\n"
|
"pxl8_mat4 pxl8_mat4_translate(float x, float y, float z);\n"
|
||||||
"\n"
|
"\n"
|
||||||
|
"typedef struct pxl8_world pxl8_world;\n"
|
||||||
|
"pxl8_world* pxl8_world_create(void);\n"
|
||||||
|
"void pxl8_world_destroy(pxl8_world* world);\n"
|
||||||
|
"int pxl8_world_load(pxl8_world* world, const char* path);\n"
|
||||||
|
"void pxl8_world_render(pxl8_world* world, pxl8_gfx* gfx, pxl8_vec3 camera_pos);\n"
|
||||||
|
"void pxl8_world_unload(pxl8_world* world);\n"
|
||||||
|
"bool pxl8_world_is_loaded(const pxl8_world* world);\n"
|
||||||
|
"\n"
|
||||||
"typedef struct pxl8_ui pxl8_ui;\n"
|
"typedef struct pxl8_ui pxl8_ui;\n"
|
||||||
"typedef struct { unsigned char bg_color; unsigned int sprite_id; int corner_size; int edge_size; int padding; } pxl8_frame_theme;\n"
|
"typedef struct { unsigned char bg_color; unsigned int sprite_id; int corner_size; int edge_size; int padding; } pxl8_frame_theme;\n"
|
||||||
"typedef struct { bool enabled; const char* label; } pxl8_menu_item;\n"
|
"typedef struct { bool enabled; const char* label; } pxl8_menu_item;\n"
|
||||||
|
|
|
||||||
75
src/pxl8_world.c
Normal file
75
src/pxl8_world.c
Normal file
|
|
@ -0,0 +1,75 @@
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <SDL3/SDL.h>
|
||||||
|
|
||||||
|
#include "pxl8_bsp.h"
|
||||||
|
#include "pxl8_macros.h"
|
||||||
|
#include "pxl8_world.h"
|
||||||
|
|
||||||
|
struct pxl8_world {
|
||||||
|
pxl8_bsp bsp;
|
||||||
|
bool loaded;
|
||||||
|
u32 wireframe_color;
|
||||||
|
};
|
||||||
|
|
||||||
|
pxl8_world* pxl8_world_create(void) {
|
||||||
|
pxl8_world* world = (pxl8_world*)SDL_calloc(1, sizeof(pxl8_world));
|
||||||
|
if (!world) {
|
||||||
|
pxl8_error("Failed to allocate world");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
world->loaded = false;
|
||||||
|
world->wireframe_color = 15;
|
||||||
|
|
||||||
|
return world;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pxl8_world_destroy(pxl8_world* world) {
|
||||||
|
if (!world) return;
|
||||||
|
|
||||||
|
if (world->loaded) {
|
||||||
|
pxl8_bsp_destroy(&world->bsp);
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_free(world);
|
||||||
|
}
|
||||||
|
|
||||||
|
pxl8_result pxl8_world_load(pxl8_world* world, const char* path) {
|
||||||
|
if (!world || !path) return PXL8_ERROR_INVALID_ARGUMENT;
|
||||||
|
|
||||||
|
if (world->loaded) {
|
||||||
|
pxl8_bsp_destroy(&world->bsp);
|
||||||
|
world->loaded = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&world->bsp, 0, sizeof(pxl8_bsp));
|
||||||
|
|
||||||
|
pxl8_result result = pxl8_bsp_load(path, &world->bsp);
|
||||||
|
if (result != PXL8_OK) {
|
||||||
|
pxl8_error("Failed to load world: %s", path);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
world->loaded = true;
|
||||||
|
pxl8_info("Loaded world: %s", path);
|
||||||
|
|
||||||
|
return PXL8_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pxl8_world_render(pxl8_world* world, pxl8_gfx* gfx, pxl8_vec3 camera_pos) {
|
||||||
|
if (!world || !gfx || !world->loaded) return;
|
||||||
|
|
||||||
|
pxl8_bsp_render_wireframe(gfx, &world->bsp, camera_pos, world->wireframe_color);
|
||||||
|
}
|
||||||
|
|
||||||
|
void pxl8_world_unload(pxl8_world* world) {
|
||||||
|
if (!world || !world->loaded) return;
|
||||||
|
|
||||||
|
pxl8_bsp_destroy(&world->bsp);
|
||||||
|
world->loaded = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool pxl8_world_is_loaded(const pxl8_world* world) {
|
||||||
|
return world && world->loaded;
|
||||||
|
}
|
||||||
24
src/pxl8_world.h
Normal file
24
src/pxl8_world.h
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "pxl8_gfx.h"
|
||||||
|
#include "pxl8_math.h"
|
||||||
|
#include "pxl8_types.h"
|
||||||
|
|
||||||
|
typedef struct pxl8_world pxl8_world;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
pxl8_world* pxl8_world_create(void);
|
||||||
|
void pxl8_world_destroy(pxl8_world* world);
|
||||||
|
|
||||||
|
pxl8_result pxl8_world_load(pxl8_world* world, const char* path);
|
||||||
|
void pxl8_world_render(pxl8_world* world, pxl8_gfx* gfx, pxl8_vec3 camera_pos);
|
||||||
|
void pxl8_world_unload(pxl8_world* world);
|
||||||
|
|
||||||
|
bool pxl8_world_is_loaded(const pxl8_world* world);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
Loading…
Add table
Add a link
Reference in a new issue