diff --git a/demo/cart.fnl b/demo/cart.fnl index 235cffe..1c3d431 100644 --- a/demo/cart.fnl +++ b/demo/cart.fnl @@ -1,4 +1,3 @@ {:title "pxl8 demo" - :pixel-mode "indexed" :resolution "640x360" :window-size [1280 720]} diff --git a/demo/mod/first_person3d.fnl b/demo/mod/first_person3d.fnl index cc10e25..3b2afa6 100644 --- a/demo/mod/first_person3d.fnl +++ b/demo/mod/first_person3d.fnl @@ -18,6 +18,10 @@ (local SIM_FLAG_GROUNDED 4) +(local door-spawn-x 860) +(local door-spawn-z 416) +(local door-spawn-yaw 1.5708) + (local sim-cfg (pxl8.sim_config {:move_speed 150 :gravity 600 :jump_velocity 180 @@ -48,7 +52,7 @@ (var light-time 0) (var glows nil) (var lights nil) -(var bsp-materials-setup false) +(var materials-for-chunk 0) (var network nil) (var portal-cooldown 0) (var real-time 0) @@ -136,17 +140,25 @@ (setup-textures 1)) (fn setup-materials [] - (when (and world (not bsp-materials-setup) floor-tex trim-tex wall-tex) + (when (not world) (lua "return")) + (when (not network) (lua "return")) + (let [net-chunk (network:chunk_id)] + (when (or (= net-chunk 0) (= materials-for-chunk net-chunk)) (lua "return")) + (when (not= current-bsp-id net-chunk) + (setup-textures net-chunk)) + (when (not floor-tex) (lua "return")) + (when (not wall-tex) (lua "return")) (let [chunk (world:active_chunk)] - (when (and chunk (chunk:ready)) - (let [floor-mat (pxl8.create_material {:texture floor-tex :lighting true :double_sided true}) - trim-mat (pxl8.create_material {:texture trim-tex :lighting true :double_sided true}) - wall-mat (pxl8.create_material {:texture wall-tex :lighting true :double_sided true})] - (world:set_bsp_material 0 floor-mat) - (world:set_bsp_material 1 wall-mat) - (world:set_bsp_material 3 trim-mat) - (entities.setup-lighting (chunk:bsp) 2) - (set bsp-materials-setup true)))))) + (when (not chunk) (lua "return")) + (when (not (chunk:ready)) (lua "return")) + (let [floor-mat (pxl8.create_material {:texture floor-tex :lighting true :double_sided true}) + trim-mat (pxl8.create_material {:texture trim-tex :lighting true :double_sided true}) + wall-mat (pxl8.create_material {:texture wall-tex :lighting true :double_sided true})] + (world:set_bsp_material 0 floor-mat) + (world:set_bsp_material 1 wall-mat) + (world:set_bsp_material 3 trim-mat) + (entities.setup-lighting (chunk:bsp) 2) + (set materials-for-chunk net-chunk))))) (fn sample-input [] (when (pxl8.key_pressed "`") @@ -187,27 +199,31 @@ (if (= current-id 1) (do (pxl8.info "Door: BSP 1 -> BSP 2") - (network:enter_scene 1 2 416 0 416) - (world:init_local_player 416 0 416) - (set cam-x 416) + (network:enter_scene 1 2 door-spawn-x 0 door-spawn-z) + (world:init_local_player door-spawn-x 0 door-spawn-z) + (world:set_look door-spawn-yaw 0) + (set cam-x door-spawn-x) (set cam-y 0) - (set cam-z 416) - (set smooth-cam-x 416) - (set smooth-cam-z 416) - (set bsp-materials-setup false) + (set cam-z door-spawn-z) + (set cam-yaw door-spawn-yaw) + (set cam-pitch 0) + (set smooth-cam-x door-spawn-x) + (set smooth-cam-z door-spawn-z) (setup-textures 2) (set portal-cooldown 2.0)) (= current-id 2) (do (pxl8.info "Door: BSP 2 -> BSP 1") - (network:enter_scene 1 1 416 0 416) - (world:init_local_player 416 0 416) - (set cam-x 416) + (network:enter_scene 1 1 door-spawn-x 0 door-spawn-z) + (world:init_local_player door-spawn-x 0 door-spawn-z) + (world:set_look door-spawn-yaw 0) + (set cam-x door-spawn-x) (set cam-y 0) - (set cam-z 416) - (set smooth-cam-x 416) - (set smooth-cam-z 416) - (set bsp-materials-setup false) + (set cam-z door-spawn-z) + (set cam-yaw door-spawn-yaw) + (set cam-pitch 0) + (set smooth-cam-x door-spawn-x) + (set smooth-cam-z door-spawn-z) (setup-textures 1) (set portal-cooldown 2.0))))))) @@ -282,7 +298,8 @@ r2 (* 0.04 (math.sin (+ (* real-time 3.2) phase))) light-radius (* 150 (+ 0.95 r1 r2))] (lights:clear) - (lights:add light-x light-y light-z 2 light-intensity light-radius) + (when (= current-bsp-id 1) + (lights:add light-x light-y light-z 2 light-intensity light-radius)) (pxl8.push_target) (pxl8.begin_frame_3d camera lights { @@ -300,7 +317,7 @@ (pxl8.set_wireframe (menu.is-wireframe)) (world:render [smooth-cam-x eye-y smooth-cam-z]) - (when chunk + (when (and chunk (= current-bsp-id 1)) (entities.render-fireball light-x light-y light-z (menu.is-wireframe))) (entities.render-door (menu.is-wireframe) 0) diff --git a/pxl8d/src/main.rs b/pxl8d/src/main.rs index e626355..bbcb4fb 100644 --- a/pxl8d/src/main.rs +++ b/pxl8d/src/main.rs @@ -174,6 +174,7 @@ pub extern "C" fn main(_argc: i32, _argv: *const *const u8) -> i32 { if let Some(pid) = player_id { if let Some(_player) = sim.get_player_position(pid) { + let mut burst = false; while let Some(chunk_id) = client_chunks.next_pending() { match chunk_id { ChunkId::Bsp(id) => { @@ -182,13 +183,15 @@ pub extern "C" fn main(_argc: i32, _argv: *const *const u8) -> i32 { let msgs = bsp_to_messages(bsp, id, chunk.version()); client_chunks.queue_messages(msgs); client_chunks.mark_sent(chunk_id, chunk.version()); + burst = true; } } } } } - for _ in 0..8 { + let send_limit = if burst { 256 } else { 8 }; + for _ in 0..send_limit { if let Some(msg) = client_chunks.next_message() { transport.send_chunk(&msg, sequence); sequence = sequence.wrapping_add(1); diff --git a/pxl8d/src/procgen.rs b/pxl8d/src/procgen.rs index 0f0f611..6be0cb9 100644 --- a/pxl8d/src/procgen.rs +++ b/pxl8d/src/procgen.rs @@ -169,7 +169,15 @@ fn build_bsp_node_grid(ctx: &mut BspBuildContext, x0: i32, y0: i32, x1: i32, y1: let plane_idx = ctx.plane_offset; ctx.plane_offset += 1; - if depth % 2 == 0 { + let split_x = if x1 - x0 <= 1 { + false + } else if y1 - y0 <= 1 { + true + } else { + depth % 2 == 0 + }; + + if split_x { let mid_x = (x0 + x1) / 2; let split_pos = mid_x as f32 * CELL_SIZE; @@ -479,6 +487,16 @@ fn compute_vertex_ao(bsp: &BspBuilder, pos: Vec3, normal: Vec3) -> f32 { continue; } + let cx = offset_pos.x.max(face.aabb_min.x).min(face.aabb_max.x); + let cy = offset_pos.y.max(face.aabb_min.y).min(face.aabb_max.y); + let cz = offset_pos.z.max(face.aabb_min.z).min(face.aabb_max.z); + let dx = offset_pos.x - cx; + let dy = offset_pos.y - cy; + let dz = offset_pos.z - cz; + if dx * dx + dy * dy + dz * dz > AO_RAY_LENGTH * AO_RAY_LENGTH { + continue; + } + let mut verts = [Vec3::new(0.0, 0.0, 0.0); 4]; let mut num_verts = 0usize; diff --git a/src/asset/pxl8_cart.c b/src/asset/pxl8_cart.c index 9f4131e..45be3fc 100644 --- a/src/asset/pxl8_cart.c +++ b/src/asset/pxl8_cart.c @@ -49,7 +49,6 @@ struct pxl8_cart { char* title; pxl8_resolution resolution; pxl8_size window_size; - pxl8_pixel_mode pixel_mode; bool is_folder; bool is_mounted; }; @@ -156,7 +155,6 @@ pxl8_cart* pxl8_cart_create(void) { if (cart) { cart->resolution = PXL8_RESOLUTION_640x360; cart->window_size = (pxl8_size){1280, 720}; - cart->pixel_mode = PXL8_PIXEL_INDEXED; } return cart; } @@ -364,14 +362,6 @@ void pxl8_cart_set_window_size(pxl8_cart* cart, pxl8_size size) { if (cart) cart->window_size = size; } -pxl8_pixel_mode pxl8_cart_get_pixel_mode(const pxl8_cart* cart) { - return cart ? cart->pixel_mode : PXL8_PIXEL_INDEXED; -} - -void pxl8_cart_set_pixel_mode(pxl8_cart* cart, pxl8_pixel_mode mode) { - if (cart) cart->pixel_mode = mode; -} - bool pxl8_cart_is_packed(const pxl8_cart* cart) { return cart && !cart->is_folder; } diff --git a/src/asset/pxl8_cart.h b/src/asset/pxl8_cart.h index 9384192..e81b406 100644 --- a/src/asset/pxl8_cart.h +++ b/src/asset/pxl8_cart.h @@ -25,11 +25,9 @@ const char* pxl8_cart_get_base_path(const pxl8_cart* cart); const char* pxl8_cart_get_title(const pxl8_cart* cart); pxl8_resolution pxl8_cart_get_resolution(const pxl8_cart* cart); pxl8_size pxl8_cart_get_window_size(const pxl8_cart* cart); -pxl8_pixel_mode pxl8_cart_get_pixel_mode(const pxl8_cart* cart); void pxl8_cart_set_title(pxl8_cart* cart, const char* title); void pxl8_cart_set_resolution(pxl8_cart* cart, pxl8_resolution resolution); void pxl8_cart_set_window_size(pxl8_cart* cart, pxl8_size size); -void pxl8_cart_set_pixel_mode(pxl8_cart* cart, pxl8_pixel_mode mode); bool pxl8_cart_is_packed(const pxl8_cart* cart); bool pxl8_cart_has_embedded(const char* exe_path); diff --git a/src/core/pxl8.c b/src/core/pxl8.c index 5d9d794..3ae384c 100644 --- a/src/core/pxl8.c +++ b/src/core/pxl8.c @@ -239,7 +239,6 @@ pxl8_result pxl8_init(pxl8* sys, i32 argc, char* argv[]) { const char* window_title = pxl8_cart_get_title(sys->cart); if (!window_title) window_title = "pxl8"; pxl8_resolution resolution = pxl8_cart_get_resolution(sys->cart); - pxl8_pixel_mode pixel_mode = pxl8_cart_get_pixel_mode(sys->cart); pxl8_size window_size = pxl8_cart_get_window_size(sys->cart); pxl8_size render_size = pxl8_get_resolution_dimensions(resolution); @@ -249,7 +248,7 @@ pxl8_result pxl8_init(pxl8* sys, i32 argc, char* argv[]) { return PXL8_ERROR_INITIALIZATION_FAILED; } - game->gfx = pxl8_gfx_create(sys->hal, sys->platform_data, pixel_mode, resolution); + game->gfx = pxl8_gfx_create(sys->hal, sys->platform_data, resolution); if (!game->gfx) { pxl8_error("failed to create graphics context"); return PXL8_ERROR_INITIALIZATION_FAILED; diff --git a/src/core/pxl8_types.h b/src/core/pxl8_types.h index 761afea..83c4122 100644 --- a/src/core/pxl8_types.h +++ b/src/core/pxl8_types.h @@ -31,12 +31,6 @@ typedef __int128_t i128; typedef __uint128_t u128; #endif -typedef enum pxl8_pixel_mode { - PXL8_PIXEL_INDEXED = 1, - PXL8_PIXEL_HICOLOR = 2, - PXL8_PIXEL_RGBA = 4, -} pxl8_pixel_mode; - typedef enum pxl8_cursor { PXL8_CURSOR_ARROW, PXL8_CURSOR_HAND diff --git a/src/gfx/pxl8_atlas.c b/src/gfx/pxl8_atlas.c index 910dba6..3811699 100644 --- a/src/gfx/pxl8_atlas.c +++ b/src/gfx/pxl8_atlas.c @@ -1,11 +1,8 @@ #include "pxl8_atlas.h" #include -#include -#include #include -#include "pxl8_color.h" #include "pxl8_log.h" #include "pxl8_mem.h" @@ -144,15 +141,14 @@ static void pxl8_skyline_compact(pxl8_skyline* skyline) { } } -pxl8_atlas* pxl8_atlas_create(u32 width, u32 height, pxl8_pixel_mode pixel_mode) { +pxl8_atlas* pxl8_atlas_create(u32 width, u32 height) { pxl8_atlas* atlas = (pxl8_atlas*)pxl8_calloc(1, sizeof(pxl8_atlas)); if (!atlas) return NULL; atlas->height = height; atlas->width = width; - i32 bytes_per_pixel = pxl8_bytes_per_pixel(pixel_mode); - atlas->pixels = (u8*)pxl8_calloc(width * height, bytes_per_pixel); + atlas->pixels = (u8*)pxl8_calloc(width * height, 1); if (!atlas->pixels) { pxl8_free(atlas); return NULL; @@ -226,14 +222,13 @@ void pxl8_atlas_clear(pxl8_atlas* atlas, u32 preserve_count) { atlas->dirty = true; } -bool pxl8_atlas_expand(pxl8_atlas* atlas, pxl8_pixel_mode pixel_mode) { +bool pxl8_atlas_expand(pxl8_atlas* atlas) { if (!atlas || atlas->width >= 4096) return false; - i32 bytes_per_pixel = pxl8_bytes_per_pixel(pixel_mode); u32 new_size = atlas->width * 2; u32 old_width = atlas->width; - u8* new_pixels = (u8*)pxl8_calloc(new_size * new_size, bytes_per_pixel); + u8* new_pixels = (u8*)pxl8_calloc(new_size * new_size, 1); if (!new_pixels) return false; pxl8_skyline new_skyline; @@ -268,11 +263,7 @@ bool pxl8_atlas_expand(pxl8_atlas* atlas, pxl8_pixel_mode pixel_mode) { for (u32 x = 0; x < (u32)atlas->entries[i].w; x++) { u32 src_idx = (atlas->entries[i].y + y) * old_width + (atlas->entries[i].x + x); u32 dst_idx = (fit.pos.y + y) * new_size + (fit.pos.x + x); - if (bytes_per_pixel == 2) { - ((u16*)new_pixels)[dst_idx] = ((u16*)atlas->pixels)[src_idx]; - } else { - new_pixels[dst_idx] = atlas->pixels[src_idx]; - } + new_pixels[dst_idx] = atlas->pixels[src_idx]; } } @@ -304,15 +295,14 @@ u32 pxl8_atlas_add_texture( pxl8_atlas* atlas, const u8* pixels, u32 w, - u32 h, - pxl8_pixel_mode pixel_mode + u32 h ) { if (!atlas || !pixels) return UINT32_MAX; pxl8_skyline_fit fit = pxl8_skyline_find_position(&atlas->skyline, atlas->width, atlas->height, w, h); if (!fit.found) { - if (!pxl8_atlas_expand(atlas, pixel_mode)) { + if (!pxl8_atlas_expand(atlas)) { return UINT32_MAX; } @@ -347,17 +337,11 @@ u32 pxl8_atlas_add_texture( entry->h = h; entry->log2_w = pxl8_log2(w); - i32 bytes_per_pixel = pxl8_bytes_per_pixel(pixel_mode); for (u32 y = 0; y < h; y++) { for (u32 x = 0; x < w; x++) { u32 src_idx = y * w + x; u32 dst_idx = (fit.pos.y + y) * atlas->width + (fit.pos.x + x); - - if (bytes_per_pixel == 2) { - ((u16*)atlas->pixels)[dst_idx] = ((const u16*)pixels)[src_idx]; - } else { - atlas->pixels[dst_idx] = pixels[src_idx]; - } + atlas->pixels[dst_idx] = pixels[src_idx]; } } diff --git a/src/gfx/pxl8_atlas.h b/src/gfx/pxl8_atlas.h index 94e0a95..46d46e2 100644 --- a/src/gfx/pxl8_atlas.h +++ b/src/gfx/pxl8_atlas.h @@ -30,11 +30,11 @@ static inline u8 pxl8_log2(u32 v) { extern "C" { #endif -u32 pxl8_atlas_add_texture(pxl8_atlas* atlas, const u8* pixels, u32 w, u32 h, pxl8_pixel_mode pixel_mode); +u32 pxl8_atlas_add_texture(pxl8_atlas* atlas, const u8* pixels, u32 w, u32 h); void pxl8_atlas_clear(pxl8_atlas* atlas, u32 preserve_count); -pxl8_atlas* pxl8_atlas_create(u32 width, u32 height, pxl8_pixel_mode pixel_mode); +pxl8_atlas* pxl8_atlas_create(u32 width, u32 height); void pxl8_atlas_destroy(pxl8_atlas* atlas); -bool pxl8_atlas_expand(pxl8_atlas* atlas, pxl8_pixel_mode pixel_mode); +bool pxl8_atlas_expand(pxl8_atlas* atlas); const pxl8_atlas_entry* pxl8_atlas_get_entry(const pxl8_atlas* atlas, u32 id); u32 pxl8_atlas_get_entry_count(const pxl8_atlas* atlas); u32 pxl8_atlas_get_height(const pxl8_atlas* atlas); diff --git a/src/gfx/pxl8_blit.c b/src/gfx/pxl8_blit.c index 7409066..8fa3192 100644 --- a/src/gfx/pxl8_blit.c +++ b/src/gfx/pxl8_blit.c @@ -1,34 +1,7 @@ #include "pxl8_blit.h" -void pxl8_blit_hicolor(u16* fb, u32 fb_width, const u16* sprite, u32 atlas_width, - i32 x, i32 y, u32 w, u32 h) { - u16* dest_base = fb + y * fb_width + x; - const u16* src_base = sprite; - - for (u32 row = 0; row < h; row++) { - u16* dest_row = dest_base + row * fb_width; - const u16* src_row = src_base + row * atlas_width; - - u32 col = 0; - u32 count2 = w / 2; - for (u32 i = 0; i < count2; i++) { - u32 pixels = ((const u32*)src_row)[i]; - if (pixels == 0) { - col += 2; - continue; - } - dest_row[col] = pxl8_blend_hicolor((u16)(pixels), dest_row[col]); - dest_row[col + 1] = pxl8_blend_hicolor((u16)(pixels >> 16), dest_row[col + 1]); - col += 2; - } - if (w & 1) { - dest_row[col] = pxl8_blend_hicolor(src_row[col], dest_row[col]); - } - } -} - -void pxl8_blit_indexed(u8* fb, u32 fb_width, const u8* sprite, u32 atlas_width, - i32 x, i32 y, u32 w, u32 h) { +void pxl8_blit(u8* fb, u32 fb_width, const u8* sprite, u32 atlas_width, + i32 x, i32 y, u32 w, u32 h) { u8* dest_base = fb + y * fb_width + x; const u8* src_base = sprite; @@ -44,14 +17,14 @@ void pxl8_blit_indexed(u8* fb, u32 fb_width, const u8* sprite, u32 atlas_width, col += 4; continue; } - dest_row[col] = pxl8_blend_indexed((u8)(pixels), dest_row[col]); - dest_row[col + 1] = pxl8_blend_indexed((u8)(pixels >> 8), dest_row[col + 1]); - dest_row[col + 2] = pxl8_blend_indexed((u8)(pixels >> 16), dest_row[col + 2]); - dest_row[col + 3] = pxl8_blend_indexed((u8)(pixels >> 24), dest_row[col + 3]); + dest_row[col] = pxl8_blit_mask((u8)(pixels), dest_row[col]); + dest_row[col + 1] = pxl8_blit_mask((u8)(pixels >> 8), dest_row[col + 1]); + dest_row[col + 2] = pxl8_blit_mask((u8)(pixels >> 16), dest_row[col + 2]); + dest_row[col + 3] = pxl8_blit_mask((u8)(pixels >> 24), dest_row[col + 3]); col += 4; } for (; col < w; col++) { - dest_row[col] = pxl8_blend_indexed(src_row[col], dest_row[col]); + dest_row[col] = pxl8_blit_mask(src_row[col], dest_row[col]); } } } diff --git a/src/gfx/pxl8_blit.h b/src/gfx/pxl8_blit.h index 0ab5bd8..63a65c6 100644 --- a/src/gfx/pxl8_blit.h +++ b/src/gfx/pxl8_blit.h @@ -6,22 +6,12 @@ extern "C" { #endif -static inline u8 pxl8_blend_indexed(u8 src, u8 dst) { +static inline u8 pxl8_blit_mask(u8 src, u8 dst) { u8 m = (u8)(-(src != 0)); return (src & m) | (dst & ~m); } -static inline u16 pxl8_blend_hicolor(u16 src, u16 dst) { - u16 m = (u16)(-(src != 0)); - return (src & m) | (dst & ~m); -} - -void pxl8_blit_hicolor( - u16* fb, u32 fb_width, - const u16* sprite, u32 atlas_width, - i32 x, i32 y, u32 w, u32 h -); -void pxl8_blit_indexed( +void pxl8_blit( u8* fb, u32 fb_width, const u8* sprite, u32 atlas_width, i32 x, i32 y, u32 w, u32 h diff --git a/src/gfx/pxl8_color.h b/src/gfx/pxl8_color.h index f159724..8915454 100644 --- a/src/gfx/pxl8_color.h +++ b/src/gfx/pxl8_color.h @@ -2,10 +2,6 @@ #include "pxl8_types.h" -static inline i32 pxl8_bytes_per_pixel(pxl8_pixel_mode mode) { - return (i32)mode; -} - static inline u32 pxl8_color_from_rgba(u32 rgba) { u8 r = (rgba >> 24) & 0xFF; u8 g = (rgba >> 16) & 0xFF; @@ -76,30 +72,10 @@ static inline void pxl8_rgb332_unpack(u8 c, u8* r, u8* g, u8* b) { *b = (bi << 6) | (bi << 4) | (bi << 2) | bi; } -static inline u16 pxl8_rgb565_pack(u8 r, u8 g, u8 b) { - return ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3); -} - -static inline void pxl8_rgb565_unpack(u16 color, u8* r, u8* g, u8* b) { - *r = (color >> 11) << 3; - *g = ((color >> 5) & 0x3F) << 2; - *b = (color & 0x1F) << 3; -} - -static inline u32 pxl8_rgb565_to_rgba32(u16 color) { - u8 r, g, b; - pxl8_rgb565_unpack(color, &r, &g, &b); - return r | ((u32)g << 8) | ((u32)b << 16) | 0xFF000000; -} - static inline u32 pxl8_rgba32_pack(u8 r, u8 g, u8 b, u8 a) { return r | ((u32)g << 8) | ((u32)b << 16) | ((u32)a << 24); } -static inline u16 pxl8_rgba32_to_rgb565(u32 rgba) { - return pxl8_rgb565_pack(rgba & 0xFF, (rgba >> 8) & 0xFF, (rgba >> 16) & 0xFF); -} - static inline void pxl8_rgba32_unpack(u32 color, u8* r, u8* g, u8* b, u8* a) { *r = color & 0xFF; *g = (color >> 8) & 0xFF; diff --git a/src/gfx/pxl8_gfx.c b/src/gfx/pxl8_gfx.c index de4ad2c..9b331e1 100644 --- a/src/gfx/pxl8_gfx.c +++ b/src/gfx/pxl8_gfx.c @@ -6,7 +6,6 @@ #include "pxl8_ase.h" #include "pxl8_atlas.h" #include "pxl8_blit.h" -#include "pxl8_color.h" #include "pxl8_colormap.h" #include "pxl8_font.h" #include "pxl8_glows.h" @@ -72,7 +71,6 @@ struct pxl8_gfx { pxl8_palette_cube* palette_cube; pxl8_gfx_pass frame_pass; pxl8_frame_resources frame_res; - pxl8_pixel_mode pixel_mode; void* platform_data; pxl8_sprite_cache_entry* sprite_cache; u32 sprite_cache_capacity; @@ -100,20 +98,11 @@ pxl8_bounds pxl8_gfx_get_bounds(pxl8_gfx* gfx) { return bounds; } -pxl8_pixel_mode pxl8_gfx_get_pixel_mode(pxl8_gfx* gfx) { - return gfx ? gfx->pixel_mode : PXL8_PIXEL_INDEXED; -} - -u8* pxl8_gfx_get_framebuffer_indexed(pxl8_gfx* gfx) { - if (!gfx || gfx->pixel_mode == PXL8_PIXEL_HICOLOR) return NULL; +u8* pxl8_gfx_framebuffer(pxl8_gfx* gfx) { + if (!gfx) return NULL; return (u8*)pxl8_texture_get_data(gfx->renderer, gfx->color_target); } -u16* pxl8_gfx_get_framebuffer_hicolor(pxl8_gfx* gfx) { - if (!gfx || gfx->pixel_mode != PXL8_PIXEL_HICOLOR) return NULL; - return (u16*)pxl8_texture_get_data(gfx->renderer, gfx->color_target); -} - i32 pxl8_gfx_get_height(const pxl8_gfx* gfx) { return gfx ? gfx->framebuffer_height : 0; } @@ -125,9 +114,8 @@ u32* pxl8_gfx_get_output(pxl8_gfx* gfx) { void pxl8_gfx_resolve(pxl8_gfx* gfx) { if (!gfx || !gfx->initialized) return; - if (gfx->pixel_mode != PXL8_PIXEL_INDEXED) return; - const u32* pal = gfx->palette ? pxl8_palette_colors(gfx->palette) : NULL; + const u32* pal = pxl8_palette_colors(gfx->palette); if (!pal) { pxl8_error("resolve: no palette!"); return; @@ -180,10 +168,8 @@ i32 pxl8_gfx_load_palette(pxl8_gfx* gfx, const char* filepath) { if (!gfx || !gfx->palette || !filepath) return -1; pxl8_result result = pxl8_palette_load_ase(gfx->palette, filepath); if (result != PXL8_OK) return (i32)result; - if (gfx->pixel_mode != PXL8_PIXEL_HICOLOR) { - if (gfx->colormap) { - pxl8_colormap_generate(gfx->colormap, pxl8_palette_colors(gfx->palette)); - } + if (gfx->colormap) { + pxl8_colormap_generate(gfx->colormap, pxl8_palette_colors(gfx->palette)); } return 0; } @@ -191,7 +177,6 @@ i32 pxl8_gfx_load_palette(pxl8_gfx* gfx, const char* filepath) { pxl8_gfx* pxl8_gfx_create( const pxl8_hal* hal, void* platform_data, - pxl8_pixel_mode mode, pxl8_resolution resolution ) { pxl8_shader_registry_init(); @@ -205,7 +190,6 @@ pxl8_gfx* pxl8_gfx_create( gfx->hal = hal; gfx->platform_data = platform_data; - gfx->pixel_mode = mode; pxl8_size size = pxl8_get_resolution_dimensions(resolution); gfx->framebuffer_width = size.w; gfx->framebuffer_height = size.h; @@ -216,9 +200,7 @@ pxl8_gfx* pxl8_gfx_create( return NULL; } - if (mode != PXL8_PIXEL_HICOLOR) { - gfx->palette = pxl8_palette_create(); - } + gfx->palette = pxl8_palette_create(); gfx->renderer = pxl8_renderer_create(gfx->framebuffer_width, gfx->framebuffer_height); if (!gfx->renderer) { @@ -258,9 +240,7 @@ pxl8_gfx* pxl8_gfx_create( return NULL; } - if (mode != PXL8_PIXEL_HICOLOR) { - gfx->colormap = pxl8_calloc(1, sizeof(pxl8_colormap)); - } + gfx->colormap = pxl8_calloc(1, sizeof(pxl8_colormap)); gfx->target_stack[0] = (pxl8_target_entry){ .color = gfx->color_target, @@ -313,7 +293,7 @@ void pxl8_gfx_destroy(pxl8_gfx* gfx) { static pxl8_result pxl8_gfx_ensure_atlas(pxl8_gfx* gfx) { if (gfx->atlas) return PXL8_OK; - gfx->atlas = pxl8_atlas_create(PXL8_DEFAULT_ATLAS_SIZE, PXL8_DEFAULT_ATLAS_SIZE, gfx->pixel_mode); + gfx->atlas = pxl8_atlas_create(PXL8_DEFAULT_ATLAS_SIZE, PXL8_DEFAULT_ATLAS_SIZE); return gfx->atlas ? PXL8_OK : PXL8_ERROR_OUT_OF_MEMORY; } @@ -335,7 +315,7 @@ pxl8_result pxl8_gfx_create_texture(pxl8_gfx* gfx, const u8* pixels, u32 width, pxl8_result result = pxl8_gfx_ensure_atlas(gfx); if (result != PXL8_OK) return result; - u32 texture_id = pxl8_atlas_add_texture(gfx->atlas, pixels, width, height, gfx->pixel_mode); + u32 texture_id = pxl8_atlas_add_texture(gfx->atlas, pixels, width, height); if (texture_id == UINT32_MAX) { pxl8_error("Texture doesn't fit in atlas"); return PXL8_ERROR_INVALID_SIZE; @@ -381,8 +361,7 @@ pxl8_result pxl8_gfx_load_sprite(pxl8_gfx* gfx, const char* path) { gfx->atlas, ase_file.frames[0].pixels, ase_file.header.width, - ase_file.header.height, - gfx->pixel_mode + ase_file.header.height ); pxl8_ase_destroy(&ase_file); @@ -426,28 +405,14 @@ pxl8_result pxl8_gfx_load_font_atlas(pxl8_gfx* gfx) { void pxl8_gfx_upload_framebuffer(pxl8_gfx* gfx) { if (!gfx || !gfx->initialized || !gfx->hal) return; - if (gfx->pixel_mode == PXL8_PIXEL_INDEXED) { - pxl8_gfx_resolve(gfx); - gfx->hal->upload_texture( - gfx->platform_data, - gfx->output, - gfx->framebuffer_width, - gfx->framebuffer_height, - PXL8_PIXEL_RGBA, - NULL - ); - return; - } - - u32* colors = gfx->palette ? pxl8_palette_colors(gfx->palette) : NULL; - u8* framebuffer = (u8*)pxl8_texture_get_data(gfx->renderer, gfx->color_target); + pxl8_gfx_resolve(gfx); gfx->hal->upload_texture( gfx->platform_data, - framebuffer, + gfx->output, gfx->framebuffer_width, gfx->framebuffer_height, - gfx->pixel_mode, - colors + 4, + NULL ); } @@ -639,7 +604,7 @@ void pxl8_2d_sprite(pxl8_gfx* gfx, u32 sprite_id, i32 x, i32 y, i32 w, i32 h, bo if (is_1to1_scale && is_unclipped && !is_flipped) { const u8* sprite_data = atlas_pixels + entry->y * atlas_width + entry->x; - pxl8_blit_indexed(framebuffer, fb_width, sprite_data, atlas_width, x, y, w, h); + pxl8_blit(framebuffer, fb_width, sprite_data, atlas_width, x, y, w, h); } else { for (i32 py = 0; py < draw_height; py++) { for (i32 px = 0; px < draw_width; px++) { @@ -652,7 +617,7 @@ void pxl8_2d_sprite(pxl8_gfx* gfx, u32 sprite_id, i32 x, i32 y, i32 w, i32 h, bo i32 src_idx = src_y * atlas_width + src_x; i32 dest_idx = (dest_y + py) * fb_width + (dest_x + px); - framebuffer[dest_idx] = pxl8_blend_indexed(atlas_pixels[src_idx], framebuffer[dest_idx]); + framebuffer[dest_idx] = pxl8_blit_mask(atlas_pixels[src_idx], framebuffer[dest_idx]); } } } diff --git a/src/gfx/pxl8_gfx.h b/src/gfx/pxl8_gfx.h index ad13479..51267b7 100644 --- a/src/gfx/pxl8_gfx.h +++ b/src/gfx/pxl8_gfx.h @@ -36,7 +36,7 @@ typedef enum pxl8_gfx_effect { extern "C" { #endif -pxl8_gfx* pxl8_gfx_create(const pxl8_hal* hal, void* platform_data, pxl8_pixel_mode mode, pxl8_resolution resolution); +pxl8_gfx* pxl8_gfx_create(const pxl8_hal* hal, void* platform_data, pxl8_resolution resolution); void pxl8_gfx_destroy(pxl8_gfx* gfx); void pxl8_gfx_present(pxl8_gfx* gfx); @@ -46,14 +46,12 @@ void pxl8_gfx_upload_framebuffer(pxl8_gfx* gfx); u8 pxl8_gfx_find_color(pxl8_gfx* gfx, u32 color); pxl8_bounds pxl8_gfx_get_bounds(pxl8_gfx* gfx); -u8* pxl8_gfx_get_framebuffer_indexed(pxl8_gfx* gfx); -u16* pxl8_gfx_get_framebuffer_hicolor(pxl8_gfx* gfx); +u8* pxl8_gfx_framebuffer(pxl8_gfx* gfx); i32 pxl8_gfx_get_height(const pxl8_gfx* gfx); const u32* pxl8_gfx_palette_colors(pxl8_gfx* gfx); u16* pxl8_gfx_get_zbuffer(pxl8_gfx* gfx); pxl8_palette* pxl8_gfx_palette(pxl8_gfx* gfx); pxl8_colormap* pxl8_gfx_colormap(pxl8_gfx* gfx); -pxl8_pixel_mode pxl8_gfx_get_pixel_mode(pxl8_gfx* gfx); i32 pxl8_gfx_get_width(const pxl8_gfx* gfx); i32 pxl8_gfx_load_palette(pxl8_gfx* gfx, const char* filepath); diff --git a/src/gfx/pxl8_render.c b/src/gfx/pxl8_render.c index 00c3362..31003de 100644 --- a/src/gfx/pxl8_render.c +++ b/src/gfx/pxl8_render.c @@ -83,7 +83,7 @@ static u8 palette_find_closest(const u32* palette, u8 r, u8 g, u8 b) { return best_idx; } -static u8 blend_indexed( +static u8 blend_colors( const pxl8_gfx_pipeline_desc* pipeline, u8 src, u8 dst, @@ -540,7 +540,7 @@ static void rasterize_triangle( if (color != 0) { u8 out_color = color; if (blend_enabled) { - out_color = blend_indexed(pipeline, color, prow[px], palette); + out_color = blend_colors(pipeline, color, prow[px], palette); } prow[px] = out_color; @@ -586,7 +586,7 @@ static void rasterize_triangle( if (color != 0) { u8 out_color = color; if (blend_enabled) { - out_color = blend_indexed(pipeline, color, prow[px], palette); + out_color = blend_colors(pipeline, color, prow[px], palette); } prow[px] = out_color; diff --git a/src/gfx/pxl8_tilemap.c b/src/gfx/pxl8_tilemap.c index 263b65c..33ceef2 100644 --- a/src/gfx/pxl8_tilemap.c +++ b/src/gfx/pxl8_tilemap.c @@ -17,7 +17,6 @@ struct pxl8_tilesheet { u32 tiles_per_row; u32 total_tiles; u32 width; - pxl8_pixel_mode pixel_mode; u32 ref_count; pxl8_tile_animation* animations; u32 animation_count; @@ -547,7 +546,6 @@ pxl8_result pxl8_tilemap_load_ase(pxl8_tilemap* tilemap, const char* filepath, u tilemap->tilesheet->height = tilesheet_height; tilemap->tilesheet->tiles_per_row = tiles_per_row; tilemap->tilesheet->total_tiles = tileset->tile_count; - tilemap->tilesheet->pixel_mode = PXL8_PIXEL_INDEXED; if (tilemap->tilesheet->tile_valid) pxl8_free(tilemap->tilesheet->tile_valid); tilemap->tilesheet->tile_valid = pxl8_calloc(tileset->tile_count + 1, sizeof(bool)); diff --git a/src/gfx/pxl8_tilesheet.c b/src/gfx/pxl8_tilesheet.c index 9f41cd3..1782220 100644 --- a/src/gfx/pxl8_tilesheet.c +++ b/src/gfx/pxl8_tilesheet.c @@ -4,7 +4,6 @@ #include #include "pxl8_ase.h" -#include "pxl8_color.h" #include "pxl8_gfx.h" #include "pxl8_log.h" #include "pxl8_mem.h" @@ -20,7 +19,6 @@ struct pxl8_tilesheet { u32 total_tiles; u32 width; - pxl8_pixel_mode pixel_mode; u32 ref_count; pxl8_tile_animation* animations; @@ -106,14 +104,10 @@ pxl8_result pxl8_tilesheet_load(pxl8_tilesheet* tilesheet, const char* filepath, tilesheet->height = height; tilesheet->tiles_per_row = width / tilesheet->tile_size; tilesheet->total_tiles = (width / tilesheet->tile_size) * (height / tilesheet->tile_size); - tilesheet->pixel_mode = pxl8_gfx_get_pixel_mode(gfx); - u32 pixel_count = width * height; u16 ase_depth = ase_file.header.color_depth; - bool gfx_hicolor = (tilesheet->pixel_mode == PXL8_PIXEL_HICOLOR); - usize data_size = pixel_count * pxl8_bytes_per_pixel(tilesheet->pixel_mode); - tilesheet->data = pxl8_malloc(data_size); + tilesheet->data = pxl8_malloc(pixel_count); if (!tilesheet->data) { pxl8_ase_destroy(&ase_file); return PXL8_ERROR_OUT_OF_MEMORY; @@ -122,34 +116,10 @@ pxl8_result pxl8_tilesheet_load(pxl8_tilesheet* tilesheet, const char* filepath, if (ase_file.frame_count > 0 && ase_file.frames[0].pixels) { const u8* src = ase_file.frames[0].pixels; - if (ase_depth == 8 && !gfx_hicolor) { - memcpy(tilesheet->data, src, pixel_count); - } else if (ase_depth == 32 && gfx_hicolor) { - u16* dst = (u16*)tilesheet->data; - const u32* rgba = (const u32*)src; - for (u32 i = 0; i < pixel_count; i++) { - u32 c = rgba[i]; - u8 a = (c >> 24) & 0xFF; - if (a == 0) { - dst[i] = 0; - } else { - dst[i] = pxl8_rgba32_to_rgb565(c); - } - } - } else if (ase_depth == 8 && gfx_hicolor) { - pxl8_warn("Indexed ASE with hicolor gfx - storing as indexed"); - tilesheet->pixel_mode = PXL8_PIXEL_INDEXED; - u8* new_data = pxl8_realloc(tilesheet->data, pixel_count); - if (!new_data) { - pxl8_free(tilesheet->data); - tilesheet->data = NULL; - pxl8_ase_destroy(&ase_file); - return PXL8_ERROR_OUT_OF_MEMORY; - } - tilesheet->data = new_data; + if (ase_depth == 8) { memcpy(tilesheet->data, src, pixel_count); } else { - pxl8_error("Unsupported ASE color depth %d for gfx mode", ase_depth); + pxl8_error("Unsupported ASE color depth %d (expected indexed 8-bit)", ase_depth); pxl8_free(tilesheet->data); tilesheet->data = NULL; pxl8_ase_destroy(&ase_file); @@ -166,7 +136,6 @@ pxl8_result pxl8_tilesheet_load(pxl8_tilesheet* tilesheet, const char* filepath, } u32 valid_tiles = 0; - bool is_hicolor = (tilesheet->pixel_mode == PXL8_PIXEL_HICOLOR); for (u32 tile_id = 1; tile_id <= tilesheet->total_tiles; tile_id++) { u32 tile_x = ((tile_id - 1) % tilesheet->tiles_per_row) * tilesheet->tile_size; @@ -176,16 +145,9 @@ pxl8_result pxl8_tilesheet_load(pxl8_tilesheet* tilesheet, const char* filepath, for (u32 py = 0; py < tilesheet->tile_size && !has_content; py++) { for (u32 px = 0; px < tilesheet->tile_size; px++) { u32 idx = (tile_y + py) * width + (tile_x + px); - if (is_hicolor) { - if (((u16*)tilesheet->data)[idx] != 0) { - has_content = true; - break; - } - } else { - if (tilesheet->data[idx] != 0) { - has_content = true; - break; - } + if (tilesheet->data[idx] != 0) { + has_content = true; + break; } } } @@ -312,7 +274,6 @@ pxl8_result pxl8_tilesheet_set_tile_pixels(pxl8_tilesheet* tilesheet, u16 tile_i u32 tile_x = (tile_id - 1) % tilesheet->tiles_per_row; u32 tile_y = (tile_id - 1) / tilesheet->tiles_per_row; - u32 bytes_per_pixel = pxl8_bytes_per_pixel(tilesheet->pixel_mode); for (u32 py = 0; py < tilesheet->tile_size; py++) { for (u32 px = 0; px < tilesheet->tile_size; px++) { @@ -320,12 +281,7 @@ pxl8_result pxl8_tilesheet_set_tile_pixels(pxl8_tilesheet* tilesheet, u16 tile_i u32 dst_x = tile_x * tilesheet->tile_size + px; u32 dst_y = tile_y * tilesheet->tile_size + py; u32 dst_idx = dst_y * tilesheet->width + dst_x; - - if (bytes_per_pixel == 2) { - ((u16*)tilesheet->data)[dst_idx] = ((const u16*)pixels)[src_idx]; - } else { - tilesheet->data[dst_idx] = pixels[src_idx]; - } + tilesheet->data[dst_idx] = pixels[src_idx]; } } diff --git a/src/gfx/pxl8_transition.c b/src/gfx/pxl8_transition.c index ba76e1d..5c16266 100644 --- a/src/gfx/pxl8_transition.c +++ b/src/gfx/pxl8_transition.c @@ -170,11 +170,7 @@ void pxl8_transition_render(const pxl8_transition* transition, pxl8_gfx* gfx) { i32 block_size = (i32)(max_block_size * progress); if (block_size < 1) block_size = 1; - pxl8_pixel_mode mode = pxl8_gfx_get_pixel_mode(gfx); - bool has_fb = (mode == PXL8_PIXEL_HICOLOR) - ? (pxl8_gfx_get_framebuffer_hicolor(gfx) != NULL) - : (pxl8_gfx_get_framebuffer_indexed(gfx) != NULL); - if (!has_fb) break; + if (!pxl8_gfx_framebuffer(gfx)) break; for (i32 y = 0; y < height; y += block_size) { for (i32 x = 0; x < width; x += block_size) { diff --git a/src/hal/pxl8_hal_sdl3.c b/src/hal/pxl8_hal_sdl3.c index 581b257..58b8d33 100644 --- a/src/hal/pxl8_hal_sdl3.c +++ b/src/hal/pxl8_hal_sdl3.c @@ -125,16 +125,9 @@ static void sdl3_upload_texture(void* platform_data, const void* pixels, u32 w, ctx->rgba_buffer_size = pixel_count; } - if (bpp == 2) { - const u16* pixels16 = (const u16*)pixels; - for (u32 i = 0; i < pixel_count; i++) { - ctx->rgba_buffer[i] = pxl8_rgb565_to_rgba32(pixels16[i]); - } - } else { - const u8* pixels8 = (const u8*)pixels; - for (u32 i = 0; i < pixel_count; i++) { - ctx->rgba_buffer[i] = palette[pixels8[i]]; - } + const u8* pixels8 = (const u8*)pixels; + for (u32 i = 0; i < pixel_count; i++) { + ctx->rgba_buffer[i] = palette[pixels8[i]]; } SDL_UpdateTexture(ctx->framebuffer, NULL, ctx->rgba_buffer, w * 4); diff --git a/src/lua/pxl8/world.lua b/src/lua/pxl8/world.lua index 152ef84..f2eab50 100644 --- a/src/lua/pxl8/world.lua +++ b/src/lua/pxl8/world.lua @@ -64,6 +64,10 @@ function World:init_local_player(x, y, z) C.pxl8_world_init_local_player(self._ptr, x, y, z) end +function World:set_look(yaw, pitch) + C.pxl8_world_set_look(self._ptr, yaw, pitch or 0) +end + function World:local_player() local ptr = C.pxl8_world_local_player(self._ptr) if ptr == nil then return nil end diff --git a/src/script/pxl8_script.c b/src/script/pxl8_script.c index 3685650..ace4c1f 100644 --- a/src/script/pxl8_script.c +++ b/src/script/pxl8_script.c @@ -1214,12 +1214,6 @@ static pxl8_resolution parse_resolution(const char* str) { return PXL8_RESOLUTION_640x360; } -static pxl8_pixel_mode parse_pixel_mode(const char* str) { - if (strcmp(str, "indexed") == 0) return PXL8_PIXEL_INDEXED; - if (strcmp(str, "hicolor") == 0) return PXL8_PIXEL_HICOLOR; - return PXL8_PIXEL_INDEXED; -} - pxl8_result pxl8_script_load_cart_manifest(pxl8_script* script, pxl8_cart* cart) { if (!script || !script->L || !cart) return PXL8_ERROR_NULL_POINTER; @@ -1267,12 +1261,6 @@ pxl8_result pxl8_script_load_cart_manifest(pxl8_script* script, pxl8_cart* cart) } lua_pop(script->L, 1); - lua_getfield(script->L, -1, "pixel-mode"); - if (lua_isstring(script->L, -1)) { - pxl8_cart_set_pixel_mode(cart, parse_pixel_mode(lua_tostring(script->L, -1))); - } - lua_pop(script->L, 1); - lua_getfield(script->L, -1, "window-size"); if (lua_istable(script->L, -1)) { lua_rawgeti(script->L, -1, 1); diff --git a/src/script/pxl8_script_ffi.h b/src/script/pxl8_script_ffi.h index f3e27f9..07ec16f 100644 --- a/src/script/pxl8_script_ffi.h +++ b/src/script/pxl8_script_ffi.h @@ -27,7 +27,7 @@ static const char* pxl8_ffi_cdefs = "f32 pxl8_get_fps(const pxl8* sys);\n" "\n" "u8 pxl8_gfx_find_color(pxl8_gfx* gfx, u32 color);\n" -"u8* pxl8_gfx_get_framebuffer_indexed(pxl8_gfx* gfx);\n" +"u8* pxl8_gfx_framebuffer(pxl8_gfx* gfx);\n" "i32 pxl8_gfx_get_height(pxl8_gfx* ctx);\n" "u32* pxl8_gfx_get_light_accum(pxl8_gfx* gfx);\n" "const u32* pxl8_gfx_palette_colors(pxl8_gfx* gfx);\n" @@ -437,6 +437,7 @@ static const char* pxl8_ffi_cdefs = "} pxl8_sim_entity;\n" "\n" "void pxl8_world_init_local_player(pxl8_world* world, f32 x, f32 y, f32 z);\n" +"void pxl8_world_set_look(pxl8_world* world, f32 yaw, f32 pitch);\n" "pxl8_sim_entity* pxl8_world_local_player(pxl8_world* world);\n" "\n" "typedef struct { i32 cursor_x; i32 cursor_y; bool cursor_down; bool cursor_clicked; u32 hot_id; u32 active_id; } pxl8_gui_state;\n" diff --git a/src/world/pxl8_world.c b/src/world/pxl8_world.c index 854d7f3..5333269 100644 --- a/src/world/pxl8_world.c +++ b/src/world/pxl8_world.c @@ -316,6 +316,7 @@ void pxl8_world_init_local_player(pxl8_world* world, f32 x, f32 y, f32 z) { world->local_player.flags = PXL8_SIM_FLAG_ALIVE | PXL8_SIM_FLAG_PLAYER | PXL8_SIM_FLAG_GROUNDED; world->local_player.kind = 0; world->client_tick = 0; + world->pointer_motion = (pxl8_vec2){0}; #ifdef PXL8_ASYNC_THREADS world->render_state[0] = world->local_player; @@ -323,6 +324,20 @@ void pxl8_world_init_local_player(pxl8_world* world, f32 x, f32 y, f32 z) { #endif } +void pxl8_world_set_look(pxl8_world* world, f32 yaw, f32 pitch) { + if (!world) return; + world->local_player.yaw = yaw; + world->local_player.pitch = pitch; + world->pointer_motion = (pxl8_vec2){.yaw = yaw, .pitch = pitch}; + +#ifdef PXL8_ASYNC_THREADS + world->render_state[0].yaw = yaw; + world->render_state[0].pitch = pitch; + world->render_state[1].yaw = yaw; + world->render_state[1].pitch = pitch; +#endif +} + pxl8_sim_entity* pxl8_world_local_player(pxl8_world* world) { if (!world) return NULL; #ifdef PXL8_ASYNC_THREADS diff --git a/src/world/pxl8_world.h b/src/world/pxl8_world.h index bb09a41..90a1609 100644 --- a/src/world/pxl8_world.h +++ b/src/world/pxl8_world.h @@ -37,6 +37,7 @@ void pxl8_world_set_bsp_material(pxl8_world* world, u16 material_id, const pxl8_ void pxl8_world_set_sim_config(pxl8_world* world, const pxl8_sim_config* config); void pxl8_world_init_local_player(pxl8_world* world, f32 x, f32 y, f32 z); +void pxl8_world_set_look(pxl8_world* world, f32 yaw, f32 pitch); pxl8_sim_entity* pxl8_world_local_player(pxl8_world* world); pxl8_sim_world pxl8_world_sim_world(const pxl8_world* world, pxl8_vec3 pos); void pxl8_world_predict(pxl8_world* world, pxl8_net* net, const pxl8_input_msg* input, f32 dt);