add debug code for rendering issues

This commit is contained in:
asrael 2025-11-10 01:42:19 -06:00
parent db0e47b6ad
commit 588176a645
12 changed files with 291 additions and 203 deletions

View file

@ -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,7 +33,11 @@
(pxl8.info "Generated procedural cave"))))
(fn update [dt]
(set fps-accumulator (+ fps-accumulator dt))
(let [clamped-dt (math.min dt 0.1)]
(when (> dt 0.05)
(pxl8.debug (.. "Large dt: " (string.format "%.3f" dt) "s")))
(set fps-accumulator (+ fps-accumulator clamped-dt))
(set fps-frame-count (+ fps-frame-count 1))
(when (>= fps-accumulator 0.25)
@ -52,30 +56,30 @@
right-z (- (math.sin cam-yaw))
cell-size 64
grid-min 0
grid-max (* 32 cell-size)]
grid-max (* 16 cell-size)]
(var moving false)
(var new-x cam-x)
(var new-z cam-z)
(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 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 "s")
(set new-x (- new-x (* forward-x move-speed dt)))
(set new-z (- new-z (* forward-z move-speed dt)))
(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 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 (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 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)
@ -84,24 +88,23 @@
(set cam-z new-z))
(when (or (pxl8.key_down "left") (pxl8.key_down "a"))
(set cam-yaw (+ cam-yaw (* turn-speed dt))))
(set cam-yaw (+ cam-yaw (* turn-speed clamped-dt))))
(when (or (pxl8.key_down "right") (pxl8.key_down "d"))
(set cam-yaw (- cam-yaw (* turn-speed dt))))
(set cam-yaw (- cam-yaw (* turn-speed clamped-dt))))
(when (pxl8.key_down "up")
(set cam-pitch (+ cam-pitch (* turn-speed dt)))
(set cam-pitch (+ cam-pitch (* turn-speed clamped-dt)))
(when (> cam-pitch 1.5) (set cam-pitch 1.5)))
(when (pxl8.key_down "down")
(set cam-pitch (- cam-pitch (* turn-speed dt)))
(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)))
(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))))))))
(set bob-time (+ (* bob-time 0.8) (* target-phase 0.2)))))))))
(fn frame []
(pxl8.clr 0)
@ -119,6 +122,7 @@
(string.format "%.0f" cam-z)) 10 25 12)
(pxl8.clear_zbuffer)
(pxl8.set_backface_culling true)
(pxl8.set_wireframe false)
@ -134,7 +138,8 @@
(pxl8.set_model (pxl8.mat4_identity))
(pxl8.set_affine_textures affine)
(pxl8.world_render world [cam-x eye-y cam-z]))
(pxl8.world_render world [cam-x eye-y cam-z])))
(let [new-state (debug-ui.render {:show-debug-ui show-debug-ui
:fps fps
@ -144,7 +149,7 @@
: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)))))
(when (not= new-state.affine nil) (set affine new-state.affine))))
{:init init
:update update

View file

@ -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
View 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);

View file

@ -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(

View file

@ -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 {

View file

@ -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);

View file

@ -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);
}
}
}

View file

@ -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) {

View file

@ -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;

View file

@ -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();

View file

@ -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,

View file

@ -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) {