improve 3d renderer
This commit is contained in:
parent
f19b06d705
commit
59be43d80e
17 changed files with 556 additions and 486 deletions
|
|
@ -39,6 +39,8 @@
|
|||
(pxl8.transition_update transition dt)
|
||||
(when (pxl8.transition_is_complete transition)
|
||||
(when transition-pending
|
||||
(when (and (= active-demo :worldgen) (not= transition-pending :worldgen))
|
||||
(pxl8.set_relative_mouse_mode false))
|
||||
(set active-demo transition-pending)
|
||||
(set transition-pending nil)
|
||||
(when (= active-demo :fire) (set fire-init? false))
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
(var angle-y 0)
|
||||
(var angle-z 0)
|
||||
(var auto-rotate? true)
|
||||
(var orthographic? true)
|
||||
(var orthographic? false)
|
||||
(var wireframe? true)
|
||||
(var time 0)
|
||||
(var zoom 5.0)
|
||||
|
|
@ -27,7 +27,7 @@
|
|||
(set angle-y 0)
|
||||
(set angle-z 0)
|
||||
(set auto-rotate? true)
|
||||
(set orthographic? true)
|
||||
(set orthographic? false)
|
||||
(set wireframe? true)
|
||||
(set time 0)
|
||||
(set zoom 5.0)
|
||||
|
|
@ -169,12 +169,11 @@
|
|||
|
||||
(fn draw-cube [pos scale rotation-offset]
|
||||
(let [[x y z] pos
|
||||
model (-> (pxl8.mat4_identity)
|
||||
(pxl8.mat4_multiply (pxl8.mat4_scale scale scale scale))
|
||||
(pxl8.mat4_multiply (pxl8.mat4_rotate_x (+ angle-x rotation-offset)))
|
||||
(pxl8.mat4_multiply (pxl8.mat4_rotate_y (+ angle-y (* rotation-offset 1.3))))
|
||||
model (-> (pxl8.mat4_translate x y z)
|
||||
(pxl8.mat4_multiply (pxl8.mat4_rotate_z (+ angle-z (* rotation-offset 0.7))))
|
||||
(pxl8.mat4_multiply (pxl8.mat4_translate x y z)))]
|
||||
(pxl8.mat4_multiply (pxl8.mat4_rotate_y (+ angle-y (* rotation-offset 1.3))))
|
||||
(pxl8.mat4_multiply (pxl8.mat4_rotate_x (+ angle-x rotation-offset)))
|
||||
(pxl8.mat4_multiply (pxl8.mat4_scale scale scale scale)))]
|
||||
(pxl8.set_model model))
|
||||
|
||||
(let [vertices (make-cube-vertices)]
|
||||
|
|
|
|||
|
|
@ -3,21 +3,23 @@
|
|||
(local bob-amount 4.0)
|
||||
(local bob-speed 8.0)
|
||||
(var bob-time 0)
|
||||
(var cam-pitch 0)
|
||||
(var cam-x 1000)
|
||||
(var cam-y 64)
|
||||
(var cam-z 1000)
|
||||
(var cam-pitch 0)
|
||||
(var cam-yaw 0)
|
||||
(var cam-z 1000)
|
||||
(local cell-size 64)
|
||||
(local gravity -800)
|
||||
(local grid-size 32)
|
||||
(var grounded? true)
|
||||
(local ground-y 64)
|
||||
(local jump-force 175)
|
||||
(var land-squash 0)
|
||||
(local land-squash-amount -4)
|
||||
(local land-recovery-speed 20)
|
||||
(local land-squash-amount -4)
|
||||
(var land-squash 0)
|
||||
(local max-pitch 1.5)
|
||||
(var mouse-look? true)
|
||||
(local mouse-sensitivity 0.008)
|
||||
(local move-speed 200)
|
||||
(local turn-speed 2.0)
|
||||
(var velocity-y 0)
|
||||
|
|
@ -66,6 +68,11 @@
|
|||
(pxl8.error (.. "Failed to apply textures - result: " result))))))))
|
||||
|
||||
(fn update [dt]
|
||||
(pxl8.set_relative_mouse_mode mouse-look?)
|
||||
|
||||
(when (pxl8.key_pressed "escape")
|
||||
(set mouse-look? (not mouse-look?)))
|
||||
|
||||
(when (pxl8.world_is_loaded world)
|
||||
(let [forward-x (- (math.sin cam-yaw))
|
||||
forward-z (- (math.cos cam-yaw))
|
||||
|
|
@ -84,10 +91,10 @@
|
|||
(when (pxl8.key_down "s")
|
||||
(set move-forward (- move-forward 1)))
|
||||
|
||||
(when (pxl8.key_down "q")
|
||||
(when (pxl8.key_down "a")
|
||||
(set move-right (- move-right 1)))
|
||||
|
||||
(when (pxl8.key_down "e")
|
||||
(when (pxl8.key_down "d")
|
||||
(set move-right (+ move-right 1)))
|
||||
|
||||
(set moving (or (not= move-forward 0) (not= move-right 0)))
|
||||
|
|
@ -107,16 +114,24 @@
|
|||
(set cam-x new-x)
|
||||
(set cam-z new-z))
|
||||
|
||||
(when (or (pxl8.key_down "left") (pxl8.key_down "a"))
|
||||
(when mouse-look?
|
||||
(let [dx (pxl8.mouse_dx)
|
||||
dy (pxl8.mouse_dy)]
|
||||
(set cam-yaw (- cam-yaw (* dx mouse-sensitivity)))
|
||||
(set cam-pitch (math.max (- max-pitch)
|
||||
(math.min max-pitch
|
||||
(- cam-pitch (* dy mouse-sensitivity)))))))
|
||||
|
||||
(when (and (not mouse-look?) (pxl8.key_down "left"))
|
||||
(set cam-yaw (+ cam-yaw (* turn-speed dt))))
|
||||
|
||||
(when (or (pxl8.key_down "right") (pxl8.key_down "d"))
|
||||
(when (and (not mouse-look?) (pxl8.key_down "right"))
|
||||
(set cam-yaw (- cam-yaw (* turn-speed dt))))
|
||||
|
||||
(when (pxl8.key_down "up")
|
||||
(when (and (not mouse-look?) (pxl8.key_down "up"))
|
||||
(set cam-pitch (math.min max-pitch (+ cam-pitch (* turn-speed dt)))))
|
||||
|
||||
(when (pxl8.key_down "down")
|
||||
(when (and (not mouse-look?) (pxl8.key_down "down"))
|
||||
(set cam-pitch (math.max (- max-pitch) (- cam-pitch (* turn-speed dt)))))
|
||||
|
||||
(when (and (pxl8.key_pressed "space") grounded?)
|
||||
|
|
@ -170,10 +185,10 @@
|
|||
|
||||
(pxl8.world_render world [cam-x eye-y cam-z])
|
||||
|
||||
(pxl8.text (.. "Pos: " (string.format "%.0f" cam-x) ","
|
||||
(pxl8.text (.. "fps: " (string.format "%.1f" (pxl8.get_fps))) 5 5 12)
|
||||
(pxl8.text (.. "pos: " (string.format "%.0f" cam-x) ","
|
||||
(string.format "%.0f" cam-y) ","
|
||||
(string.format "%.0f" cam-z)) 10 25 12)
|
||||
(pxl8.text (.. "FPS: " (string.format "%.1f" (pxl8.get_fps))) 10 40 12))))
|
||||
(string.format "%.0f" cam-z)) 5 15 12))))
|
||||
|
||||
{:init init
|
||||
:update update
|
||||
|
|
|
|||
|
|
@ -45,10 +45,13 @@ pxl8.gfx_fade_palette = gfx2d.fade_palette
|
|||
pxl8.key_down = input.key_down
|
||||
pxl8.key_pressed = input.key_pressed
|
||||
pxl8.key_released = input.key_released
|
||||
pxl8.mouse_dx = input.mouse_dx
|
||||
pxl8.mouse_dy = input.mouse_dy
|
||||
pxl8.mouse_wheel_x = input.mouse_wheel_x
|
||||
pxl8.mouse_wheel_y = input.mouse_wheel_y
|
||||
pxl8.mouse_x = input.mouse_x
|
||||
pxl8.mouse_y = input.mouse_y
|
||||
pxl8.set_relative_mouse_mode = input.set_relative_mouse_mode
|
||||
|
||||
pxl8.vfx_raster_bars = vfx.raster_bars
|
||||
pxl8.vfx_plasma = vfx.plasma
|
||||
|
|
|
|||
|
|
@ -32,4 +32,16 @@ function input.mouse_y()
|
|||
return C.pxl8_mouse_y(core.input)
|
||||
end
|
||||
|
||||
function input.mouse_dx()
|
||||
return C.pxl8_mouse_dx(core.input)
|
||||
end
|
||||
|
||||
function input.mouse_dy()
|
||||
return C.pxl8_mouse_dy(core.input)
|
||||
end
|
||||
|
||||
function input.set_relative_mouse_mode(enabled)
|
||||
C.pxl8_set_relative_mouse_mode(core.sys, enabled)
|
||||
end
|
||||
|
||||
return input
|
||||
|
|
|
|||
57
src/pxl8.c
57
src/pxl8.c
|
|
@ -253,9 +253,6 @@ pxl8_result pxl8_update(pxl8* sys) {
|
|||
}
|
||||
|
||||
if (game->ui) {
|
||||
i32 render_width, render_height;
|
||||
pxl8_gfx_get_resolution_dimensions(game->resolution, &render_width, &render_height);
|
||||
|
||||
pxl8_ui_input_mousemove(game->ui, game->input.mouse_x, game->input.mouse_y);
|
||||
|
||||
if (game->input.mouse_wheel_x != 0 || game->input.mouse_wheel_y != 0) {
|
||||
|
|
@ -306,25 +303,23 @@ pxl8_result pxl8_frame(pxl8* sys) {
|
|||
} else {
|
||||
pxl8_clear(game->gfx, 32);
|
||||
|
||||
i32 render_width, render_height;
|
||||
pxl8_gfx_get_resolution_dimensions(game->resolution, &render_width, &render_height);
|
||||
pxl8_size render_size = pxl8_get_resolution_dimensions(game->resolution);
|
||||
|
||||
for (i32 y = 0; y < render_height; y += 24) {
|
||||
for (i32 x = 0; x < render_width; x += 32) {
|
||||
for (i32 y = 0; y < render_size.h; y += 24) {
|
||||
for (i32 x = 0; x < render_size.w; x += 32) {
|
||||
u32 color = ((x / 32) + (y / 24) + (i32)(game->time * 2)) % 8;
|
||||
pxl8_rect_fill(game->gfx, x, y, 31, 23, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
i32 render_width, render_height;
|
||||
pxl8_gfx_get_resolution_dimensions(game->resolution, &render_width, &render_height);
|
||||
pxl8_size render_size = pxl8_get_resolution_dimensions(game->resolution);
|
||||
|
||||
if (game->ui) {
|
||||
pxl8_ui_frame_end(game->ui);
|
||||
}
|
||||
|
||||
pxl8_gfx_set_viewport(game->gfx, pxl8_gfx_viewport(bounds, render_width, render_height));
|
||||
pxl8_gfx_set_viewport(game->gfx, pxl8_gfx_viewport(bounds, render_size.w, render_size.h));
|
||||
pxl8_gfx_upload_framebuffer(game->gfx);
|
||||
pxl8_gfx_upload_atlas(game->gfx);
|
||||
pxl8_gfx_present(game->gfx);
|
||||
|
|
@ -333,8 +328,12 @@ pxl8_result pxl8_frame(pxl8* sys) {
|
|||
memset(game->input.keys_released, 0, sizeof(game->input.keys_released));
|
||||
memset(game->input.mouse_buttons_pressed, 0, sizeof(game->input.mouse_buttons_pressed));
|
||||
memset(game->input.mouse_buttons_released, 0, sizeof(game->input.mouse_buttons_released));
|
||||
game->input.mouse_dx = 0;
|
||||
game->input.mouse_dy = 0;
|
||||
game->input.mouse_wheel_x = 0;
|
||||
game->input.mouse_wheel_y = 0;
|
||||
game->input.mouse_x = 0;
|
||||
game->input.mouse_y = 0;
|
||||
|
||||
game->frame_count++;
|
||||
|
||||
|
|
@ -378,14 +377,46 @@ f32 pxl8_get_fps(const pxl8* sys) {
|
|||
return (sys && sys->game) ? sys->game->fps : 0.0f;
|
||||
}
|
||||
|
||||
pxl8_gfx* pxl8_get_gfx(pxl8* sys) {
|
||||
pxl8_gfx* pxl8_get_gfx(const pxl8* sys) {
|
||||
return (sys && sys->game) ? sys->game->gfx : NULL;
|
||||
}
|
||||
|
||||
pxl8_input_state* pxl8_get_input(pxl8* sys) {
|
||||
pxl8_input_state* pxl8_get_input(const pxl8* sys) {
|
||||
return (sys && sys->game) ? &sys->game->input : NULL;
|
||||
}
|
||||
|
||||
pxl8_resolution pxl8_get_resolution(pxl8* sys) {
|
||||
pxl8_resolution pxl8_get_resolution(const pxl8* sys) {
|
||||
return (sys && sys->game) ? sys->game->resolution : PXL8_RESOLUTION_640x360;
|
||||
}
|
||||
|
||||
void pxl8_set_relative_mouse_mode(pxl8* sys, bool enabled) {
|
||||
if (!sys || !sys->hal || !sys->hal->set_relative_mouse_mode) return;
|
||||
sys->hal->set_relative_mouse_mode(sys->platform_data, enabled);
|
||||
if (sys->game) {
|
||||
sys->game->input.mouse_relative_mode = enabled;
|
||||
}
|
||||
}
|
||||
|
||||
u32 pxl8_get_palette_size(pxl8_color_mode mode) {
|
||||
switch (mode) {
|
||||
case PXL8_COLOR_MODE_HICOLOR: return 0;
|
||||
case PXL8_COLOR_MODE_FAMI: return 64;
|
||||
case PXL8_COLOR_MODE_MEGA: return 512;
|
||||
case PXL8_COLOR_MODE_GBA: return 32768;
|
||||
case PXL8_COLOR_MODE_SNES: return 32768;
|
||||
default: return 256;
|
||||
}
|
||||
}
|
||||
|
||||
pxl8_size pxl8_get_resolution_dimensions(pxl8_resolution resolution) {
|
||||
switch (resolution) {
|
||||
case PXL8_RESOLUTION_240x160: return (pxl8_size){240, 160};
|
||||
case PXL8_RESOLUTION_320x180: return (pxl8_size){320, 180};
|
||||
case PXL8_RESOLUTION_320x240: return (pxl8_size){320, 240};
|
||||
case PXL8_RESOLUTION_640x360: return (pxl8_size){640, 360};
|
||||
case PXL8_RESOLUTION_640x480: return (pxl8_size){640, 480};
|
||||
case PXL8_RESOLUTION_800x600: return (pxl8_size){800, 600};
|
||||
case PXL8_RESOLUTION_960x540: return (pxl8_size){960, 540};
|
||||
default: return (pxl8_size){640, 360};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -55,6 +55,44 @@ static bool validate_chunk(const pxl8_bsp_chunk* chunk, u32 element_size, size_t
|
|||
return true;
|
||||
}
|
||||
|
||||
static inline bool pxl8_bsp_get_edge_vertex(const pxl8_bsp* bsp, i32 surfedge_idx, u32* out_vert_idx) {
|
||||
if (surfedge_idx >= (i32)bsp->num_surfedges) return false;
|
||||
|
||||
i32 edge_idx = bsp->surfedges[surfedge_idx];
|
||||
u32 vertex_index;
|
||||
|
||||
if (edge_idx >= 0) {
|
||||
if ((u32)edge_idx >= bsp->num_edges) return false;
|
||||
vertex_index = 0;
|
||||
} else {
|
||||
edge_idx = -edge_idx;
|
||||
if ((u32)edge_idx >= bsp->num_edges) return false;
|
||||
vertex_index = 1;
|
||||
}
|
||||
|
||||
*out_vert_idx = bsp->edges[edge_idx].vertex[vertex_index];
|
||||
return *out_vert_idx < bsp->num_vertices;
|
||||
}
|
||||
|
||||
static inline bool pxl8_bsp_get_edge_vertices(const pxl8_bsp* bsp, i32 surfedge_idx, u32* out_v0_idx, u32* out_v1_idx) {
|
||||
if (surfedge_idx >= (i32)bsp->num_surfedges) return false;
|
||||
|
||||
i32 edge_idx = bsp->surfedges[surfedge_idx];
|
||||
|
||||
if (edge_idx >= 0) {
|
||||
if ((u32)edge_idx >= bsp->num_edges) return false;
|
||||
*out_v0_idx = bsp->edges[edge_idx].vertex[0];
|
||||
*out_v1_idx = bsp->edges[edge_idx].vertex[1];
|
||||
} else {
|
||||
edge_idx = -edge_idx;
|
||||
if ((u32)edge_idx >= bsp->num_edges) return false;
|
||||
*out_v0_idx = bsp->edges[edge_idx].vertex[1];
|
||||
*out_v1_idx = bsp->edges[edge_idx].vertex[0];
|
||||
}
|
||||
|
||||
return *out_v0_idx < bsp->num_vertices && *out_v1_idx < bsp->num_vertices;
|
||||
}
|
||||
|
||||
pxl8_result pxl8_bsp_load(const char* path, pxl8_bsp* bsp) {
|
||||
if (!path || !bsp) return PXL8_ERROR_INVALID_ARGUMENT;
|
||||
|
||||
|
|
@ -280,21 +318,9 @@ pxl8_result pxl8_bsp_load(const char* path, pxl8_bsp* bsp) {
|
|||
|
||||
for (u32 j = 0; j < face->num_edges; j++) {
|
||||
i32 surfedge_idx = face->first_edge + j;
|
||||
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;
|
||||
if (!pxl8_bsp_get_edge_vertex(bsp, surfedge_idx, &vert_idx)) continue;
|
||||
|
||||
pxl8_vec3 v = bsp->vertices[vert_idx].position;
|
||||
|
||||
|
|
@ -392,21 +418,10 @@ void pxl8_bsp_render_face(pxl8_gfx* gfx, const pxl8_bsp* bsp, u32 face_id, u32 t
|
|||
|
||||
for (u32 i = 0; i < face->num_edges && num_verts < 64; i++) {
|
||||
i32 surfedge_idx = face->first_edge + i;
|
||||
if (surfedge_idx >= (i32)bsp->num_surfedges) continue;
|
||||
|
||||
i32 edge_idx = bsp->surfedges[surfedge_idx];
|
||||
u32 vert_idx;
|
||||
|
||||
if (edge_idx >= 0) {
|
||||
if ((u32)edge_idx >= bsp->num_edges) continue;
|
||||
vert_idx = bsp->edges[edge_idx].vertex[0];
|
||||
} else {
|
||||
edge_idx = -edge_idx;
|
||||
if ((u32)edge_idx >= bsp->num_edges) continue;
|
||||
vert_idx = bsp->edges[edge_idx].vertex[1];
|
||||
}
|
||||
if (!pxl8_bsp_get_edge_vertex(bsp, surfedge_idx, &vert_idx)) continue;
|
||||
|
||||
if (vert_idx >= bsp->num_vertices) continue;
|
||||
verts[num_verts++] = bsp->vertices[vert_idx].position;
|
||||
}
|
||||
|
||||
|
|
@ -494,6 +509,7 @@ void pxl8_bsp_render_textured(
|
|||
pxl8_bsp_render_face(gfx, bsp, face_id, texture_id);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void pxl8_bsp_render_wireframe(
|
||||
|
|
@ -532,21 +548,9 @@ void pxl8_bsp_render_wireframe(
|
|||
if (surfedge_idx >= (i32)bsp->num_surfedges ||
|
||||
next_surfedge_idx >= (i32)bsp->num_surfedges) continue;
|
||||
|
||||
i32 edge_idx = bsp->surfedges[surfedge_idx];
|
||||
u32 v0_idx, v1_idx;
|
||||
|
||||
if (edge_idx >= 0) {
|
||||
if ((u32)edge_idx >= bsp->num_edges) continue;
|
||||
v0_idx = bsp->edges[edge_idx].vertex[0];
|
||||
v1_idx = bsp->edges[edge_idx].vertex[1];
|
||||
} else {
|
||||
edge_idx = -edge_idx;
|
||||
if ((u32)edge_idx >= bsp->num_edges) continue;
|
||||
v0_idx = bsp->edges[edge_idx].vertex[1];
|
||||
v1_idx = bsp->edges[edge_idx].vertex[0];
|
||||
}
|
||||
|
||||
if (v0_idx >= bsp->num_vertices || v1_idx >= bsp->num_vertices) continue;
|
||||
if (!pxl8_bsp_get_edge_vertices(bsp, surfedge_idx, &v0_idx, &v1_idx)) continue;
|
||||
|
||||
pxl8_vec3 p0 = bsp->vertices[v0_idx].position;
|
||||
pxl8_vec3 p1 = bsp->vertices[v1_idx].position;
|
||||
|
|
|
|||
520
src/pxl8_gfx.c
520
src/pxl8_gfx.c
|
|
@ -10,6 +10,7 @@
|
|||
#include "pxl8_hal.h"
|
||||
#include "pxl8_macros.h"
|
||||
#include "pxl8_math.h"
|
||||
#include "pxl8_sys.h"
|
||||
#include "pxl8_types.h"
|
||||
|
||||
typedef struct pxl8_sprite_cache_entry {
|
||||
|
|
@ -52,8 +53,6 @@ struct pxl8_gfx {
|
|||
|
||||
bool affine_textures;
|
||||
|
||||
u32 frame_triangle_count;
|
||||
u32 frame_pixel_count;
|
||||
};
|
||||
|
||||
static inline void pxl8_color_unpack(u32 color, u8* r, u8* g, u8* b, u8* a) {
|
||||
|
|
@ -71,38 +70,6 @@ static inline u8 pxl8_color_lerp_channel(u8 c1, u8 c2, f32 t) {
|
|||
return c1 + (i32)((c2 - c1) * t);
|
||||
}
|
||||
|
||||
static u32 pxl8_get_palette_size(pxl8_color_mode mode) {
|
||||
switch (mode) {
|
||||
case PXL8_COLOR_MODE_HICOLOR: return 0;
|
||||
case PXL8_COLOR_MODE_FAMI: return 64;
|
||||
case PXL8_COLOR_MODE_MEGA: return 512;
|
||||
case PXL8_COLOR_MODE_GBA: return 32768;
|
||||
case PXL8_COLOR_MODE_SNES: return 32768;
|
||||
default: return 256;
|
||||
}
|
||||
}
|
||||
|
||||
void pxl8_gfx_get_resolution_dimensions(pxl8_resolution resolution, i32* width, i32* height) {
|
||||
switch (resolution) {
|
||||
case PXL8_RESOLUTION_240x160:
|
||||
*width = 240; *height = 160; break;
|
||||
case PXL8_RESOLUTION_320x180:
|
||||
*width = 320; *height = 180; break;
|
||||
case PXL8_RESOLUTION_320x240:
|
||||
*width = 320; *height = 240; break;
|
||||
case PXL8_RESOLUTION_640x360:
|
||||
*width = 640; *height = 360; break;
|
||||
case PXL8_RESOLUTION_640x480:
|
||||
*width = 640; *height = 480; break;
|
||||
case PXL8_RESOLUTION_800x600:
|
||||
*width = 800; *height = 600; break;
|
||||
case PXL8_RESOLUTION_960x540:
|
||||
*width = 960; *height = 540; break;
|
||||
default:
|
||||
*width = 640; *height = 360; break;
|
||||
}
|
||||
}
|
||||
|
||||
pxl8_bounds pxl8_gfx_get_bounds(pxl8_gfx* gfx) {
|
||||
pxl8_bounds bounds = {0};
|
||||
if (!gfx) {
|
||||
|
|
@ -149,11 +116,9 @@ pxl8_gfx* pxl8_gfx_create(
|
|||
gfx->platform_data = platform_data;
|
||||
|
||||
gfx->color_mode = mode;
|
||||
pxl8_gfx_get_resolution_dimensions(
|
||||
resolution,
|
||||
&gfx->framebuffer_width,
|
||||
&gfx->framebuffer_height
|
||||
);
|
||||
pxl8_size size = pxl8_get_resolution_dimensions(resolution);
|
||||
gfx->framebuffer_width = size.w;
|
||||
gfx->framebuffer_height = size.h;
|
||||
|
||||
if (!gfx->platform_data) {
|
||||
pxl8_error("Platform data cannot be NULL");
|
||||
|
|
@ -404,18 +369,6 @@ void pxl8_gfx_project(pxl8_gfx* gfx, f32 left, f32 right, f32 top, f32 bottom) {
|
|||
void pxl8_clear(pxl8_gfx* gfx, u32 color) {
|
||||
if (!gfx || !gfx->framebuffer) return;
|
||||
|
||||
static u32 frame_count = 0;
|
||||
if (gfx->frame_triangle_count > 0) {
|
||||
if (frame_count % 60 == 0) {
|
||||
i32 fb_pixels = gfx->framebuffer_width * gfx->framebuffer_height;
|
||||
f32 overdraw = (f32)gfx->frame_pixel_count / (f32)fb_pixels;
|
||||
pxl8_trace("Frame triangles: %u, pixels: %u, overdraw: %.2fx",
|
||||
gfx->frame_triangle_count, gfx->frame_pixel_count, overdraw);
|
||||
}
|
||||
frame_count++;
|
||||
}
|
||||
gfx->frame_triangle_count = 0;
|
||||
gfx->frame_pixel_count = 0;
|
||||
|
||||
i32 bytes_per_pixel = (gfx->color_mode == PXL8_COLOR_MODE_HICOLOR) ? 4 : 1;
|
||||
i32 size = gfx->framebuffer_width * gfx->framebuffer_height;
|
||||
|
|
@ -903,7 +856,7 @@ void pxl8_3d_draw_line_3d(pxl8_gfx* gfx, pxl8_vec3 p0, pxl8_vec3 p1, u32 color)
|
|||
pxl8_line(gfx, x0, y0, x1, y1, color);
|
||||
}
|
||||
|
||||
static inline void pxl8_fill_scanline_hicolor(pxl8_gfx* gfx, i32 y, i32 xs, i32 xe, f32 z0, f32 z1, u32 color) {
|
||||
static inline void pxl8_fill_scanline(pxl8_gfx* gfx, i32 y, i32 xs, i32 xe, f32 z0, f32 z1, u32 color) {
|
||||
if (y < 0 || y >= gfx->framebuffer_height) return;
|
||||
if (xs > xe) {
|
||||
i32 tmp = xs; xs = xe; xe = tmp;
|
||||
|
|
@ -915,12 +868,16 @@ static inline void pxl8_fill_scanline_hicolor(pxl8_gfx* gfx, i32 y, i32 xs, i32
|
|||
if (xs > xe) return;
|
||||
|
||||
i32 width = xe - xs;
|
||||
i32 zbuf_offset = y * gfx->zbuffer_width;
|
||||
i32 fb_offset = y * gfx->framebuffer_width;
|
||||
|
||||
if (gfx->color_mode == PXL8_COLOR_MODE_HICOLOR) {
|
||||
u32* fb = (u32*)gfx->framebuffer;
|
||||
if (width == 0) {
|
||||
i32 idx = y * gfx->zbuffer_width + xs;
|
||||
i32 idx = zbuf_offset + xs;
|
||||
if (z0 <= gfx->zbuffer[idx]) {
|
||||
gfx->zbuffer[idx] = z0;
|
||||
i32 fb_idx = y * gfx->framebuffer_width + xs;
|
||||
((u32*)gfx->framebuffer)[fb_idx] = color;
|
||||
fb[fb_offset + xs] = color;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
@ -928,10 +885,6 @@ static inline void pxl8_fill_scanline_hicolor(pxl8_gfx* gfx, i32 y, i32 xs, i32
|
|||
f32 dz = (z1 - z0) / (f32)width;
|
||||
f32 z = z0;
|
||||
|
||||
i32 zbuf_offset = y * gfx->zbuffer_width;
|
||||
i32 fb_offset = y * gfx->framebuffer_width;
|
||||
u32* fb = (u32*)gfx->framebuffer;
|
||||
|
||||
for (i32 x = xs; x <= xe; x++) {
|
||||
i32 idx = zbuf_offset + x;
|
||||
if (z <= gfx->zbuffer[idx]) {
|
||||
|
|
@ -940,28 +893,13 @@ static inline void pxl8_fill_scanline_hicolor(pxl8_gfx* gfx, i32 y, i32 xs, i32
|
|||
}
|
||||
z += dz;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void pxl8_fill_scanline_indexed(pxl8_gfx* gfx, i32 y, i32 xs, i32 xe, f32 z0, f32 z1, u32 color) {
|
||||
if (y < 0 || y >= gfx->framebuffer_height) return;
|
||||
if (xs > xe) {
|
||||
i32 tmp = xs; xs = xe; xe = tmp;
|
||||
f32 tmpz = z0; z0 = z1; z1 = tmpz;
|
||||
}
|
||||
|
||||
if (xs < 0) xs = 0;
|
||||
if (xe >= gfx->framebuffer_width) xe = gfx->framebuffer_width - 1;
|
||||
if (xs > xe) return;
|
||||
|
||||
i32 width = xe - xs;
|
||||
} else {
|
||||
u8 idx_color = color & 0xFF;
|
||||
|
||||
if (width == 0) {
|
||||
i32 idx = y * gfx->zbuffer_width + xs;
|
||||
i32 idx = zbuf_offset + xs;
|
||||
if (z0 <= gfx->zbuffer[idx]) {
|
||||
gfx->zbuffer[idx] = z0;
|
||||
i32 fb_idx = y * gfx->framebuffer_width + xs;
|
||||
gfx->framebuffer[fb_idx] = idx_color;
|
||||
gfx->framebuffer[fb_offset + xs] = idx_color;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
@ -969,9 +907,6 @@ static inline void pxl8_fill_scanline_indexed(pxl8_gfx* gfx, i32 y, i32 xs, i32
|
|||
f32 dz = (z1 - z0) / (f32)width;
|
||||
f32 z = z0;
|
||||
|
||||
i32 zbuf_offset = y * gfx->zbuffer_width;
|
||||
i32 fb_offset = y * gfx->framebuffer_width;
|
||||
|
||||
for (i32 x = xs; x <= xe; x++) {
|
||||
i32 idx = zbuf_offset + x;
|
||||
if (z <= gfx->zbuffer[idx]) {
|
||||
|
|
@ -980,76 +915,78 @@ static inline void pxl8_fill_scanline_indexed(pxl8_gfx* gfx, i32 y, i32 xs, i32
|
|||
}
|
||||
z += dz;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline u32 pxl8_sample_texture(pxl8_gfx* gfx, u32 texture_id, f32 u, f32 v) {
|
||||
if (!gfx->atlas) return 0;
|
||||
static inline void pxl8_fill_scanline_textured(
|
||||
pxl8_gfx* gfx, i32 y, i32 xs, i32 xe,
|
||||
f32 z0, f32 z1,
|
||||
f32 u0, f32 v0, f32 w0,
|
||||
f32 u1, f32 v1, f32 w1,
|
||||
u32 texture_id
|
||||
) {
|
||||
if (y < 0 || y >= gfx->framebuffer_height) return;
|
||||
if (xs > xe) {
|
||||
i32 tmp = xs; xs = xe; xe = tmp;
|
||||
f32 tmpf;
|
||||
tmpf = z0; z0 = z1; z1 = tmpf;
|
||||
tmpf = u0; u0 = u1; u1 = tmpf;
|
||||
tmpf = v0; v0 = v1; v1 = tmpf;
|
||||
tmpf = w0; w0 = w1; w1 = tmpf;
|
||||
}
|
||||
|
||||
const pxl8_atlas_entry* entry = pxl8_atlas_get_entry(gfx->atlas, texture_id);
|
||||
if (!entry || !entry->active) {
|
||||
static bool warned = false;
|
||||
if (!warned) {
|
||||
pxl8_warn("Texture sampling failed: texture_id=%u entry=%p active=%d",
|
||||
texture_id, (void*)entry, entry ? entry->active : 0);
|
||||
warned = true;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if (!entry || !entry->active) return;
|
||||
|
||||
i32 tex_u = (i32)(u * entry->w);
|
||||
i32 tex_v = (i32)(v * entry->h);
|
||||
|
||||
i32 tx = tex_u % entry->w;
|
||||
if (tx < 0) tx += entry->w;
|
||||
i32 ty = tex_v % entry->h;
|
||||
if (ty < 0) ty += entry->h;
|
||||
|
||||
i32 atlas_x = entry->x + tx;
|
||||
i32 atlas_y = entry->y + ty;
|
||||
u32 atlas_width = pxl8_atlas_get_width(gfx->atlas);
|
||||
const u8* atlas_pixels = pxl8_atlas_get_pixels(gfx->atlas);
|
||||
i32 idx = atlas_y * atlas_width + atlas_x;
|
||||
u32 atlas_width = pxl8_atlas_get_width(gfx->atlas);
|
||||
i32 tex_w = entry->w;
|
||||
i32 tex_h = entry->h;
|
||||
bool is_pow2 = ((tex_w & (tex_w - 1)) == 0) && ((tex_h & (tex_h - 1)) == 0) && (tex_w == tex_h);
|
||||
i32 tex_mask = tex_w - 1;
|
||||
i32 atlas_x_base = entry->x;
|
||||
i32 atlas_y_base = entry->y;
|
||||
bool is_hicolor = (gfx->color_mode == PXL8_COLOR_MODE_HICOLOR);
|
||||
bool affine = gfx->affine_textures;
|
||||
|
||||
if (gfx->color_mode == PXL8_COLOR_MODE_HICOLOR) {
|
||||
return ((const u32*)atlas_pixels)[idx];
|
||||
i32 span = xe - xs;
|
||||
if (span <= 0) {
|
||||
if (xs >= 0 && xs < gfx->framebuffer_width) {
|
||||
i32 idx = y * gfx->zbuffer_width + xs;
|
||||
if (z0 <= gfx->zbuffer[idx]) {
|
||||
f32 tex_u = u0, tex_v = v0;
|
||||
if (!affine && fabsf(w0) > 1e-6f) {
|
||||
f32 perspective_w = 1.0f / w0;
|
||||
tex_u *= perspective_w;
|
||||
tex_v *= perspective_w;
|
||||
}
|
||||
|
||||
i32 tu = (i32)(tex_u * tex_w);
|
||||
i32 tv = (i32)(tex_v * tex_h);
|
||||
i32 tx, ty;
|
||||
if (is_pow2) {
|
||||
tx = tu & tex_mask;
|
||||
ty = tv & tex_mask;
|
||||
} else {
|
||||
return atlas_pixels[idx];
|
||||
}
|
||||
}
|
||||
|
||||
static inline void pxl8_fill_scanline_textured_hicolor(
|
||||
pxl8_gfx* gfx, i32 y, i32 xs, i32 xe,
|
||||
f32 z0, f32 z1,
|
||||
f32 u0, f32 v0, f32 w0,
|
||||
f32 u1, f32 v1, f32 w1,
|
||||
u32 texture_id
|
||||
) {
|
||||
if (y < 0 || y >= gfx->framebuffer_height) return;
|
||||
if (xs > xe) {
|
||||
i32 tmp = xs; xs = xe; xe = tmp;
|
||||
f32 tmpf;
|
||||
tmpf = z0; z0 = z1; z1 = tmpf;
|
||||
tmpf = u0; u0 = u1; u1 = tmpf;
|
||||
tmpf = v0; v0 = v1; v1 = tmpf;
|
||||
tmpf = w0; w0 = w1; w1 = tmpf;
|
||||
tx = tu % tex_w;
|
||||
if (tx < 0) tx += tex_w;
|
||||
ty = tv % tex_h;
|
||||
if (ty < 0) ty += tex_h;
|
||||
}
|
||||
|
||||
i32 span = xe - xs;
|
||||
if (span <= 0) {
|
||||
if (xs >= 0 && xs < gfx->framebuffer_width) {
|
||||
i32 idx = y * gfx->zbuffer_width + xs;
|
||||
if (z0 <= gfx->zbuffer[idx]) {
|
||||
gfx->frame_pixel_count++;
|
||||
f32 u = u0, v = v0;
|
||||
if (!gfx->affine_textures && fabsf(w0) > 1e-6f) {
|
||||
f32 perspective_w = 1.0f / w0;
|
||||
u *= perspective_w;
|
||||
v *= perspective_w;
|
||||
}
|
||||
u32 color = pxl8_sample_texture(gfx, texture_id, u, v);
|
||||
i32 atlas_idx = (atlas_y_base + ty) * atlas_width + (atlas_x_base + tx);
|
||||
u32 color = is_hicolor ? ((const u32*)atlas_pixels)[atlas_idx] : atlas_pixels[atlas_idx];
|
||||
|
||||
if (is_hicolor) {
|
||||
if (color & 0xFF000000) {
|
||||
gfx->zbuffer[idx] = z0;
|
||||
pxl8_pixel(gfx, xs, y, color);
|
||||
((u32*)gfx->framebuffer)[y * gfx->framebuffer_width + xs] = color;
|
||||
}
|
||||
} else {
|
||||
if (color != 0) {
|
||||
gfx->zbuffer[idx] = z0;
|
||||
gfx->framebuffer[y * gfx->framebuffer_width + xs] = (u8)color;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1071,92 +1008,40 @@ static inline void pxl8_fill_scanline_textured_hicolor(
|
|||
if (x >= 0 && x < gfx->framebuffer_width) {
|
||||
i32 idx = y * gfx->zbuffer_width + x;
|
||||
if (z <= gfx->zbuffer[idx]) {
|
||||
gfx->frame_pixel_count++;
|
||||
|
||||
f32 tex_u = u, tex_v = v;
|
||||
if (!gfx->affine_textures && fabsf(w) > 1e-6f) {
|
||||
if (!affine && fabsf(w) > 1e-6f) {
|
||||
f32 perspective_w = 1.0f / w;
|
||||
tex_u *= perspective_w;
|
||||
tex_v *= perspective_w;
|
||||
}
|
||||
u32 color = pxl8_sample_texture(gfx, texture_id, tex_u, tex_v);
|
||||
|
||||
i32 tu = (i32)(tex_u * tex_w);
|
||||
i32 tv = (i32)(tex_v * tex_h);
|
||||
i32 tx, ty;
|
||||
if (is_pow2) {
|
||||
tx = tu & tex_mask;
|
||||
ty = tv & tex_mask;
|
||||
} else {
|
||||
tx = tu % tex_w;
|
||||
if (tx < 0) tx += tex_w;
|
||||
ty = tv % tex_h;
|
||||
if (ty < 0) ty += tex_h;
|
||||
}
|
||||
|
||||
i32 atlas_idx = (atlas_y_base + ty) * atlas_width + (atlas_x_base + tx);
|
||||
u32 color = is_hicolor ? ((const u32*)atlas_pixels)[atlas_idx] : atlas_pixels[atlas_idx];
|
||||
|
||||
if (is_hicolor) {
|
||||
if (color & 0xFF000000) {
|
||||
gfx->zbuffer[idx] = z;
|
||||
pxl8_pixel(gfx, x, y, color);
|
||||
((u32*)gfx->framebuffer)[y * gfx->framebuffer_width + x] = color;
|
||||
}
|
||||
}
|
||||
}
|
||||
z += dz;
|
||||
u += du;
|
||||
v += dv;
|
||||
w += dw;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void pxl8_fill_scanline_textured_indexed(
|
||||
pxl8_gfx* gfx, i32 y, i32 xs, i32 xe,
|
||||
f32 z0, f32 z1,
|
||||
f32 u0, f32 v0, f32 w0,
|
||||
f32 u1, f32 v1, f32 w1,
|
||||
u32 texture_id
|
||||
) {
|
||||
if (y < 0 || y >= gfx->framebuffer_height) return;
|
||||
if (xs > xe) {
|
||||
i32 tmp = xs; xs = xe; xe = tmp;
|
||||
f32 tmpf;
|
||||
tmpf = z0; z0 = z1; z1 = tmpf;
|
||||
tmpf = u0; u0 = u1; u1 = tmpf;
|
||||
tmpf = v0; v0 = v1; v1 = tmpf;
|
||||
tmpf = w0; w0 = w1; w1 = tmpf;
|
||||
}
|
||||
|
||||
i32 span = xe - xs;
|
||||
if (span <= 0) {
|
||||
if (xs >= 0 && xs < gfx->framebuffer_width) {
|
||||
i32 idx = y * gfx->zbuffer_width + xs;
|
||||
if (z0 <= gfx->zbuffer[idx]) {
|
||||
gfx->frame_pixel_count++;
|
||||
f32 u = u0, v = v0;
|
||||
if (!gfx->affine_textures && fabsf(w0) > 1e-6f) {
|
||||
f32 perspective_w = 1.0f / w0;
|
||||
u *= perspective_w;
|
||||
v *= perspective_w;
|
||||
}
|
||||
u32 color = pxl8_sample_texture(gfx, texture_id, u, v);
|
||||
if (color != 0) {
|
||||
gfx->zbuffer[idx] = z0;
|
||||
pxl8_pixel(gfx, xs, y, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
f32 inv_span = 1.0f / (f32)span;
|
||||
f32 dz = (z1 - z0) * inv_span;
|
||||
f32 du = (u1 - u0) * inv_span;
|
||||
f32 dv = (v1 - v0) * inv_span;
|
||||
f32 dw = (w1 - w0) * inv_span;
|
||||
|
||||
f32 z = z0;
|
||||
f32 u = u0;
|
||||
f32 v = v0;
|
||||
f32 w = w0;
|
||||
|
||||
for (i32 x = xs; x <= xe; x++) {
|
||||
if (x >= 0 && x < gfx->framebuffer_width) {
|
||||
i32 idx = y * gfx->zbuffer_width + x;
|
||||
if (z <= gfx->zbuffer[idx]) {
|
||||
gfx->frame_pixel_count++;
|
||||
f32 tex_u = u, tex_v = v;
|
||||
if (!gfx->affine_textures && fabsf(w) > 1e-6f) {
|
||||
f32 perspective_w = 1.0f / w;
|
||||
tex_u *= perspective_w;
|
||||
tex_v *= perspective_w;
|
||||
}
|
||||
u32 color = pxl8_sample_texture(gfx, texture_id, tex_u, tex_v);
|
||||
} else {
|
||||
if (color != 0) {
|
||||
gfx->zbuffer[idx] = z;
|
||||
pxl8_pixel(gfx, x, y, color);
|
||||
gfx->framebuffer[y * gfx->framebuffer_width + x] = (u8)color;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1228,19 +1113,21 @@ void pxl8_3d_draw_triangle_raw(pxl8_gfx* gfx, pxl8_vec3 v0, pxl8_vec3 v1, pxl8_v
|
|||
void pxl8_3d_draw_triangle(pxl8_gfx* gfx, pxl8_triangle tri) {
|
||||
if (!gfx || !pxl8_3d_init_zbuffer(gfx)) return;
|
||||
|
||||
gfx->frame_triangle_count++;
|
||||
|
||||
pxl8_vec4 v0 = pxl8_transform_vertex(gfx, tri.v[0].position);
|
||||
pxl8_vec4 v1 = pxl8_transform_vertex(gfx, tri.v[1].position);
|
||||
pxl8_vec4 v2 = pxl8_transform_vertex(gfx, tri.v[2].position);
|
||||
|
||||
if (v0.w <= 0 || v1.w <= 0 || v2.w <= 0) return;
|
||||
pxl8_vec4 tv0 = v0;
|
||||
pxl8_vec4 tv1 = v1;
|
||||
pxl8_vec4 tv2 = v2;
|
||||
u32 tc0 = tri.v[0].color;
|
||||
|
||||
i32 x0, y0, x1, y1, x2, y2;
|
||||
f32 z0, z1, z2;
|
||||
pxl8_project_to_screen(gfx, v0, &x0, &y0, &z0);
|
||||
pxl8_project_to_screen(gfx, v1, &x1, &y1, &z1);
|
||||
pxl8_project_to_screen(gfx, v2, &x2, &y2, &z2);
|
||||
pxl8_project_to_screen(gfx, tv0, &x0, &y0, &z0);
|
||||
pxl8_project_to_screen(gfx, tv1, &x1, &y1, &z1);
|
||||
pxl8_project_to_screen(gfx, tv2, &x2, &y2, &z2);
|
||||
|
||||
if (gfx->backface_culling) {
|
||||
i32 cross = (x1 - x0) * (y2 - y0) - (y1 - y0) * (x2 - x0);
|
||||
|
|
@ -1248,10 +1135,9 @@ void pxl8_3d_draw_triangle(pxl8_gfx* gfx, pxl8_triangle tri) {
|
|||
}
|
||||
|
||||
if (gfx->wireframe) {
|
||||
u32 color = tri.v[0].color;
|
||||
pxl8_line(gfx, x0, y0, x1, y1, color);
|
||||
pxl8_line(gfx, x1, y1, x2, y2, color);
|
||||
pxl8_line(gfx, x2, y2, x0, y0, color);
|
||||
pxl8_line(gfx, x0, y0, x1, y1, tc0);
|
||||
pxl8_line(gfx, x1, y1, x2, y2, tc0);
|
||||
pxl8_line(gfx, x2, y2, x0, y0, tc0);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -1271,23 +1157,19 @@ void pxl8_3d_draw_triangle(pxl8_gfx* gfx, pxl8_triangle tri) {
|
|||
f32 tmp_f = z1; z1 = z2; z2 = tmp_f;
|
||||
}
|
||||
|
||||
u32 color = tri.v[0].color;
|
||||
|
||||
pxl8_scanline_func fill_scanline = (gfx->color_mode == PXL8_COLOR_MODE_HICOLOR)
|
||||
? pxl8_fill_scanline_hicolor
|
||||
: pxl8_fill_scanline_indexed;
|
||||
pxl8_scanline_func fill_scanline = pxl8_fill_scanline;
|
||||
|
||||
if (y1 == y2) {
|
||||
pxl8_scan_triangle(gfx, x0, y0, z0, x1, y1, z1, x2, y2, z2, color, fill_scanline, true);
|
||||
pxl8_scan_triangle(gfx, x0, y0, z0, x1, y1, z1, x2, y2, z2, tc0, fill_scanline, true);
|
||||
} else if (y0 == y1) {
|
||||
pxl8_scan_triangle(gfx, x0, y0, z0, x1, y1, z1, x2, y2, z2, color, fill_scanline, false);
|
||||
pxl8_scan_triangle(gfx, x0, y0, z0, x1, y1, z1, x2, y2, z2, tc0, fill_scanline, false);
|
||||
} else {
|
||||
i32 x3 = x0 + (i32)(((f32)(y1 - y0) / (f32)(y2 - y0)) * (x2 - x0));
|
||||
i32 y3 = y1;
|
||||
f32 z3 = z0 + ((f32)(y1 - y0) / (f32)(y2 - y0)) * (z2 - z0);
|
||||
|
||||
pxl8_scan_triangle(gfx, x0, y0, z0, x1, y1, z1, x3, y3, z3, color, fill_scanline, true);
|
||||
pxl8_scan_triangle(gfx, x1, y1, z1, x3, y3, z3, x2, y2, z2, color, fill_scanline, false);
|
||||
pxl8_scan_triangle(gfx, x0, y0, z0, x1, y1, z1, x3, y3, z3, tc0, fill_scanline, true);
|
||||
pxl8_scan_triangle(gfx, x1, y1, z1, x3, y3, z3, x2, y2, z2, tc0, fill_scanline, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1312,7 +1194,7 @@ static void pxl8_scan_triangle_textured(
|
|||
f32 inv_slope_u1, inv_slope_u2, inv_slope_v1, inv_slope_v2, inv_slope_w1, inv_slope_w2;
|
||||
|
||||
if (is_bottom) {
|
||||
if (v1.y == v0.y || v1.y < v0.y || v1.y - v0.y > gfx->framebuffer_height) return;
|
||||
if (v1.y == v0.y || v1.y < v0.y) return;
|
||||
y_start = v0.y;
|
||||
y_end = v1.y;
|
||||
y_step = 1;
|
||||
|
|
@ -1332,7 +1214,7 @@ static void pxl8_scan_triangle_textured(
|
|||
inv_slope_w1 = (v1.w - v0.w) / (f32)(v1.y - v0.y);
|
||||
inv_slope_w2 = (v2.w - v0.w) / (f32)(v2.y - v0.y);
|
||||
} else {
|
||||
if (v2.y == v0.y || v2.y < v0.y || v2.y - v0.y > gfx->framebuffer_height) return;
|
||||
if (v2.y == v0.y || v2.y < v0.y) return;
|
||||
y_start = v2.y;
|
||||
y_end = v0.y;
|
||||
y_step = -1;
|
||||
|
|
@ -1381,6 +1263,83 @@ static void pxl8_scan_triangle_textured(
|
|||
}
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
pxl8_vec4 clip;
|
||||
f32 u, v;
|
||||
} pxl8_clip_vert;
|
||||
|
||||
typedef struct {
|
||||
i32 x, y;
|
||||
f32 z, u, v, w;
|
||||
} pxl8_screen_vert;
|
||||
|
||||
static void pxl8_clip_screen_axis(pxl8_screen_vert* in, i32 in_count, pxl8_screen_vert* out, i32* out_count, i32 plane_pos, bool is_x, bool is_min) {
|
||||
*out_count = 0;
|
||||
|
||||
for (i32 i = 0; i < in_count; i++) {
|
||||
pxl8_screen_vert curr = in[i];
|
||||
pxl8_screen_vert next = in[(i + 1) % in_count];
|
||||
|
||||
i32 curr_val = is_x ? curr.x : curr.y;
|
||||
i32 next_val = is_x ? next.x : next.y;
|
||||
|
||||
bool curr_inside = is_min ? (curr_val >= plane_pos) : (curr_val <= plane_pos);
|
||||
bool next_inside = is_min ? (next_val >= plane_pos) : (next_val <= plane_pos);
|
||||
|
||||
if (curr_inside) {
|
||||
out[(*out_count)++] = curr;
|
||||
}
|
||||
|
||||
if (curr_inside != next_inside) {
|
||||
i32 denom = next_val - curr_val;
|
||||
if (denom != 0) {
|
||||
f32 t = (f32)(plane_pos - curr_val) / (f32)denom;
|
||||
out[*out_count] = (pxl8_screen_vert){
|
||||
.x = curr.x + (i32)(t * (next.x - curr.x)),
|
||||
.y = curr.y + (i32)(t * (next.y - curr.y)),
|
||||
.z = curr.z + t * (next.z - curr.z),
|
||||
.u = curr.u + t * (next.u - curr.u),
|
||||
.v = curr.v + t * (next.v - curr.v),
|
||||
.w = curr.w + t * (next.w - curr.w)
|
||||
};
|
||||
(*out_count)++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void pxl8_clip_near_plane(pxl8_clip_vert* in, i32 in_count, pxl8_clip_vert* out, i32* out_count, f32 near) {
|
||||
*out_count = 0;
|
||||
|
||||
for (i32 i = 0; i < in_count; i++) {
|
||||
pxl8_clip_vert curr = in[i];
|
||||
pxl8_clip_vert next = in[(i + 1) % in_count];
|
||||
|
||||
bool curr_inside = curr.clip.w >= near;
|
||||
bool next_inside = next.clip.w >= near;
|
||||
|
||||
if (curr_inside) {
|
||||
out[(*out_count)++] = curr;
|
||||
}
|
||||
|
||||
if (curr_inside != next_inside) {
|
||||
f32 t = (near - curr.clip.w) / (next.clip.w - curr.clip.w);
|
||||
|
||||
out[*out_count] = (pxl8_clip_vert){
|
||||
.clip = {
|
||||
curr.clip.x + t * (next.clip.x - curr.clip.x),
|
||||
curr.clip.y + t * (next.clip.y - curr.clip.y),
|
||||
curr.clip.z + t * (next.clip.z - curr.clip.z),
|
||||
near
|
||||
},
|
||||
.u = curr.u + t * (next.u - curr.u),
|
||||
.v = curr.v + t * (next.v - curr.v)
|
||||
};
|
||||
(*out_count)++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void pxl8_3d_draw_triangle_textured(
|
||||
pxl8_gfx* gfx,
|
||||
pxl8_vec3 v0,
|
||||
|
|
@ -1396,36 +1355,83 @@ void pxl8_3d_draw_triangle_textured(
|
|||
) {
|
||||
if (!gfx || !pxl8_3d_init_zbuffer(gfx)) return;
|
||||
|
||||
|
||||
pxl8_vec4 cv0 = pxl8_transform_vertex(gfx, v0);
|
||||
pxl8_vec4 cv1 = pxl8_transform_vertex(gfx, v1);
|
||||
pxl8_vec4 cv2 = pxl8_transform_vertex(gfx, v2);
|
||||
|
||||
if (cv0.w <= 0 || cv1.w <= 0 || cv2.w <= 0) return;
|
||||
pxl8_clip_vert input[3] = {
|
||||
{cv0, u0, v0f},
|
||||
{cv1, u1, v1f},
|
||||
{cv2, u2, v2f}
|
||||
};
|
||||
|
||||
pxl8_clip_vert clipped[8];
|
||||
i32 clipped_count = 0;
|
||||
|
||||
f32 near_clip = 0.1f;
|
||||
pxl8_clip_near_plane(input, 3, clipped, &clipped_count, near_clip);
|
||||
|
||||
if (clipped_count < 3) return;
|
||||
|
||||
i32 guard_band = (gfx->framebuffer_width > gfx->framebuffer_height ? gfx->framebuffer_width : gfx->framebuffer_height) * 2;
|
||||
|
||||
for (i32 tri = 0; tri < clipped_count - 2; tri++) {
|
||||
pxl8_vec4 c0 = clipped[0].clip;
|
||||
pxl8_vec4 c1 = clipped[tri + 1].clip;
|
||||
pxl8_vec4 c2 = clipped[tri + 2].clip;
|
||||
f32 tu0 = clipped[0].u;
|
||||
f32 tv0 = clipped[0].v;
|
||||
f32 tu1 = clipped[tri + 1].u;
|
||||
f32 tv1 = clipped[tri + 1].v;
|
||||
f32 tu2 = clipped[tri + 2].u;
|
||||
f32 tv2 = clipped[tri + 2].v;
|
||||
|
||||
i32 sx0, sy0, sx1, sy1, sx2, sy2;
|
||||
f32 z0, z1, z2;
|
||||
pxl8_project_to_screen(gfx, c0, &sx0, &sy0, &z0);
|
||||
pxl8_project_to_screen(gfx, c1, &sx1, &sy1, &z1);
|
||||
pxl8_project_to_screen(gfx, c2, &sx2, &sy2, &z2);
|
||||
|
||||
f32 w0_recip = 1.0f / c0.w;
|
||||
f32 w1_recip = 1.0f / c1.w;
|
||||
f32 w2_recip = 1.0f / c2.w;
|
||||
|
||||
pxl8_screen_vert screen_tri[3] = {
|
||||
{sx0, sy0, z0, tu0 * w0_recip, tv0 * w0_recip, w0_recip},
|
||||
{sx1, sy1, z1, tu1 * w1_recip, tv1 * w1_recip, w1_recip},
|
||||
{sx2, sy2, z2, tu2 * w2_recip, tv2 * w2_recip, w2_recip}
|
||||
};
|
||||
|
||||
pxl8_screen_vert temp1[8], temp2[8];
|
||||
i32 count1, count2;
|
||||
|
||||
pxl8_clip_screen_axis(screen_tri, 3, temp1, &count1, -guard_band, true, true);
|
||||
if (count1 < 3) continue;
|
||||
pxl8_clip_screen_axis(temp1, count1, temp2, &count2, guard_band, true, false);
|
||||
if (count2 < 3) continue;
|
||||
pxl8_clip_screen_axis(temp2, count2, temp1, &count1, -guard_band, false, true);
|
||||
if (count1 < 3) continue;
|
||||
pxl8_clip_screen_axis(temp1, count1, temp2, &count2, guard_band, false, false);
|
||||
if (count2 < 3) continue;
|
||||
|
||||
for (i32 i = 1; i < count2 - 1; i++) {
|
||||
pxl8_screen_vert v0 = temp2[0];
|
||||
pxl8_screen_vert v1 = temp2[i];
|
||||
pxl8_screen_vert v2 = temp2[i + 1];
|
||||
|
||||
pxl8_textured_vertex tv[3];
|
||||
f32 z_tmp;
|
||||
pxl8_project_to_screen(gfx, cv0, &tv[0].x, &tv[0].y, &z_tmp);
|
||||
tv[0].z = z_tmp;
|
||||
tv[0].u = gfx->affine_textures ? u0 : u0 / cv0.w;
|
||||
tv[0].v = gfx->affine_textures ? v0f : v0f / cv0.w;
|
||||
tv[0].w = gfx->affine_textures ? 1.0f : 1.0f / cv0.w;
|
||||
|
||||
pxl8_project_to_screen(gfx, cv1, &tv[1].x, &tv[1].y, &z_tmp);
|
||||
tv[1].z = z_tmp;
|
||||
tv[1].u = gfx->affine_textures ? u1 : u1 / cv1.w;
|
||||
tv[1].v = gfx->affine_textures ? v1f : v1f / cv1.w;
|
||||
tv[1].w = gfx->affine_textures ? 1.0f : 1.0f / cv1.w;
|
||||
|
||||
pxl8_project_to_screen(gfx, cv2, &tv[2].x, &tv[2].y, &z_tmp);
|
||||
tv[2].z = z_tmp;
|
||||
tv[2].u = gfx->affine_textures ? u2 : u2 / cv2.w;
|
||||
tv[2].v = gfx->affine_textures ? v2f : v2f / cv2.w;
|
||||
tv[2].w = gfx->affine_textures ? 1.0f : 1.0f / cv2.w;
|
||||
tv[0].x = v0.x; tv[0].y = v0.y; tv[0].z = v0.z;
|
||||
tv[0].u = v0.u; tv[0].v = v0.v; tv[0].w = v0.w;
|
||||
tv[1].x = v1.x; tv[1].y = v1.y; tv[1].z = v1.z;
|
||||
tv[1].u = v1.u; tv[1].v = v1.v; tv[1].w = v1.w;
|
||||
tv[2].x = v2.x; tv[2].y = v2.y; tv[2].z = v2.z;
|
||||
tv[2].u = v2.u; tv[2].v = v2.v; tv[2].w = v2.w;
|
||||
|
||||
if (gfx->backface_culling) {
|
||||
i32 cross =
|
||||
(tv[1].x - tv[0].x) * (tv[2].y - tv[0].y) - (tv[1].y - tv[0].y) * (tv[2].x - tv[0].x);
|
||||
if (cross >= 0) return;
|
||||
if (cross >= 0) continue;
|
||||
}
|
||||
|
||||
if (tv[0].y > tv[1].y) {
|
||||
|
|
@ -1438,9 +1444,7 @@ void pxl8_3d_draw_triangle_textured(
|
|||
pxl8_textured_vertex tmp = tv[1]; tv[1] = tv[2]; tv[2] = tmp;
|
||||
}
|
||||
|
||||
pxl8_scanline_textured_func fill_scanline = (gfx->color_mode == PXL8_COLOR_MODE_HICOLOR)
|
||||
? pxl8_fill_scanline_textured_hicolor
|
||||
: pxl8_fill_scanline_textured_indexed;
|
||||
pxl8_scanline_textured_func fill_scanline = pxl8_fill_scanline_textured;
|
||||
|
||||
if (tv[1].y == tv[2].y) {
|
||||
pxl8_scan_triangle_textured(gfx, tv[0], tv[1], tv[2], texture_id, fill_scanline, true);
|
||||
|
|
@ -1459,4 +1463,6 @@ void pxl8_3d_draw_triangle_textured(
|
|||
pxl8_scan_triangle_textured(gfx, tv[0], tv[1], v3, texture_id, fill_scanline, true);
|
||||
pxl8_scan_triangle_textured(gfx, tv[1], v3, tv[2], texture_id, fill_scanline, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,7 +57,6 @@ pxl8_color_mode pxl8_gfx_get_color_mode(pxl8_gfx* gfx);
|
|||
u8* pxl8_gfx_get_framebuffer(pxl8_gfx* gfx);
|
||||
i32 pxl8_gfx_get_height(const pxl8_gfx* gfx);
|
||||
u32 pxl8_gfx_get_palette_size(const pxl8_gfx* gfx);
|
||||
void pxl8_gfx_get_resolution_dimensions(pxl8_resolution resolution, i32* width, i32* height);
|
||||
i32 pxl8_gfx_get_width(const pxl8_gfx* gfx);
|
||||
pxl8_result pxl8_gfx_load_font_atlas(pxl8_gfx* gfx);
|
||||
pxl8_result pxl8_gfx_load_palette(pxl8_gfx* gfx, const char* path);
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ typedef struct pxl8_hal {
|
|||
u64 (*get_ticks)(void);
|
||||
|
||||
void (*present)(void* platform_data);
|
||||
void (*set_relative_mouse_mode)(void* platform_data, bool enabled);
|
||||
void (*upload_atlas)(void* platform_data, const pxl8_atlas* atlas,
|
||||
const u32* palette, pxl8_color_mode mode);
|
||||
void (*upload_framebuffer)(void* platform_data, const u8* fb,
|
||||
|
|
|
|||
|
|
@ -179,3 +179,13 @@ i32 pxl8_mouse_y(const pxl8_input_state* input) {
|
|||
if (!input) return 0;
|
||||
return input->mouse_y;
|
||||
}
|
||||
|
||||
i32 pxl8_mouse_dx(const pxl8_input_state* input) {
|
||||
if (!input) return 0;
|
||||
return input->mouse_dx;
|
||||
}
|
||||
|
||||
i32 pxl8_mouse_dy(const pxl8_input_state* input) {
|
||||
if (!input) return 0;
|
||||
return input->mouse_dy;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -104,6 +104,8 @@ i32 pxl8_mouse_wheel_x(const pxl8_input_state* input);
|
|||
i32 pxl8_mouse_wheel_y(const pxl8_input_state* input);
|
||||
i32 pxl8_mouse_x(const pxl8_input_state* input);
|
||||
i32 pxl8_mouse_y(const pxl8_input_state* input);
|
||||
i32 pxl8_mouse_dx(const pxl8_input_state* input);
|
||||
i32 pxl8_mouse_dy(const pxl8_input_state* input);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
|||
129
src/pxl8_math.c
129
src/pxl8_math.c
|
|
@ -96,13 +96,13 @@ pxl8_mat4 pxl8_mat4_identity(void) {
|
|||
pxl8_mat4 pxl8_mat4_multiply(pxl8_mat4 a, pxl8_mat4 b) {
|
||||
pxl8_mat4 mat = {0};
|
||||
|
||||
for (i32 i = 0; i < 4; i++) {
|
||||
for (i32 j = 0; j < 4; j++) {
|
||||
mat.m[i * 4 + j] =
|
||||
a.m[i * 4 + 0] * b.m[0 * 4 + j] +
|
||||
a.m[i * 4 + 1] * b.m[1 * 4 + j] +
|
||||
a.m[i * 4 + 2] * b.m[2 * 4 + j] +
|
||||
a.m[i * 4 + 3] * b.m[3 * 4 + j];
|
||||
for (i32 col = 0; col < 4; col++) {
|
||||
for (i32 row = 0; row < 4; row++) {
|
||||
mat.m[col * 4 + row] =
|
||||
a.m[0 * 4 + row] * b.m[col * 4 + 0] +
|
||||
a.m[1 * 4 + row] * b.m[col * 4 + 1] +
|
||||
a.m[2 * 4 + row] * b.m[col * 4 + 2] +
|
||||
a.m[3 * 4 + row] * b.m[col * 4 + 3];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -111,19 +111,19 @@ pxl8_mat4 pxl8_mat4_multiply(pxl8_mat4 a, pxl8_mat4 b) {
|
|||
|
||||
pxl8_vec4 pxl8_mat4_multiply_vec4(pxl8_mat4 m, pxl8_vec4 v) {
|
||||
return (pxl8_vec4){
|
||||
.x = m.m[0] * v.x + m.m[1] * v.y + m.m[2] * v.z + m.m[3] * v.w,
|
||||
.y = m.m[4] * v.x + m.m[5] * v.y + m.m[6] * v.z + m.m[7] * v.w,
|
||||
.z = m.m[8] * v.x + m.m[9] * v.y + m.m[10] * v.z + m.m[11] * v.w,
|
||||
.w = m.m[12] * v.x + m.m[13] * v.y + m.m[14] * v.z + m.m[15] * v.w,
|
||||
.x = m.m[0] * v.x + m.m[4] * v.y + m.m[8] * v.z + m.m[12] * v.w,
|
||||
.y = m.m[1] * v.x + m.m[5] * v.y + m.m[9] * v.z + m.m[13] * v.w,
|
||||
.z = m.m[2] * v.x + m.m[6] * v.y + m.m[10] * v.z + m.m[14] * v.w,
|
||||
.w = m.m[3] * v.x + m.m[7] * v.y + m.m[11] * v.z + m.m[15] * v.w,
|
||||
};
|
||||
}
|
||||
|
||||
pxl8_mat4 pxl8_mat4_translate(f32 x, f32 y, f32 z) {
|
||||
pxl8_mat4 mat = pxl8_mat4_identity();
|
||||
|
||||
mat.m[3] = x;
|
||||
mat.m[7] = y;
|
||||
mat.m[11] = z;
|
||||
mat.m[12] = x;
|
||||
mat.m[13] = y;
|
||||
mat.m[14] = z;
|
||||
|
||||
return mat;
|
||||
}
|
||||
|
|
@ -134,8 +134,8 @@ pxl8_mat4 pxl8_mat4_rotate_x(f32 angle) {
|
|||
f32 s = sinf(angle);
|
||||
|
||||
mat.m[5] = c;
|
||||
mat.m[6] = -s;
|
||||
mat.m[9] = s;
|
||||
mat.m[9] = -s;
|
||||
mat.m[6] = s;
|
||||
mat.m[10] = c;
|
||||
|
||||
return mat;
|
||||
|
|
@ -147,8 +147,8 @@ pxl8_mat4 pxl8_mat4_rotate_y(f32 angle) {
|
|||
f32 s = sinf(angle);
|
||||
|
||||
mat.m[0] = c;
|
||||
mat.m[2] = s;
|
||||
mat.m[8] = -s;
|
||||
mat.m[8] = s;
|
||||
mat.m[2] = -s;
|
||||
mat.m[10] = c;
|
||||
|
||||
return mat;
|
||||
|
|
@ -160,8 +160,8 @@ pxl8_mat4 pxl8_mat4_rotate_z(f32 angle) {
|
|||
f32 s = sinf(angle);
|
||||
|
||||
mat.m[0] = c;
|
||||
mat.m[1] = -s;
|
||||
mat.m[4] = s;
|
||||
mat.m[4] = -s;
|
||||
mat.m[1] = s;
|
||||
mat.m[5] = c;
|
||||
|
||||
return mat;
|
||||
|
|
@ -183,9 +183,9 @@ pxl8_mat4 pxl8_mat4_ortho(f32 left, f32 right, f32 bottom, f32 top, f32 near, f3
|
|||
mat.m[0] = 2.0f / (right - left);
|
||||
mat.m[5] = 2.0f / (top - bottom);
|
||||
mat.m[10] = -2.0f / (far - near);
|
||||
mat.m[3] = -(right + left) / (right - left);
|
||||
mat.m[7] = -(top + bottom) / (top - bottom);
|
||||
mat.m[11] = -(far + near) / (far - near);
|
||||
mat.m[12] = -(right + left) / (right - left);
|
||||
mat.m[13] = -(top + bottom) / (top - bottom);
|
||||
mat.m[14] = -(far + near) / (far - near);
|
||||
mat.m[15] = 1.0f;
|
||||
|
||||
return mat;
|
||||
|
|
@ -198,8 +198,8 @@ pxl8_mat4 pxl8_mat4_perspective(f32 fov, f32 aspect, f32 near, f32 far) {
|
|||
mat.m[0] = 1.0f / (aspect * tan_half_fov);
|
||||
mat.m[5] = 1.0f / tan_half_fov;
|
||||
mat.m[10] = -(far + near) / (far - near);
|
||||
mat.m[11] = -(2.0f * far * near) / (far - near);
|
||||
mat.m[14] = -1.0f;
|
||||
mat.m[14] = -(2.0f * far * near) / (far - near);
|
||||
mat.m[11] = -1.0f;
|
||||
|
||||
return mat;
|
||||
}
|
||||
|
|
@ -211,17 +211,17 @@ pxl8_mat4 pxl8_mat4_lookat(pxl8_vec3 eye, pxl8_vec3 center, pxl8_vec3 up) {
|
|||
pxl8_vec3 u = pxl8_vec3_cross(s, f);
|
||||
|
||||
mat.m[0] = s.x;
|
||||
mat.m[1] = s.y;
|
||||
mat.m[2] = s.z;
|
||||
mat.m[4] = u.x;
|
||||
mat.m[4] = s.y;
|
||||
mat.m[8] = s.z;
|
||||
mat.m[1] = u.x;
|
||||
mat.m[5] = u.y;
|
||||
mat.m[6] = u.z;
|
||||
mat.m[8] = -f.x;
|
||||
mat.m[9] = -f.y;
|
||||
mat.m[9] = u.z;
|
||||
mat.m[2] = -f.x;
|
||||
mat.m[6] = -f.y;
|
||||
mat.m[10] = -f.z;
|
||||
mat.m[3] = -pxl8_vec3_dot(s, eye);
|
||||
mat.m[7] = -pxl8_vec3_dot(u, eye);
|
||||
mat.m[11] = pxl8_vec3_dot(f, eye);
|
||||
mat.m[12] = -pxl8_vec3_dot(s, eye);
|
||||
mat.m[13] = -pxl8_vec3_dot(u, eye);
|
||||
mat.m[14] = pxl8_vec3_dot(f, eye);
|
||||
|
||||
return mat;
|
||||
}
|
||||
|
|
@ -230,35 +230,35 @@ pxl8_frustum pxl8_frustum_from_matrix(pxl8_mat4 vp) {
|
|||
pxl8_frustum frustum;
|
||||
const f32* m = vp.m;
|
||||
|
||||
frustum.planes[0].normal.x = m[12] - m[0];
|
||||
frustum.planes[0].normal.y = m[13] - m[1];
|
||||
frustum.planes[0].normal.z = m[14] - m[2];
|
||||
frustum.planes[0].distance = m[15] - m[3];
|
||||
frustum.planes[0].normal.x = m[3] - m[0];
|
||||
frustum.planes[0].normal.y = m[7] - m[4];
|
||||
frustum.planes[0].normal.z = m[11] - m[8];
|
||||
frustum.planes[0].distance = m[15] - m[12];
|
||||
|
||||
frustum.planes[1].normal.x = m[12] + m[0];
|
||||
frustum.planes[1].normal.y = m[13] + m[1];
|
||||
frustum.planes[1].normal.z = m[14] + m[2];
|
||||
frustum.planes[1].distance = m[15] + m[3];
|
||||
frustum.planes[1].normal.x = m[3] + m[0];
|
||||
frustum.planes[1].normal.y = m[7] + m[4];
|
||||
frustum.planes[1].normal.z = m[11] + m[8];
|
||||
frustum.planes[1].distance = m[15] + m[12];
|
||||
|
||||
frustum.planes[2].normal.x = m[12] + m[4];
|
||||
frustum.planes[2].normal.y = m[13] + m[5];
|
||||
frustum.planes[2].normal.z = m[14] + m[6];
|
||||
frustum.planes[2].distance = m[15] + m[7];
|
||||
frustum.planes[2].normal.x = m[3] + m[1];
|
||||
frustum.planes[2].normal.y = m[7] + m[5];
|
||||
frustum.planes[2].normal.z = m[11] + m[9];
|
||||
frustum.planes[2].distance = m[15] + m[13];
|
||||
|
||||
frustum.planes[3].normal.x = m[12] - m[4];
|
||||
frustum.planes[3].normal.y = m[13] - m[5];
|
||||
frustum.planes[3].normal.z = m[14] - m[6];
|
||||
frustum.planes[3].distance = m[15] - m[7];
|
||||
frustum.planes[3].normal.x = m[3] - m[1];
|
||||
frustum.planes[3].normal.y = m[7] - m[5];
|
||||
frustum.planes[3].normal.z = m[11] - m[9];
|
||||
frustum.planes[3].distance = m[15] - m[13];
|
||||
|
||||
frustum.planes[4].normal.x = m[12] - m[8];
|
||||
frustum.planes[4].normal.y = m[13] - m[9];
|
||||
frustum.planes[4].normal.z = m[14] - m[10];
|
||||
frustum.planes[4].distance = m[15] - m[11];
|
||||
frustum.planes[4].normal.x = m[3] - m[2];
|
||||
frustum.planes[4].normal.y = m[7] - m[6];
|
||||
frustum.planes[4].normal.z = m[11] - m[10];
|
||||
frustum.planes[4].distance = m[15] - m[14];
|
||||
|
||||
frustum.planes[5].normal.x = m[12] + m[8];
|
||||
frustum.planes[5].normal.y = m[13] + m[9];
|
||||
frustum.planes[5].normal.z = m[14] + m[10];
|
||||
frustum.planes[5].distance = m[15] + m[11];
|
||||
frustum.planes[5].normal.x = m[3] + m[2];
|
||||
frustum.planes[5].normal.y = m[7] + m[6];
|
||||
frustum.planes[5].normal.z = m[11] + m[10];
|
||||
frustum.planes[5].distance = m[15] + m[14];
|
||||
|
||||
for (i32 i = 0; i < 6; i++) {
|
||||
f32 len = pxl8_vec3_length(frustum.planes[i].normal);
|
||||
|
|
@ -283,22 +283,11 @@ bool pxl8_frustum_test_aabb(const pxl8_frustum* frustum, pxl8_vec3 min, pxl8_vec
|
|||
(normal.z >= 0.0f) ? max.z : min.z
|
||||
};
|
||||
|
||||
pxl8_vec3 n_vertex = {
|
||||
(normal.x >= 0.0f) ? min.x : max.x,
|
||||
(normal.y >= 0.0f) ? min.y : max.y,
|
||||
(normal.z >= 0.0f) ? min.z : max.z
|
||||
};
|
||||
|
||||
f32 p_dist = pxl8_vec3_dot(normal, p_vertex) + d;
|
||||
f32 n_dist = pxl8_vec3_dot(normal, n_vertex) + d;
|
||||
|
||||
if (p_dist < -0.1f) {
|
||||
if (p_dist < 0.0f) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (n_dist > 0.1f) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -113,6 +113,9 @@ static const char* pxl8_ffi_cdefs =
|
|||
"int pxl8_mouse_wheel_y(const pxl8_input_state* input);\n"
|
||||
"int pxl8_mouse_x(const pxl8_input_state* input);\n"
|
||||
"int pxl8_mouse_y(const pxl8_input_state* input);\n"
|
||||
"int pxl8_mouse_dx(const pxl8_input_state* input);\n"
|
||||
"int pxl8_mouse_dy(const pxl8_input_state* input);\n"
|
||||
"void pxl8_set_relative_mouse_mode(pxl8* sys, bool enabled);\n"
|
||||
"void pxl8_lua_debug(const char* msg);\n"
|
||||
"void pxl8_lua_error(const char* msg);\n"
|
||||
"void pxl8_lua_info(const char* msg);\n"
|
||||
|
|
|
|||
|
|
@ -31,17 +31,7 @@ static void* sdl3_create(pxl8_color_mode mode, pxl8_resolution resolution,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
i32 fb_w, fb_h;
|
||||
switch (resolution) {
|
||||
case PXL8_RESOLUTION_240x160: fb_w = 240; fb_h = 160; break;
|
||||
case PXL8_RESOLUTION_320x180: fb_w = 320; fb_h = 180; break;
|
||||
case PXL8_RESOLUTION_320x240: fb_w = 320; fb_h = 240; break;
|
||||
case PXL8_RESOLUTION_640x360: fb_w = 640; fb_h = 360; break;
|
||||
case PXL8_RESOLUTION_640x480: fb_w = 640; fb_h = 480; break;
|
||||
case PXL8_RESOLUTION_800x600: fb_w = 800; fb_h = 600; break;
|
||||
case PXL8_RESOLUTION_960x540: fb_w = 960; fb_h = 540; break;
|
||||
default: fb_w = 640; fb_h = 360; break;
|
||||
}
|
||||
pxl8_size fb_size = pxl8_get_resolution_dimensions(resolution);
|
||||
|
||||
ctx->window = SDL_CreateWindow(title, win_w, win_h, SDL_WINDOW_RESIZABLE);
|
||||
if (!ctx->window) {
|
||||
|
|
@ -65,7 +55,7 @@ static void* sdl3_create(pxl8_color_mode mode, pxl8_resolution resolution,
|
|||
ctx->framebuffer_texture = SDL_CreateTexture(ctx->renderer,
|
||||
SDL_PIXELFORMAT_RGBA32,
|
||||
SDL_TEXTUREACCESS_STREAMING,
|
||||
fb_w, fb_h);
|
||||
fb_size.w, fb_size.h);
|
||||
if (!ctx->framebuffer_texture) {
|
||||
pxl8_error("Failed to create framebuffer texture: %s", SDL_GetError());
|
||||
SDL_DestroyRenderer(ctx->renderer);
|
||||
|
|
@ -145,14 +135,7 @@ static void sdl3_upload_framebuffer(void* platform_data, const u8* fb,
|
|||
|
||||
if (!ctx->rgba_buffer) return;
|
||||
|
||||
u32 palette_size;
|
||||
switch (mode) {
|
||||
case PXL8_COLOR_MODE_FAMI: palette_size = 64; break;
|
||||
case PXL8_COLOR_MODE_MEGA: palette_size = 512; break;
|
||||
case PXL8_COLOR_MODE_GBA: palette_size = 32768; break;
|
||||
case PXL8_COLOR_MODE_SNES: palette_size = 32768; break;
|
||||
default: palette_size = 256; break;
|
||||
}
|
||||
u32 palette_size = pxl8_get_palette_size(mode);
|
||||
|
||||
for (i32 i = 0; i < w * h; i++) {
|
||||
u8 index = fb[i];
|
||||
|
|
@ -212,14 +195,7 @@ static void sdl3_upload_atlas(void* platform_data, const pxl8_atlas* atlas,
|
|||
|
||||
if (!ctx->rgba_buffer) return;
|
||||
|
||||
u32 palette_size;
|
||||
switch (mode) {
|
||||
case PXL8_COLOR_MODE_FAMI: palette_size = 64; break;
|
||||
case PXL8_COLOR_MODE_MEGA: palette_size = 512; break;
|
||||
case PXL8_COLOR_MODE_GBA: palette_size = 32768; break;
|
||||
case PXL8_COLOR_MODE_SNES: palette_size = 32768; break;
|
||||
default: palette_size = 256; break;
|
||||
}
|
||||
u32 palette_size = pxl8_get_palette_size(mode);
|
||||
|
||||
for (u32 i = 0; i < atlas_w * atlas_h; i++) {
|
||||
u8 index = atlas_pixels[i];
|
||||
|
|
@ -290,12 +266,6 @@ SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event) {
|
|||
break;
|
||||
|
||||
case SDL_EVENT_KEY_DOWN: {
|
||||
#ifdef DEBUG
|
||||
if (event->key.key == SDLK_ESCAPE) {
|
||||
pxl8_set_running(sys, false);
|
||||
}
|
||||
#endif
|
||||
|
||||
SDL_Scancode scancode = event->key.scancode;
|
||||
if (scancode < 256) {
|
||||
if (!input->keys_down[scancode]) {
|
||||
|
|
@ -343,6 +313,9 @@ SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event) {
|
|||
pxl8_gfx* gfx = pxl8_get_gfx(sys);
|
||||
if (!gfx) break;
|
||||
|
||||
input->mouse_dx = (i32)event->motion.xrel;
|
||||
input->mouse_dy = (i32)event->motion.yrel;
|
||||
|
||||
i32 window_mouse_x = (i32)event->motion.x;
|
||||
i32 window_mouse_y = (i32)event->motion.y;
|
||||
|
||||
|
|
@ -352,12 +325,11 @@ SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event) {
|
|||
i32 window_width, window_height;
|
||||
SDL_GetWindowSize(window, &window_width, &window_height);
|
||||
|
||||
i32 render_width, render_height;
|
||||
pxl8_resolution resolution = pxl8_get_resolution(sys);
|
||||
pxl8_gfx_get_resolution_dimensions(resolution, &render_width, &render_height);
|
||||
pxl8_size render_size = pxl8_get_resolution_dimensions(resolution);
|
||||
|
||||
pxl8_bounds window_bounds = {0, 0, window_width, window_height};
|
||||
pxl8_viewport vp = pxl8_gfx_viewport(window_bounds, render_width, render_height);
|
||||
pxl8_viewport vp = pxl8_gfx_viewport(window_bounds, render_size.w, render_size.h);
|
||||
|
||||
input->mouse_x = (i32)((window_mouse_x - vp.offset_x) / vp.scale);
|
||||
input->mouse_y = (i32)((window_mouse_y - vp.offset_y) / vp.scale);
|
||||
|
|
@ -386,6 +358,15 @@ void SDL_AppQuit(void* appstate, SDL_AppResult result) {
|
|||
SDL_Quit();
|
||||
}
|
||||
|
||||
static void sdl3_set_relative_mouse_mode(void* platform_data, bool enabled) {
|
||||
if (!platform_data) return;
|
||||
|
||||
pxl8_sdl3_context* ctx = (pxl8_sdl3_context*)platform_data;
|
||||
if (!SDL_SetWindowRelativeMouseMode(ctx->window, enabled)) {
|
||||
pxl8_error("Failed to set relative mouse mode: %s", SDL_GetError());
|
||||
}
|
||||
}
|
||||
|
||||
const pxl8_hal pxl8_hal_sdl3 = {
|
||||
.create = sdl3_create,
|
||||
.destroy = sdl3_destroy,
|
||||
|
|
@ -393,4 +374,5 @@ const pxl8_hal pxl8_hal_sdl3 = {
|
|||
.present = sdl3_present,
|
||||
.upload_atlas = sdl3_upload_atlas,
|
||||
.upload_framebuffer = sdl3_upload_framebuffer,
|
||||
.set_relative_mouse_mode = sdl3_set_relative_mouse_mode,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -14,11 +14,16 @@ bool pxl8_is_running(const pxl8* sys);
|
|||
void pxl8_set_running(pxl8* sys, bool running);
|
||||
|
||||
f32 pxl8_get_fps(const pxl8* sys);
|
||||
pxl8_gfx* pxl8_get_gfx(pxl8* sys);
|
||||
pxl8_input_state* pxl8_get_input(pxl8* sys);
|
||||
pxl8_resolution pxl8_get_resolution(pxl8* sys);
|
||||
pxl8_gfx* pxl8_get_gfx(const pxl8* sys);
|
||||
pxl8_input_state* pxl8_get_input(const pxl8* sys);
|
||||
pxl8_resolution pxl8_get_resolution(const pxl8* sys);
|
||||
|
||||
void pxl8_set_relative_mouse_mode(pxl8* sys, bool enabled);
|
||||
|
||||
pxl8_result pxl8_init(pxl8* sys, i32 argc, char* argv[]);
|
||||
pxl8_result pxl8_update(pxl8* sys);
|
||||
pxl8_result pxl8_frame(pxl8* sys);
|
||||
void pxl8_quit(pxl8* sys);
|
||||
|
||||
u32 pxl8_get_palette_size(pxl8_color_mode mode);
|
||||
pxl8_size pxl8_get_resolution_dimensions(pxl8_resolution resolution);
|
||||
|
|
|
|||
|
|
@ -75,12 +75,19 @@ typedef struct pxl8_input_state {
|
|||
i32 mouse_wheel_y;
|
||||
i32 mouse_x;
|
||||
i32 mouse_y;
|
||||
i32 mouse_dx;
|
||||
i32 mouse_dy;
|
||||
bool mouse_relative_mode;
|
||||
} pxl8_input_state;
|
||||
|
||||
typedef struct pxl8_point {
|
||||
i32 x, y;
|
||||
} pxl8_point;
|
||||
|
||||
typedef struct pxl8_size {
|
||||
i32 w, h;
|
||||
} pxl8_size;
|
||||
|
||||
typedef struct pxl8_viewport {
|
||||
i32 offset_x, offset_y;
|
||||
i32 scaled_width, scaled_height;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue