add colored lighting back in via the colormap
This commit is contained in:
parent
01e6059dd1
commit
a29a6018b8
16 changed files with 149 additions and 466 deletions
|
|
@ -349,11 +349,12 @@
|
|||
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 0xFFB888 light-intensity light-radius)
|
||||
(lights:add light-x light-y light-z 2 light-intensity light-radius)
|
||||
|
||||
(pxl8.push_target)
|
||||
(pxl8.begin_frame_3d camera lights {
|
||||
:ambient 25
|
||||
:dither true
|
||||
:fog_density 0.0
|
||||
:celestial_dir [0.5 -0.8 0.3]
|
||||
:celestial_intensity 0.3})
|
||||
|
|
|
|||
|
|
@ -340,7 +340,6 @@ pxl8_result pxl8_update(pxl8* sys) {
|
|||
|
||||
if (game->fps_accumulator >= 1.0f) {
|
||||
game->fps = (f32)game->fps_frame_count / game->fps_accumulator;
|
||||
pxl8_info("FPS: %.1f", game->fps);
|
||||
game->fps_accumulator = 0.0f;
|
||||
game->fps_frame_count = 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ typedef struct {
|
|||
static const pxl8_rgb pxl8_light_colors[PXL8_LIGHT_COLORS] = {
|
||||
{255, 255, 255},
|
||||
{255, 64, 64},
|
||||
{255, 160, 64},
|
||||
{255, 192, 64},
|
||||
{255, 255, 64},
|
||||
{64, 255, 64},
|
||||
{64, 255, 255},
|
||||
|
|
|
|||
|
|
@ -53,7 +53,6 @@ struct pxl8_gfx {
|
|||
pxl8_renderer* renderer;
|
||||
pxl8_gfx_texture color_target;
|
||||
pxl8_gfx_texture depth_target;
|
||||
pxl8_gfx_texture light_target;
|
||||
pxl8_gfx_cmdbuf* cmdbuf;
|
||||
pxl8_target_entry target_stack[PXL8_MAX_TARGET_STACK];
|
||||
u32 target_stack_depth;
|
||||
|
|
@ -115,11 +114,6 @@ i32 pxl8_gfx_get_height(const pxl8_gfx* gfx) {
|
|||
return gfx ? gfx->framebuffer_height : 0;
|
||||
}
|
||||
|
||||
u32* pxl8_gfx_get_light_accum(pxl8_gfx* gfx) {
|
||||
if (!gfx) return NULL;
|
||||
return (u32*)pxl8_texture_get_data(gfx->renderer, gfx->light_target);
|
||||
}
|
||||
|
||||
u32* pxl8_gfx_get_output(pxl8_gfx* gfx) {
|
||||
if (!gfx) return NULL;
|
||||
return gfx->output;
|
||||
|
|
@ -137,7 +131,6 @@ void pxl8_gfx_resolve(pxl8_gfx* gfx) {
|
|||
pxl8_resolve_to_rgba(
|
||||
gfx->renderer,
|
||||
gfx->color_target,
|
||||
gfx->light_target,
|
||||
pal,
|
||||
gfx->output
|
||||
);
|
||||
|
|
@ -246,14 +239,6 @@ pxl8_gfx* pxl8_gfx_create(
|
|||
};
|
||||
gfx->depth_target = pxl8_create_texture(gfx->renderer, &depth_desc);
|
||||
|
||||
pxl8_gfx_texture_desc light_desc = {
|
||||
.width = (u32)gfx->framebuffer_width,
|
||||
.height = (u32)gfx->framebuffer_height,
|
||||
.format = PXL8_GFX_FORMAT_LIGHT_ACCUM,
|
||||
.render_target = true,
|
||||
};
|
||||
gfx->light_target = pxl8_create_texture(gfx->renderer, &light_desc);
|
||||
|
||||
u32 pixel_count = (u32)gfx->framebuffer_width * (u32)gfx->framebuffer_height;
|
||||
gfx->output = pxl8_calloc(pixel_count, sizeof(u32));
|
||||
if (!gfx->output) {
|
||||
|
|
@ -276,7 +261,6 @@ pxl8_gfx* pxl8_gfx_create(
|
|||
gfx->target_stack[0] = (pxl8_target_entry){
|
||||
.color = gfx->color_target,
|
||||
.depth = gfx->depth_target,
|
||||
.light = gfx->light_target,
|
||||
};
|
||||
gfx->target_stack_depth = 1;
|
||||
|
||||
|
|
@ -469,16 +453,6 @@ void pxl8_gfx_present(pxl8_gfx* gfx) {
|
|||
gfx->hal->present(gfx->platform_data);
|
||||
}
|
||||
|
||||
void pxl8_gfx_reset_stats(pxl8_gfx* gfx) {
|
||||
if (!gfx || !gfx->renderer) return;
|
||||
pxl8_renderer_reset_stats(gfx->renderer);
|
||||
}
|
||||
|
||||
const pxl8_gfx_stats* pxl8_gfx_get_stats(pxl8_gfx* gfx) {
|
||||
if (!gfx || !gfx->renderer) return NULL;
|
||||
return pxl8_renderer_get_stats(gfx->renderer);
|
||||
}
|
||||
|
||||
pxl8_viewport pxl8_gfx_viewport(pxl8_bounds bounds, i32 width, i32 height) {
|
||||
pxl8_viewport vp = {0};
|
||||
vp.scale = fminf(bounds.w / (f32)width, bounds.h / (f32)height);
|
||||
|
|
@ -508,11 +482,6 @@ static pxl8_gfx_texture gfx_current_depth(pxl8_gfx* gfx) {
|
|||
return gfx->target_stack[gfx->target_stack_depth - 1].depth;
|
||||
}
|
||||
|
||||
static pxl8_gfx_texture gfx_current_light(pxl8_gfx* gfx) {
|
||||
if (gfx->target_stack_depth == 0) return gfx->light_target;
|
||||
return gfx->target_stack[gfx->target_stack_depth - 1].light;
|
||||
}
|
||||
|
||||
static void gfx_composite_over(pxl8_gfx* gfx, const pxl8_target_entry* src, pxl8_target_entry* dst) {
|
||||
if (!gfx || !src || !dst) return;
|
||||
|
||||
|
|
@ -546,7 +515,6 @@ static void gfx_composite_over(pxl8_gfx* gfx, const pxl8_target_entry* src, pxl8
|
|||
void pxl8_2d_clear(pxl8_gfx* gfx, u32 color) {
|
||||
if (!gfx) return;
|
||||
pxl8_clear(gfx->renderer, gfx_current_color(gfx), (u8)color);
|
||||
pxl8_clear_light(gfx->renderer, gfx_current_light(gfx));
|
||||
}
|
||||
|
||||
void pxl8_2d_pixel(pxl8_gfx* gfx, i32 x, i32 y, u32 color) {
|
||||
|
|
@ -745,7 +713,6 @@ void pxl8_3d_begin_frame(pxl8_gfx* gfx, const pxl8_3d_camera* camera, const pxl8
|
|||
pxl8_gfx_pass_desc pass_desc = {
|
||||
.color = { .texture = gfx_current_color(gfx), .load = PXL8_GFX_LOAD_CLEAR, .clear_value = 0 },
|
||||
.depth = { .texture = gfx_current_depth(gfx), .load = PXL8_GFX_LOAD_CLEAR, .clear_value = 0xFFFF },
|
||||
.light_accum = { .texture = gfx_current_light(gfx), .load = PXL8_GFX_LOAD_CLEAR },
|
||||
};
|
||||
gfx->frame_pass = pxl8_create_pass(gfx->renderer, &pass_desc);
|
||||
pxl8_begin_pass(gfx->cmdbuf, gfx->frame_pass);
|
||||
|
|
@ -791,7 +758,6 @@ u32 pxl8_3d_project_points(pxl8_gfx* gfx, const pxl8_vec3* in, pxl8_vec3* out, u
|
|||
void pxl8_3d_clear(pxl8_gfx* gfx, u8 color) {
|
||||
if (!gfx) return;
|
||||
pxl8_clear(gfx->renderer, gfx_current_color(gfx), color);
|
||||
pxl8_clear_light(gfx->renderer, gfx_current_light(gfx));
|
||||
}
|
||||
|
||||
void pxl8_3d_clear_depth(pxl8_gfx* gfx) {
|
||||
|
|
@ -1001,18 +967,9 @@ bool pxl8_gfx_push_target(pxl8_gfx* gfx) {
|
|||
};
|
||||
pxl8_gfx_texture new_depth = pxl8_create_texture(gfx->renderer, &depth_desc);
|
||||
|
||||
pxl8_gfx_texture_desc light_desc = {
|
||||
.width = (u32)gfx->framebuffer_width,
|
||||
.height = (u32)gfx->framebuffer_height,
|
||||
.format = PXL8_GFX_FORMAT_LIGHT_ACCUM,
|
||||
.render_target = true,
|
||||
};
|
||||
pxl8_gfx_texture new_light = pxl8_create_texture(gfx->renderer, &light_desc);
|
||||
|
||||
gfx->target_stack[gfx->target_stack_depth] = (pxl8_target_entry){
|
||||
.color = new_color,
|
||||
.depth = new_depth,
|
||||
.light = new_light,
|
||||
};
|
||||
gfx->target_stack_depth++;
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,19 @@
|
|||
#include "pxl8_gui_palette.h"
|
||||
|
||||
typedef struct pxl8_gfx pxl8_gfx;
|
||||
typedef struct pxl8_gfx_stats pxl8_gfx_stats;
|
||||
|
||||
typedef struct pxl8_gfx_stats {
|
||||
u64 draw_calls;
|
||||
u64 triangles;
|
||||
u64 clipped_triangles;
|
||||
u64 depth_tests;
|
||||
u64 depth_passes;
|
||||
u64 shader_calls;
|
||||
u64 pixels_written;
|
||||
u64 submit_ns;
|
||||
u64 execute_draw_ns;
|
||||
u64 raster_ns;
|
||||
} pxl8_gfx_stats;
|
||||
|
||||
typedef enum pxl8_gfx_effect {
|
||||
PXL8_GFX_EFFECT_GLOWS = 0,
|
||||
|
|
@ -26,8 +38,6 @@ void pxl8_gfx_destroy(pxl8_gfx* gfx);
|
|||
void pxl8_gfx_present(pxl8_gfx* gfx);
|
||||
void pxl8_gfx_update(pxl8_gfx* gfx, f32 dt);
|
||||
void pxl8_gfx_upload_framebuffer(pxl8_gfx* gfx);
|
||||
void pxl8_gfx_reset_stats(pxl8_gfx* gfx);
|
||||
const pxl8_gfx_stats* pxl8_gfx_get_stats(pxl8_gfx* gfx);
|
||||
|
||||
u8 pxl8_gfx_find_color(pxl8_gfx* gfx, u32 color);
|
||||
|
||||
|
|
@ -35,7 +45,6 @@ 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);
|
||||
i32 pxl8_gfx_get_height(const pxl8_gfx* gfx);
|
||||
u32* pxl8_gfx_get_light_accum(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);
|
||||
|
|
|
|||
|
|
@ -33,16 +33,16 @@ void pxl8_lights_destroy(pxl8_lights* lights) {
|
|||
pxl8_free(lights);
|
||||
}
|
||||
|
||||
void pxl8_lights_add(pxl8_lights* lights, f32 x, f32 y, f32 z, u8 r, u8 g, u8 b, u8 intensity, f32 radius) {
|
||||
(void)r; (void)g; (void)b;
|
||||
void pxl8_lights_add(pxl8_lights* lights, f32 x, f32 y, f32 z, u8 color, u8 intensity, f32 radius) {
|
||||
if (!lights || lights->count >= lights->capacity) return;
|
||||
|
||||
f32 radius_sq = radius * radius;
|
||||
pxl8_light* l = &lights->data[lights->count++];
|
||||
l->color = color;
|
||||
l->intensity = (f32)intensity / 255.0f;
|
||||
l->inv_radius_sq = radius_sq > 0.0f ? 1.0f / radius_sq : 0.0f;
|
||||
l->position = (pxl8_vec3){{x, y, z}};
|
||||
l->radius_sq = radius_sq;
|
||||
l->inv_radius_sq = radius_sq > 0.0f ? 1.0f / radius_sq : 0.0f;
|
||||
l->intensity = (f32)intensity / 255.0f;
|
||||
}
|
||||
|
||||
void pxl8_lights_clear(pxl8_lights* lights) {
|
||||
|
|
|
|||
|
|
@ -6,10 +6,11 @@
|
|||
#define PXL8_LIGHTS_MAX 256
|
||||
|
||||
typedef struct pxl8_light {
|
||||
u8 color;
|
||||
f32 intensity;
|
||||
f32 inv_radius_sq;
|
||||
pxl8_vec3 position;
|
||||
f32 radius_sq;
|
||||
f32 inv_radius_sq;
|
||||
f32 intensity;
|
||||
} pxl8_light;
|
||||
|
||||
typedef struct pxl8_lights pxl8_lights;
|
||||
|
|
@ -21,7 +22,7 @@ extern "C" {
|
|||
pxl8_lights* pxl8_lights_create(u32 capacity);
|
||||
void pxl8_lights_destroy(pxl8_lights* lights);
|
||||
|
||||
void pxl8_lights_add(pxl8_lights* lights, f32 x, f32 y, f32 z, u8 r, u8 g, u8 b, u8 intensity, f32 radius);
|
||||
void pxl8_lights_add(pxl8_lights* lights, f32 x, f32 y, f32 z, u8 color, u8 intensity, f32 radius);
|
||||
void pxl8_lights_clear(pxl8_lights* lights);
|
||||
u32 pxl8_lights_count(const pxl8_lights* lights);
|
||||
const pxl8_light* pxl8_lights_data(const pxl8_lights* lights);
|
||||
|
|
|
|||
|
|
@ -12,16 +12,6 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#if PXL8_GFX_ENABLE_STATS
|
||||
#define STATS_INC(stats, field, val) do { (stats)->field += (val); } while (0)
|
||||
#define STATS_START() pxl8_get_ticks_ns()
|
||||
#define STATS_ADD(stats, field, start) do { (stats)->field += pxl8_get_ticks_ns() - (start); } while (0)
|
||||
#else
|
||||
#define STATS_INC(stats, field, val) do { (void)(stats); } while (0)
|
||||
#define STATS_START() 0
|
||||
#define STATS_ADD(stats, field, start) do { (void)(stats); (void)(start); } while (0)
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
pxl8_vec4 clip_pos;
|
||||
pxl8_vec3 world_pos;
|
||||
|
|
@ -300,8 +290,7 @@ static void rasterize_triangle(
|
|||
pxl8_shader_fn shader,
|
||||
const pxl8_gfx_pipeline_desc* pipeline,
|
||||
const pxl8_shader_bindings* bindings,
|
||||
const pxl8_shader_uniforms* uniforms,
|
||||
pxl8_gfx_stats* stats
|
||||
const pxl8_shader_uniforms* uniforms
|
||||
) {
|
||||
const i32 SUBDIV = 16;
|
||||
|
||||
|
|
@ -490,8 +479,6 @@ static void rasterize_triangle(
|
|||
pxl8_i32_simd zbuf = pxl8_i32_simd_set4((i32)zrow[px], (i32)zrow[px+1], (i32)zrow[px+2], (i32)zrow[px+3]);
|
||||
i32 mask = pxl8_i32_simd_movemask(pxl8_i32_simd_cmpgt(zbuf, z16_4));
|
||||
|
||||
STATS_INC(stats, depth_tests, 4);
|
||||
|
||||
if (mask) {
|
||||
pxl8_shader_ctx frag_ctx = {
|
||||
.color_count = 4,
|
||||
|
|
@ -517,20 +504,16 @@ static void rasterize_triangle(
|
|||
|
||||
u8 colors[4];
|
||||
shader(&frag_ctx, bindings, uniforms, colors);
|
||||
STATS_INC(stats, shader_calls, 1);
|
||||
|
||||
i32 z16_arr[4];
|
||||
pxl8_i32_simd_store(z16_arr, z16_4);
|
||||
|
||||
for (i32 i = 0; i < 4; i++) {
|
||||
if (!(mask & (0x8 << (i * 4)))) continue;
|
||||
STATS_INC(stats, depth_passes, 1);
|
||||
|
||||
u8 color = colors[i];
|
||||
if (!(alpha_test && color <= alpha_ref) && color != 0) {
|
||||
prow[px + i] = color;
|
||||
if (depth_write) zrow[px + i] = (u16)z16_arr[i];
|
||||
STATS_INC(stats, pixels_written, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -540,16 +523,12 @@ static void rasterize_triangle(
|
|||
z4 = pxl8_f32_simd_add(z4, dz4_simd);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
for (; px <= span_end; px++) {
|
||||
f32 depth_norm = pxl8_clamp((z_a + 1.0f) * 0.5f, 0.0f, 1.0f);
|
||||
u16 z16 = (u16)(depth_norm * 65535.0f);
|
||||
|
||||
STATS_INC(stats, depth_tests, 1);
|
||||
bool depth_pass = !depth_test || depth_test_pass(depth_compare, z16, zrow[px]);
|
||||
if (depth_pass) {
|
||||
STATS_INC(stats, depth_passes, 1);
|
||||
pxl8_shader_ctx frag_ctx = {
|
||||
.color_count = 1,
|
||||
.x = pxl8_i32_simd_set(px),
|
||||
|
|
@ -564,7 +543,6 @@ static void rasterize_triangle(
|
|||
|
||||
u8 color;
|
||||
shader(&frag_ctx, bindings, uniforms, &color);
|
||||
STATS_INC(stats, shader_calls, 1);
|
||||
|
||||
if (!(alpha_test && color <= alpha_ref)) {
|
||||
if (color != 0) {
|
||||
|
|
@ -577,7 +555,6 @@ static void rasterize_triangle(
|
|||
if (depth_write) {
|
||||
zrow[px] = z16;
|
||||
}
|
||||
STATS_INC(stats, pixels_written, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -591,6 +568,53 @@ static void rasterize_triangle(
|
|||
wy_a += dwy;
|
||||
wz_a += dwz;
|
||||
}
|
||||
#else
|
||||
for (; px <= span_end; px++) {
|
||||
f32 depth_norm = pxl8_clamp((z_a + 1.0f) * 0.5f, 0.0f, 1.0f);
|
||||
u16 z16 = (u16)(depth_norm * 65535.0f);
|
||||
|
||||
bool depth_pass = !depth_test || depth_test_pass(depth_compare, z16, zrow[px]);
|
||||
if (depth_pass) {
|
||||
pxl8_shader_ctx frag_ctx = {
|
||||
.color_count = 1,
|
||||
.x = px,
|
||||
.y = y,
|
||||
.v_uv = { u_a, v_a },
|
||||
.v_world = { wx_a, wy_a, wz_a },
|
||||
.v_normal = setup->normal,
|
||||
.v_light = l_a / 255.0f,
|
||||
.v_color = c_a,
|
||||
.v_depth = z_a,
|
||||
};
|
||||
|
||||
u8 color;
|
||||
shader(&frag_ctx, bindings, uniforms, &color);
|
||||
|
||||
if (!(alpha_test && color <= alpha_ref)) {
|
||||
if (color != 0) {
|
||||
u8 out_color = color;
|
||||
if (blend_enabled) {
|
||||
out_color = blend_indexed(pipeline, color, prow[px], palette, colormap);
|
||||
}
|
||||
|
||||
prow[px] = out_color;
|
||||
if (depth_write) {
|
||||
zrow[px] = z16;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
u_a += du;
|
||||
v_a += dv;
|
||||
l_a += dl;
|
||||
c_a += dc;
|
||||
z_a += dz;
|
||||
wx_a += dwx;
|
||||
wy_a += dwy;
|
||||
wz_a += dwz;
|
||||
}
|
||||
#endif
|
||||
|
||||
wr += dwr * (f32)span_len;
|
||||
uw += duw * (f32)span_len;
|
||||
|
|
@ -618,8 +642,7 @@ static void draw_line_clipped(
|
|||
i32 clip_min_x,
|
||||
i32 clip_min_y,
|
||||
i32 clip_max_x,
|
||||
i32 clip_max_y,
|
||||
pxl8_gfx_stats* stats
|
||||
i32 clip_max_y
|
||||
) {
|
||||
i32 dx = abs(x1 - x0);
|
||||
i32 dy = -abs(y1 - y0);
|
||||
|
|
@ -631,7 +654,6 @@ static void draw_line_clipped(
|
|||
if (x0 >= clip_min_x && x0 <= clip_max_x && y0 >= clip_min_y && y0 <= clip_max_y) {
|
||||
if (x0 >= 0 && y0 >= 0 && x0 < (i32)fb_w && y0 < (i32)fb_h) {
|
||||
fb[y0 * (i32)fb_w + x0] = color;
|
||||
STATS_INC(stats, pixels_written, 1);
|
||||
}
|
||||
}
|
||||
if (x0 == x1 && y0 == y1) break;
|
||||
|
|
@ -718,7 +740,6 @@ struct pxl8_renderer {
|
|||
u32 scissor_w, scissor_h;
|
||||
|
||||
pxl8_shader_fn shader;
|
||||
pxl8_gfx_stats stats;
|
||||
};
|
||||
|
||||
struct pxl8_gfx_cmdbuf {
|
||||
|
|
@ -735,7 +756,6 @@ pxl8_renderer* pxl8_renderer_create(u32 width, u32 height) {
|
|||
r->viewport_h = height;
|
||||
r->scissor_w = width;
|
||||
r->scissor_h = height;
|
||||
pxl8_renderer_reset_stats(r);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
|
@ -762,20 +782,10 @@ void pxl8_renderer_set_shader(pxl8_renderer* r, pxl8_shader_fn fn) {
|
|||
if (r) r->shader = fn;
|
||||
}
|
||||
|
||||
void pxl8_renderer_reset_stats(pxl8_renderer* r) {
|
||||
if (!r) return;
|
||||
memset(&r->stats, 0, sizeof(r->stats));
|
||||
}
|
||||
|
||||
const pxl8_gfx_stats* pxl8_renderer_get_stats(const pxl8_renderer* r) {
|
||||
return r ? &r->stats : NULL;
|
||||
}
|
||||
|
||||
static u32 texture_byte_size(pxl8_gfx_texture_format fmt, u32 w, u32 h) {
|
||||
switch (fmt) {
|
||||
case PXL8_GFX_FORMAT_INDEXED8: return w * h;
|
||||
case PXL8_GFX_FORMAT_DEPTH16: return w * h * 2;
|
||||
case PXL8_GFX_FORMAT_LIGHT_ACCUM: return w * h * 4;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1085,9 +1095,6 @@ static void execute_draw(
|
|||
if (!VALID_PASS(r, r->current_pass)) return;
|
||||
if (!VALID_PIPELINE(r, r->current_pipeline)) return;
|
||||
|
||||
u64 exec_start = STATS_START();
|
||||
STATS_INC(&r->stats, draw_calls, 1);
|
||||
|
||||
buffer_slot* vb = &r->buffers[SLOT_INDEX(cmd->vertex_buffer.id)];
|
||||
buffer_slot* ib = use_indices ? &r->buffers[SLOT_INDEX(cmd->index_buffer.id)] : NULL;
|
||||
pass_slot* pass = &r->passes[SLOT_INDEX(r->current_pass.id)];
|
||||
|
|
@ -1095,12 +1102,10 @@ static void execute_draw(
|
|||
|
||||
if (!VALID_TEX(r, pass->desc.color.texture)) {
|
||||
pxl8_error("draw: invalid color texture");
|
||||
STATS_ADD(&r->stats, execute_draw_ns, exec_start);
|
||||
return;
|
||||
}
|
||||
if (!VALID_TEX(r, pass->desc.depth.texture)) {
|
||||
pxl8_error("draw: invalid depth texture");
|
||||
STATS_ADD(&r->stats, execute_draw_ns, exec_start);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -1112,10 +1117,7 @@ static void execute_draw(
|
|||
u32 fb_w = color_tex->width;
|
||||
u32 fb_h = color_tex->height;
|
||||
|
||||
if (r->viewport_w == 0 || r->viewport_h == 0) {
|
||||
STATS_ADD(&r->stats, execute_draw_ns, exec_start);
|
||||
return;
|
||||
}
|
||||
if (r->viewport_w == 0 || r->viewport_h == 0) return;
|
||||
|
||||
i32 vp_x = r->viewport_x;
|
||||
i32 vp_y = r->viewport_y;
|
||||
|
|
@ -1143,10 +1145,7 @@ static void execute_draw(
|
|||
if (clip_min_y < 0) clip_min_y = 0;
|
||||
if (clip_max_x >= (i32)fb_w) clip_max_x = (i32)fb_w - 1;
|
||||
if (clip_max_y >= (i32)fb_h) clip_max_y = (i32)fb_h - 1;
|
||||
if (clip_min_x > clip_max_x || clip_min_y > clip_max_y) {
|
||||
STATS_ADD(&r->stats, execute_draw_ns, exec_start);
|
||||
return;
|
||||
}
|
||||
if (clip_min_x > clip_max_x || clip_min_y > clip_max_y) return;
|
||||
|
||||
const pxl8_vertex* vertices = vb->data;
|
||||
const u16* indices = use_indices ? ib->data : NULL;
|
||||
|
|
@ -1156,10 +1155,7 @@ static void execute_draw(
|
|||
f32 near = 0.1f;
|
||||
|
||||
pxl8_shader_fn shader = pip->desc.shader;
|
||||
if (!shader) {
|
||||
STATS_ADD(&r->stats, execute_draw_ns, exec_start);
|
||||
return;
|
||||
}
|
||||
if (!shader) return;
|
||||
|
||||
pxl8_shader_bindings shader_bindings = {0};
|
||||
pxl8_shader_uniforms shader_uniforms = r->current_draw_params.shader;
|
||||
|
|
@ -1190,8 +1186,8 @@ static void execute_draw(
|
|||
bool is_wireframe = pip->desc.rasterizer.fill == PXL8_GFX_FILL_WIREFRAME;
|
||||
|
||||
for (u32 i = cmd->first_index; i < cmd->first_index + cmd->index_count; i += 3) {
|
||||
STATS_INC(&r->stats, triangles, 1);
|
||||
u16 i0, i1, i2;
|
||||
|
||||
if (use_indices) {
|
||||
if (i + 2 >= ib->size / sizeof(u16)) break;
|
||||
i0 = indices[i] + cmd->base_vertex;
|
||||
|
|
@ -1262,7 +1258,6 @@ static void execute_draw(
|
|||
i32 clipped_count = clip_triangle_near(&rv0, &rv1, &rv2, near, clipped);
|
||||
|
||||
for (i32 t = 0; t < clipped_count; t += 3) {
|
||||
STATS_INC(&r->stats, clipped_triangles, 1);
|
||||
if (is_wireframe) {
|
||||
f32 hw = (f32)vp_w * 0.5f;
|
||||
f32 hh = (f32)vp_h * 0.5f;
|
||||
|
|
@ -1286,11 +1281,11 @@ static void execute_draw(
|
|||
|
||||
u8 wire_color = v0->color ? v0->color : 15;
|
||||
draw_line_clipped(fb, fb_w, fb_h, sx0, sy0, sx1, sy1, wire_color,
|
||||
clip_min_x, clip_min_y, clip_max_x, clip_max_y, &r->stats);
|
||||
clip_min_x, clip_min_y, clip_max_x, clip_max_y);
|
||||
draw_line_clipped(fb, fb_w, fb_h, sx1, sy1, sx2, sy2, wire_color,
|
||||
clip_min_x, clip_min_y, clip_max_x, clip_max_y, &r->stats);
|
||||
clip_min_x, clip_min_y, clip_max_x, clip_max_y);
|
||||
draw_line_clipped(fb, fb_w, fb_h, sx2, sy2, sx0, sy0, wire_color,
|
||||
clip_min_x, clip_min_y, clip_max_x, clip_max_y, &r->stats);
|
||||
clip_min_x, clip_min_y, clip_max_x, clip_max_y);
|
||||
} else {
|
||||
tri_setup setup;
|
||||
if (!setup_tri(&setup, &clipped[t], &clipped[t+1], &clipped[t+2],
|
||||
|
|
@ -1300,19 +1295,14 @@ static void execute_draw(
|
|||
continue;
|
||||
}
|
||||
|
||||
u64 raster_start = STATS_START();
|
||||
rasterize_triangle(&setup, fb, zb, fb_w, shader, &pip->desc,
|
||||
&shader_bindings, &shader_uniforms, &r->stats);
|
||||
STATS_ADD(&r->stats, raster_ns, raster_start);
|
||||
&shader_bindings, &shader_uniforms);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
STATS_ADD(&r->stats, execute_draw_ns, exec_start);
|
||||
}
|
||||
|
||||
void pxl8_gfx_submit(pxl8_renderer* r, pxl8_gfx_cmdbuf* cb) {
|
||||
u64 submit_start = STATS_START();
|
||||
for (u32 i = 0; i < cb->count; i++) {
|
||||
pxl8_gfx_cmd* cmd = &cb->commands[i];
|
||||
switch (cmd->type) {
|
||||
|
|
@ -1322,13 +1312,8 @@ void pxl8_gfx_submit(pxl8_renderer* r, pxl8_gfx_cmdbuf* cb) {
|
|||
pass_slot* p = &r->passes[SLOT_INDEX(cmd->begin_pass.pass.id)];
|
||||
if (p->desc.color.load == PXL8_GFX_LOAD_CLEAR) {
|
||||
pxl8_clear(r, p->desc.color.texture, p->desc.color.clear_value);
|
||||
}
|
||||
if (p->desc.depth.load == PXL8_GFX_LOAD_CLEAR) {
|
||||
pxl8_clear_depth(r, p->desc.depth.texture);
|
||||
}
|
||||
if (p->desc.light_accum.load == PXL8_GFX_LOAD_CLEAR) {
|
||||
pxl8_clear_light(r, p->desc.light_accum.texture);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case PXL8_GFX_CMD_END_PASS:
|
||||
|
|
@ -1368,7 +1353,6 @@ void pxl8_gfx_submit(pxl8_renderer* r, pxl8_gfx_cmdbuf* cb) {
|
|||
r->buffers[i].append_pos = 0;
|
||||
}
|
||||
}
|
||||
STATS_ADD(&r->stats, submit_ns, submit_start);
|
||||
}
|
||||
|
||||
void pxl8_clear(pxl8_renderer* r, pxl8_gfx_texture target, u8 color) {
|
||||
|
|
@ -1387,14 +1371,6 @@ void pxl8_clear_depth(pxl8_renderer* r, pxl8_gfx_texture target) {
|
|||
}
|
||||
}
|
||||
|
||||
void pxl8_clear_light(pxl8_renderer* r, pxl8_gfx_texture target) {
|
||||
if (!VALID_TEX(r, target)) return;
|
||||
texture_slot* s = &r->textures[SLOT_INDEX(target.id)];
|
||||
if (s->format == PXL8_GFX_FORMAT_LIGHT_ACCUM) {
|
||||
memset(s->data, 0, s->width * s->height * 4);
|
||||
}
|
||||
}
|
||||
|
||||
void pxl8_draw_pixel(pxl8_renderer* r, pxl8_gfx_texture target, i32 x, i32 y, u8 color) {
|
||||
if (!VALID_TEX(r, target)) return;
|
||||
texture_slot* s = &r->textures[SLOT_INDEX(target.id)];
|
||||
|
|
@ -1516,8 +1492,7 @@ void pxl8_draw_circle_fill(pxl8_renderer* r, pxl8_gfx_texture target, i32 cx, i3
|
|||
}
|
||||
}
|
||||
|
||||
void pxl8_resolve_to_rgba(pxl8_renderer* r, pxl8_gfx_texture color, pxl8_gfx_texture light_accum,
|
||||
const u32* palette, u32* output) {
|
||||
void pxl8_resolve_to_rgba(pxl8_renderer* r, pxl8_gfx_texture color, const u32* palette, u32* output) {
|
||||
if (!VALID_TEX(r, color)) return;
|
||||
texture_slot* cs = &r->textures[SLOT_INDEX(color.id)];
|
||||
|
||||
|
|
@ -1525,12 +1500,10 @@ void pxl8_resolve_to_rgba(pxl8_renderer* r, pxl8_gfx_texture color, pxl8_gfx_tex
|
|||
u32 w = cs->width;
|
||||
u32 h = cs->height;
|
||||
u32 total = w * h;
|
||||
|
||||
(void)light_accum;
|
||||
u32 i = 0;
|
||||
|
||||
#if defined(PXL8_SIMD_SSE) || defined(PXL8_SIMD_NEON)
|
||||
pxl8_i32_simd alpha_mask = pxl8_i32_simd_set((i32)0xFF000000);
|
||||
u32 i = 0;
|
||||
for (; i + 4 <= total; i += 4) {
|
||||
pxl8_i32_simd base = pxl8_i32_simd_set4(
|
||||
(i32)palette[fb[i + 0]], (i32)palette[fb[i + 1]],
|
||||
|
|
@ -1539,12 +1512,10 @@ void pxl8_resolve_to_rgba(pxl8_renderer* r, pxl8_gfx_texture color, pxl8_gfx_tex
|
|||
base = pxl8_i32_simd_or(base, alpha_mask);
|
||||
pxl8_i32_simd_store((i32*)&output[i], base);
|
||||
}
|
||||
#endif
|
||||
|
||||
for (; i < total; i++) {
|
||||
output[i] = palette[fb[i]] | 0xFF000000;
|
||||
}
|
||||
#else
|
||||
for (u32 i = 0; i < total; i++) {
|
||||
output[i] = palette[fb[i]] | 0xFF000000;
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,10 +4,6 @@
|
|||
#include "pxl8_render_types.h"
|
||||
#include "pxl8_shader.h"
|
||||
|
||||
#ifndef PXL8_GFX_ENABLE_STATS
|
||||
#define PXL8_GFX_ENABLE_STATS 1
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
|
@ -15,25 +11,9 @@ extern "C" {
|
|||
typedef struct pxl8_renderer pxl8_renderer;
|
||||
typedef struct pxl8_gfx_cmdbuf pxl8_gfx_cmdbuf;
|
||||
|
||||
typedef struct pxl8_gfx_stats {
|
||||
u64 draw_calls;
|
||||
u64 triangles;
|
||||
u64 clipped_triangles;
|
||||
u64 depth_tests;
|
||||
u64 depth_passes;
|
||||
u64 shader_calls;
|
||||
u64 pixels_written;
|
||||
u64 light_writes;
|
||||
u64 submit_ns;
|
||||
u64 execute_draw_ns;
|
||||
u64 raster_ns;
|
||||
} pxl8_gfx_stats;
|
||||
|
||||
pxl8_renderer* pxl8_renderer_create(u32 width, u32 height);
|
||||
void pxl8_renderer_destroy(pxl8_renderer* r);
|
||||
void pxl8_renderer_set_shader(pxl8_renderer* r, pxl8_shader_fn fn);
|
||||
void pxl8_renderer_reset_stats(pxl8_renderer* r);
|
||||
const pxl8_gfx_stats* pxl8_renderer_get_stats(const pxl8_renderer* r);
|
||||
|
||||
u32 pxl8_renderer_get_width(const pxl8_renderer* r);
|
||||
u32 pxl8_renderer_get_height(const pxl8_renderer* r);
|
||||
|
|
@ -73,14 +53,12 @@ void pxl8_set_draw_params(pxl8_gfx_cmdbuf* cb, const pxl8_gfx_cmd_draw_params* p
|
|||
void pxl8_set_pipeline(pxl8_gfx_cmdbuf* cb, pxl8_gfx_pipeline pipeline);
|
||||
void pxl8_set_scissor(pxl8_gfx_cmdbuf* cb, i32 x, i32 y, u32 w, u32 h);
|
||||
void pxl8_set_viewport(pxl8_gfx_cmdbuf* cb, i32 x, i32 y, u32 w, u32 h);
|
||||
|
||||
void pxl8_draw(pxl8_gfx_cmdbuf* cb, pxl8_gfx_buffer vb, pxl8_gfx_buffer ib, u32 first, u32 count, u32 base_vertex);
|
||||
|
||||
void pxl8_gfx_submit(pxl8_renderer* r, pxl8_gfx_cmdbuf* cb);
|
||||
|
||||
void pxl8_clear(pxl8_renderer* r, pxl8_gfx_texture target, u8 color);
|
||||
void pxl8_clear_depth(pxl8_renderer* r, pxl8_gfx_texture target);
|
||||
void pxl8_clear_light(pxl8_renderer* r, pxl8_gfx_texture target);
|
||||
|
||||
void pxl8_draw_pixel(pxl8_renderer* r, pxl8_gfx_texture target, i32 x, i32 y, u8 color);
|
||||
u8 pxl8_get_pixel(pxl8_renderer* r, pxl8_gfx_texture target, i32 x, i32 y);
|
||||
|
|
@ -90,8 +68,7 @@ void pxl8_draw_rect_fill(pxl8_renderer* r, pxl8_gfx_texture target, i32 x, i32 y
|
|||
void pxl8_draw_circle(pxl8_renderer* r, pxl8_gfx_texture target, i32 cx, i32 cy, i32 radius, u8 color);
|
||||
void pxl8_draw_circle_fill(pxl8_renderer* r, pxl8_gfx_texture target, i32 cx, i32 cy, i32 radius, u8 color);
|
||||
|
||||
void pxl8_resolve_to_rgba(pxl8_renderer* r, pxl8_gfx_texture color, pxl8_gfx_texture light_accum,
|
||||
const u32* palette, u32* output);
|
||||
void pxl8_resolve_to_rgba(pxl8_renderer* r, pxl8_gfx_texture color, const u32* palette, u32* output);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,7 +48,6 @@ typedef enum pxl8_gfx_usage {
|
|||
typedef enum pxl8_gfx_texture_format {
|
||||
PXL8_GFX_FORMAT_INDEXED8,
|
||||
PXL8_GFX_FORMAT_DEPTH16,
|
||||
PXL8_GFX_FORMAT_LIGHT_ACCUM,
|
||||
} pxl8_gfx_texture_format;
|
||||
|
||||
typedef enum pxl8_gfx_cull_mode {
|
||||
|
|
|
|||
|
|
@ -43,11 +43,22 @@ static inline u8 pxl8_sample_indexed(const pxl8_shader_bindings* b, pxl8_vec2 uv
|
|||
}
|
||||
}
|
||||
|
||||
static inline u8 pxl8_colormap_lookup(const pxl8_shader_bindings* b, u8 color, u8 light) {
|
||||
static inline u8 pxl8_colormap_lookup(const pxl8_shader_bindings* b, u8 color, u8 light_color, u8 intensity) {
|
||||
if (!b) return color;
|
||||
const u8* cm = b->colormap;
|
||||
if (!cm) return color;
|
||||
u32 row = light >> 5;
|
||||
u32 row = ((u32)light_color << 3) + (intensity >> 5);
|
||||
return cm[(row << 8) | (u32)color];
|
||||
}
|
||||
|
||||
static inline u8 pxl8_colormap_lookup_dithered(const pxl8_shader_bindings* b, u8 color, u8 light_color, u8 intensity, u32 x, u32 y) {
|
||||
if (!b) return color;
|
||||
const u8* cm = b->colormap;
|
||||
if (!cm) return color;
|
||||
u32 base_row = intensity >> 5;
|
||||
u32 frac = intensity & 31;
|
||||
u32 threshold = PXL8_BAYER_4X4[(y & 3) * 4 + (x & 3)] * 2;
|
||||
u32 row = ((u32)light_color << 3) + (frac > threshold && base_row < 7 ? base_row + 1 : base_row);
|
||||
return cm[(row << 8) | (u32)color];
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,14 +2,14 @@
|
|||
|
||||
#include <string.h>
|
||||
|
||||
extern u8 pxl8_shader_lit(pxl8_shader_ctx* ctx, const pxl8_shader_bindings* bindings, const pxl8_shader_uniforms* uniforms);
|
||||
extern u8 pxl8_shader_unlit(pxl8_shader_ctx* ctx, const pxl8_shader_bindings* bindings, const pxl8_shader_uniforms* uniforms);
|
||||
extern void pxl8_shader_lit(const pxl8_shader_ctx* ctx, const pxl8_shader_bindings* bindings, const pxl8_shader_uniforms* uniforms, u8* colors_out);
|
||||
extern void pxl8_shader_unlit(const pxl8_shader_ctx* ctx, const pxl8_shader_bindings* bindings, const pxl8_shader_uniforms* uniforms, u8* colors_out);
|
||||
|
||||
void pxl8_shader_registry_init(void) {}
|
||||
void pxl8_shader_registry_reload(void) {}
|
||||
|
||||
pxl8_shader_fn pxl8_shader_registry_get(const char* name) {
|
||||
if (strcmp(name, "lit") == 0) return (pxl8_shader_fn)pxl8_shader_lit;
|
||||
if (strcmp(name, "unlit") == 0) return (pxl8_shader_fn)pxl8_shader_unlit;
|
||||
if (strcmp(name, "lit") == 0) return pxl8_shader_lit;
|
||||
if (strcmp(name, "unlit") == 0) return pxl8_shader_unlit;
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,6 +32,8 @@ void pxl8_shader_lit(
|
|||
}
|
||||
|
||||
pxl8_f32_simd light = ctx->v_light;
|
||||
f32 max_strength[4] = {0, 0, 0, 0};
|
||||
u8 dominant_color[4] = {0, 0, 0, 0};
|
||||
|
||||
if (uniforms) {
|
||||
pxl8_f32_simd ambient = pxl8_f32_simd_set((f32)uniforms->ambient / 255.0f);
|
||||
|
|
@ -72,11 +74,32 @@ void pxl8_shader_lit(
|
|||
);
|
||||
falloff = pxl8_f32_simd_max(falloff, pxl8_f32_simd_zero());
|
||||
|
||||
if (uniforms->dither) {
|
||||
f32 falloff_arr[4];
|
||||
pxl8_f32_simd_store(falloff_arr, falloff);
|
||||
for (u32 j = 0; j < 4; j++) {
|
||||
if (falloff_arr[j] < 0.5f) {
|
||||
f32 threshold = (PXL8_BAYER_4X4[((u32)py[j] & 3) * 4 + ((u32)px[j] & 3)] + 0.5f) * (1.0f / 16.0f);
|
||||
if (falloff_arr[j] < threshold * 0.5f) falloff_arr[j] = 0.0f;
|
||||
}
|
||||
}
|
||||
falloff = pxl8_f32_simd_load(falloff_arr);
|
||||
}
|
||||
|
||||
pxl8_f32_simd strength = pxl8_f32_simd_mul(
|
||||
pxl8_f32_simd_mul(pxl8_f32_simd_set(l->intensity), falloff),
|
||||
ndotl
|
||||
);
|
||||
|
||||
f32 strength_arr[4];
|
||||
pxl8_f32_simd_store(strength_arr, strength);
|
||||
for (u32 j = 0; j < 4; j++) {
|
||||
if (strength_arr[j] > max_strength[j]) {
|
||||
max_strength[j] = strength_arr[j];
|
||||
dominant_color[j] = l->color;
|
||||
}
|
||||
}
|
||||
|
||||
light = pxl8_f32_simd_add(light, strength);
|
||||
}
|
||||
}
|
||||
|
|
@ -88,13 +111,12 @@ void pxl8_shader_lit(
|
|||
pxl8_f32_simd_store(light_arr, light_f);
|
||||
|
||||
for (u32 i = 0; i < ctx->color_count; i++) {
|
||||
u8 light_u8;
|
||||
u8 light_u8 = (u8)light_arr[i];
|
||||
if (uniforms && uniforms->dither) {
|
||||
light_u8 = pxl8_gfx_dither(light_arr[i], (u32)px[i], (u32)py[i]);
|
||||
colors_out[i] = pxl8_colormap_lookup_dithered(bindings, tex_idx[i], dominant_color[i], light_u8, (u32)px[i], (u32)py[i]);
|
||||
} else {
|
||||
light_u8 = (u8)light_arr[i];
|
||||
colors_out[i] = pxl8_colormap_lookup(bindings, tex_idx[i], dominant_color[i], light_u8);
|
||||
}
|
||||
colors_out[i] = pxl8_colormap_lookup(bindings, tex_idx[i], light_u8);
|
||||
}
|
||||
|
||||
#else
|
||||
|
|
@ -111,6 +133,8 @@ void pxl8_shader_lit(
|
|||
}
|
||||
|
||||
f32 light = ctx->v_light;
|
||||
f32 max_strength = 0;
|
||||
u8 dominant_color = 0;
|
||||
|
||||
if (uniforms) {
|
||||
f32 ambient = (f32)uniforms->ambient / 255.0f;
|
||||
|
|
@ -143,8 +167,16 @@ void pxl8_shader_lit(
|
|||
|
||||
f32 falloff = 1.0f - dist_sq * l->inv_radius_sq;
|
||||
if (falloff <= 0.0f) continue;
|
||||
if (uniforms->dither && falloff < 0.5f) {
|
||||
f32 threshold = (PXL8_BAYER_4X4[((u32)ctx->y & 3) * 4 + ((u32)ctx->x & 3)] + 0.5f) * (1.0f / 16.0f);
|
||||
if (falloff < threshold * 0.5f) continue;
|
||||
}
|
||||
|
||||
f32 strength = l->intensity * falloff * ndotl;
|
||||
if (strength > max_strength) {
|
||||
max_strength = strength;
|
||||
dominant_color = l->color;
|
||||
}
|
||||
light += strength;
|
||||
}
|
||||
}
|
||||
|
|
@ -155,9 +187,9 @@ void pxl8_shader_lit(
|
|||
f32 light_f = light * 255.0f;
|
||||
u8 light_u8 = (u8)light_f;
|
||||
if (uniforms && uniforms->dither) {
|
||||
light_u8 = pxl8_gfx_dither(light_f, (u32)ctx->x, (u32)ctx->y);
|
||||
colors_out[0] = pxl8_colormap_lookup_dithered(bindings, tex_idx, dominant_color, light_u8, (u32)ctx->x, (u32)ctx->y);
|
||||
} else {
|
||||
colors_out[0] = pxl8_colormap_lookup(bindings, tex_idx, dominant_color, light_u8);
|
||||
}
|
||||
|
||||
colors_out[0] = pxl8_colormap_lookup(bindings, tex_idx, light_u8);
|
||||
#endif
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,16 +14,8 @@ function Lights.new(capacity)
|
|||
return setmetatable({ _ptr = ptr }, Lights)
|
||||
end
|
||||
|
||||
function Lights:add(x, y, z, r, g, b, intensity, radius)
|
||||
if r and r > 255 then
|
||||
local rgb = r
|
||||
intensity = g
|
||||
radius = b
|
||||
r = bit.band(bit.rshift(rgb, 16), 0xFF)
|
||||
g = bit.band(bit.rshift(rgb, 8), 0xFF)
|
||||
b = bit.band(rgb, 0xFF)
|
||||
end
|
||||
C.pxl8_lights_add(self._ptr, x, y, z, r or 255, g or 255, b or 255, intensity or 255, radius or 10)
|
||||
function Lights:add(x, y, z, color, intensity, radius)
|
||||
C.pxl8_lights_add(self._ptr, x, y, z, color or 0, intensity or 255, radius or 10)
|
||||
end
|
||||
|
||||
function Lights:clear()
|
||||
|
|
|
|||
|
|
@ -1,265 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
static inline f32 pxl8_fast_inv_sqrt(f32 x) {
|
||||
f32 half = 0.5f * x;
|
||||
i32 i = *(i32*)&x;
|
||||
i = 0x5f3759df - (i >> 1);
|
||||
x = *(f32*)&i;
|
||||
x = x * (1.5f - half * x * x);
|
||||
return x;
|
||||
}
|
||||
|
||||
static inline u32 pxl8_hash32(u32 x) {
|
||||
x ^= x >> 16;
|
||||
x *= 0x85EBCA6Bu;
|
||||
x ^= x >> 13;
|
||||
x *= 0xC2B2AE35u;
|
||||
x ^= x >> 16;
|
||||
return x;
|
||||
}
|
||||
|
||||
static inline u64 pxl8_hash64(u64 x) {
|
||||
x ^= x >> 33;
|
||||
x *= 0xff51afd7ed558ccdULL;
|
||||
x ^= x >> 33;
|
||||
x *= 0xc4ceb9fe1a85ec53ULL;
|
||||
x ^= x >> 33;
|
||||
return x;
|
||||
}
|
||||
|
||||
static inline f32 pxl8_smoothstep(f32 t) {
|
||||
return t * t * (3.0f - 2.0f * t);
|
||||
}
|
||||
|
||||
static inline pxl8_vec2 pxl8_vec2_add(pxl8_vec2 a, pxl8_vec2 b) {
|
||||
return (pxl8_vec2){ .x = a.x + b.x, .y = a.y + b.y };
|
||||
}
|
||||
|
||||
static inline pxl8_vec2 pxl8_vec2_sub(pxl8_vec2 a, pxl8_vec2 b) {
|
||||
return (pxl8_vec2){ .x = a.x - b.x, .y = a.y - b.y };
|
||||
}
|
||||
|
||||
static inline pxl8_vec2 pxl8_vec2_scale(pxl8_vec2 v, f32 s) {
|
||||
return (pxl8_vec2){ .x = v.x * s, .y = v.y * s };
|
||||
}
|
||||
|
||||
static inline f32 pxl8_vec2_cross(pxl8_vec2 a, pxl8_vec2 b) {
|
||||
return a.x * b.y - a.y * b.x;
|
||||
}
|
||||
|
||||
static inline f32 pxl8_vec2_dot(pxl8_vec2 a, pxl8_vec2 b) {
|
||||
return a.x * b.x + a.y * b.y;
|
||||
}
|
||||
|
||||
static inline f32 pxl8_vec2_length(pxl8_vec2 v) {
|
||||
return sqrtf(v.x * v.x + v.y * v.y);
|
||||
}
|
||||
|
||||
static inline pxl8_vec2 pxl8_vec2_normalize(pxl8_vec2 v) {
|
||||
f32 len_sq = pxl8_vec2_dot(v, v);
|
||||
if (len_sq < 1e-12f) return (pxl8_vec2){0};
|
||||
return pxl8_vec2_scale(v, pxl8_fast_inv_sqrt(len_sq));
|
||||
}
|
||||
|
||||
static inline pxl8_vec3 pxl8_vec3_add(pxl8_vec3 a, pxl8_vec3 b) {
|
||||
return (pxl8_vec3){ .x = a.x + b.x, .y = a.y + b.y, .z = a.z + b.z };
|
||||
}
|
||||
|
||||
static inline pxl8_vec3 pxl8_vec3_sub(pxl8_vec3 a, pxl8_vec3 b) {
|
||||
return (pxl8_vec3){ .x = a.x - b.x, .y = a.y - b.y, .z = a.z - b.z };
|
||||
}
|
||||
|
||||
static inline pxl8_vec3 pxl8_vec3_scale(pxl8_vec3 v, f32 s) {
|
||||
return (pxl8_vec3){ .x = v.x * s, .y = v.y * s, .z = v.z * s };
|
||||
}
|
||||
|
||||
static inline f32 pxl8_vec3_dot(pxl8_vec3 a, pxl8_vec3 b) {
|
||||
return a.x * b.x + a.y * b.y + a.z * b.z;
|
||||
}
|
||||
|
||||
static inline pxl8_vec3 pxl8_vec3_cross(pxl8_vec3 a, pxl8_vec3 b) {
|
||||
return (pxl8_vec3){
|
||||
.x = a.y * b.z - a.z * b.y,
|
||||
.y = a.z * b.x - a.x * b.z,
|
||||
.z = a.x * b.y - a.y * b.x,
|
||||
};
|
||||
}
|
||||
|
||||
static inline f32 pxl8_vec3_length(pxl8_vec3 v) {
|
||||
return sqrtf(pxl8_vec3_dot(v, v));
|
||||
}
|
||||
|
||||
static inline pxl8_vec3 pxl8_vec3_lerp(pxl8_vec3 a, pxl8_vec3 b, f32 t) {
|
||||
return (pxl8_vec3){
|
||||
a.x + (b.x - a.x) * t,
|
||||
a.y + (b.y - a.y) * t,
|
||||
a.z + (b.z - a.z) * t
|
||||
};
|
||||
}
|
||||
|
||||
static inline pxl8_vec3 pxl8_vec3_normalize(pxl8_vec3 v) {
|
||||
f32 len_sq = pxl8_vec3_dot(v, v);
|
||||
if (len_sq < 1e-12f) return (pxl8_vec3){0};
|
||||
return pxl8_vec3_scale(v, pxl8_fast_inv_sqrt(len_sq));
|
||||
}
|
||||
|
||||
static inline pxl8_mat4 pxl8_mat4_identity(void) {
|
||||
pxl8_mat4 mat = {0};
|
||||
mat.m[0] = mat.m[5] = mat.m[10] = mat.m[15] = 1.0f;
|
||||
return mat;
|
||||
}
|
||||
|
||||
static inline pxl8_mat4 pxl8_mat4_multiply(pxl8_mat4 a, pxl8_mat4 b) {
|
||||
pxl8_mat4 mat = {0};
|
||||
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];
|
||||
}
|
||||
}
|
||||
return mat;
|
||||
}
|
||||
|
||||
static inline pxl8_vec4 pxl8_mat4_multiply_vec4(pxl8_mat4 m, pxl8_vec4 v) {
|
||||
return (pxl8_vec4){
|
||||
.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,
|
||||
};
|
||||
}
|
||||
|
||||
static inline pxl8_vec3 pxl8_mat4_multiply_vec3(pxl8_mat4 m, pxl8_vec3 v) {
|
||||
return (pxl8_vec3){
|
||||
.x = m.m[0] * v.x + m.m[4] * v.y + m.m[8] * v.z,
|
||||
.y = m.m[1] * v.x + m.m[5] * v.y + m.m[9] * v.z,
|
||||
.z = m.m[2] * v.x + m.m[6] * v.y + m.m[10] * v.z,
|
||||
};
|
||||
}
|
||||
|
||||
static inline pxl8_mat4 pxl8_mat4_translate(f32 x, f32 y, f32 z) {
|
||||
pxl8_mat4 mat = pxl8_mat4_identity();
|
||||
mat.m[12] = x; mat.m[13] = y; mat.m[14] = z;
|
||||
return mat;
|
||||
}
|
||||
|
||||
static inline pxl8_mat4 pxl8_mat4_rotate_x(f32 angle) {
|
||||
pxl8_mat4 mat = pxl8_mat4_identity();
|
||||
f32 c = cosf(angle), s = sinf(angle);
|
||||
mat.m[5] = c; mat.m[9] = -s; mat.m[6] = s; mat.m[10] = c;
|
||||
return mat;
|
||||
}
|
||||
|
||||
static inline pxl8_mat4 pxl8_mat4_rotate_y(f32 angle) {
|
||||
pxl8_mat4 mat = pxl8_mat4_identity();
|
||||
f32 c = cosf(angle), s = sinf(angle);
|
||||
mat.m[0] = c; mat.m[8] = s; mat.m[2] = -s; mat.m[10] = c;
|
||||
return mat;
|
||||
}
|
||||
|
||||
static inline pxl8_mat4 pxl8_mat4_rotate_z(f32 angle) {
|
||||
pxl8_mat4 mat = pxl8_mat4_identity();
|
||||
f32 c = cosf(angle), s = sinf(angle);
|
||||
mat.m[0] = c; mat.m[4] = -s; mat.m[1] = s; mat.m[5] = c;
|
||||
return mat;
|
||||
}
|
||||
|
||||
static inline pxl8_mat4 pxl8_mat4_scale(f32 x, f32 y, f32 z) {
|
||||
pxl8_mat4 mat = pxl8_mat4_identity();
|
||||
mat.m[0] = x; mat.m[5] = y; mat.m[10] = z;
|
||||
return mat;
|
||||
}
|
||||
|
||||
static inline pxl8_mat4 pxl8_mat4_orthographic(f32 left, f32 right, f32 bottom, f32 top, f32 near, f32 far) {
|
||||
pxl8_mat4 mat = {0};
|
||||
mat.m[0] = 2.0f / (right - left);
|
||||
mat.m[5] = 2.0f / (top - bottom);
|
||||
mat.m[10] = -2.0f / (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;
|
||||
}
|
||||
|
||||
static inline pxl8_mat4 pxl8_mat4_perspective(f32 fov, f32 aspect, f32 near, f32 far) {
|
||||
pxl8_mat4 mat = {0};
|
||||
f32 tan_half_fov = tanf(fov / 2.0f);
|
||||
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[14] = -(2.0f * far * near) / (far - near);
|
||||
mat.m[11] = -1.0f;
|
||||
return mat;
|
||||
}
|
||||
|
||||
static inline pxl8_mat4 pxl8_mat4_lookat(pxl8_vec3 eye, pxl8_vec3 center, pxl8_vec3 up) {
|
||||
pxl8_mat4 mat = pxl8_mat4_identity();
|
||||
pxl8_vec3 f = pxl8_vec3_normalize(pxl8_vec3_sub(center, eye));
|
||||
pxl8_vec3 s = pxl8_vec3_normalize(pxl8_vec3_cross(f, up));
|
||||
pxl8_vec3 u = pxl8_vec3_cross(s, f);
|
||||
mat.m[0] = s.x; mat.m[4] = s.y; mat.m[8] = s.z;
|
||||
mat.m[1] = u.x; mat.m[5] = u.y; mat.m[9] = u.z;
|
||||
mat.m[2] = -f.x; mat.m[6] = -f.y; mat.m[10] = -f.z;
|
||||
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;
|
||||
}
|
||||
|
||||
static inline pxl8_frustum pxl8_frustum_from_matrix(pxl8_mat4 vp) {
|
||||
pxl8_frustum frustum;
|
||||
const f32* m = vp.m;
|
||||
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[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[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[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[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[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);
|
||||
if (len > 1e-6f) {
|
||||
f32 inv_len = 1.0f / len;
|
||||
frustum.planes[i].normal = pxl8_vec3_scale(frustum.planes[i].normal, inv_len);
|
||||
frustum.planes[i].distance *= inv_len;
|
||||
}
|
||||
}
|
||||
return frustum;
|
||||
}
|
||||
|
||||
static inline bool pxl8_frustum_test_aabb(const pxl8_frustum* frustum, pxl8_vec3 min, pxl8_vec3 max) {
|
||||
const f32 FRUSTUM_EPSILON = -75.0f;
|
||||
for (i32 i = 0; i < 6; i++) {
|
||||
pxl8_vec3 normal = frustum->planes[i].normal;
|
||||
f32 d = frustum->planes[i].distance;
|
||||
pxl8_vec3 p_vertex = {
|
||||
(normal.x > 0.0f) ? max.x : min.x,
|
||||
(normal.y > 0.0f) ? max.y : min.y,
|
||||
(normal.z > 0.0f) ? max.z : min.z
|
||||
};
|
||||
f32 p_dist = pxl8_vec3_dot(normal, p_vertex) + d;
|
||||
if (p_dist < FRUSTUM_EPSILON) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
@ -205,18 +205,17 @@ static const char* pxl8_ffi_cdefs =
|
|||
"typedef struct { float m[16]; } pxl8_mat4;\n"
|
||||
"\n"
|
||||
"typedef struct pxl8_light {\n"
|
||||
" pxl8_vec3 position;\n"
|
||||
" u8 color;\n"
|
||||
" f32 intensity;\n"
|
||||
" f32 inv_radius_sq;\n"
|
||||
" u8 r, g, b;\n"
|
||||
" u8 intensity;\n"
|
||||
" f32 radius;\n"
|
||||
" pxl8_vec3 position;\n"
|
||||
" f32 radius_sq;\n"
|
||||
"} pxl8_light;\n"
|
||||
"\n"
|
||||
"typedef struct pxl8_lights pxl8_lights;\n"
|
||||
"pxl8_lights* pxl8_lights_create(u32 capacity);\n"
|
||||
"void pxl8_lights_destroy(pxl8_lights* lights);\n"
|
||||
"void pxl8_lights_add(pxl8_lights* lights, f32 x, f32 y, f32 z, u8 r, u8 g, u8 b, u8 intensity, f32 radius);\n"
|
||||
"void pxl8_lights_add(pxl8_lights* lights, f32 x, f32 y, f32 z, u8 color, u8 intensity, f32 radius);\n"
|
||||
"void pxl8_lights_clear(pxl8_lights* lights);\n"
|
||||
"u32 pxl8_lights_count(const pxl8_lights* lights);\n"
|
||||
"const pxl8_light* pxl8_lights_data(const pxl8_lights* lights);\n"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue