better lighting

This commit is contained in:
asrael 2026-01-31 09:31:17 -06:00
parent 805a2713a3
commit 6ed4e17065
75 changed files with 6417 additions and 3667 deletions

View file

@ -4,11 +4,12 @@ use alloc::vec;
use alloc::vec::Vec;
use libm::sqrtf;
use crate::bsp::{Bsp, BspVertex, BspEdge, BspFace, BspPlane, BspNode, BspLeaf, BspPortal, BspCellPortals};
use crate::math::Vec3;
use crate::bsp::{Bsp, BspBuilder, CellPortals, Edge, Face, Leaf, Node, Plane, Portal, Vertex};
use crate::math::{Vec3, Vec3Ext};
pub const CELL_SIZE: f32 = 64.0;
pub const WALL_HEIGHT: f32 = 128.0;
pub const TRIM_HEIGHT: f32 = 12.0;
pub const PVS_MAX_DEPTH: u32 = 64;
#[derive(Clone, Copy)]
@ -107,7 +108,7 @@ impl Bounds {
}
struct BspBuildContext<'a> {
bsp: &'a mut Bsp,
bsp: &'a mut BspBuilder,
grid: &'a RoomGrid,
node_count: u32,
plane_offset: u32,
@ -133,7 +134,7 @@ fn carve_corridor_v(grid: &mut RoomGrid, y1: i32, y2: i32, x: i32) {
}
}
fn compute_face_aabb(face: &mut BspFace, verts: &[BspVertex], vert_idx: usize) {
fn compute_face_aabb(face: &mut Face, verts: &[Vertex], vert_idx: usize) {
face.aabb_min = Vec3::new(1e30, 1e30, 1e30);
face.aabb_max = Vec3::new(-1e30, -1e30, -1e30);
@ -148,7 +149,7 @@ fn compute_face_aabb(face: &mut BspFace, verts: &[BspVertex], vert_idx: usize) {
}
}
fn build_bsp_node(ctx: &mut BspBuildContext, x0: i32, y0: i32, x1: i32, y1: i32, depth: i32) -> i32 {
fn build_bsp_node_grid(ctx: &mut BspBuildContext, x0: i32, y0: i32, x1: i32, y1: i32, depth: i32) -> i32 {
if x1 - x0 == 1 && y1 - y0 == 1 {
let leaf_idx = y0 * ctx.grid.width + x0;
return -(leaf_idx + 1);
@ -164,16 +165,16 @@ fn build_bsp_node(ctx: &mut BspBuildContext, x0: i32, y0: i32, x1: i32, y1: i32,
let mid_x = (x0 + x1) / 2;
let split_pos = mid_x as f32 * CELL_SIZE;
ctx.bsp.planes[plane_idx as usize] = BspPlane {
ctx.bsp.planes[plane_idx as usize] = Plane {
normal: Vec3::new(1.0, 0.0, 0.0),
dist: split_pos,
plane_type: 0,
type_: 0,
};
let child0 = build_bsp_node(ctx, mid_x, y0, x1, y1, depth + 1);
let child1 = build_bsp_node(ctx, x0, y0, mid_x, y1, depth + 1);
let child0 = build_bsp_node_grid(ctx, mid_x, y0, x1, y1, depth + 1);
let child1 = build_bsp_node_grid(ctx, x0, y0, mid_x, y1, depth + 1);
ctx.bsp.nodes[node_idx as usize] = BspNode {
ctx.bsp.nodes[node_idx as usize] = Node {
plane_id: plane_idx,
children: [child0, child1],
..Default::default()
@ -182,16 +183,16 @@ fn build_bsp_node(ctx: &mut BspBuildContext, x0: i32, y0: i32, x1: i32, y1: i32,
let mid_y = (y0 + y1) / 2;
let split_pos = mid_y as f32 * CELL_SIZE;
ctx.bsp.planes[plane_idx as usize] = BspPlane {
ctx.bsp.planes[plane_idx as usize] = Plane {
normal: Vec3::new(0.0, 0.0, 1.0),
dist: split_pos,
plane_type: 0,
type_: 0,
};
let child0 = build_bsp_node(ctx, x0, mid_y, x1, y1, depth + 1);
let child1 = build_bsp_node(ctx, x0, y0, x1, mid_y, depth + 1);
let child0 = build_bsp_node_grid(ctx, x0, mid_y, x1, y1, depth + 1);
let child1 = build_bsp_node_grid(ctx, x0, y0, x1, mid_y, depth + 1);
ctx.bsp.nodes[node_idx as usize] = BspNode {
ctx.bsp.nodes[node_idx as usize] = Node {
plane_id: plane_idx,
children: [child0, child1],
..Default::default()
@ -201,9 +202,33 @@ fn build_bsp_node(ctx: &mut BspBuildContext, x0: i32, y0: i32, x1: i32, y1: i32,
node_idx as i32
}
fn build_cell_portals(grid: &RoomGrid) -> Vec<BspCellPortals> {
fn build_bsp_node(ctx: &mut BspBuildContext, x0: i32, y0: i32, x1: i32, y1: i32, depth: i32, floor_leaf_idx: i32) -> i32 {
let node_idx = ctx.node_count;
ctx.node_count += 1;
let plane_idx = ctx.plane_offset;
ctx.plane_offset += 1;
ctx.bsp.planes[plane_idx as usize] = Plane {
normal: Vec3::new(0.0, 1.0, 0.0),
dist: 0.0,
type_: 1,
};
let above_floor = build_bsp_node_grid(ctx, x0, y0, x1, y1, depth);
ctx.bsp.nodes[node_idx as usize] = Node {
plane_id: plane_idx,
children: [above_floor, -(floor_leaf_idx + 1)],
..Default::default()
};
node_idx as i32
}
fn build_cell_portals(grid: &RoomGrid) -> Vec<CellPortals> {
let total_cells = (grid.width * grid.height) as usize;
let mut portals = vec![BspCellPortals::default(); total_cells];
let mut portals = vec![CellPortals::default(); total_cells];
for y in 0..grid.height {
for x in 0..grid.width {
@ -218,7 +243,7 @@ fn build_cell_portals(grid: &RoomGrid) -> Vec<BspCellPortals> {
if x > 0 && grid.get(x - 1, y) == 0 {
let p = &mut portals[c];
let idx = p.num_portals as usize;
p.portals[idx] = BspPortal {
p.portals[idx] = Portal {
x0: cx,
z0: cz,
x1: cx,
@ -230,7 +255,7 @@ fn build_cell_portals(grid: &RoomGrid) -> Vec<BspCellPortals> {
if x < grid.width - 1 && grid.get(x + 1, y) == 0 {
let p = &mut portals[c];
let idx = p.num_portals as usize;
p.portals[idx] = BspPortal {
p.portals[idx] = Portal {
x0: cx + CELL_SIZE,
z0: cz + CELL_SIZE,
x1: cx + CELL_SIZE,
@ -242,7 +267,7 @@ fn build_cell_portals(grid: &RoomGrid) -> Vec<BspCellPortals> {
if y > 0 && grid.get(x, y - 1) == 0 {
let p = &mut portals[c];
let idx = p.num_portals as usize;
p.portals[idx] = BspPortal {
p.portals[idx] = Portal {
x0: cx + CELL_SIZE,
z0: cz,
x1: cx,
@ -254,7 +279,7 @@ fn build_cell_portals(grid: &RoomGrid) -> Vec<BspCellPortals> {
if y < grid.height - 1 && grid.get(x, y + 1) == 0 {
let p = &mut portals[c];
let idx = p.num_portals as usize;
p.portals[idx] = BspPortal {
p.portals[idx] = Portal {
x0: cx,
z0: cz + CELL_SIZE,
x1: cx + CELL_SIZE,
@ -277,8 +302,8 @@ struct FloodEntry {
fn portal_flood_bfs(
start_leaf: u32,
portals: &[BspCellPortals],
leafs: &[BspLeaf],
portals: &[CellPortals],
leafs: &[Leaf],
pvs: &mut [u8],
num_leafs: u32,
) {
@ -325,8 +350,8 @@ fn portal_flood_bfs(
fn compute_leaf_pvs(
start_leaf: u32,
portals: &[BspCellPortals],
leafs: &[BspLeaf],
portals: &[CellPortals],
leafs: &[Leaf],
num_leafs: u32,
) -> Vec<u8> {
let pvs_bytes = ((num_leafs + 7) / 8) as usize;
@ -357,7 +382,7 @@ fn rle_compress_pvs(pvs: &[u8]) -> Vec<u8> {
out
}
fn build_pvs_data(bsp: &mut Bsp, portals: &[BspCellPortals]) {
fn build_pvs_data(bsp: &mut BspBuilder, portals: &[CellPortals]) {
let num_leafs = bsp.leafs.len() as u32;
let mut visdata = Vec::new();
@ -417,7 +442,7 @@ fn compute_vertex_light(
total.min(1.0)
}
fn compute_bsp_vertex_lighting(bsp: &mut Bsp, lights: &[LightSource], ambient: f32) {
fn compute_bsp_vertex_lighting(bsp: &mut BspBuilder, lights: &[LightSource], ambient: f32) {
if bsp.vertices.is_empty() {
return;
}
@ -462,35 +487,35 @@ fn compute_bsp_vertex_lighting(bsp: &mut Bsp, lights: &[LightSource], ambient: f
}
}
fn grid_to_bsp(bsp: &mut Bsp, grid: &RoomGrid) {
let mut face_count = 0;
fn grid_to_bsp(bsp: &mut BspBuilder, grid: &RoomGrid) {
let mut wall_count = 0;
let mut floor_ceiling_count = 0;
for y in 0..grid.height {
for x in 0..grid.width {
if grid.get(x, y) == 0 {
if grid.get(x - 1, y) == 1 { face_count += 1; }
if grid.get(x + 1, y) == 1 { face_count += 1; }
if grid.get(x, y - 1) == 1 { face_count += 1; }
if grid.get(x, y + 1) == 1 { face_count += 1; }
if grid.get(x - 1, y) == 1 { wall_count += 1; }
if grid.get(x + 1, y) == 1 { wall_count += 1; }
if grid.get(x, y - 1) == 1 { wall_count += 1; }
if grid.get(x, y + 1) == 1 { wall_count += 1; }
floor_ceiling_count += 1;
}
}
}
face_count += floor_ceiling_count;
let face_count = wall_count * 2 + floor_ceiling_count;
let vertex_count = face_count * 4;
let total_cells = (grid.width * grid.height) as usize;
let max_nodes = 2 * total_cells;
let total_planes = face_count + max_nodes;
let max_nodes = 2 * total_cells + 1;
let total_planes = face_count + max_nodes + 1;
bsp.vertices = vec![BspVertex::default(); vertex_count];
bsp.faces = vec![BspFace::default(); face_count];
bsp.planes = vec![BspPlane::default(); total_planes];
bsp.edges = vec![BspEdge::default(); vertex_count];
bsp.vertices = vec![Vertex::default(); vertex_count];
bsp.faces = vec![Face::default(); face_count];
bsp.planes = vec![Plane::default(); total_planes];
bsp.edges = vec![Edge::default(); vertex_count];
bsp.surfedges = vec![0i32; vertex_count];
bsp.nodes = vec![BspNode::default(); max_nodes];
bsp.nodes = vec![Node::default(); max_nodes];
let mut face_cell = vec![0u32; face_count];
@ -506,9 +531,35 @@ fn grid_to_bsp(bsp: &mut Bsp, grid: &RoomGrid) {
let cell_idx = (y * grid.width + x) as u32;
if grid.get(x - 1, y) == 1 {
bsp.vertices[vert_idx + 0].position = Vec3::new(fx, 0.0, fy);
bsp.vertices[vert_idx + 0].position = Vec3::new(fx, TRIM_HEIGHT, fy);
bsp.vertices[vert_idx + 1].position = Vec3::new(fx, WALL_HEIGHT, fy);
bsp.vertices[vert_idx + 2].position = Vec3::new(fx, WALL_HEIGHT, fy + CELL_SIZE);
bsp.vertices[vert_idx + 3].position = Vec3::new(fx, TRIM_HEIGHT, fy + CELL_SIZE);
bsp.planes[face_idx].normal = Vec3::new(1.0, 0.0, 0.0);
bsp.planes[face_idx].dist = fx;
bsp.faces[face_idx].plane_id = face_idx as u16;
bsp.faces[face_idx].num_edges = 4;
bsp.faces[face_idx].first_edge = edge_idx as u32;
bsp.faces[face_idx].material_id = 1;
for i in 0..4 {
bsp.edges[edge_idx + i].vertex[0] = (vert_idx + i) as u16;
bsp.edges[edge_idx + i].vertex[1] = (vert_idx + ((i + 1) % 4)) as u16;
bsp.surfedges[edge_idx + i] = (edge_idx + i) as i32;
}
compute_face_aabb(&mut bsp.faces[face_idx], &bsp.vertices, vert_idx);
face_cell[face_idx] = cell_idx;
vert_idx += 4;
edge_idx += 4;
face_idx += 1;
bsp.vertices[vert_idx + 0].position = Vec3::new(fx, 0.0, fy);
bsp.vertices[vert_idx + 1].position = Vec3::new(fx, TRIM_HEIGHT, fy);
bsp.vertices[vert_idx + 2].position = Vec3::new(fx, TRIM_HEIGHT, fy + CELL_SIZE);
bsp.vertices[vert_idx + 3].position = Vec3::new(fx, 0.0, fy + CELL_SIZE);
bsp.planes[face_idx].normal = Vec3::new(1.0, 0.0, 0.0);
@ -517,7 +568,7 @@ fn grid_to_bsp(bsp: &mut Bsp, grid: &RoomGrid) {
bsp.faces[face_idx].plane_id = face_idx as u16;
bsp.faces[face_idx].num_edges = 4;
bsp.faces[face_idx].first_edge = edge_idx as u32;
bsp.faces[face_idx].material_id = 0;
bsp.faces[face_idx].material_id = 3;
for i in 0..4 {
bsp.edges[edge_idx + i].vertex[0] = (vert_idx + i) as u16;
@ -534,8 +585,8 @@ fn grid_to_bsp(bsp: &mut Bsp, grid: &RoomGrid) {
}
if grid.get(x + 1, y) == 1 {
bsp.vertices[vert_idx + 0].position = Vec3::new(fx + CELL_SIZE, 0.0, fy);
bsp.vertices[vert_idx + 1].position = Vec3::new(fx + CELL_SIZE, 0.0, fy + CELL_SIZE);
bsp.vertices[vert_idx + 0].position = Vec3::new(fx + CELL_SIZE, TRIM_HEIGHT, fy);
bsp.vertices[vert_idx + 1].position = Vec3::new(fx + CELL_SIZE, TRIM_HEIGHT, fy + CELL_SIZE);
bsp.vertices[vert_idx + 2].position = Vec3::new(fx + CELL_SIZE, WALL_HEIGHT, fy + CELL_SIZE);
bsp.vertices[vert_idx + 3].position = Vec3::new(fx + CELL_SIZE, WALL_HEIGHT, fy);
@ -545,7 +596,33 @@ fn grid_to_bsp(bsp: &mut Bsp, grid: &RoomGrid) {
bsp.faces[face_idx].plane_id = face_idx as u16;
bsp.faces[face_idx].num_edges = 4;
bsp.faces[face_idx].first_edge = edge_idx as u32;
bsp.faces[face_idx].material_id = 0;
bsp.faces[face_idx].material_id = 1;
for i in 0..4 {
bsp.edges[edge_idx + i].vertex[0] = (vert_idx + i) as u16;
bsp.edges[edge_idx + i].vertex[1] = (vert_idx + ((i + 1) % 4)) as u16;
bsp.surfedges[edge_idx + i] = (edge_idx + i) as i32;
}
compute_face_aabb(&mut bsp.faces[face_idx], &bsp.vertices, vert_idx);
face_cell[face_idx] = cell_idx;
vert_idx += 4;
edge_idx += 4;
face_idx += 1;
bsp.vertices[vert_idx + 0].position = Vec3::new(fx + CELL_SIZE, 0.0, fy);
bsp.vertices[vert_idx + 1].position = Vec3::new(fx + CELL_SIZE, 0.0, fy + CELL_SIZE);
bsp.vertices[vert_idx + 2].position = Vec3::new(fx + CELL_SIZE, TRIM_HEIGHT, fy + CELL_SIZE);
bsp.vertices[vert_idx + 3].position = Vec3::new(fx + CELL_SIZE, TRIM_HEIGHT, fy);
bsp.planes[face_idx].normal = Vec3::new(-1.0, 0.0, 0.0);
bsp.planes[face_idx].dist = -(fx + CELL_SIZE);
bsp.faces[face_idx].plane_id = face_idx as u16;
bsp.faces[face_idx].num_edges = 4;
bsp.faces[face_idx].first_edge = edge_idx as u32;
bsp.faces[face_idx].material_id = 3;
for i in 0..4 {
bsp.edges[edge_idx + i].vertex[0] = (vert_idx + i) as u16;
@ -562,8 +639,8 @@ fn grid_to_bsp(bsp: &mut Bsp, grid: &RoomGrid) {
}
if grid.get(x, y - 1) == 1 {
bsp.vertices[vert_idx + 0].position = Vec3::new(fx, 0.0, fy);
bsp.vertices[vert_idx + 1].position = Vec3::new(fx + CELL_SIZE, 0.0, fy);
bsp.vertices[vert_idx + 0].position = Vec3::new(fx, TRIM_HEIGHT, fy);
bsp.vertices[vert_idx + 1].position = Vec3::new(fx + CELL_SIZE, TRIM_HEIGHT, fy);
bsp.vertices[vert_idx + 2].position = Vec3::new(fx + CELL_SIZE, WALL_HEIGHT, fy);
bsp.vertices[vert_idx + 3].position = Vec3::new(fx, WALL_HEIGHT, fy);
@ -573,7 +650,33 @@ fn grid_to_bsp(bsp: &mut Bsp, grid: &RoomGrid) {
bsp.faces[face_idx].plane_id = face_idx as u16;
bsp.faces[face_idx].num_edges = 4;
bsp.faces[face_idx].first_edge = edge_idx as u32;
bsp.faces[face_idx].material_id = 0;
bsp.faces[face_idx].material_id = 1;
for i in 0..4 {
bsp.edges[edge_idx + i].vertex[0] = (vert_idx + i) as u16;
bsp.edges[edge_idx + i].vertex[1] = (vert_idx + ((i + 1) % 4)) as u16;
bsp.surfedges[edge_idx + i] = (edge_idx + i) as i32;
}
compute_face_aabb(&mut bsp.faces[face_idx], &bsp.vertices, vert_idx);
face_cell[face_idx] = cell_idx;
vert_idx += 4;
edge_idx += 4;
face_idx += 1;
bsp.vertices[vert_idx + 0].position = Vec3::new(fx, 0.0, fy);
bsp.vertices[vert_idx + 1].position = Vec3::new(fx + CELL_SIZE, 0.0, fy);
bsp.vertices[vert_idx + 2].position = Vec3::new(fx + CELL_SIZE, TRIM_HEIGHT, fy);
bsp.vertices[vert_idx + 3].position = Vec3::new(fx, TRIM_HEIGHT, fy);
bsp.planes[face_idx].normal = Vec3::new(0.0, 0.0, 1.0);
bsp.planes[face_idx].dist = fy;
bsp.faces[face_idx].plane_id = face_idx as u16;
bsp.faces[face_idx].num_edges = 4;
bsp.faces[face_idx].first_edge = edge_idx as u32;
bsp.faces[face_idx].material_id = 3;
for i in 0..4 {
bsp.edges[edge_idx + i].vertex[0] = (vert_idx + i) as u16;
@ -590,9 +693,35 @@ fn grid_to_bsp(bsp: &mut Bsp, grid: &RoomGrid) {
}
if grid.get(x, y + 1) == 1 {
bsp.vertices[vert_idx + 0].position = Vec3::new(fx, 0.0, fy + CELL_SIZE);
bsp.vertices[vert_idx + 0].position = Vec3::new(fx, TRIM_HEIGHT, fy + CELL_SIZE);
bsp.vertices[vert_idx + 1].position = Vec3::new(fx, WALL_HEIGHT, fy + CELL_SIZE);
bsp.vertices[vert_idx + 2].position = Vec3::new(fx + CELL_SIZE, WALL_HEIGHT, fy + CELL_SIZE);
bsp.vertices[vert_idx + 3].position = Vec3::new(fx + CELL_SIZE, TRIM_HEIGHT, fy + CELL_SIZE);
bsp.planes[face_idx].normal = Vec3::new(0.0, 0.0, -1.0);
bsp.planes[face_idx].dist = -(fy + CELL_SIZE);
bsp.faces[face_idx].plane_id = face_idx as u16;
bsp.faces[face_idx].num_edges = 4;
bsp.faces[face_idx].first_edge = edge_idx as u32;
bsp.faces[face_idx].material_id = 1;
for i in 0..4 {
bsp.edges[edge_idx + i].vertex[0] = (vert_idx + i) as u16;
bsp.edges[edge_idx + i].vertex[1] = (vert_idx + ((i + 1) % 4)) as u16;
bsp.surfedges[edge_idx + i] = (edge_idx + i) as i32;
}
compute_face_aabb(&mut bsp.faces[face_idx], &bsp.vertices, vert_idx);
face_cell[face_idx] = cell_idx;
vert_idx += 4;
edge_idx += 4;
face_idx += 1;
bsp.vertices[vert_idx + 0].position = Vec3::new(fx, 0.0, fy + CELL_SIZE);
bsp.vertices[vert_idx + 1].position = Vec3::new(fx, TRIM_HEIGHT, fy + CELL_SIZE);
bsp.vertices[vert_idx + 2].position = Vec3::new(fx + CELL_SIZE, TRIM_HEIGHT, fy + CELL_SIZE);
bsp.vertices[vert_idx + 3].position = Vec3::new(fx + CELL_SIZE, 0.0, fy + CELL_SIZE);
bsp.planes[face_idx].normal = Vec3::new(0.0, 0.0, -1.0);
@ -601,7 +730,7 @@ fn grid_to_bsp(bsp: &mut Bsp, grid: &RoomGrid) {
bsp.faces[face_idx].plane_id = face_idx as u16;
bsp.faces[face_idx].num_edges = 4;
bsp.faces[face_idx].first_edge = edge_idx as u32;
bsp.faces[face_idx].material_id = 0;
bsp.faces[face_idx].material_id = 3;
for i in 0..4 {
bsp.edges[edge_idx + i].vertex[0] = (vert_idx + i) as u16;
@ -661,7 +790,7 @@ fn grid_to_bsp(bsp: &mut Bsp, grid: &RoomGrid) {
bsp.edges.truncate(edge_idx);
bsp.surfedges.truncate(edge_idx);
bsp.leafs = vec![BspLeaf::default(); total_cells];
bsp.leafs = vec![Leaf::default(); total_cells + 1];
bsp.marksurfaces = vec![0u16; face_idx];
let mut faces_per_cell = vec![0u32; total_cells];
@ -712,6 +841,17 @@ fn grid_to_bsp(bsp: &mut Bsp, grid: &RoomGrid) {
}
}
let floor_leaf_idx = total_cells as i32;
let floor_leaf = &mut bsp.leafs[total_cells];
floor_leaf.contents = -1;
floor_leaf.mins = [0, i16::MIN, 0];
floor_leaf.maxs = [
(grid.width as f32 * CELL_SIZE) as i16,
0,
(grid.height as f32 * CELL_SIZE) as i16,
];
floor_leaf.visofs = -1;
let face_count_final = face_idx;
let mut ctx = BspBuildContext {
bsp,
@ -720,7 +860,7 @@ fn grid_to_bsp(bsp: &mut Bsp, grid: &RoomGrid) {
plane_offset: face_count_final as u32,
};
build_bsp_node(&mut ctx, 0, 0, grid.width, grid.height, 0);
build_bsp_node(&mut ctx, 0, 0, grid.width, grid.height, 0, floor_leaf_idx);
let node_count = ctx.node_count as usize;
let plane_count = ctx.plane_offset as usize;
@ -782,7 +922,7 @@ pub fn generate_rooms(params: &ProcgenParams) -> Bsp {
}
}
let mut bsp = Bsp::new();
let mut bsp = BspBuilder::new();
grid_to_bsp(&mut bsp, &grid);
let light_height = 80.0;
@ -798,7 +938,7 @@ pub fn generate_rooms(params: &ProcgenParams) -> Bsp {
compute_bsp_vertex_lighting(&mut bsp, &lights, 0.1);
bsp
bsp.into()
}
pub fn generate(params: &ProcgenParams) -> Bsp {