From f18652dc97e8932ab2abe1019dea193b648bad4f Mon Sep 17 00:00:00 2001 From: asrael Date: Fri, 23 Jan 2026 12:09:35 -0600 Subject: [PATCH] improve lighting system --- demo/mod/first_person3d.fnl | 12 +++---- pxl8.sh | 1 + src/gfx/pxl8_cpu.c | 8 ++--- src/gfx/pxl8_cpu.h | 2 +- src/gfx/pxl8_gfx.c | 6 ++-- src/gfx/pxl8_gfx.h | 48 +-------------------------- src/gfx/pxl8_gfx3d.h | 32 +++--------------- src/gfx/pxl8_glows.c | 8 +++-- src/gfx/pxl8_glows.h | 22 ++++++++++++- src/gfx/pxl8_lights.c | 63 ++++++++++++++++++++++++++++++++++++ src/gfx/pxl8_lights.h | 33 +++++++++++++++++++ src/lua/pxl8.lua | 2 ++ src/lua/pxl8/effects.lua | 32 ++++++++++++++++++ src/lua/pxl8/gfx3d.lua | 25 ++------------ src/script/pxl8_script_ffi.h | 18 +++++++---- 15 files changed, 193 insertions(+), 119 deletions(-) create mode 100644 src/gfx/pxl8_lights.c create mode 100644 src/gfx/pxl8_lights.h diff --git a/demo/mod/first_person3d.fnl b/demo/mod/first_person3d.fnl index cd3a361..7df90ea 100644 --- a/demo/mod/first_person3d.fnl +++ b/demo/mod/first_person3d.fnl @@ -50,6 +50,7 @@ (var fps-sample-count 0) (var fireball-mesh nil) (var last-dt 0.016) +(var lights nil) (local cursor-look? true) (local FIREBALL_COLOR 218) @@ -248,6 +249,7 @@ (pxl8.update_palette_deps) (set camera (pxl8.create_camera_3d)) (set world (pxl8.create_world)) + (set lights (pxl8.create_lights)) (sky.generate-stars 12345) (create-fireball-mesh) @@ -469,15 +471,13 @@ r1 (* 0.06 (math.sin (+ (* real-time 1.8) (* phase 0.5)))) r2 (* 0.04 (math.sin (+ (* real-time 3.2) phase))) light-radius (* 150 (+ 0.95 r1 r2))] - (pxl8.begin_frame_3d camera { + (lights:clear) + (lights:add light-x light-y light-z 255 200 150 light-intensity light-radius) + (pxl8.begin_frame_3d camera lights { :ambient 30 :fog_density 0.0 :celestial_dir [0.5 -0.8 0.3] - :celestial_intensity 0.5 - :lights [{:x light-x :y light-y :z light-z - :r 255 :g 200 :b 150 - :intensity light-intensity - :radius light-radius}]}) + :celestial_intensity 0.5}) (pxl8.clear_depth) (sky.update-gradient 1 2 6 6 10 18) diff --git a/pxl8.sh b/pxl8.sh index 8a5cd43..3087f63 100755 --- a/pxl8.sh +++ b/pxl8.sh @@ -397,6 +397,7 @@ case "$COMMAND" in src/gfx/pxl8_gfx.c src/gfx/pxl8_glows.c src/gfx/pxl8_lightmap.c + src/gfx/pxl8_lights.c src/gfx/pxl8_mesh.c src/gfx/pxl8_palette.c src/gfx/pxl8_particles.c diff --git a/src/gfx/pxl8_cpu.c b/src/gfx/pxl8_cpu.c index 72d0542..31d177b 100644 --- a/src/gfx/pxl8_cpu.c +++ b/src/gfx/pxl8_cpu.c @@ -71,8 +71,8 @@ static pxl8_light_result calc_vertex_light( if (sky_factor < 0.0f) sky_factor = 0.0f; intensity += sky_factor * frame->uniforms.celestial_intensity * 0.3f; - for (u32 i = 0; i < frame->uniforms.num_lights; i++) { - const pxl8_light* light = &frame->uniforms.lights[i]; + for (u32 i = 0; i < frame->lights_count; i++) { + const pxl8_light* light = &frame->lights[i]; f32 contrib = calc_light_intensity(light, world_pos, normal); if (contrib > 0.0f) { intensity += contrib; @@ -1329,7 +1329,7 @@ u32* pxl8_cpu_get_output(pxl8_cpu_backend* cpu) { void pxl8_cpu_render_glows( pxl8_cpu_backend* cpu, - const pxl8_glow_source* glows, + const pxl8_glow* glows, u32 glow_count ) { if (!cpu || cpu->target_stack_depth == 0) return; @@ -1344,7 +1344,7 @@ void pxl8_cpu_render_glows( u32* light_accum = target->light_accum; for (u32 gi = 0; gi < glow_count; gi++) { - const pxl8_glow_source* glow = &glows[gi]; + const pxl8_glow* glow = &glows[gi]; i32 cx = glow->x; i32 cy = glow->y; i32 radius = glow->radius; diff --git a/src/gfx/pxl8_cpu.h b/src/gfx/pxl8_cpu.h index d67d4c8..bfde3f1 100644 --- a/src/gfx/pxl8_cpu.h +++ b/src/gfx/pxl8_cpu.h @@ -64,7 +64,7 @@ u32 pxl8_cpu_get_width(const pxl8_cpu_backend* cpu); void pxl8_cpu_render_glows( pxl8_cpu_backend* cpu, - const pxl8_glow_source* glows, + const pxl8_glow* glows, u32 glow_count ); diff --git a/src/gfx/pxl8_gfx.c b/src/gfx/pxl8_gfx.c index f11f279..f243062 100644 --- a/src/gfx/pxl8_gfx.c +++ b/src/gfx/pxl8_gfx.c @@ -607,10 +607,12 @@ pxl8_3d_frame pxl8_3d_frame_from_camera(const pxl8_3d_camera* camera, const pxl8 return frame; } -void pxl8_3d_begin_frame(pxl8_gfx* gfx, const pxl8_3d_camera* camera, const pxl8_3d_uniforms* uniforms) { +void pxl8_3d_begin_frame(pxl8_gfx* gfx, const pxl8_3d_camera* camera, const pxl8_lights* lights, const pxl8_3d_uniforms* uniforms) { if (!gfx || !camera) return; pxl8_3d_frame frame = pxl8_3d_frame_from_camera(camera, uniforms); + frame.lights = lights ? pxl8_lights_data(lights) : NULL; + frame.lights_count = lights ? pxl8_lights_count(lights) : 0; pxl8_mat4 vp = pxl8_mat4_multiply(frame.projection, frame.view); @@ -802,7 +804,7 @@ void pxl8_gfx_apply_effect(pxl8_gfx* gfx, pxl8_gfx_effect effect, const void* pa switch (effect) { case PXL8_GFX_EFFECT_GLOWS: { - const pxl8_glow_source* glows = (const pxl8_glow_source*)params; + const pxl8_glow* glows = (const pxl8_glow*)params; switch (gfx->backend.type) { case PXL8_GFX_BACKEND_CPU: pxl8_cpu_render_glows(gfx->backend.cpu, glows, count); diff --git a/src/gfx/pxl8_gfx.h b/src/gfx/pxl8_gfx.h index e543068..ec03ed4 100644 --- a/src/gfx/pxl8_gfx.h +++ b/src/gfx/pxl8_gfx.h @@ -2,6 +2,7 @@ #include "pxl8_gfx2d.h" #include "pxl8_gfx3d.h" +#include "pxl8_glows.h" #include "pxl8_hal.h" #include "pxl8_colormap.h" #include "pxl8_palette.h" @@ -14,53 +15,6 @@ typedef enum pxl8_gfx_effect { PXL8_GFX_EFFECT_GLOWS = 0, } pxl8_gfx_effect; -#define PXL8_MAX_GLOWS 256 - -typedef enum pxl8_glow_shape { - PXL8_GLOW_CIRCLE = 0, - PXL8_GLOW_DIAMOND = 1, - PXL8_GLOW_SHAFT = 2, -} pxl8_glow_shape; - -typedef struct pxl8_glow_source { - u8 color; - u16 depth; - u8 height; - u16 intensity; - u8 radius; - pxl8_glow_shape shape; - i16 x; - i16 y; -} pxl8_glow_source; - -static inline pxl8_glow_source pxl8_glow_create(i32 x, i32 y, u8 radius, u16 intensity, u8 color) { - return (pxl8_glow_source){ - .color = color, - .depth = 0xFFFF, - .height = 0, - .intensity = intensity, - .radius = radius, - .shape = PXL8_GLOW_CIRCLE, - .x = (i16)x, - .y = (i16)y, - }; -} - -static inline pxl8_glow_source pxl8_glow_with_depth(pxl8_glow_source g, u16 depth) { - g.depth = depth; - return g; -} - -static inline pxl8_glow_source pxl8_glow_with_shape(pxl8_glow_source g, pxl8_glow_shape shape) { - g.shape = shape; - return g; -} - -static inline pxl8_glow_source pxl8_glow_with_height(pxl8_glow_source g, u8 height) { - g.height = height; - return g; -} - #ifdef __cplusplus extern "C" { #endif diff --git a/src/gfx/pxl8_gfx3d.h b/src/gfx/pxl8_gfx3d.h index ac37f50..b5cf0e9 100644 --- a/src/gfx/pxl8_gfx3d.h +++ b/src/gfx/pxl8_gfx3d.h @@ -1,53 +1,31 @@ #pragma once #include "pxl8_3d_camera.h" +#include "pxl8_lights.h" #include "pxl8_math.h" #include "pxl8_mesh.h" #include "pxl8_types.h" typedef struct pxl8_gfx pxl8_gfx; -#define PXL8_MAX_LIGHTS 16 - -typedef struct pxl8_light { - pxl8_vec3 position; - u8 r, g, b; - u8 intensity; - f32 radius; - f32 radius_sq; - f32 inv_radius_sq; -} pxl8_light; - -static inline pxl8_light pxl8_light_create(pxl8_vec3 pos, u8 r, u8 g, u8 b, u8 intensity, f32 radius) { - f32 radius_sq = radius * radius; - return (pxl8_light){ - .position = pos, - .r = r, .g = g, .b = b, - .intensity = intensity, - .radius = radius, - .radius_sq = radius_sq, - .inv_radius_sq = radius_sq > 0.0f ? 1.0f / radius_sq : 0.0f, - }; -} - typedef struct pxl8_3d_uniforms { u8 ambient; pxl8_vec3 celestial_dir; f32 celestial_intensity; u8 fog_color; f32 fog_density; - pxl8_light lights[PXL8_MAX_LIGHTS]; - u32 num_lights; f32 time; } pxl8_3d_uniforms; typedef struct pxl8_3d_frame { - pxl8_3d_uniforms uniforms; pxl8_vec3 camera_dir; pxl8_vec3 camera_pos; f32 far_clip; + const pxl8_light* lights; + u32 lights_count; f32 near_clip; pxl8_mat4 projection; + pxl8_3d_uniforms uniforms; pxl8_mat4 view; } pxl8_3d_frame; @@ -55,7 +33,7 @@ typedef struct pxl8_3d_frame { extern "C" { #endif -void pxl8_3d_begin_frame(pxl8_gfx* gfx, const pxl8_3d_camera* camera, const pxl8_3d_uniforms* uniforms); +void pxl8_3d_begin_frame(pxl8_gfx* gfx, const pxl8_3d_camera* camera, const pxl8_lights* lights, const pxl8_3d_uniforms* uniforms); void pxl8_3d_clear(pxl8_gfx* gfx, u8 color); void pxl8_3d_clear_depth(pxl8_gfx* gfx); void pxl8_3d_draw_line(pxl8_gfx* gfx, pxl8_vec3 v0, pxl8_vec3 v1, u8 color); diff --git a/src/gfx/pxl8_glows.c b/src/gfx/pxl8_glows.c index 4279d8e..0fba4b4 100644 --- a/src/gfx/pxl8_glows.c +++ b/src/gfx/pxl8_glows.c @@ -1,9 +1,11 @@ #include "pxl8_glows.h" +#include "pxl8_gfx.h" + #include struct pxl8_glows { - pxl8_glow_source* data; + pxl8_glow* data; u32 capacity; u32 count; }; @@ -12,7 +14,7 @@ pxl8_glows* pxl8_glows_create(u32 capacity) { pxl8_glows* glows = calloc(1, sizeof(pxl8_glows)); if (!glows) return NULL; - glows->data = calloc(capacity, sizeof(pxl8_glow_source)); + glows->data = calloc(capacity, sizeof(pxl8_glow)); if (!glows->data) { free(glows); return NULL; @@ -33,7 +35,7 @@ void pxl8_glows_destroy(pxl8_glows* glows) { void pxl8_glows_add(pxl8_glows* glows, i16 x, i16 y, u8 radius, u16 intensity, u8 color, u8 shape) { if (!glows || glows->count >= glows->capacity) return; - pxl8_glow_source* g = &glows->data[glows->count++]; + pxl8_glow* g = &glows->data[glows->count++]; g->x = x; g->y = y; g->radius = radius; diff --git a/src/gfx/pxl8_glows.h b/src/gfx/pxl8_glows.h index f292d1b..5edb1bd 100644 --- a/src/gfx/pxl8_glows.h +++ b/src/gfx/pxl8_glows.h @@ -1,8 +1,27 @@ #pragma once -#include "pxl8_gfx.h" #include "pxl8_types.h" +#define PXL8_GLOWS_MAX 16384 + +typedef enum pxl8_glow_shape { + PXL8_GLOW_CIRCLE = 0, + PXL8_GLOW_DIAMOND = 1, + PXL8_GLOW_SHAFT = 2, +} pxl8_glow_shape; + +typedef struct pxl8_glow { + u8 color; + u16 depth; + u8 height; + u16 intensity; + u8 radius; + pxl8_glow_shape shape; + i16 x; + i16 y; +} pxl8_glow; + +typedef struct pxl8_gfx pxl8_gfx; typedef struct pxl8_glows pxl8_glows; #ifdef __cplusplus @@ -15,6 +34,7 @@ void pxl8_glows_destroy(pxl8_glows* glows); void pxl8_glows_add(pxl8_glows* glows, i16 x, i16 y, u8 radius, u16 intensity, u8 color, u8 shape); void pxl8_glows_clear(pxl8_glows* glows); u32 pxl8_glows_count(const pxl8_glows* glows); +const pxl8_glow* pxl8_glows_data(const pxl8_glows* glows); void pxl8_glows_render(pxl8_glows* glows, pxl8_gfx* gfx); #ifdef __cplusplus diff --git a/src/gfx/pxl8_lights.c b/src/gfx/pxl8_lights.c new file mode 100644 index 0000000..c3280f1 --- /dev/null +++ b/src/gfx/pxl8_lights.c @@ -0,0 +1,63 @@ +#include "pxl8_lights.h" + +#include + +struct pxl8_lights { + pxl8_light* data; + u32 capacity; + u32 count; +}; + +pxl8_lights* pxl8_lights_create(u32 capacity) { + if (capacity > PXL8_LIGHTS_MAX) capacity = PXL8_LIGHTS_MAX; + + pxl8_lights* lights = calloc(1, sizeof(pxl8_lights)); + if (!lights) return NULL; + + lights->data = calloc(capacity, sizeof(pxl8_light)); + if (!lights->data) { + free(lights); + return NULL; + } + + lights->capacity = capacity; + lights->count = 0; + + return lights; +} + +void pxl8_lights_destroy(pxl8_lights* lights) { + if (!lights) return; + free(lights->data); + 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) { + if (!lights || lights->count >= lights->capacity) return; + + f32 radius_sq = radius * radius; + pxl8_light* l = &lights->data[lights->count++]; + l->position.x = x; + l->position.y = y; + l->position.z = z; + l->r = r; + l->g = g; + l->b = b; + l->intensity = intensity; + l->radius = radius; + l->radius_sq = radius_sq; + l->inv_radius_sq = radius_sq > 0.0f ? 1.0f / radius_sq : 0.0f; +} + +void pxl8_lights_clear(pxl8_lights* lights) { + if (!lights) return; + lights->count = 0; +} + +u32 pxl8_lights_count(const pxl8_lights* lights) { + return lights ? lights->count : 0; +} + +const pxl8_light* pxl8_lights_data(const pxl8_lights* lights) { + return lights ? lights->data : NULL; +} diff --git a/src/gfx/pxl8_lights.h b/src/gfx/pxl8_lights.h new file mode 100644 index 0000000..4a445bd --- /dev/null +++ b/src/gfx/pxl8_lights.h @@ -0,0 +1,33 @@ +#pragma once + +#include "pxl8_math.h" +#include "pxl8_types.h" + +#define PXL8_LIGHTS_MAX 256 + +typedef struct pxl8_light { + pxl8_vec3 position; + f32 inv_radius_sq; + u8 r, g, b; + u8 intensity; + f32 radius; + f32 radius_sq; +} pxl8_light; + +typedef struct pxl8_lights pxl8_lights; + +#ifdef __cplusplus +extern "C" { +#endif + +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_clear(pxl8_lights* lights); +u32 pxl8_lights_count(const pxl8_lights* lights); +const pxl8_light* pxl8_lights_data(const pxl8_lights* lights); + +#ifdef __cplusplus +} +#endif diff --git a/src/lua/pxl8.lua b/src/lua/pxl8.lua index b486b05..3f02c39 100644 --- a/src/lua/pxl8.lua +++ b/src/lua/pxl8.lua @@ -104,6 +104,8 @@ pxl8.GLOW_DIAMOND = effects.GLOW_DIAMOND pxl8.GLOW_SHAFT = effects.GLOW_SHAFT pxl8.Glows = effects.Glows pxl8.create_glows = effects.Glows.new +pxl8.Lights = effects.Lights +pxl8.create_lights = effects.Lights.new pxl8.Compressor = sfx.Compressor pxl8.create_compressor = sfx.Compressor.new diff --git a/src/lua/pxl8/effects.lua b/src/lua/pxl8/effects.lua index 260d04c..7edc0a2 100644 --- a/src/lua/pxl8/effects.lua +++ b/src/lua/pxl8/effects.lua @@ -44,4 +44,36 @@ end effects.Glows = Glows +local Lights = {} +Lights.__index = Lights + +function Lights.new(capacity) + local ptr = C.pxl8_lights_create(capacity or 256) + if ptr == nil then + return nil + end + return setmetatable({ _ptr = ptr }, Lights) +end + +function Lights:add(x, y, z, r, g, b, intensity, radius) + C.pxl8_lights_add(self._ptr, x, y, z, r or 255, g or 255, b or 255, intensity or 255, radius or 10) +end + +function Lights:clear() + C.pxl8_lights_clear(self._ptr) +end + +function Lights:count() + return C.pxl8_lights_count(self._ptr) +end + +function Lights:destroy() + if self._ptr then + C.pxl8_lights_destroy(self._ptr) + self._ptr = nil + end +end + +effects.Lights = Lights + return effects diff --git a/src/lua/pxl8/gfx3d.lua b/src/lua/pxl8/gfx3d.lua index ecf0810..61ec31c 100644 --- a/src/lua/pxl8/gfx3d.lua +++ b/src/lua/pxl8/gfx3d.lua @@ -155,7 +155,7 @@ function gfx3d.draw_mesh(mesh, opts) C.pxl8_3d_draw_mesh(core.gfx, mesh._ptr, model, material) end -function gfx3d.begin_frame(camera, uniforms) +function gfx3d.begin_frame(camera, lights, uniforms) uniforms = uniforms or {} local u = ffi.new("pxl8_3d_uniforms") @@ -175,27 +175,8 @@ function gfx3d.begin_frame(camera, uniforms) end u.celestial_intensity = uniforms.celestial_intensity or 0.0 - u.num_lights = 0 - if uniforms.lights then - for i, light in ipairs(uniforms.lights) do - if i > 16 then break end - local idx = i - 1 - u.lights[idx].position.x = light.x or 0 - u.lights[idx].position.y = light.y or 0 - u.lights[idx].position.z = light.z or 0 - u.lights[idx].r = light.r or 255 - u.lights[idx].g = light.g or 255 - u.lights[idx].b = light.b or 255 - u.lights[idx].intensity = light.intensity or 255 - u.lights[idx].radius = light.radius or 100 - local radius_sq = u.lights[idx].radius * u.lights[idx].radius - u.lights[idx].radius_sq = radius_sq - u.lights[idx].inv_radius_sq = radius_sq > 0 and (1.0 / radius_sq) or 0 - u.num_lights = i - end - end - - C.pxl8_3d_begin_frame(core.gfx, camera._ptr, u) + local lights_ptr = lights and lights._ptr or nil + C.pxl8_3d_begin_frame(core.gfx, camera._ptr, lights_ptr, u) end function gfx3d.clear(color) diff --git a/src/script/pxl8_script_ffi.h b/src/script/pxl8_script_ffi.h index b66e161..63ac9d7 100644 --- a/src/script/pxl8_script_ffi.h +++ b/src/script/pxl8_script_ffi.h @@ -197,21 +197,27 @@ static const char* pxl8_ffi_cdefs = "\n" "typedef struct pxl8_light {\n" " pxl8_vec3 position;\n" +" f32 inv_radius_sq;\n" " u8 r, g, b;\n" " u8 intensity;\n" " f32 radius;\n" " f32 radius_sq;\n" -" f32 inv_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_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" +"\n" "typedef struct pxl8_3d_uniforms {\n" " u8 ambient;\n" " pxl8_vec3 celestial_dir;\n" " f32 celestial_intensity;\n" " u8 fog_color;\n" " f32 fog_density;\n" -" pxl8_light lights[16];\n" -" u32 num_lights;\n" " f32 time;\n" "} pxl8_3d_uniforms;\n" "\n" @@ -236,7 +242,7 @@ static const char* pxl8_ffi_cdefs = "\n" "typedef enum pxl8_glow_shape { PXL8_GLOW_CIRCLE = 0, PXL8_GLOW_DIAMOND = 1, PXL8_GLOW_SHAFT = 2 } pxl8_glow_shape;\n" "\n" -"typedef struct pxl8_glow_source {\n" +"typedef struct pxl8_glow {\n" " u8 color;\n" " u16 depth;\n" " u8 height;\n" @@ -245,7 +251,7 @@ static const char* pxl8_ffi_cdefs = " pxl8_glow_shape shape;\n" " i16 x;\n" " i16 y;\n" -"} pxl8_glow_source;\n" +"} pxl8_glow;\n" "\n" "void pxl8_gfx_apply_effect(pxl8_gfx* gfx, pxl8_gfx_effect effect, const void* params, u32 count);\n" "void pxl8_gfx_blend_tables_update(pxl8_gfx* gfx);\n" @@ -259,7 +265,7 @@ static const char* pxl8_ffi_cdefs = "void pxl8_glows_render(pxl8_glows* glows, pxl8_gfx* gfx);\n" "void pxl8_gfx_colormap_update(pxl8_gfx* gfx);\n" "\n" -"void pxl8_3d_begin_frame(pxl8_gfx* gfx, const pxl8_3d_camera* camera, const pxl8_3d_uniforms* uniforms);\n" +"void pxl8_3d_begin_frame(pxl8_gfx* gfx, const pxl8_3d_camera* camera, const pxl8_lights* lights, const pxl8_3d_uniforms* uniforms);\n" "void pxl8_3d_clear(pxl8_gfx* gfx, u8 color);\n" "void pxl8_3d_clear_depth(pxl8_gfx* gfx);\n" "void pxl8_3d_draw_line(pxl8_gfx* gfx, pxl8_vec3 p0, pxl8_vec3 p1, u8 color);\n"