diff --git a/demo/mod/first_person3d.fnl b/demo/mod/first_person3d.fnl index fefa7ec..c0051dd 100644 --- a/demo/mod/first_person3d.fnl +++ b/demo/mod/first_person3d.fnl @@ -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}) diff --git a/src/gfx/pxl8_colormap.h b/src/gfx/pxl8_colormap.h index fb9f714..584e448 100644 --- a/src/gfx/pxl8_colormap.h +++ b/src/gfx/pxl8_colormap.h @@ -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}, diff --git a/src/gfx/pxl8_lights.c b/src/gfx/pxl8_lights.c index 7180e6a..de3d304 100644 --- a/src/gfx/pxl8_lights.c +++ b/src/gfx/pxl8_lights.c @@ -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) { diff --git a/src/gfx/pxl8_lights.h b/src/gfx/pxl8_lights.h index 5763410..15d861a 100644 --- a/src/gfx/pxl8_lights.h +++ b/src/gfx/pxl8_lights.h @@ -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); diff --git a/src/gfx/pxl8_shader_builtins.h b/src/gfx/pxl8_shader_builtins.h index 4efb9bd..a4eaf5f 100644 --- a/src/gfx/pxl8_shader_builtins.h +++ b/src/gfx/pxl8_shader_builtins.h @@ -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]; } diff --git a/src/gfx/pxl8_shader_registry.c b/src/gfx/pxl8_shader_registry.c index 370f183..0461b4e 100644 --- a/src/gfx/pxl8_shader_registry.c +++ b/src/gfx/pxl8_shader_registry.c @@ -2,14 +2,14 @@ #include -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; } diff --git a/src/gfx/shaders/cpu/lit.c b/src/gfx/shaders/cpu/lit.c index 58aaf5a..b776fef 100644 --- a/src/gfx/shaders/cpu/lit.c +++ b/src/gfx/shaders/cpu/lit.c @@ -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 } diff --git a/src/lua/pxl8/effects.lua b/src/lua/pxl8/effects.lua index f38381d..567d64c 100644 --- a/src/lua/pxl8/effects.lua +++ b/src/lua/pxl8/effects.lua @@ -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() diff --git a/src/script/pxl8_script_ffi.h b/src/script/pxl8_script_ffi.h index 036da56..a7577a3 100644 --- a/src/script/pxl8_script_ffi.h +++ b/src/script/pxl8_script_ffi.h @@ -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"