add debug code for rendering issues
This commit is contained in:
parent
db0e47b6ad
commit
588176a645
12 changed files with 291 additions and 203 deletions
|
|
@ -2,9 +2,9 @@
|
|||
(local debug-ui (require :mod.debug_ui))
|
||||
|
||||
(var world nil)
|
||||
(var cam-x 1000)
|
||||
(var cam-x 512)
|
||||
(var cam-y 64)
|
||||
(var cam-z 1000)
|
||||
(var cam-z 512)
|
||||
(var cam-yaw 0)
|
||||
(var cam-pitch 0)
|
||||
(var bob-time 0)
|
||||
|
|
@ -23,8 +23,8 @@
|
|||
(set world (pxl8.world_new))
|
||||
(let [result (pxl8.world_generate world {
|
||||
:type pxl8.PROCGEN_CAVE
|
||||
:width 32
|
||||
:height 32
|
||||
:width 16
|
||||
:height 16
|
||||
:seed 42
|
||||
:density 0.45
|
||||
:iterations 4})]
|
||||
|
|
@ -33,118 +33,123 @@
|
|||
(pxl8.info "Generated procedural cave"))))
|
||||
|
||||
(fn update [dt]
|
||||
(set fps-accumulator (+ fps-accumulator dt))
|
||||
(set fps-frame-count (+ fps-frame-count 1))
|
||||
(let [clamped-dt (math.min dt 0.1)]
|
||||
(when (> dt 0.05)
|
||||
(pxl8.debug (.. "Large dt: " (string.format "%.3f" dt) "s")))
|
||||
|
||||
(when (>= fps-accumulator 0.25)
|
||||
(set fps (/ fps-frame-count fps-accumulator))
|
||||
(set fps-accumulator 0)
|
||||
(set fps-frame-count 0))
|
||||
(set fps-accumulator (+ fps-accumulator clamped-dt))
|
||||
(set fps-frame-count (+ fps-frame-count 1))
|
||||
|
||||
(when (pxl8.key_pressed "F8")
|
||||
(set show-debug-ui (not show-debug-ui))
|
||||
(pxl8.ui_window_set_open "Debug Menu (F8)" show-debug-ui))
|
||||
(when (>= fps-accumulator 0.25)
|
||||
(set fps (/ fps-frame-count fps-accumulator))
|
||||
(set fps-accumulator 0)
|
||||
(set fps-frame-count 0))
|
||||
|
||||
(when (pxl8.world_is_loaded world)
|
||||
(let [forward-x (- (math.sin cam-yaw))
|
||||
forward-z (- (math.cos cam-yaw))
|
||||
right-x (math.cos cam-yaw)
|
||||
right-z (- (math.sin cam-yaw))
|
||||
cell-size 64
|
||||
grid-min 0
|
||||
grid-max (* 32 cell-size)]
|
||||
(when (pxl8.key_pressed "F8")
|
||||
(set show-debug-ui (not show-debug-ui))
|
||||
(pxl8.ui_window_set_open "Debug Menu (F8)" show-debug-ui))
|
||||
|
||||
(var moving false)
|
||||
(var new-x cam-x)
|
||||
(var new-z cam-z)
|
||||
(when (pxl8.world_is_loaded world)
|
||||
(let [forward-x (- (math.sin cam-yaw))
|
||||
forward-z (- (math.cos cam-yaw))
|
||||
right-x (math.cos cam-yaw)
|
||||
right-z (- (math.sin cam-yaw))
|
||||
cell-size 64
|
||||
grid-min 0
|
||||
grid-max (* 16 cell-size)]
|
||||
|
||||
(when (pxl8.key_down "w")
|
||||
(set new-x (+ new-x (* forward-x move-speed dt)))
|
||||
(set new-z (+ new-z (* forward-z move-speed dt)))
|
||||
(set moving true))
|
||||
(var moving false)
|
||||
(var new-x cam-x)
|
||||
(var new-z cam-z)
|
||||
|
||||
(when (pxl8.key_down "s")
|
||||
(set new-x (- new-x (* forward-x move-speed dt)))
|
||||
(set new-z (- new-z (* forward-z move-speed dt)))
|
||||
(set moving true))
|
||||
(when (pxl8.key_down "w")
|
||||
(set new-x (+ new-x (* forward-x move-speed clamped-dt)))
|
||||
(set new-z (+ new-z (* forward-z move-speed clamped-dt)))
|
||||
(set moving true))
|
||||
|
||||
(when (pxl8.key_down "q")
|
||||
(set new-x (- new-x (* right-x move-speed dt)))
|
||||
(set new-z (- new-z (* right-z move-speed dt)))
|
||||
(set moving true))
|
||||
(when (pxl8.key_down "s")
|
||||
(set new-x (- new-x (* forward-x move-speed clamped-dt)))
|
||||
(set new-z (- new-z (* forward-z move-speed clamped-dt)))
|
||||
(set moving true))
|
||||
|
||||
(when (pxl8.key_down "e")
|
||||
(set new-x (+ new-x (* right-x move-speed dt)))
|
||||
(set new-z (+ new-z (* right-z move-speed dt)))
|
||||
(set moving true))
|
||||
(when (pxl8.key_down "q")
|
||||
(set new-x (- new-x (* right-x move-speed clamped-dt)))
|
||||
(set new-z (- new-z (* right-z move-speed clamped-dt)))
|
||||
(set moving true))
|
||||
|
||||
(when (and (>= new-x grid-min) (<= new-x grid-max)
|
||||
(>= new-z grid-min) (<= new-z grid-max))
|
||||
(set cam-x new-x)
|
||||
(set cam-z new-z))
|
||||
(when (pxl8.key_down "e")
|
||||
(set new-x (+ new-x (* right-x move-speed clamped-dt)))
|
||||
(set new-z (+ new-z (* right-z move-speed clamped-dt)))
|
||||
(set moving true))
|
||||
|
||||
(when (or (pxl8.key_down "left") (pxl8.key_down "a"))
|
||||
(set cam-yaw (+ cam-yaw (* turn-speed dt))))
|
||||
(when (and (>= new-x grid-min) (<= new-x grid-max)
|
||||
(>= new-z grid-min) (<= new-z grid-max))
|
||||
(set cam-x new-x)
|
||||
(set cam-z new-z))
|
||||
|
||||
(when (or (pxl8.key_down "right") (pxl8.key_down "d"))
|
||||
(set cam-yaw (- cam-yaw (* turn-speed dt))))
|
||||
(when (or (pxl8.key_down "left") (pxl8.key_down "a"))
|
||||
(set cam-yaw (+ cam-yaw (* turn-speed clamped-dt))))
|
||||
|
||||
(when (pxl8.key_down "up")
|
||||
(set cam-pitch (+ cam-pitch (* turn-speed dt)))
|
||||
(when (> cam-pitch 1.5) (set cam-pitch 1.5)))
|
||||
(when (or (pxl8.key_down "right") (pxl8.key_down "d"))
|
||||
(set cam-yaw (- cam-yaw (* turn-speed clamped-dt))))
|
||||
|
||||
(when (pxl8.key_down "down")
|
||||
(set cam-pitch (- cam-pitch (* turn-speed dt)))
|
||||
(when (< cam-pitch -1.5) (set cam-pitch -1.5)))
|
||||
(when (pxl8.key_down "up")
|
||||
(set cam-pitch (+ cam-pitch (* turn-speed clamped-dt)))
|
||||
(when (> cam-pitch 1.5) (set cam-pitch 1.5)))
|
||||
|
||||
(if moving
|
||||
(set bob-time (+ bob-time (* dt bob-speed)))
|
||||
(let [target-phase (* (math.floor (/ bob-time math.pi)) math.pi)]
|
||||
(set bob-time (+ (* bob-time 0.8) (* target-phase 0.2))))))))
|
||||
(when (pxl8.key_down "down")
|
||||
(set cam-pitch (- cam-pitch (* turn-speed clamped-dt)))
|
||||
(when (< cam-pitch -1.5) (set cam-pitch -1.5)))
|
||||
|
||||
(if moving
|
||||
(set bob-time (+ bob-time (* clamped-dt bob-speed)))
|
||||
(let [target-phase (* (math.floor (/ bob-time math.pi)) math.pi)]
|
||||
(set bob-time (+ (* bob-time 0.8) (* target-phase 0.2)))))))))
|
||||
(fn frame []
|
||||
(pxl8.clr 0)
|
||||
|
||||
(when (pxl8.world_is_loaded world)
|
||||
(let [bob-offset (* (math.sin bob-time) bob-amount)
|
||||
eye-y (+ cam-y bob-offset)
|
||||
forward-x (- (math.sin cam-yaw))
|
||||
forward-z (- (math.cos cam-yaw))
|
||||
target-x (+ cam-x forward-x)
|
||||
target-y (+ eye-y (math.sin cam-pitch))
|
||||
target-z (+ cam-z forward-z)]
|
||||
(when (pxl8.world_is_loaded world)
|
||||
(let [bob-offset (* (math.sin bob-time) bob-amount)
|
||||
eye-y (+ cam-y bob-offset)
|
||||
forward-x (- (math.sin cam-yaw))
|
||||
forward-z (- (math.cos cam-yaw))
|
||||
target-x (+ cam-x forward-x)
|
||||
target-y (+ eye-y (math.sin cam-pitch))
|
||||
target-z (+ cam-z forward-z)]
|
||||
|
||||
(pxl8.text (.. "Pos: " (string.format "%.0f" cam-x) ","
|
||||
(string.format "%.0f" cam-y) ","
|
||||
(string.format "%.0f" cam-z)) 10 25 12)
|
||||
(pxl8.text (.. "Pos: " (string.format "%.0f" cam-x) ","
|
||||
(string.format "%.0f" cam-y) ","
|
||||
(string.format "%.0f" cam-z)) 10 25 12)
|
||||
|
||||
(pxl8.clear_zbuffer)
|
||||
(pxl8.set_backface_culling true)
|
||||
(pxl8.set_wireframe false)
|
||||
(pxl8.clear_zbuffer)
|
||||
|
||||
(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_backface_culling true)
|
||||
(pxl8.set_wireframe false)
|
||||
|
||||
(pxl8.set_view (pxl8.mat4_lookat
|
||||
[cam-x eye-y cam-z]
|
||||
[target-x target-y target-z]
|
||||
[0 1 0]))
|
||||
(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_model (pxl8.mat4_identity))
|
||||
(pxl8.set_view (pxl8.mat4_lookat
|
||||
[cam-x eye-y cam-z]
|
||||
[target-x target-y target-z]
|
||||
[0 1 0]))
|
||||
|
||||
(pxl8.set_affine_textures affine)
|
||||
(pxl8.world_render world [cam-x eye-y cam-z]))
|
||||
(pxl8.set_model (pxl8.mat4_identity))
|
||||
|
||||
(let [new-state (debug-ui.render {:show-debug-ui show-debug-ui
|
||||
:fps fps
|
||||
:wireframe false
|
||||
:auto-rotate false
|
||||
:orthographic false
|
||||
:use-texture true
|
||||
:affine affine})]
|
||||
(when (not= new-state.show-debug-ui nil) (set show-debug-ui new-state.show-debug-ui))
|
||||
(when (not= new-state.affine nil) (set affine new-state.affine)))))
|
||||
(pxl8.set_affine_textures affine)
|
||||
|
||||
(pxl8.world_render world [cam-x eye-y cam-z])))
|
||||
|
||||
(let [new-state (debug-ui.render {:show-debug-ui show-debug-ui
|
||||
:fps fps
|
||||
:wireframe false
|
||||
:auto-rotate false
|
||||
:orthographic false
|
||||
:use-texture true
|
||||
:affine affine})]
|
||||
(when (not= new-state.show-debug-ui nil) (set show-debug-ui new-state.show-debug-ui))
|
||||
(when (not= new-state.affine nil) (set affine new-state.affine))))
|
||||
|
||||
{:init init
|
||||
:update update
|
||||
|
|
|
|||
71
src/pxl8.c
71
src/pxl8.c
|
|
@ -8,6 +8,7 @@
|
|||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "pxl8.h"
|
||||
#include "pxl8_cart.h"
|
||||
#include "pxl8_game.h"
|
||||
#include "pxl8_hal.h"
|
||||
|
|
@ -16,16 +17,18 @@
|
|||
#include "pxl8_types.h"
|
||||
#include "pxl8_ui.h"
|
||||
|
||||
pxl8_game_result pxl8_init(pxl8_game* game, i32 argc, char* argv[]) {
|
||||
if (!game) {
|
||||
return PXL8_GAME_FAILURE;
|
||||
pxl8_result pxl8_init(pxl8* system, i32 argc, char* argv[]) {
|
||||
if (!system) {
|
||||
return PXL8_FAILURE;
|
||||
}
|
||||
|
||||
if (!game->hal) {
|
||||
if (!system->hal) {
|
||||
pxl8_error("HAL must be set before calling pxl8_init");
|
||||
return PXL8_GAME_FAILURE;
|
||||
return PXL8_FAILURE;
|
||||
}
|
||||
|
||||
pxl8_game* game = &system->game;
|
||||
|
||||
game->color_mode = PXL8_COLOR_MODE_MEGA;
|
||||
game->resolution = PXL8_RESOLUTION_640x360;
|
||||
|
||||
|
|
@ -44,7 +47,7 @@ pxl8_game_result pxl8_init(pxl8_game* game, i32 argc, char* argv[]) {
|
|||
pack_output = argv[++i];
|
||||
} else {
|
||||
pxl8_error("--pack requires <folder> <output.pxc>");
|
||||
return PXL8_GAME_FAILURE;
|
||||
return PXL8_FAILURE;
|
||||
}
|
||||
} else if (!script_arg) {
|
||||
script_arg = argv[i];
|
||||
|
|
@ -53,7 +56,7 @@ pxl8_game_result pxl8_init(pxl8_game* game, i32 argc, char* argv[]) {
|
|||
|
||||
if (pack_mode) {
|
||||
pxl8_result result = pxl8_cart_pack(pack_input, pack_output);
|
||||
return (result == PXL8_OK) ? PXL8_GAME_SUCCESS : PXL8_GAME_FAILURE;
|
||||
return (result == PXL8_OK) ? PXL8_SUCCESS : PXL8_FAILURE;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -63,29 +66,29 @@ pxl8_game_result pxl8_init(pxl8_game* game, i32 argc, char* argv[]) {
|
|||
|
||||
pxl8_info("Starting up");
|
||||
|
||||
game->gfx = pxl8_gfx_create(game->hal, game->color_mode, game->resolution, "pxl8", 1280, 720);
|
||||
game->gfx = pxl8_gfx_create(system->hal, game->color_mode, game->resolution, "pxl8", 1280, 720);
|
||||
if (!game->gfx) {
|
||||
pxl8_error("Failed to create graphics context");
|
||||
return PXL8_GAME_FAILURE;
|
||||
return PXL8_FAILURE;
|
||||
}
|
||||
|
||||
if (pxl8_gfx_load_font_atlas(game->gfx) != PXL8_OK) {
|
||||
pxl8_error("Failed to load font atlas");
|
||||
return PXL8_GAME_FAILURE;
|
||||
return PXL8_FAILURE;
|
||||
}
|
||||
|
||||
game->ui = pxl8_ui_create(game->gfx);
|
||||
if (!game->ui) {
|
||||
pxl8_error("Failed to create UI");
|
||||
pxl8_gfx_destroy(game->gfx);
|
||||
return PXL8_GAME_FAILURE;
|
||||
return PXL8_FAILURE;
|
||||
}
|
||||
|
||||
game->script = pxl8_script_create();
|
||||
if (!game->script) {
|
||||
pxl8_error("Failed to initialize scripting: %s", pxl8_script_get_last_error(game->script));
|
||||
pxl8_gfx_destroy(game->gfx);
|
||||
return PXL8_GAME_FAILURE;
|
||||
return PXL8_FAILURE;
|
||||
}
|
||||
|
||||
const char* cart_path = script_arg ? script_arg : "demo";
|
||||
|
|
@ -99,7 +102,7 @@ pxl8_game_result pxl8_init(pxl8_game* game, i32 argc, char* argv[]) {
|
|||
game->cart = pxl8_cart_create();
|
||||
if (!game->cart) {
|
||||
pxl8_error("Failed to create cart");
|
||||
return PXL8_GAME_FAILURE;
|
||||
return PXL8_FAILURE;
|
||||
}
|
||||
if (pxl8_cart_load(game->cart, cart_path) == PXL8_OK) {
|
||||
pxl8_script_set_cart_path(game->script, pxl8_cart_get_base_path(game->cart), original_cwd);
|
||||
|
|
@ -108,7 +111,7 @@ pxl8_game_result pxl8_init(pxl8_game* game, i32 argc, char* argv[]) {
|
|||
pxl8_info("Loaded cart: %s", pxl8_cart_get_name(game->cart));
|
||||
} else {
|
||||
pxl8_error("Failed to load cart: %s", cart_path);
|
||||
return PXL8_GAME_FAILURE;
|
||||
return PXL8_FAILURE;
|
||||
}
|
||||
free(original_cwd);
|
||||
} else if (script_arg) {
|
||||
|
|
@ -129,19 +132,21 @@ pxl8_game_result pxl8_init(pxl8_game* game, i32 argc, char* argv[]) {
|
|||
}
|
||||
}
|
||||
|
||||
game->last_time = game->hal->get_ticks();
|
||||
game->last_time = pxl8_get_ticks(system);
|
||||
game->running = true;
|
||||
|
||||
|
||||
return PXL8_GAME_CONTINUE;
|
||||
return PXL8_CONTINUE;
|
||||
}
|
||||
|
||||
pxl8_game_result pxl8_update(pxl8_game* game) {
|
||||
if (!game) {
|
||||
return PXL8_GAME_FAILURE;
|
||||
pxl8_result pxl8_update(pxl8* system) {
|
||||
if (!system) {
|
||||
return PXL8_FAILURE;
|
||||
}
|
||||
|
||||
u64 current_time = game->hal->get_ticks();
|
||||
pxl8_game* game = &system->game;
|
||||
|
||||
u64 current_time = pxl8_get_ticks(system);
|
||||
f32 dt = (f32)(current_time - game->last_time) / 1000000000.0f;
|
||||
|
||||
game->last_time = current_time;
|
||||
|
|
@ -234,14 +239,16 @@ pxl8_game_result pxl8_update(pxl8_game* game) {
|
|||
pxl8_script_call_function_f32(game->script, "update", dt);
|
||||
}
|
||||
|
||||
return PXL8_GAME_CONTINUE;
|
||||
return PXL8_CONTINUE;
|
||||
}
|
||||
|
||||
pxl8_game_result pxl8_frame(pxl8_game* game) {
|
||||
if (!game) {
|
||||
return PXL8_GAME_FAILURE;
|
||||
pxl8_result pxl8_frame(pxl8* system) {
|
||||
if (!system) {
|
||||
return PXL8_FAILURE;
|
||||
}
|
||||
|
||||
pxl8_game* game = &system->game;
|
||||
|
||||
pxl8_bounds bounds = pxl8_gfx_get_bounds(game->gfx);
|
||||
|
||||
if (game->script_loaded) {
|
||||
|
|
@ -282,11 +289,13 @@ pxl8_game_result pxl8_frame(pxl8_game* game) {
|
|||
game->input.mouse_wheel_x = 0;
|
||||
game->input.mouse_wheel_y = 0;
|
||||
|
||||
return game->running ? PXL8_GAME_CONTINUE : PXL8_GAME_SUCCESS;
|
||||
return game->running ? PXL8_CONTINUE : PXL8_SUCCESS;
|
||||
}
|
||||
|
||||
void pxl8_quit(pxl8_game* game) {
|
||||
if (!game) return;
|
||||
void pxl8_quit(pxl8* system) {
|
||||
if (!system) return;
|
||||
|
||||
pxl8_game* game = &system->game;
|
||||
|
||||
if (game->repl_mode && game->repl) {
|
||||
fprintf(stderr, "\r\033[K");
|
||||
|
|
@ -307,3 +316,11 @@ void pxl8_quit(pxl8_game* game) {
|
|||
pxl8_script_destroy(game->script);
|
||||
if (game->ui) pxl8_ui_destroy(game->ui);
|
||||
}
|
||||
|
||||
u64 pxl8_get_ticks(const pxl8* system) {
|
||||
if (!system || !system->hal) {
|
||||
pxl8_error("Invalid pxl8 system");
|
||||
return 0;
|
||||
}
|
||||
return system->hal->get_ticks();
|
||||
}
|
||||
|
|
|
|||
24
src/pxl8.h
Normal file
24
src/pxl8.h
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
#pragma once
|
||||
|
||||
#include "pxl8_game.h"
|
||||
#include "pxl8_hal.h"
|
||||
#include "pxl8_types.h"
|
||||
|
||||
typedef struct pxl8 {
|
||||
const pxl8_hal* hal;
|
||||
pxl8_game game;
|
||||
} pxl8;
|
||||
|
||||
typedef struct pxl8_callbacks {
|
||||
pxl8_result (*init)(pxl8* system, i32 argc, char* argv[]);
|
||||
pxl8_result (*update)(pxl8* system);
|
||||
pxl8_result (*frame)(pxl8* system);
|
||||
void (*quit)(pxl8* system);
|
||||
} pxl8_callbacks;
|
||||
|
||||
pxl8_result pxl8_init(pxl8* system, i32 argc, char* argv[]);
|
||||
pxl8_result pxl8_update(pxl8* system);
|
||||
pxl8_result pxl8_frame(pxl8* system);
|
||||
void pxl8_quit(pxl8* system);
|
||||
|
||||
u64 pxl8_get_ticks(const pxl8* system);
|
||||
|
|
@ -302,7 +302,8 @@ void pxl8_bsp_destroy(pxl8_bsp* bsp) {
|
|||
}
|
||||
|
||||
i32 pxl8_bsp_find_leaf(const pxl8_bsp* bsp, pxl8_vec3 pos) {
|
||||
if (!bsp || bsp->num_nodes == 0) return -1;
|
||||
if (!bsp) return -1;
|
||||
if (bsp->num_nodes == 0) return 0;
|
||||
|
||||
i32 node_id = 0;
|
||||
|
||||
|
|
@ -334,42 +335,7 @@ bool pxl8_bsp_is_leaf_visible(const pxl8_bsp* bsp, i32 leaf_from, i32 leaf_to) {
|
|||
|
||||
static inline bool face_in_frustum(const pxl8_bsp* bsp, u32 face_id, const pxl8_frustum* frustum) {
|
||||
const pxl8_bsp_face* face = &bsp->faces[face_id];
|
||||
|
||||
f32 min_x = 1e30f, min_y = 1e30f, min_z = 1e30f;
|
||||
f32 max_x = -1e30f, max_y = -1e30f, max_z = -1e30f;
|
||||
|
||||
for (u32 i = 0; i < face->num_edges; 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;
|
||||
|
||||
pxl8_vec3 v = bsp->vertices[vert_idx].position;
|
||||
|
||||
if (v.x < min_x) min_x = v.x;
|
||||
if (v.x > max_x) max_x = v.x;
|
||||
if (v.y < min_y) min_y = v.y;
|
||||
if (v.y > max_y) max_y = v.y;
|
||||
if (v.z < min_z) min_z = v.z;
|
||||
if (v.z > max_z) max_z = v.z;
|
||||
}
|
||||
|
||||
pxl8_vec3 aabb_min = {min_x, min_y, min_z};
|
||||
pxl8_vec3 aabb_max = {max_x, max_y, max_z};
|
||||
|
||||
return pxl8_frustum_test_aabb(frustum, aabb_min, aabb_max);
|
||||
return pxl8_frustum_test_aabb(frustum, face->bounds_min, face->bounds_max);
|
||||
}
|
||||
|
||||
void pxl8_bsp_render_face(pxl8_gfx* gfx, const pxl8_bsp* bsp, u32 face_id, u32 texture_id) {
|
||||
|
|
@ -449,23 +415,41 @@ void pxl8_bsp_render_solid(
|
|||
) {
|
||||
if (!gfx || !bsp || bsp->num_faces == 0) return;
|
||||
|
||||
static bool first_call = true;
|
||||
static u32 frame_count = 0;
|
||||
frame_count++;
|
||||
|
||||
if (first_call) {
|
||||
pxl8_debug("BSP render solid FIRST CALL - frame %u", frame_count);
|
||||
first_call = false;
|
||||
}
|
||||
|
||||
const pxl8_frustum* frustum = pxl8_3d_get_frustum(gfx);
|
||||
if (!frustum) return;
|
||||
|
||||
pxl8_debug("Finding camera leaf START");
|
||||
i32 camera_leaf = pxl8_bsp_find_leaf(bsp, camera_pos);
|
||||
pxl8_debug("Finding camera leaf DONE - leaf: %d", camera_leaf);
|
||||
|
||||
static u8* rendered_faces = NULL;
|
||||
static u32 rendered_faces_capacity = 0;
|
||||
|
||||
if (rendered_faces_capacity < bsp->num_faces) {
|
||||
pxl8_debug("Face buffer realloc START - %u bytes", bsp->num_faces);
|
||||
rendered_faces = realloc(rendered_faces, bsp->num_faces);
|
||||
if (!rendered_faces) return;
|
||||
rendered_faces_capacity = bsp->num_faces;
|
||||
pxl8_debug("Allocated face tracking buffer: %u bytes", bsp->num_faces);
|
||||
pxl8_debug("Face buffer realloc DONE");
|
||||
}
|
||||
|
||||
memset(rendered_faces, 0, bsp->num_faces);
|
||||
|
||||
const f32 max_draw_distance = 768.0f;
|
||||
const f32 max_draw_distance_sq = max_draw_distance * max_draw_distance;
|
||||
|
||||
pxl8_debug("Leaf visibility check START - %u leafs", bsp->num_leafs);
|
||||
u32 visible_face_count = 0;
|
||||
|
||||
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;
|
||||
|
||||
|
|
@ -479,12 +463,32 @@ void pxl8_bsp_render_solid(
|
|||
if (face_id >= bsp->num_faces) continue;
|
||||
|
||||
if (rendered_faces[face_id]) continue;
|
||||
|
||||
const pxl8_bsp_face* face = &bsp->faces[face_id];
|
||||
|
||||
pxl8_vec3 face_center = {
|
||||
(face->bounds_min.x + face->bounds_max.x) * 0.5f,
|
||||
(face->bounds_min.y + face->bounds_max.y) * 0.5f,
|
||||
(face->bounds_min.z + face->bounds_max.z) * 0.5f
|
||||
};
|
||||
|
||||
f32 dx = face_center.x - camera_pos.x;
|
||||
f32 dy = face_center.y - camera_pos.y;
|
||||
f32 dz = face_center.z - camera_pos.z;
|
||||
f32 dist_sq = dx * dx + dy * dy + dz * dz;
|
||||
|
||||
if (dist_sq > max_draw_distance_sq) {
|
||||
continue;
|
||||
}
|
||||
|
||||
rendered_faces[face_id] = 1;
|
||||
visible_face_count++;
|
||||
|
||||
pxl8_bsp_render_face(gfx, bsp, face_id, texture_id);
|
||||
}
|
||||
}
|
||||
|
||||
pxl8_debug("Leaf visibility check DONE - rendered %u faces", visible_face_count);
|
||||
}
|
||||
|
||||
void pxl8_bsp_render_wireframe(
|
||||
|
|
|
|||
|
|
@ -37,6 +37,9 @@ typedef struct pxl8_bsp_face {
|
|||
|
||||
u8 styles[4];
|
||||
u16 texinfo_id;
|
||||
|
||||
pxl8_vec3 bounds_min;
|
||||
pxl8_vec3 bounds_max;
|
||||
} pxl8_bsp_face;
|
||||
|
||||
typedef struct pxl8_bsp_node {
|
||||
|
|
|
|||
|
|
@ -7,15 +7,7 @@
|
|||
#include "pxl8_types.h"
|
||||
#include "pxl8_ui.h"
|
||||
|
||||
typedef enum pxl8_game_result {
|
||||
PXL8_GAME_CONTINUE,
|
||||
PXL8_GAME_SUCCESS,
|
||||
PXL8_GAME_FAILURE
|
||||
} pxl8_game_result;
|
||||
|
||||
typedef struct pxl8_game {
|
||||
const pxl8_hal* hal;
|
||||
|
||||
pxl8_cart* cart;
|
||||
pxl8_color_mode color_mode;
|
||||
pxl8_gfx* gfx;
|
||||
|
|
@ -40,15 +32,3 @@ typedef struct pxl8_game {
|
|||
pxl8_input_state input;
|
||||
pxl8_script_repl* repl;
|
||||
} pxl8_game;
|
||||
|
||||
typedef struct pxl8_game_callbacks {
|
||||
pxl8_game_result (*init)(pxl8_game* game, i32 argc, char* argv[]);
|
||||
pxl8_game_result (*update)(pxl8_game* game);
|
||||
pxl8_game_result (*frame)(pxl8_game* game);
|
||||
void (*quit)(pxl8_game* game);
|
||||
} pxl8_game_callbacks;
|
||||
|
||||
pxl8_game_result pxl8_init(pxl8_game* game, i32 argc, char* argv[]);
|
||||
pxl8_game_result pxl8_update(pxl8_game* game);
|
||||
pxl8_game_result pxl8_frame(pxl8_game* game);
|
||||
void pxl8_quit(pxl8_game* game);
|
||||
|
|
|
|||
|
|
@ -810,6 +810,14 @@ void pxl8_3d_clear_zbuffer(pxl8_gfx* gfx) {
|
|||
i32 count = gfx->zbuffer_width * gfx->zbuffer_height;
|
||||
const f32 far_z = 1e30f;
|
||||
|
||||
static u32 clear_count = 0;
|
||||
f32 sample_before = gfx->zbuffer[count / 2];
|
||||
|
||||
if ((clear_count++ % 240) == 0) {
|
||||
pxl8_debug("Z-buffer clear #%u: %d pixels, sample_before=%.0f, far_z=%.0f",
|
||||
clear_count, count, sample_before, far_z);
|
||||
}
|
||||
|
||||
#if defined(PXL8_SIMD_NEON)
|
||||
float32x4_t far_vec = vdupq_n_f32(far_z);
|
||||
i32 i = 0;
|
||||
|
|
@ -833,6 +841,11 @@ void pxl8_3d_clear_zbuffer(pxl8_gfx* gfx) {
|
|||
gfx->zbuffer[i] = far_z;
|
||||
}
|
||||
#endif
|
||||
|
||||
if ((clear_count % 240) == 0) {
|
||||
f32 sample_after = gfx->zbuffer[count / 2];
|
||||
pxl8_debug("Z-buffer verified: sample_after=%.0f (should be %.0f)", sample_after, far_z);
|
||||
}
|
||||
}
|
||||
|
||||
void pxl8_3d_set_backface_culling(pxl8_gfx* gfx, bool culling) {
|
||||
|
|
@ -1093,7 +1106,7 @@ static inline void pxl8_fill_scanline_textured(
|
|||
if ((gfx->color_mode == PXL8_COLOR_MODE_HICOLOR && (color & 0xFF000000)) ||
|
||||
(gfx->color_mode != PXL8_COLOR_MODE_HICOLOR && color != 0)) {
|
||||
gfx->zbuffer[idx] = z;
|
||||
pxl8_pixel(gfx, x, y, color);
|
||||
pxl8_pixel_unchecked(gfx, x, y, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1137,7 +1150,7 @@ static inline void pxl8_fill_scanline_textured(
|
|||
if ((gfx->color_mode == PXL8_COLOR_MODE_HICOLOR && (color & 0xFF000000)) ||
|
||||
(gfx->color_mode != PXL8_COLOR_MODE_HICOLOR && color != 0)) {
|
||||
gfx->zbuffer[idx] = z;
|
||||
pxl8_pixel(gfx, x, y, color);
|
||||
pxl8_pixel_unchecked(gfx, x, y, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,7 +60,9 @@ static inline i32 pxl8_read_i32(pxl8_stream* stream) {
|
|||
|
||||
static inline f32 pxl8_read_f32(pxl8_stream* stream) {
|
||||
u32 val = pxl8_read_u32(stream);
|
||||
return *(f32*)&val;
|
||||
f32 result;
|
||||
memcpy(&result, &val, sizeof(f32));
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline void pxl8_read_bytes(pxl8_stream* stream, void* dest, u32 count) {
|
||||
|
|
|
|||
|
|
@ -91,6 +91,15 @@ static void calculate_texture_axes(const pxl8_vec3 normal, pxl8_vec3* u_axis, px
|
|||
}
|
||||
}
|
||||
|
||||
static inline void compute_face_bounds(pxl8_bsp_face* face, const pxl8_bsp_vertex* verts, u32 v0, u32 v1, u32 v2, u32 v3) {
|
||||
face->bounds_min.x = fminf(fminf(verts[v0].position.x, verts[v1].position.x), fminf(verts[v2].position.x, verts[v3].position.x));
|
||||
face->bounds_min.y = fminf(fminf(verts[v0].position.y, verts[v1].position.y), fminf(verts[v2].position.y, verts[v3].position.y));
|
||||
face->bounds_min.z = fminf(fminf(verts[v0].position.z, verts[v1].position.z), fminf(verts[v2].position.z, verts[v3].position.z));
|
||||
face->bounds_max.x = fmaxf(fmaxf(verts[v0].position.x, verts[v1].position.x), fmaxf(verts[v2].position.x, verts[v3].position.x));
|
||||
face->bounds_max.y = fmaxf(fmaxf(verts[v0].position.y, verts[v1].position.y), fmaxf(verts[v2].position.y, verts[v3].position.y));
|
||||
face->bounds_max.z = fmaxf(fmaxf(verts[v0].position.z, verts[v1].position.z), fmaxf(verts[v2].position.z, verts[v3].position.z));
|
||||
}
|
||||
|
||||
static void cave_grid_initialize(cave_grid* grid, f32 density) {
|
||||
for (i32 y = 0; y < grid->height; y++) {
|
||||
for (i32 x = 0; x < grid->width; x++) {
|
||||
|
|
@ -189,6 +198,8 @@ static pxl8_result cave_to_bsp(pxl8_bsp* bsp, const cave_grid* grid) {
|
|||
bsp->surfedges[edge_idx + i] = edge_idx + i;
|
||||
}
|
||||
|
||||
compute_face_bounds(&bsp->faces[face_idx], bsp->vertices, vert_idx, vert_idx + 1, vert_idx + 2, vert_idx + 3);
|
||||
|
||||
vert_idx += 4;
|
||||
edge_idx += 4;
|
||||
face_idx++;
|
||||
|
|
@ -220,6 +231,8 @@ static pxl8_result cave_to_bsp(pxl8_bsp* bsp, const cave_grid* grid) {
|
|||
bsp->surfedges[edge_idx + i] = edge_idx + i;
|
||||
}
|
||||
|
||||
compute_face_bounds(&bsp->faces[face_idx], bsp->vertices, vert_idx, vert_idx + 1, vert_idx + 2, vert_idx + 3);
|
||||
|
||||
vert_idx += 4;
|
||||
edge_idx += 4;
|
||||
face_idx++;
|
||||
|
|
@ -251,6 +264,8 @@ static pxl8_result cave_to_bsp(pxl8_bsp* bsp, const cave_grid* grid) {
|
|||
bsp->surfedges[edge_idx + i] = edge_idx + i;
|
||||
}
|
||||
|
||||
compute_face_bounds(&bsp->faces[face_idx], bsp->vertices, vert_idx, vert_idx + 1, vert_idx + 2, vert_idx + 3);
|
||||
|
||||
vert_idx += 4;
|
||||
edge_idx += 4;
|
||||
face_idx++;
|
||||
|
|
@ -282,6 +297,8 @@ static pxl8_result cave_to_bsp(pxl8_bsp* bsp, const cave_grid* grid) {
|
|||
bsp->surfedges[edge_idx + i] = edge_idx + i;
|
||||
}
|
||||
|
||||
compute_face_bounds(&bsp->faces[face_idx], bsp->vertices, vert_idx, vert_idx + 1, vert_idx + 2, vert_idx + 3);
|
||||
|
||||
vert_idx += 4;
|
||||
edge_idx += 4;
|
||||
face_idx++;
|
||||
|
|
@ -321,6 +338,8 @@ static pxl8_result cave_to_bsp(pxl8_bsp* bsp, const cave_grid* grid) {
|
|||
bsp->surfedges[edge_idx + i] = edge_idx + i;
|
||||
}
|
||||
|
||||
compute_face_bounds(&bsp->faces[face_idx], bsp->vertices, vert_idx, vert_idx + 1, vert_idx + 2, vert_idx + 3);
|
||||
|
||||
vert_idx += 4;
|
||||
edge_idx += 4;
|
||||
face_idx++;
|
||||
|
|
@ -350,6 +369,8 @@ static pxl8_result cave_to_bsp(pxl8_bsp* bsp, const cave_grid* grid) {
|
|||
bsp->surfedges[edge_idx + i] = edge_idx + i;
|
||||
}
|
||||
|
||||
compute_face_bounds(&bsp->faces[face_idx], bsp->vertices, vert_idx, vert_idx + 1, vert_idx + 2, vert_idx + 3);
|
||||
|
||||
vert_idx += 4;
|
||||
edge_idx += 4;
|
||||
face_idx++;
|
||||
|
|
@ -440,12 +461,12 @@ void pxl8_procgen_tex(u8* buffer, const pxl8_procgen_tex_params* params) {
|
|||
i32 ix = (i32)((f32)x * params->scale);
|
||||
i32 iy = (i32)((f32)y * params->scale);
|
||||
|
||||
u32 block_hash = (ix * 374761393 + iy * 668265263) ^ params->seed;
|
||||
u32 block_hash = ((u32)ix * 374761393U + (u32)iy * 668265263U) ^ params->seed;
|
||||
block_hash ^= block_hash >> 13;
|
||||
block_hash ^= block_hash << 17;
|
||||
block_hash ^= block_hash >> 5;
|
||||
|
||||
u32 pixel_hash = (x * 1597334677 + y * 3812015801) ^ params->seed;
|
||||
u32 pixel_hash = ((u32)x * 1597334677U + (u32)y * 3812015801U) ^ params->seed;
|
||||
pixel_hash ^= pixel_hash >> 13;
|
||||
pixel_hash ^= pixel_hash << 17;
|
||||
pixel_hash ^= pixel_hash >> 5;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#include "pxl8_sdl3.h"
|
||||
#include "pxl8.h"
|
||||
#include "pxl8_atlas.h"
|
||||
#include "pxl8_game.h"
|
||||
#include "pxl8_macros.h"
|
||||
|
|
@ -238,56 +239,58 @@ SDL_AppResult SDL_AppInit(void** appstate, int argc, char* argv[]) {
|
|||
return SDL_APP_FAILURE;
|
||||
}
|
||||
|
||||
pxl8_game* game = (pxl8_game*)SDL_calloc(1, sizeof(pxl8_game));
|
||||
if (!game) {
|
||||
pxl8_error("Failed to allocate game instance");
|
||||
pxl8* system = (pxl8*)SDL_calloc(1, sizeof(pxl8));
|
||||
if (!system) {
|
||||
pxl8_error("Failed to allocate pxl8 instance");
|
||||
SDL_Quit();
|
||||
return SDL_APP_FAILURE;
|
||||
}
|
||||
|
||||
game->hal = &pxl8_hal_sdl3;
|
||||
system->hal = &pxl8_hal_sdl3;
|
||||
|
||||
pxl8_game_result result = pxl8_init(game, argc, argv);
|
||||
if (result != PXL8_GAME_CONTINUE) {
|
||||
SDL_free(game);
|
||||
pxl8_result result = pxl8_init(system, argc, argv);
|
||||
if (result != PXL8_CONTINUE) {
|
||||
SDL_free(system);
|
||||
SDL_Quit();
|
||||
return SDL_APP_FAILURE;
|
||||
}
|
||||
|
||||
*appstate = game;
|
||||
*appstate = system;
|
||||
return SDL_APP_CONTINUE;
|
||||
}
|
||||
|
||||
SDL_AppResult SDL_AppIterate(void* appstate) {
|
||||
pxl8_game* game = (pxl8_game*)appstate;
|
||||
pxl8* system = (pxl8*)appstate;
|
||||
|
||||
if (!game) {
|
||||
if (!system) {
|
||||
return SDL_APP_FAILURE;
|
||||
}
|
||||
|
||||
pxl8_game_result update_result = pxl8_update(game);
|
||||
if (update_result == PXL8_GAME_FAILURE) {
|
||||
pxl8_result update_result = pxl8_update(system);
|
||||
if (update_result == PXL8_FAILURE) {
|
||||
return SDL_APP_FAILURE;
|
||||
}
|
||||
if (update_result == PXL8_GAME_SUCCESS) {
|
||||
if (update_result == PXL8_SUCCESS) {
|
||||
return SDL_APP_SUCCESS;
|
||||
}
|
||||
|
||||
pxl8_game_result frame_result = pxl8_frame(game);
|
||||
if (frame_result == PXL8_GAME_FAILURE) {
|
||||
pxl8_result frame_result = pxl8_frame(system);
|
||||
if (frame_result == PXL8_FAILURE) {
|
||||
return SDL_APP_FAILURE;
|
||||
}
|
||||
|
||||
return (frame_result == PXL8_GAME_SUCCESS) ? SDL_APP_SUCCESS : SDL_APP_CONTINUE;
|
||||
return (frame_result == PXL8_SUCCESS) ? SDL_APP_SUCCESS : SDL_APP_CONTINUE;
|
||||
}
|
||||
|
||||
SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event) {
|
||||
pxl8_game* game = (pxl8_game*)appstate;
|
||||
pxl8* system = (pxl8*)appstate;
|
||||
|
||||
if (!game) {
|
||||
if (!system) {
|
||||
return SDL_APP_CONTINUE;
|
||||
}
|
||||
|
||||
pxl8_game* game = &system->game;
|
||||
|
||||
switch (event->type) {
|
||||
case SDL_EVENT_QUIT:
|
||||
game->running = false;
|
||||
|
|
@ -379,10 +382,10 @@ SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event) {
|
|||
void SDL_AppQuit(void* appstate, SDL_AppResult result) {
|
||||
(void)result;
|
||||
|
||||
pxl8_game* game = (pxl8_game*)appstate;
|
||||
if (game) {
|
||||
pxl8_quit(game);
|
||||
SDL_free(game);
|
||||
pxl8* system = (pxl8*)appstate;
|
||||
if (system) {
|
||||
pxl8_quit(system);
|
||||
SDL_free(system);
|
||||
}
|
||||
|
||||
SDL_Quit();
|
||||
|
|
|
|||
|
|
@ -40,6 +40,9 @@ typedef enum pxl8_resolution {
|
|||
|
||||
typedef enum pxl8_result {
|
||||
PXL8_OK = 0,
|
||||
PXL8_CONTINUE,
|
||||
PXL8_SUCCESS,
|
||||
PXL8_FAILURE,
|
||||
PXL8_ERROR_ASE_INVALID_FRAME_MAGIC,
|
||||
PXL8_ERROR_ASE_INVALID_MAGIC,
|
||||
PXL8_ERROR_ASE_MALFORMED_CHUNK,
|
||||
|
|
|
|||
|
|
@ -86,7 +86,15 @@ void pxl8_world_render(pxl8_world* world, pxl8_gfx* gfx, pxl8_vec3 camera_pos) {
|
|||
|
||||
static bool texture_generated = false;
|
||||
static u32 wall_texture_id = 0;
|
||||
static bool first_render = true;
|
||||
|
||||
if (first_render) {
|
||||
pxl8_debug("World render ENTRY - first render");
|
||||
first_render = false;
|
||||
}
|
||||
|
||||
if (!texture_generated) {
|
||||
pxl8_debug("Texture generation START");
|
||||
u8 texture_data[64 * 64];
|
||||
|
||||
pxl8_procgen_tex_params tex_params = {
|
||||
|
|
@ -100,11 +108,14 @@ void pxl8_world_render(pxl8_world* world, pxl8_gfx* gfx, pxl8_vec3 camera_pos) {
|
|||
};
|
||||
|
||||
pxl8_procgen_tex(texture_data, &tex_params);
|
||||
pxl8_debug("Texture generation DONE, creating GPU texture");
|
||||
|
||||
pxl8_result result = pxl8_gfx_create_texture(gfx, texture_data, 64, 64);
|
||||
if (result >= 0) {
|
||||
wall_texture_id = (u32)result;
|
||||
pxl8_debug("Uploading atlas START");
|
||||
pxl8_gfx_upload_atlas(gfx);
|
||||
pxl8_debug("Uploading atlas DONE");
|
||||
texture_generated = true;
|
||||
pxl8_info("Generated stone texture with ID: %u", wall_texture_id);
|
||||
} else {
|
||||
|
|
@ -112,11 +123,13 @@ void pxl8_world_render(pxl8_world* world, pxl8_gfx* gfx, pxl8_vec3 camera_pos) {
|
|||
}
|
||||
}
|
||||
|
||||
pxl8_debug("BSP render START");
|
||||
if (world->wireframe) {
|
||||
pxl8_bsp_render_wireframe(gfx, &world->bsp, camera_pos, world->wireframe_color);
|
||||
} else {
|
||||
pxl8_bsp_render_solid(gfx, &world->bsp, camera_pos, wall_texture_id);
|
||||
}
|
||||
pxl8_debug("BSP render DONE");
|
||||
}
|
||||
|
||||
void pxl8_world_unload(pxl8_world* world) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue