fix(bsp): fill in exterior cells
This commit is contained in:
parent
ab0d2a4b04
commit
1341b30920
8 changed files with 740 additions and 102 deletions
|
|
@ -166,6 +166,10 @@ pub struct BspBuilder {
|
|||
pub heightfield_ox: f32,
|
||||
pub heightfield_oz: f32,
|
||||
pub heightfield_cell_size: f32,
|
||||
pub bounds_min_x: f32,
|
||||
pub bounds_min_z: f32,
|
||||
pub bounds_max_x: f32,
|
||||
pub bounds_max_z: f32,
|
||||
}
|
||||
|
||||
impl BspBuilder {
|
||||
|
|
@ -225,6 +229,10 @@ impl From<BspBuilder> for Bsp {
|
|||
heightfield_w: b.heightfield_w,
|
||||
heightfield_h: b.heightfield_h,
|
||||
visdata_size: visdata.len() as u32,
|
||||
bounds_min_x: b.bounds_min_x,
|
||||
bounds_min_z: b.bounds_min_z,
|
||||
bounds_max_x: b.bounds_max_x,
|
||||
bounds_max_z: b.bounds_max_z,
|
||||
};
|
||||
|
||||
Self {
|
||||
|
|
|
|||
|
|
@ -313,5 +313,11 @@ fn bsp_to_messages(bsp: &bsp::Bsp, cx: i32, cz: i32, version: u32) -> Vec<transp
|
|||
data.extend_from_slice(&c_bsp.heightfield_cell_size.to_be_bytes());
|
||||
}
|
||||
|
||||
let c_bsp = bsp.as_c_bsp();
|
||||
data.extend_from_slice(&c_bsp.bounds_min_x.to_be_bytes());
|
||||
data.extend_from_slice(&c_bsp.bounds_min_z.to_be_bytes());
|
||||
data.extend_from_slice(&c_bsp.bounds_max_x.to_be_bytes());
|
||||
data.extend_from_slice(&c_bsp.bounds_max_z.to_be_bytes());
|
||||
|
||||
transport::ChunkMessage::from_bsp(data, cx, cz, version)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -199,6 +199,45 @@ fn carve_entries(grid: &mut RoomGrid, entries: &[ChunkEntry]) {
|
|||
}
|
||||
}
|
||||
|
||||
fn shrink_grid(grid: &RoomGrid, entries: &[ChunkEntry]) -> (RoomGrid, i32, i32) {
|
||||
let (mut min_x, mut min_z, mut max_x, mut max_z) = (grid.width, grid.height, 0i32, 0i32);
|
||||
for z in 0..grid.height {
|
||||
for x in 0..grid.width {
|
||||
if grid.get(x, z) == 0 {
|
||||
if x < min_x { min_x = x; }
|
||||
if x > max_x { max_x = x; }
|
||||
if z < min_z { min_z = z; }
|
||||
if z > max_z { max_z = z; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
min_x = (min_x - 1).max(0);
|
||||
min_z = (min_z - 1).max(0);
|
||||
max_x = (max_x + 1).min(grid.width - 1);
|
||||
max_z = (max_z + 1).min(grid.height - 1);
|
||||
|
||||
for e in entries {
|
||||
match e.edge {
|
||||
ChunkEdge::West => min_x = 0,
|
||||
ChunkEdge::East => max_x = grid.width - 1,
|
||||
ChunkEdge::North => min_z = 0,
|
||||
ChunkEdge::South => max_z = grid.height - 1,
|
||||
}
|
||||
}
|
||||
|
||||
let tw = max_x - min_x + 1;
|
||||
let th = max_z - min_z + 1;
|
||||
let mut tight = RoomGrid::new(tw, th);
|
||||
for z in 0..th {
|
||||
for x in 0..tw {
|
||||
tight.set(x, z, grid.get(x + min_x, z + min_z));
|
||||
}
|
||||
}
|
||||
|
||||
(tight, min_x, min_z)
|
||||
}
|
||||
|
||||
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);
|
||||
|
|
@ -364,6 +403,8 @@ fn build_cell_portals(grid: &RoomGrid, origin_x: f32, origin_z: f32) -> Vec<Cell
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
portals
|
||||
}
|
||||
|
||||
|
|
@ -790,6 +831,14 @@ struct BspMaterials {
|
|||
const DUNGEON_MATS: BspMaterials = BspMaterials { floor: 0, wall: 1, trim: 3 };
|
||||
const COURTYARD_MATS: BspMaterials = BspMaterials { floor: 4, wall: 5, trim: 6 };
|
||||
|
||||
fn is_adj_wall(grid: &RoomGrid, x: i32, y: i32) -> bool {
|
||||
if x < 0 || x >= grid.width || y < 0 || y >= grid.height { return false; }
|
||||
grid.get(x, y) == 1 && (
|
||||
grid.get(x - 1, y) == 0 || grid.get(x + 1, y) == 0 ||
|
||||
grid.get(x, y - 1) == 0 || grid.get(x, y + 1) == 0
|
||||
)
|
||||
}
|
||||
|
||||
fn grid_to_bsp(bsp: &mut BspBuilder, grid: &RoomGrid, doorways: &[Doorway], entries: &[ChunkEntry], mats: &BspMaterials, origin_x: f32, origin_z: f32) {
|
||||
let mut wall_count = 0;
|
||||
let mut floor_ceiling_count = 0;
|
||||
|
|
@ -831,16 +880,29 @@ fn grid_to_bsp(bsp: &mut BspBuilder, grid: &RoomGrid, doorways: &[Doorway], entr
|
|||
}
|
||||
}
|
||||
|
||||
let mut solid_floor_count = 0;
|
||||
let mut filler_floor_count = 0;
|
||||
let mut ext_wall_count = 0;
|
||||
let mut wall_top_count = 0;
|
||||
for y in 0..grid.height {
|
||||
for x in 0..grid.width {
|
||||
if grid.get(x, y) == 1 {
|
||||
solid_floor_count += 1;
|
||||
let adj_room = grid.get(x-1,y)==0 || grid.get(x+1,y)==0
|
||||
|| grid.get(x,y-1)==0 || grid.get(x,y+1)==0;
|
||||
if adj_room {
|
||||
wall_top_count += 1;
|
||||
if grid.get(x-1,y) != 0 && !is_adj_wall(grid, x-1, y) { ext_wall_count += 1; }
|
||||
if grid.get(x+1,y) != 0 && !is_adj_wall(grid, x+1, y) { ext_wall_count += 1; }
|
||||
if grid.get(x,y-1) != 0 && !is_adj_wall(grid, x, y-1) { ext_wall_count += 1; }
|
||||
if grid.get(x,y+1) != 0 && !is_adj_wall(grid, x, y+1) { ext_wall_count += 1; }
|
||||
} else {
|
||||
filler_floor_count += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let face_count = wall_count * 2 + floor_ceiling_count + doorway_extra + partition_faces + solid_floor_count;
|
||||
let face_count = wall_count * 2 + floor_ceiling_count + doorway_extra + partition_faces
|
||||
+ filler_floor_count + ext_wall_count * 2 + wall_top_count;
|
||||
let vertex_count = face_count * 4;
|
||||
|
||||
let total_cells = (grid.width * grid.height) as usize;
|
||||
|
|
@ -1126,12 +1188,74 @@ fn grid_to_bsp(bsp: &mut BspBuilder, grid: &RoomGrid, doorways: &[Doorway], entr
|
|||
for x in 0..grid.width {
|
||||
if grid.get(x, y) == 1 {
|
||||
let fx = origin_x + x as f32 * CELL_SIZE;
|
||||
let fy = origin_z + y as f32 * CELL_SIZE;
|
||||
let fz = origin_z + y as f32 * CELL_SIZE;
|
||||
let cell_idx = (y * grid.width + x) as u32;
|
||||
emit_quad(bsp, &mut face_cell, &mut vert_idx, &mut face_idx, &mut edge_idx,
|
||||
[Vec3::new(fx, 0.0, fy), Vec3::new(fx, 0.0, fy + CELL_SIZE),
|
||||
Vec3::new(fx + CELL_SIZE, 0.0, fy + CELL_SIZE), Vec3::new(fx + CELL_SIZE, 0.0, fy)],
|
||||
up, 0.0, 7, cell_idx);
|
||||
|
||||
let adj_room = grid.get(x-1,y)==0 || grid.get(x+1,y)==0
|
||||
|| grid.get(x,y-1)==0 || grid.get(x,y+1)==0;
|
||||
if adj_room {
|
||||
let room_ci = if grid.get(x-1,y)==0 { ((y)*grid.width+(x-1)) as u32 }
|
||||
else if grid.get(x+1,y)==0 { ((y)*grid.width+(x+1)) as u32 }
|
||||
else if grid.get(x,y-1)==0 { ((y-1)*grid.width+(x)) as u32 }
|
||||
else { ((y+1)*grid.width+(x)) as u32 };
|
||||
|
||||
emit_quad(bsp, &mut face_cell, &mut vert_idx, &mut face_idx, &mut edge_idx,
|
||||
[Vec3::new(fx, WALL_HEIGHT, fz), Vec3::new(fx + CELL_SIZE, WALL_HEIGHT, fz),
|
||||
Vec3::new(fx + CELL_SIZE, WALL_HEIGHT, fz + CELL_SIZE), Vec3::new(fx, WALL_HEIGHT, fz + CELL_SIZE)],
|
||||
up, WALL_HEIGHT, mats.wall, room_ci);
|
||||
|
||||
if grid.get(x-1,y) != 0 && !is_adj_wall(grid, x-1, y) {
|
||||
let n = Vec3::new(-1.0, 0.0, 0.0);
|
||||
emit_quad(bsp, &mut face_cell, &mut vert_idx, &mut face_idx, &mut edge_idx,
|
||||
[Vec3::new(fx, TRIM_HEIGHT, fz + CELL_SIZE), Vec3::new(fx, TRIM_HEIGHT, fz),
|
||||
Vec3::new(fx, WALL_HEIGHT, fz), Vec3::new(fx, WALL_HEIGHT, fz + CELL_SIZE)],
|
||||
n, -fx, mats.wall, room_ci);
|
||||
emit_quad(bsp, &mut face_cell, &mut vert_idx, &mut face_idx, &mut edge_idx,
|
||||
[Vec3::new(fx, 0.0, fz + CELL_SIZE), Vec3::new(fx, 0.0, fz),
|
||||
Vec3::new(fx, TRIM_HEIGHT, fz), Vec3::new(fx, TRIM_HEIGHT, fz + CELL_SIZE)],
|
||||
n, -fx, mats.trim, room_ci);
|
||||
}
|
||||
if grid.get(x+1,y) != 0 && !is_adj_wall(grid, x+1, y) {
|
||||
let wx = fx + CELL_SIZE;
|
||||
let n = Vec3::new(1.0, 0.0, 0.0);
|
||||
emit_quad(bsp, &mut face_cell, &mut vert_idx, &mut face_idx, &mut edge_idx,
|
||||
[Vec3::new(wx, TRIM_HEIGHT, fz), Vec3::new(wx, TRIM_HEIGHT, fz + CELL_SIZE),
|
||||
Vec3::new(wx, WALL_HEIGHT, fz + CELL_SIZE), Vec3::new(wx, WALL_HEIGHT, fz)],
|
||||
n, wx, mats.wall, room_ci);
|
||||
emit_quad(bsp, &mut face_cell, &mut vert_idx, &mut face_idx, &mut edge_idx,
|
||||
[Vec3::new(wx, 0.0, fz), Vec3::new(wx, 0.0, fz + CELL_SIZE),
|
||||
Vec3::new(wx, TRIM_HEIGHT, fz + CELL_SIZE), Vec3::new(wx, TRIM_HEIGHT, fz)],
|
||||
n, wx, mats.trim, room_ci);
|
||||
}
|
||||
if grid.get(x,y-1) != 0 && !is_adj_wall(grid, x, y-1) {
|
||||
let n = Vec3::new(0.0, 0.0, -1.0);
|
||||
emit_quad(bsp, &mut face_cell, &mut vert_idx, &mut face_idx, &mut edge_idx,
|
||||
[Vec3::new(fx + CELL_SIZE, TRIM_HEIGHT, fz), Vec3::new(fx, TRIM_HEIGHT, fz),
|
||||
Vec3::new(fx, WALL_HEIGHT, fz), Vec3::new(fx + CELL_SIZE, WALL_HEIGHT, fz)],
|
||||
n, -fz, mats.wall, room_ci);
|
||||
emit_quad(bsp, &mut face_cell, &mut vert_idx, &mut face_idx, &mut edge_idx,
|
||||
[Vec3::new(fx + CELL_SIZE, 0.0, fz), Vec3::new(fx, 0.0, fz),
|
||||
Vec3::new(fx, TRIM_HEIGHT, fz), Vec3::new(fx + CELL_SIZE, TRIM_HEIGHT, fz)],
|
||||
n, -fz, mats.trim, room_ci);
|
||||
}
|
||||
if grid.get(x,y+1) != 0 && !is_adj_wall(grid, x, y+1) {
|
||||
let wz = fz + CELL_SIZE;
|
||||
let n = Vec3::new(0.0, 0.0, 1.0);
|
||||
emit_quad(bsp, &mut face_cell, &mut vert_idx, &mut face_idx, &mut edge_idx,
|
||||
[Vec3::new(fx, TRIM_HEIGHT, wz), Vec3::new(fx + CELL_SIZE, TRIM_HEIGHT, wz),
|
||||
Vec3::new(fx + CELL_SIZE, WALL_HEIGHT, wz), Vec3::new(fx, WALL_HEIGHT, wz)],
|
||||
n, wz, mats.wall, room_ci);
|
||||
emit_quad(bsp, &mut face_cell, &mut vert_idx, &mut face_idx, &mut edge_idx,
|
||||
[Vec3::new(fx, 0.0, wz), Vec3::new(fx + CELL_SIZE, 0.0, wz),
|
||||
Vec3::new(fx + CELL_SIZE, TRIM_HEIGHT, wz), Vec3::new(fx, TRIM_HEIGHT, wz)],
|
||||
n, wz, mats.trim, room_ci);
|
||||
}
|
||||
} else {
|
||||
emit_quad(bsp, &mut face_cell, &mut vert_idx, &mut face_idx, &mut edge_idx,
|
||||
[Vec3::new(fx, 0.0, fz), Vec3::new(fx, 0.0, fz + CELL_SIZE),
|
||||
Vec3::new(fx + CELL_SIZE, 0.0, fz + CELL_SIZE), Vec3::new(fx + CELL_SIZE, 0.0, fz)],
|
||||
up, 0.0, 7, cell_idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1181,13 +1305,16 @@ fn grid_to_bsp(bsp: &mut BspBuilder, grid: &RoomGrid, doorways: &[Doorway], entr
|
|||
|
||||
if grid.get(x, y) == 0 {
|
||||
leaf.contents = -2;
|
||||
leaf.first_marksurface = cell_offset[c] as u16;
|
||||
leaf.num_marksurfaces = faces_per_cell[c] as u16;
|
||||
} else {
|
||||
leaf.contents = -1;
|
||||
leaf.first_marksurface = cell_offset[c] as u16;
|
||||
leaf.num_marksurfaces = faces_per_cell[c] as u16;
|
||||
let adjacent_to_room =
|
||||
grid.get(x - 1, y) == 0 ||
|
||||
grid.get(x + 1, y) == 0 ||
|
||||
grid.get(x, y - 1) == 0 ||
|
||||
grid.get(x, y + 1) == 0;
|
||||
leaf.contents = if adjacent_to_room { -1 } else { 0 };
|
||||
}
|
||||
leaf.first_marksurface = cell_offset[c] as u16;
|
||||
leaf.num_marksurfaces = faces_per_cell[c] as u16;
|
||||
leaf.visofs = -1;
|
||||
}
|
||||
}
|
||||
|
|
@ -1274,10 +1401,10 @@ fn grid_to_bsp_exterior(bsp: &mut BspBuilder, grid: &RoomGrid, origin_x: f32, or
|
|||
let wx = origin_x + vx as f32 * CELL_SIZE;
|
||||
let wz = origin_z + vz as f32 * CELL_SIZE;
|
||||
let h = unsafe {
|
||||
crate::pxl8::pxl8_fbm(wx * 0.005, wz * 0.005, world_seed + 5000, 4)
|
||||
crate::pxl8::pxl8_fbm(wx * 0.002, wz * 0.002, world_seed + 5000, 4)
|
||||
};
|
||||
let blend = edge_blend(wx, wz, world_seed);
|
||||
corner_heights[vz as usize * vw + vx as usize] = h * 64.0 * blend;
|
||||
corner_heights[vz as usize * vw + vx as usize] = h * 128.0 * blend;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1286,6 +1413,28 @@ fn grid_to_bsp_exterior(bsp: &mut BspBuilder, grid: &RoomGrid, origin_x: f32, or
|
|||
if border_south { border_face_count += grid.width; }
|
||||
if border_west { border_face_count += grid.height; }
|
||||
if border_east { border_face_count += grid.height; }
|
||||
if border_north && border_west { border_face_count += 1; }
|
||||
if border_north && border_east { border_face_count += 1; }
|
||||
if border_south && border_west { border_face_count += 1; }
|
||||
if border_south && border_east { border_face_count += 1; }
|
||||
|
||||
let bg_north = if border_north { generate_building_grid(cx, cz - 1, world_seed) } else { None };
|
||||
let bg_south = if border_south { generate_building_grid(cx, cz + 1, world_seed) } else { None };
|
||||
let bg_west = if border_west { generate_building_grid(cx - 1, cz, world_seed) } else { None };
|
||||
let bg_east = if border_east { generate_building_grid(cx + 1, cz, world_seed) } else { None };
|
||||
|
||||
let mut building_face_count = 0usize;
|
||||
for bg in [&bg_north, &bg_south, &bg_west, &bg_east] {
|
||||
if let Some(g) = bg {
|
||||
for y in 0..g.height {
|
||||
for x in 0..g.width {
|
||||
if g.get(x, y) != 0 && !is_adj_wall(g, x, y) {
|
||||
building_face_count += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut face_count = 0;
|
||||
for y in 0..grid.height {
|
||||
|
|
@ -1295,7 +1444,7 @@ fn grid_to_bsp_exterior(bsp: &mut BspBuilder, grid: &RoomGrid, origin_x: f32, or
|
|||
}
|
||||
}
|
||||
}
|
||||
face_count += border_face_count as usize;
|
||||
face_count += border_face_count as usize + building_face_count;
|
||||
|
||||
let vertex_count = face_count * 4;
|
||||
let max_nodes = 2 * total_cells + 1;
|
||||
|
|
@ -1400,6 +1549,124 @@ fn grid_to_bsp_exterior(bsp: &mut BspBuilder, grid: &RoomGrid, origin_x: f32, or
|
|||
}
|
||||
}
|
||||
|
||||
if border_north && border_west {
|
||||
let fx_outer = origin_x - CELL_SIZE;
|
||||
let fx_inner = origin_x;
|
||||
let fz_outer = origin_z - CELL_SIZE;
|
||||
let fz_inner = origin_z;
|
||||
let h = corner_heights[0];
|
||||
let cell_idx = 0u32;
|
||||
emit_quad(bsp, &mut face_cell, &mut vert_idx, &mut face_idx, &mut edge_idx,
|
||||
[Vec3::new(fx_outer, 0.0, fz_outer), Vec3::new(fx_inner, 0.0, fz_outer),
|
||||
Vec3::new(fx_inner, h, fz_inner), Vec3::new(fx_outer, 0.0, fz_inner)],
|
||||
up, 0.0, 7, cell_idx);
|
||||
}
|
||||
if border_north && border_east {
|
||||
let last_col = grid.width as usize;
|
||||
let fx_inner = origin_x + grid.width as f32 * CELL_SIZE;
|
||||
let fx_outer = fx_inner + CELL_SIZE;
|
||||
let fz_outer = origin_z - CELL_SIZE;
|
||||
let fz_inner = origin_z;
|
||||
let h = corner_heights[last_col];
|
||||
let cell_idx = (grid.width - 1) as u32;
|
||||
emit_quad(bsp, &mut face_cell, &mut vert_idx, &mut face_idx, &mut edge_idx,
|
||||
[Vec3::new(fx_inner, 0.0, fz_outer), Vec3::new(fx_outer, 0.0, fz_outer),
|
||||
Vec3::new(fx_outer, 0.0, fz_inner), Vec3::new(fx_inner, h, fz_inner)],
|
||||
up, 0.0, 7, cell_idx);
|
||||
}
|
||||
if border_south && border_west {
|
||||
let last_row = grid.height as usize;
|
||||
let fx_outer = origin_x - CELL_SIZE;
|
||||
let fx_inner = origin_x;
|
||||
let fz_inner = origin_z + grid.height as f32 * CELL_SIZE;
|
||||
let fz_outer = fz_inner + CELL_SIZE;
|
||||
let h = corner_heights[last_row * vw];
|
||||
let cell_idx = ((grid.height - 1) * grid.width) as u32;
|
||||
emit_quad(bsp, &mut face_cell, &mut vert_idx, &mut face_idx, &mut edge_idx,
|
||||
[Vec3::new(fx_outer, 0.0, fz_inner), Vec3::new(fx_inner, h, fz_inner),
|
||||
Vec3::new(fx_inner, 0.0, fz_outer), Vec3::new(fx_outer, 0.0, fz_outer)],
|
||||
up, 0.0, 7, cell_idx);
|
||||
}
|
||||
if border_south && border_east {
|
||||
let last_row = grid.height as usize;
|
||||
let last_col = grid.width as usize;
|
||||
let fx_inner = origin_x + grid.width as f32 * CELL_SIZE;
|
||||
let fx_outer = fx_inner + CELL_SIZE;
|
||||
let fz_inner = origin_z + grid.height as f32 * CELL_SIZE;
|
||||
let fz_outer = fz_inner + CELL_SIZE;
|
||||
let h = corner_heights[last_row * vw + last_col];
|
||||
let cell_idx = ((grid.height - 1) * grid.width + grid.width - 1) as u32;
|
||||
emit_quad(bsp, &mut face_cell, &mut vert_idx, &mut face_idx, &mut edge_idx,
|
||||
[Vec3::new(fx_inner, h, fz_inner), Vec3::new(fx_outer, 0.0, fz_inner),
|
||||
Vec3::new(fx_outer, 0.0, fz_outer), Vec3::new(fx_inner, 0.0, fz_outer)],
|
||||
up, 0.0, 7, cell_idx);
|
||||
}
|
||||
|
||||
if let Some(ref bg) = bg_north {
|
||||
let bg_oz = (cz - 1) as f32 * chunk_size;
|
||||
for by in 0..bg.height {
|
||||
for bx in 0..bg.width {
|
||||
if bg.get(bx, by) != 0 && !is_adj_wall(bg, bx, by) {
|
||||
let fx = origin_x + bx as f32 * CELL_SIZE;
|
||||
let fz = bg_oz + by as f32 * CELL_SIZE;
|
||||
let cell_idx = bx as u32;
|
||||
emit_quad(bsp, &mut face_cell, &mut vert_idx, &mut face_idx, &mut edge_idx,
|
||||
[Vec3::new(fx, 0.0, fz), Vec3::new(fx + CELL_SIZE, 0.0, fz),
|
||||
Vec3::new(fx + CELL_SIZE, 0.0, fz + CELL_SIZE), Vec3::new(fx, 0.0, fz + CELL_SIZE)],
|
||||
up, 0.0, 7, cell_idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(ref bg) = bg_south {
|
||||
let bg_oz = (cz + 1) as f32 * chunk_size;
|
||||
for by in 0..bg.height {
|
||||
for bx in 0..bg.width {
|
||||
if bg.get(bx, by) != 0 && !is_adj_wall(bg, bx, by) {
|
||||
let fx = origin_x + bx as f32 * CELL_SIZE;
|
||||
let fz = bg_oz + by as f32 * CELL_SIZE;
|
||||
let cell_idx = ((grid.height - 1) * grid.width + bx) as u32;
|
||||
emit_quad(bsp, &mut face_cell, &mut vert_idx, &mut face_idx, &mut edge_idx,
|
||||
[Vec3::new(fx, 0.0, fz), Vec3::new(fx + CELL_SIZE, 0.0, fz),
|
||||
Vec3::new(fx + CELL_SIZE, 0.0, fz + CELL_SIZE), Vec3::new(fx, 0.0, fz + CELL_SIZE)],
|
||||
up, 0.0, 7, cell_idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(ref bg) = bg_west {
|
||||
let bg_ox = (cx - 1) as f32 * chunk_size;
|
||||
for by in 0..bg.height {
|
||||
for bx in 0..bg.width {
|
||||
if bg.get(bx, by) != 0 && !is_adj_wall(bg, bx, by) {
|
||||
let fx = bg_ox + bx as f32 * CELL_SIZE;
|
||||
let fz = origin_z + by as f32 * CELL_SIZE;
|
||||
let cell_idx = (by * grid.width) as u32;
|
||||
emit_quad(bsp, &mut face_cell, &mut vert_idx, &mut face_idx, &mut edge_idx,
|
||||
[Vec3::new(fx, 0.0, fz), Vec3::new(fx + CELL_SIZE, 0.0, fz),
|
||||
Vec3::new(fx + CELL_SIZE, 0.0, fz + CELL_SIZE), Vec3::new(fx, 0.0, fz + CELL_SIZE)],
|
||||
up, 0.0, 7, cell_idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(ref bg) = bg_east {
|
||||
let bg_ox = (cx + 1) as f32 * chunk_size;
|
||||
for by in 0..bg.height {
|
||||
for bx in 0..bg.width {
|
||||
if bg.get(bx, by) != 0 && !is_adj_wall(bg, bx, by) {
|
||||
let fx = bg_ox + bx as f32 * CELL_SIZE;
|
||||
let fz = origin_z + by as f32 * CELL_SIZE;
|
||||
let cell_idx = (by * grid.width + grid.width - 1) as u32;
|
||||
emit_quad(bsp, &mut face_cell, &mut vert_idx, &mut face_idx, &mut edge_idx,
|
||||
[Vec3::new(fx, 0.0, fz), Vec3::new(fx + CELL_SIZE, 0.0, fz),
|
||||
Vec3::new(fx + CELL_SIZE, 0.0, fz + CELL_SIZE), Vec3::new(fx, 0.0, fz + CELL_SIZE)],
|
||||
up, 0.0, 7, cell_idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bsp.vertices.truncate(vert_idx);
|
||||
bsp.faces.truncate(face_idx);
|
||||
bsp.edges.truncate(edge_idx);
|
||||
|
|
@ -1450,31 +1717,35 @@ fn grid_to_bsp_exterior(bsp: &mut BspBuilder, grid: &RoomGrid, origin_x: f32, or
|
|||
}
|
||||
|
||||
if border_north {
|
||||
let ext = if bg_north.is_some() { chunk_size } else { CELL_SIZE };
|
||||
for x in 0..grid.width {
|
||||
let c = (0 * grid.width + x) as usize;
|
||||
let fz = origin_z - CELL_SIZE;
|
||||
bsp.leafs[c].mins[2] = fz as i16;
|
||||
bsp.leafs[c].mins[2] = (origin_z - ext) as i16;
|
||||
if bg_north.is_some() { bsp.leafs[c].mins[1] = -64; }
|
||||
}
|
||||
}
|
||||
if border_south {
|
||||
let ext = if bg_south.is_some() { chunk_size } else { CELL_SIZE };
|
||||
for x in 0..grid.width {
|
||||
let c = ((grid.height - 1) * grid.width + x) as usize;
|
||||
let fz = origin_z + (grid.height + 1) as f32 * CELL_SIZE;
|
||||
bsp.leafs[c].maxs[2] = fz as i16;
|
||||
bsp.leafs[c].maxs[2] = (origin_z + grid.height as f32 * CELL_SIZE + ext) as i16;
|
||||
if bg_south.is_some() { bsp.leafs[c].mins[1] = -64; }
|
||||
}
|
||||
}
|
||||
if border_west {
|
||||
let ext = if bg_west.is_some() { chunk_size } else { CELL_SIZE };
|
||||
for y in 0..grid.height {
|
||||
let c = (y * grid.width + 0) as usize;
|
||||
let fx = origin_x - CELL_SIZE;
|
||||
bsp.leafs[c].mins[0] = fx as i16;
|
||||
bsp.leafs[c].mins[0] = (origin_x - ext) as i16;
|
||||
if bg_west.is_some() { bsp.leafs[c].mins[1] = -64; }
|
||||
}
|
||||
}
|
||||
if border_east {
|
||||
let ext = if bg_east.is_some() { chunk_size } else { CELL_SIZE };
|
||||
for y in 0..grid.height {
|
||||
let c = (y * grid.width + grid.width - 1) as usize;
|
||||
let fx = origin_x + (grid.width + 1) as f32 * CELL_SIZE;
|
||||
bsp.leafs[c].maxs[0] = fx as i16;
|
||||
bsp.leafs[c].maxs[0] = (origin_x + grid.width as f32 * CELL_SIZE + ext) as i16;
|
||||
if bg_east.is_some() { bsp.leafs[c].mins[1] = -64; }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1508,7 +1779,7 @@ fn grid_to_bsp_exterior(bsp: &mut BspBuilder, grid: &RoomGrid, origin_x: f32, or
|
|||
ctx.bsp.heightfield_cell_size = CELL_SIZE;
|
||||
}
|
||||
|
||||
pub fn generate_rooms(params: &ProcgenParams, doorways: &[Doorway], entries: &[ChunkEntry]) -> Bsp {
|
||||
fn generate_dungeon_grid(params: &ProcgenParams, doorways: &[Doorway], entries: &[ChunkEntry]) -> (RoomGrid, Vec<Bounds>) {
|
||||
let mut rng = Rng::new(params.seed);
|
||||
|
||||
let mut grid = RoomGrid::new(params.width, params.height);
|
||||
|
|
@ -1574,8 +1845,49 @@ pub fn generate_rooms(params: &ProcgenParams, doorways: &[Doorway], entries: &[C
|
|||
|
||||
carve_entries(&mut grid, entries);
|
||||
|
||||
(grid, rooms)
|
||||
}
|
||||
|
||||
pub fn generate_rooms(params: &ProcgenParams, doorways: &[Doorway], entries: &[ChunkEntry], world_seed: u64) -> Bsp {
|
||||
let (grid, rooms) = generate_dungeon_grid(params, doorways, entries);
|
||||
|
||||
let (tight, x_off, z_off) = shrink_grid(&grid, entries);
|
||||
let tight_origin_x = params.origin_x + x_off as f32 * CELL_SIZE;
|
||||
let tight_origin_z = params.origin_z + z_off as f32 * CELL_SIZE;
|
||||
|
||||
let tight_entries: Vec<ChunkEntry> = entries.iter().map(|e| {
|
||||
let cell = match e.edge {
|
||||
ChunkEdge::West | ChunkEdge::East => e.cell - z_off,
|
||||
ChunkEdge::North | ChunkEdge::South => e.cell - x_off,
|
||||
};
|
||||
ChunkEntry { edge: e.edge, cell }
|
||||
}).collect();
|
||||
|
||||
let mut bsp = BspBuilder::new();
|
||||
grid_to_bsp(&mut bsp, &grid, doorways, entries, &DUNGEON_MATS, params.origin_x, params.origin_z);
|
||||
grid_to_bsp(&mut bsp, &tight, doorways, &tight_entries, &DUNGEON_MATS, tight_origin_x, tight_origin_z);
|
||||
|
||||
bsp.bounds_min_x = tight_origin_x;
|
||||
bsp.bounds_min_z = tight_origin_z;
|
||||
bsp.bounds_max_x = tight_origin_x + tight.width as f32 * CELL_SIZE;
|
||||
bsp.bounds_max_z = tight_origin_z + tight.height as f32 * CELL_SIZE;
|
||||
|
||||
let vw = 17usize;
|
||||
let vh = 17usize;
|
||||
bsp.heightfield = vec![0.0f32; vw * vh];
|
||||
for vz in 0..vh as i32 {
|
||||
for vx in 0..vw as i32 {
|
||||
let wx = params.origin_x + vx as f32 * CELL_SIZE;
|
||||
let wz = params.origin_z + vz as f32 * CELL_SIZE;
|
||||
let h = unsafe { crate::pxl8::pxl8_fbm(wx * 0.002, wz * 0.002, world_seed + 5000, 4) };
|
||||
let blend = edge_blend(wx, wz, world_seed);
|
||||
bsp.heightfield[vz as usize * vw + vx as usize] = h * 128.0 * blend;
|
||||
}
|
||||
}
|
||||
bsp.heightfield_w = 17;
|
||||
bsp.heightfield_h = 17;
|
||||
bsp.heightfield_ox = params.origin_x;
|
||||
bsp.heightfield_oz = params.origin_z;
|
||||
bsp.heightfield_cell_size = CELL_SIZE;
|
||||
|
||||
let light_height = 80.0;
|
||||
|
||||
|
|
@ -1603,7 +1915,7 @@ pub fn generate_rooms(params: &ProcgenParams, doorways: &[Doorway], entries: &[C
|
|||
bsp.into()
|
||||
}
|
||||
|
||||
pub fn generate_courtyard(params: &ProcgenParams, entries: &[ChunkEntry]) -> Bsp {
|
||||
fn generate_courtyard_grid(params: &ProcgenParams, entries: &[ChunkEntry]) -> (RoomGrid, Vec<Bounds>) {
|
||||
let mut rng = Rng::new(params.seed);
|
||||
let mut grid = RoomGrid::new(params.width, params.height);
|
||||
grid.fill(1);
|
||||
|
|
@ -1701,8 +2013,49 @@ pub fn generate_courtyard(params: &ProcgenParams, entries: &[ChunkEntry]) -> Bsp
|
|||
|
||||
carve_entries(&mut grid, entries);
|
||||
|
||||
(grid, rooms)
|
||||
}
|
||||
|
||||
pub fn generate_courtyard(params: &ProcgenParams, entries: &[ChunkEntry], world_seed: u64) -> Bsp {
|
||||
let (grid, rooms) = generate_courtyard_grid(params, entries);
|
||||
|
||||
let (tight, x_off, z_off) = shrink_grid(&grid, entries);
|
||||
let tight_origin_x = params.origin_x + x_off as f32 * CELL_SIZE;
|
||||
let tight_origin_z = params.origin_z + z_off as f32 * CELL_SIZE;
|
||||
|
||||
let tight_entries: Vec<ChunkEntry> = entries.iter().map(|e| {
|
||||
let cell = match e.edge {
|
||||
ChunkEdge::West | ChunkEdge::East => e.cell - z_off,
|
||||
ChunkEdge::North | ChunkEdge::South => e.cell - x_off,
|
||||
};
|
||||
ChunkEntry { edge: e.edge, cell }
|
||||
}).collect();
|
||||
|
||||
let mut bsp = BspBuilder::new();
|
||||
grid_to_bsp(&mut bsp, &grid, &[], entries, &COURTYARD_MATS, params.origin_x, params.origin_z);
|
||||
grid_to_bsp(&mut bsp, &tight, &[], &tight_entries, &COURTYARD_MATS, tight_origin_x, tight_origin_z);
|
||||
|
||||
bsp.bounds_min_x = tight_origin_x;
|
||||
bsp.bounds_min_z = tight_origin_z;
|
||||
bsp.bounds_max_x = tight_origin_x + tight.width as f32 * CELL_SIZE;
|
||||
bsp.bounds_max_z = tight_origin_z + tight.height as f32 * CELL_SIZE;
|
||||
|
||||
let vw = 17usize;
|
||||
let vh = 17usize;
|
||||
bsp.heightfield = vec![0.0f32; vw * vh];
|
||||
for vz in 0..vh as i32 {
|
||||
for vx in 0..vw as i32 {
|
||||
let wx = params.origin_x + vx as f32 * CELL_SIZE;
|
||||
let wz = params.origin_z + vz as f32 * CELL_SIZE;
|
||||
let h = unsafe { crate::pxl8::pxl8_fbm(wx * 0.002, wz * 0.002, world_seed + 5000, 4) };
|
||||
let blend = edge_blend(wx, wz, world_seed);
|
||||
bsp.heightfield[vz as usize * vw + vx as usize] = h * 128.0 * blend;
|
||||
}
|
||||
}
|
||||
bsp.heightfield_w = 17;
|
||||
bsp.heightfield_h = 17;
|
||||
bsp.heightfield_ox = params.origin_x;
|
||||
bsp.heightfield_oz = params.origin_z;
|
||||
bsp.heightfield_cell_size = CELL_SIZE;
|
||||
|
||||
let light_height = 80.0;
|
||||
|
||||
|
|
@ -1763,7 +2116,11 @@ pub fn generate_exterior(params: &ProcgenParams, world_seed: u64) -> Bsp {
|
|||
let mut bsp = BspBuilder::new();
|
||||
grid_to_bsp_exterior(&mut bsp, &grid, params.origin_x, params.origin_z, world_seed);
|
||||
|
||||
let lights = vec![LightSource {
|
||||
let chunk_size = 16.0 * CELL_SIZE;
|
||||
let cx = libm::floorf(params.origin_x / chunk_size) as i32;
|
||||
let cz = libm::floorf(params.origin_z / chunk_size) as i32;
|
||||
|
||||
let mut lights = vec![LightSource {
|
||||
position: Vec3::new(
|
||||
params.origin_x + params.width as f32 * CELL_SIZE * 0.5,
|
||||
200.0,
|
||||
|
|
@ -1772,17 +2129,33 @@ pub fn generate_exterior(params: &ProcgenParams, world_seed: u64) -> Bsp {
|
|||
intensity: 2.0,
|
||||
radius: 2000.0,
|
||||
}];
|
||||
|
||||
for &(dx, dz) in &[(0, -1), (0, 1), (-1, 0), (1, 0)] {
|
||||
if select_biome(cx + dx, cz + dz, world_seed) != Biome::Exterior {
|
||||
lights.push(LightSource {
|
||||
position: Vec3::new(
|
||||
(cx + dx) as f32 * chunk_size + chunk_size * 0.5,
|
||||
200.0,
|
||||
(cz + dz) as f32 * chunk_size + chunk_size * 0.5,
|
||||
),
|
||||
intensity: 2.0,
|
||||
radius: 2000.0,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
compute_bsp_vertex_lighting(&mut bsp, &lights);
|
||||
|
||||
bsp.into()
|
||||
}
|
||||
|
||||
pub fn generate_chunk(cx: i32, cz: i32, world_seed: u64) -> Bsp {
|
||||
fn generate_building_grid(cx: i32, cz: i32, world_seed: u64) -> Option<RoomGrid> {
|
||||
let biome = select_biome(cx, cz, world_seed);
|
||||
if biome == Biome::Exterior { return None; }
|
||||
|
||||
let seed = chunk_seed(world_seed, cx, cz);
|
||||
let origin_x = cx as f32 * 16.0 * CELL_SIZE;
|
||||
let origin_z = cz as f32 * 16.0 * CELL_SIZE;
|
||||
|
||||
let params = ProcgenParams {
|
||||
seed,
|
||||
origin_x,
|
||||
|
|
@ -1790,6 +2163,18 @@ pub fn generate_chunk(cx: i32, cz: i32, world_seed: u64) -> Bsp {
|
|||
..Default::default()
|
||||
};
|
||||
|
||||
let (doorways, entries) = get_chunk_config(cx, cz);
|
||||
|
||||
let (grid, _) = match biome {
|
||||
Biome::Dungeon => generate_dungeon_grid(¶ms, &doorways, &entries),
|
||||
Biome::Courtyard => generate_courtyard_grid(¶ms, &entries),
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
Some(grid)
|
||||
}
|
||||
|
||||
fn get_chunk_config(cx: i32, cz: i32) -> (Vec<Doorway>, Vec<ChunkEntry>) {
|
||||
let mut doorways = Vec::new();
|
||||
let mut entries = Vec::new();
|
||||
|
||||
|
|
@ -1820,9 +2205,27 @@ pub fn generate_chunk(cx: i32, cz: i32, world_seed: u64) -> Bsp {
|
|||
entries.push(ChunkEntry { edge: ChunkEdge::South, cell: 8 });
|
||||
}
|
||||
|
||||
(doorways, entries)
|
||||
}
|
||||
|
||||
pub fn generate_chunk(cx: i32, cz: i32, world_seed: u64) -> Bsp {
|
||||
let biome = select_biome(cx, cz, world_seed);
|
||||
let seed = chunk_seed(world_seed, cx, cz);
|
||||
let origin_x = cx as f32 * 16.0 * CELL_SIZE;
|
||||
let origin_z = cz as f32 * 16.0 * CELL_SIZE;
|
||||
|
||||
let params = ProcgenParams {
|
||||
seed,
|
||||
origin_x,
|
||||
origin_z,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let (doorways, entries) = get_chunk_config(cx, cz);
|
||||
|
||||
match biome {
|
||||
Biome::Dungeon => generate_rooms(¶ms, &doorways, &entries),
|
||||
Biome::Courtyard => generate_courtyard(¶ms, &entries),
|
||||
Biome::Dungeon => generate_rooms(¶ms, &doorways, &entries, world_seed),
|
||||
Biome::Courtyard => generate_courtyard(¶ms, &entries, world_seed),
|
||||
Biome::Exterior => generate_exterior(¶ms, world_seed),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue