diff --git a/demo/mod/first_person3d.fnl b/demo/mod/first_person3d.fnl index 81d25be..bc3fa85 100644 --- a/demo/mod/first_person3d.fnl +++ b/demo/mod/first_person3d.fnl @@ -343,7 +343,7 @@ (pxl8.push_target) (pxl8.begin_frame_3d camera lights { - :ambient 25 + :ambient 2 :dither true :fog_density 0.0 :celestial_dir [0.5 -0.8 0.3] diff --git a/pxl8d/src/procgen.rs b/pxl8d/src/procgen.rs index f6fb97e..a344792 100644 --- a/pxl8d/src/procgen.rs +++ b/pxl8d/src/procgen.rs @@ -533,8 +533,9 @@ fn compute_vertex_light( let light_dir = to_light.normalize(); let ndotl = normal.dot(light_dir).max(0.0); - let attenuation = (1.0 - dist / light.radius).max(0.0); - let attenuation = attenuation * attenuation; + let dist_sq = to_light.dot(to_light); + let radius_sq = light.radius * light.radius; + let attenuation = (1.0 - dist_sq / radius_sq).max(0.0); total += light.intensity * ndotl * attenuation; } @@ -1056,7 +1057,7 @@ pub fn generate_rooms(params: &ProcgenParams) -> Bsp { Some(LightSource { position: Vec3::new(cx, light_height, cz), - intensity: 1.8, + intensity: 1.5, radius: 160.0, }) }).collect(); diff --git a/src/gfx/pxl8_gfx.h b/src/gfx/pxl8_gfx.h index 81b83cf..196b486 100644 --- a/src/gfx/pxl8_gfx.h +++ b/src/gfx/pxl8_gfx.h @@ -21,6 +21,14 @@ typedef struct pxl8_gfx_stats { u64 triangles; } pxl8_gfx_stats; +enum { + PXL8_CLIP_INSIDE = 0, + PXL8_CLIP_LEFT = 1, + PXL8_CLIP_RIGHT = 2, + PXL8_CLIP_BOTTOM = 4, + PXL8_CLIP_TOP = 8, +}; + typedef enum pxl8_gfx_effect { PXL8_GFX_EFFECT_GLOWS = 0, } pxl8_gfx_effect; diff --git a/src/gfx/pxl8_render.c b/src/gfx/pxl8_render.c index ee7954a..76417e7 100644 --- a/src/gfx/pxl8_render.c +++ b/src/gfx/pxl8_render.c @@ -630,10 +630,18 @@ static void rasterize_triangle( } } +static inline u8 clip_outcode(i32 x, i32 y, i32 xmin, i32 ymin, i32 xmax, i32 ymax) { + u8 code = PXL8_CLIP_INSIDE; + if (x < xmin) code |= PXL8_CLIP_LEFT; + else if (x > xmax) code |= PXL8_CLIP_RIGHT; + if (y < ymin) code |= PXL8_CLIP_TOP; + else if (y > ymax) code |= PXL8_CLIP_BOTTOM; + return code; +} + static void draw_line_clipped( u8* fb, u32 fb_w, - u32 fb_h, i32 x0, i32 y0, i32 x1, @@ -644,18 +652,45 @@ static void draw_line_clipped( i32 clip_max_x, i32 clip_max_y ) { + u8 c0 = clip_outcode(x0, y0, clip_min_x, clip_min_y, clip_max_x, clip_max_y); + u8 c1 = clip_outcode(x1, y1, clip_min_x, clip_min_y, clip_max_x, clip_max_y); + + for (;;) { + if ((c0 | c1) == 0) break; + if (c0 & c1) return; + + u8 out = c0 ? c0 : c1; + i32 x, y; + i32 dx = x1 - x0; + i32 dy = y1 - y0; + + if (out & PXL8_CLIP_BOTTOM) { + x = x0 + dx * (clip_max_y - y0) / dy; + y = clip_max_y; + } else if (out & PXL8_CLIP_TOP) { + x = x0 + dx * (clip_min_y - y0) / dy; + y = clip_min_y; + } else if (out & PXL8_CLIP_RIGHT) { + y = y0 + dy * (clip_max_x - x0) / dx; + x = clip_max_x; + } else { + y = y0 + dy * (clip_min_x - x0) / dx; + x = clip_min_x; + } + + if (out == c0) { x0 = x; y0 = y; c0 = clip_outcode(x0, y0, clip_min_x, clip_min_y, clip_max_x, clip_max_y); } + else { x1 = x; y1 = y; c1 = clip_outcode(x1, y1, clip_min_x, clip_min_y, clip_max_x, clip_max_y); } + } + i32 dx = abs(x1 - x0); i32 dy = -abs(y1 - y0); i32 sx = x0 < x1 ? 1 : -1; i32 sy = y0 < y1 ? 1 : -1; i32 err = dx + dy; + i32 w = (i32)fb_w; - while (true) { - 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; - } - } + for (;;) { + fb[y0 * w + x0] = color; if (x0 == x1 && y0 == y1) break; i32 e2 = 2 * err; if (e2 >= dy) { err += dy; x0 += sx; } @@ -1305,11 +1340,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, + draw_line_clipped(fb, fb_w, sx0, sy0, sx1, sy1, wire_color, 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, + draw_line_clipped(fb, fb_w, sx1, sy1, sx2, sy2, wire_color, 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, + draw_line_clipped(fb, fb_w, sx2, sy2, sx0, sy0, wire_color, clip_min_x, clip_min_y, clip_max_x, clip_max_y); } else { tri_setup setup;