fix(bsp): fill in exterior cells
This commit is contained in:
parent
ab0d2a4b04
commit
1341b30920
8 changed files with 740 additions and 102 deletions
|
|
@ -8,8 +8,8 @@
|
||||||
(local sky (require :mod.sky))
|
(local sky (require :mod.sky))
|
||||||
(local textures (require :mod.textures))
|
(local textures (require :mod.textures))
|
||||||
|
|
||||||
(local bob-amount 4.0)
|
(local bob-amount 3.0)
|
||||||
(local bob-speed 8.0)
|
(local bob-speed 6.0)
|
||||||
(local cam-smoothing 0.25)
|
(local cam-smoothing 0.25)
|
||||||
(local land-recovery-speed 20)
|
(local land-recovery-speed 20)
|
||||||
(local land-squash-amount -4)
|
(local land-squash-amount -4)
|
||||||
|
|
|
||||||
|
|
@ -166,6 +166,10 @@ pub struct BspBuilder {
|
||||||
pub heightfield_ox: f32,
|
pub heightfield_ox: f32,
|
||||||
pub heightfield_oz: f32,
|
pub heightfield_oz: f32,
|
||||||
pub heightfield_cell_size: 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 {
|
impl BspBuilder {
|
||||||
|
|
@ -225,6 +229,10 @@ impl From<BspBuilder> for Bsp {
|
||||||
heightfield_w: b.heightfield_w,
|
heightfield_w: b.heightfield_w,
|
||||||
heightfield_h: b.heightfield_h,
|
heightfield_h: b.heightfield_h,
|
||||||
visdata_size: visdata.len() as u32,
|
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 {
|
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());
|
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)
|
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) {
|
fn compute_face_aabb(face: &mut Face, verts: &[Vertex], vert_idx: usize) {
|
||||||
face.aabb_min = Vec3::new(1e30, 1e30, 1e30);
|
face.aabb_min = Vec3::new(1e30, 1e30, 1e30);
|
||||||
face.aabb_max = 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
|
portals
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -790,6 +831,14 @@ struct BspMaterials {
|
||||||
const DUNGEON_MATS: BspMaterials = BspMaterials { floor: 0, wall: 1, trim: 3 };
|
const DUNGEON_MATS: BspMaterials = BspMaterials { floor: 0, wall: 1, trim: 3 };
|
||||||
const COURTYARD_MATS: BspMaterials = BspMaterials { floor: 4, wall: 5, trim: 6 };
|
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) {
|
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 wall_count = 0;
|
||||||
let mut floor_ceiling_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 y in 0..grid.height {
|
||||||
for x in 0..grid.width {
|
for x in 0..grid.width {
|
||||||
if grid.get(x, y) == 1 {
|
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 vertex_count = face_count * 4;
|
||||||
|
|
||||||
let total_cells = (grid.width * grid.height) as usize;
|
let total_cells = (grid.width * grid.height) as usize;
|
||||||
|
|
@ -1126,15 +1188,77 @@ fn grid_to_bsp(bsp: &mut BspBuilder, grid: &RoomGrid, doorways: &[Doorway], entr
|
||||||
for x in 0..grid.width {
|
for x in 0..grid.width {
|
||||||
if grid.get(x, y) == 1 {
|
if grid.get(x, y) == 1 {
|
||||||
let fx = origin_x + x as f32 * CELL_SIZE;
|
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;
|
let cell_idx = (y * grid.width + x) as u32;
|
||||||
|
|
||||||
|
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,
|
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, WALL_HEIGHT, fz), Vec3::new(fx + CELL_SIZE, WALL_HEIGHT, fz),
|
||||||
Vec3::new(fx + CELL_SIZE, 0.0, fy + CELL_SIZE), Vec3::new(fx + CELL_SIZE, 0.0, fy)],
|
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);
|
up, 0.0, 7, cell_idx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bsp.vertices.truncate(vert_idx);
|
bsp.vertices.truncate(vert_idx);
|
||||||
bsp.faces.truncate(face_idx);
|
bsp.faces.truncate(face_idx);
|
||||||
|
|
@ -1181,13 +1305,16 @@ fn grid_to_bsp(bsp: &mut BspBuilder, grid: &RoomGrid, doorways: &[Doorway], entr
|
||||||
|
|
||||||
if grid.get(x, y) == 0 {
|
if grid.get(x, y) == 0 {
|
||||||
leaf.contents = -2;
|
leaf.contents = -2;
|
||||||
leaf.first_marksurface = cell_offset[c] as u16;
|
|
||||||
leaf.num_marksurfaces = faces_per_cell[c] as u16;
|
|
||||||
} else {
|
} else {
|
||||||
leaf.contents = -1;
|
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.first_marksurface = cell_offset[c] as u16;
|
||||||
leaf.num_marksurfaces = faces_per_cell[c] as u16;
|
leaf.num_marksurfaces = faces_per_cell[c] as u16;
|
||||||
}
|
|
||||||
leaf.visofs = -1;
|
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 wx = origin_x + vx as f32 * CELL_SIZE;
|
||||||
let wz = origin_z + vz as f32 * CELL_SIZE;
|
let wz = origin_z + vz as f32 * CELL_SIZE;
|
||||||
let h = unsafe {
|
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);
|
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_south { border_face_count += grid.width; }
|
||||||
if border_west { border_face_count += grid.height; }
|
if border_west { border_face_count += grid.height; }
|
||||||
if border_east { 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;
|
let mut face_count = 0;
|
||||||
for y in 0..grid.height {
|
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 vertex_count = face_count * 4;
|
||||||
let max_nodes = 2 * total_cells + 1;
|
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.vertices.truncate(vert_idx);
|
||||||
bsp.faces.truncate(face_idx);
|
bsp.faces.truncate(face_idx);
|
||||||
bsp.edges.truncate(edge_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 {
|
if border_north {
|
||||||
|
let ext = if bg_north.is_some() { chunk_size } else { CELL_SIZE };
|
||||||
for x in 0..grid.width {
|
for x in 0..grid.width {
|
||||||
let c = (0 * grid.width + x) as usize;
|
let c = (0 * grid.width + x) as usize;
|
||||||
let fz = origin_z - CELL_SIZE;
|
bsp.leafs[c].mins[2] = (origin_z - ext) as i16;
|
||||||
bsp.leafs[c].mins[2] = fz as i16;
|
if bg_north.is_some() { bsp.leafs[c].mins[1] = -64; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if border_south {
|
if border_south {
|
||||||
|
let ext = if bg_south.is_some() { chunk_size } else { CELL_SIZE };
|
||||||
for x in 0..grid.width {
|
for x in 0..grid.width {
|
||||||
let c = ((grid.height - 1) * grid.width + x) as usize;
|
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] = (origin_z + grid.height as f32 * CELL_SIZE + ext) as i16;
|
||||||
bsp.leafs[c].maxs[2] = fz as i16;
|
if bg_south.is_some() { bsp.leafs[c].mins[1] = -64; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if border_west {
|
if border_west {
|
||||||
|
let ext = if bg_west.is_some() { chunk_size } else { CELL_SIZE };
|
||||||
for y in 0..grid.height {
|
for y in 0..grid.height {
|
||||||
let c = (y * grid.width + 0) as usize;
|
let c = (y * grid.width + 0) as usize;
|
||||||
let fx = origin_x - CELL_SIZE;
|
bsp.leafs[c].mins[0] = (origin_x - ext) as i16;
|
||||||
bsp.leafs[c].mins[0] = fx as i16;
|
if bg_west.is_some() { bsp.leafs[c].mins[1] = -64; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if border_east {
|
if border_east {
|
||||||
|
let ext = if bg_east.is_some() { chunk_size } else { CELL_SIZE };
|
||||||
for y in 0..grid.height {
|
for y in 0..grid.height {
|
||||||
let c = (y * grid.width + grid.width - 1) as usize;
|
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] = (origin_x + grid.width as f32 * CELL_SIZE + ext) as i16;
|
||||||
bsp.leafs[c].maxs[0] = fx 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;
|
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 rng = Rng::new(params.seed);
|
||||||
|
|
||||||
let mut grid = RoomGrid::new(params.width, params.height);
|
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);
|
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();
|
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;
|
let light_height = 80.0;
|
||||||
|
|
||||||
|
|
@ -1603,7 +1915,7 @@ pub fn generate_rooms(params: &ProcgenParams, doorways: &[Doorway], entries: &[C
|
||||||
bsp.into()
|
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 rng = Rng::new(params.seed);
|
||||||
let mut grid = RoomGrid::new(params.width, params.height);
|
let mut grid = RoomGrid::new(params.width, params.height);
|
||||||
grid.fill(1);
|
grid.fill(1);
|
||||||
|
|
@ -1701,8 +2013,49 @@ pub fn generate_courtyard(params: &ProcgenParams, entries: &[ChunkEntry]) -> Bsp
|
||||||
|
|
||||||
carve_entries(&mut grid, entries);
|
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();
|
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;
|
let light_height = 80.0;
|
||||||
|
|
||||||
|
|
@ -1763,7 +2116,11 @@ pub fn generate_exterior(params: &ProcgenParams, world_seed: u64) -> Bsp {
|
||||||
let mut bsp = BspBuilder::new();
|
let mut bsp = BspBuilder::new();
|
||||||
grid_to_bsp_exterior(&mut bsp, &grid, params.origin_x, params.origin_z, world_seed);
|
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(
|
position: Vec3::new(
|
||||||
params.origin_x + params.width as f32 * CELL_SIZE * 0.5,
|
params.origin_x + params.width as f32 * CELL_SIZE * 0.5,
|
||||||
200.0,
|
200.0,
|
||||||
|
|
@ -1772,17 +2129,33 @@ pub fn generate_exterior(params: &ProcgenParams, world_seed: u64) -> Bsp {
|
||||||
intensity: 2.0,
|
intensity: 2.0,
|
||||||
radius: 2000.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);
|
compute_bsp_vertex_lighting(&mut bsp, &lights);
|
||||||
|
|
||||||
bsp.into()
|
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);
|
let biome = select_biome(cx, cz, world_seed);
|
||||||
|
if biome == Biome::Exterior { return None; }
|
||||||
|
|
||||||
let seed = chunk_seed(world_seed, cx, cz);
|
let seed = chunk_seed(world_seed, cx, cz);
|
||||||
let origin_x = cx as f32 * 16.0 * CELL_SIZE;
|
let origin_x = cx as f32 * 16.0 * CELL_SIZE;
|
||||||
let origin_z = cz as f32 * 16.0 * CELL_SIZE;
|
let origin_z = cz as f32 * 16.0 * CELL_SIZE;
|
||||||
|
|
||||||
let params = ProcgenParams {
|
let params = ProcgenParams {
|
||||||
seed,
|
seed,
|
||||||
origin_x,
|
origin_x,
|
||||||
|
|
@ -1790,6 +2163,18 @@ pub fn generate_chunk(cx: i32, cz: i32, world_seed: u64) -> Bsp {
|
||||||
..Default::default()
|
..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 doorways = Vec::new();
|
||||||
let mut entries = 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 });
|
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 {
|
match biome {
|
||||||
Biome::Dungeon => generate_rooms(¶ms, &doorways, &entries),
|
Biome::Dungeon => generate_rooms(¶ms, &doorways, &entries, world_seed),
|
||||||
Biome::Courtyard => generate_courtyard(¶ms, &entries),
|
Biome::Courtyard => generate_courtyard(¶ms, &entries, world_seed),
|
||||||
Biome::Exterior => generate_exterior(¶ms, world_seed),
|
Biome::Exterior => generate_exterior(¶ms, world_seed),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -132,6 +132,10 @@ typedef struct pxl8_bsp {
|
||||||
u16 heightfield_w;
|
u16 heightfield_w;
|
||||||
u16 heightfield_h;
|
u16 heightfield_h;
|
||||||
u32 visdata_size;
|
u32 visdata_size;
|
||||||
|
f32 bounds_min_x;
|
||||||
|
f32 bounds_min_z;
|
||||||
|
f32 bounds_max_x;
|
||||||
|
f32 bounds_max_z;
|
||||||
} pxl8_bsp;
|
} pxl8_bsp;
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,15 @@
|
||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
|
#define DIST_EPSILON 0.03125f
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
f32 fraction;
|
||||||
|
pxl8_vec3 normal;
|
||||||
|
bool all_solid;
|
||||||
|
bool start_solid;
|
||||||
|
} trace_result;
|
||||||
|
|
||||||
static i32 bsp_find_leaf(const pxl8_bsp* bsp, pxl8_vec3 pos) {
|
static i32 bsp_find_leaf(const pxl8_bsp* bsp, pxl8_vec3 pos) {
|
||||||
if (!bsp || bsp->num_nodes == 0) return -1;
|
if (!bsp || bsp->num_nodes == 0) return -1;
|
||||||
|
|
||||||
|
|
@ -16,39 +25,175 @@ static i32 bsp_find_leaf(const pxl8_bsp* bsp, pxl8_vec3 pos) {
|
||||||
return -(node_id + 1);
|
return -(node_id + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static i32 bsp_contents_from(const pxl8_bsp* bsp, i32 node_id, pxl8_vec3 pos) {
|
||||||
|
while (node_id >= 0) {
|
||||||
|
const pxl8_bsp_node* node = &bsp->nodes[node_id];
|
||||||
|
const pxl8_bsp_plane* plane = &bsp->planes[node->plane_id];
|
||||||
|
f32 d = pxl8_vec3_dot(pos, plane->normal) - plane->dist;
|
||||||
|
node_id = node->children[d < 0 ? 1 : 0];
|
||||||
|
}
|
||||||
|
i32 leaf_idx = -(node_id + 1);
|
||||||
|
if (leaf_idx < 0 || (u32)leaf_idx >= bsp->num_leafs) return -1;
|
||||||
|
return bsp->leafs[leaf_idx].contents;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool bsp_recursive_trace(const pxl8_bsp* bsp, i32 node_id,
|
||||||
|
f32 p1f, f32 p2f,
|
||||||
|
pxl8_vec3 p1, pxl8_vec3 p2,
|
||||||
|
trace_result* tr) {
|
||||||
|
if (node_id < 0) {
|
||||||
|
i32 leaf_idx = -(node_id + 1);
|
||||||
|
if (leaf_idx >= 0 && (u32)leaf_idx < bsp->num_leafs &&
|
||||||
|
bsp->leafs[leaf_idx].contents == -1) {
|
||||||
|
tr->start_solid = true;
|
||||||
|
} else {
|
||||||
|
tr->all_solid = false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const pxl8_bsp_node* node = &bsp->nodes[node_id];
|
||||||
|
const pxl8_bsp_plane* plane = &bsp->planes[node->plane_id];
|
||||||
|
|
||||||
|
f32 t1 = pxl8_vec3_dot(p1, plane->normal) - plane->dist;
|
||||||
|
f32 t2 = pxl8_vec3_dot(p2, plane->normal) - plane->dist;
|
||||||
|
|
||||||
|
if (t1 >= 0 && t2 >= 0)
|
||||||
|
return bsp_recursive_trace(bsp, node->children[0], p1f, p2f, p1, p2, tr);
|
||||||
|
if (t1 < 0 && t2 < 0)
|
||||||
|
return bsp_recursive_trace(bsp, node->children[1], p1f, p2f, p1, p2, tr);
|
||||||
|
|
||||||
|
i32 side;
|
||||||
|
f32 frac;
|
||||||
|
if (t1 < 0) {
|
||||||
|
frac = (t1 + DIST_EPSILON) / (t1 - t2);
|
||||||
|
side = 1;
|
||||||
|
} else {
|
||||||
|
frac = (t1 - DIST_EPSILON) / (t1 - t2);
|
||||||
|
side = 0;
|
||||||
|
}
|
||||||
|
if (frac < 0) frac = 0;
|
||||||
|
if (frac > 1) frac = 1;
|
||||||
|
|
||||||
|
f32 midf = p1f + (p2f - p1f) * frac;
|
||||||
|
pxl8_vec3 mid = {
|
||||||
|
p1.x + frac * (p2.x - p1.x),
|
||||||
|
p1.y + frac * (p2.y - p1.y),
|
||||||
|
p1.z + frac * (p2.z - p1.z),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!bsp_recursive_trace(bsp, node->children[side], p1f, midf, p1, mid, tr))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (bsp_contents_from(bsp, node->children[side ^ 1], mid) != -1)
|
||||||
|
return bsp_recursive_trace(bsp, node->children[side ^ 1], midf, p2f, mid, p2, tr);
|
||||||
|
|
||||||
|
if (tr->all_solid)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (midf < tr->fraction) {
|
||||||
|
tr->fraction = midf;
|
||||||
|
if (side == 0) {
|
||||||
|
tr->normal = plane->normal;
|
||||||
|
} else {
|
||||||
|
tr->normal.x = -plane->normal.x;
|
||||||
|
tr->normal.y = -plane->normal.y;
|
||||||
|
tr->normal.z = -plane->normal.z;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static trace_result bsp_trace_line(const pxl8_bsp* bsp, pxl8_vec3 from, pxl8_vec3 to) {
|
||||||
|
trace_result tr = { .fraction = 1.0f, .all_solid = true };
|
||||||
|
if (!bsp || bsp->num_nodes == 0) {
|
||||||
|
tr.all_solid = false;
|
||||||
|
return tr;
|
||||||
|
}
|
||||||
|
bsp_recursive_trace(bsp, 0, 0.0f, 1.0f, from, to, &tr);
|
||||||
|
if (tr.all_solid) {
|
||||||
|
tr.fraction = 0.0f;
|
||||||
|
tr.start_solid = true;
|
||||||
|
}
|
||||||
|
return tr;
|
||||||
|
}
|
||||||
|
|
||||||
bool pxl8_bsp_point_solid(const pxl8_bsp* bsp, pxl8_vec3 pos) {
|
bool pxl8_bsp_point_solid(const pxl8_bsp* bsp, pxl8_vec3 pos) {
|
||||||
if (!bsp) return false;
|
if (!bsp) return false;
|
||||||
|
if (bsp->bounds_max_x > bsp->bounds_min_x &&
|
||||||
|
(pos.x < bsp->bounds_min_x || pos.x >= bsp->bounds_max_x ||
|
||||||
|
pos.z < bsp->bounds_min_z || pos.z >= bsp->bounds_max_z))
|
||||||
|
return false;
|
||||||
i32 leaf = bsp_find_leaf(bsp, pos);
|
i32 leaf = bsp_find_leaf(bsp, pos);
|
||||||
if (leaf < 0 || (u32)leaf >= bsp->num_leafs) return true;
|
if (leaf < 0 || (u32)leaf >= bsp->num_leafs) return true;
|
||||||
return bsp->leafs[leaf].contents == -1;
|
return bsp->leafs[leaf].contents == -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool bsp_point_clear(const pxl8_bsp* bsp, f32 x, f32 y, f32 z, f32 radius) {
|
static void trace_offsets(const pxl8_bsp* bsp, pxl8_vec3 from, pxl8_vec3 to,
|
||||||
if (pxl8_bsp_point_solid(bsp, (pxl8_vec3){x, y, z})) return false;
|
f32 radius, f32* out_frac, pxl8_vec3* out_normal) {
|
||||||
if (pxl8_bsp_point_solid(bsp, (pxl8_vec3){x + radius, y, z})) return false;
|
f32 d = radius * 0.7071f;
|
||||||
if (pxl8_bsp_point_solid(bsp, (pxl8_vec3){x - radius, y, z})) return false;
|
pxl8_vec3 offsets[9] = {
|
||||||
if (pxl8_bsp_point_solid(bsp, (pxl8_vec3){x, y, z + radius})) return false;
|
{0, 0, 0},
|
||||||
if (pxl8_bsp_point_solid(bsp, (pxl8_vec3){x, y, z - radius})) return false;
|
{radius, 0, 0}, {-radius, 0, 0},
|
||||||
return true;
|
{0, 0, radius}, {0, 0, -radius},
|
||||||
|
{d, 0, d}, {d, 0, -d},
|
||||||
|
{-d, 0, d}, {-d, 0, -d},
|
||||||
|
};
|
||||||
|
|
||||||
|
*out_frac = 1.0f;
|
||||||
|
*out_normal = (pxl8_vec3){0, 0, 0};
|
||||||
|
|
||||||
|
for (i32 i = 0; i < 9; i++) {
|
||||||
|
pxl8_vec3 s = { from.x + offsets[i].x, from.y + offsets[i].y, from.z + offsets[i].z };
|
||||||
|
pxl8_vec3 e = { to.x + offsets[i].x, to.y + offsets[i].y, to.z + offsets[i].z };
|
||||||
|
trace_result tr = bsp_trace_line(bsp, s, e);
|
||||||
|
if (tr.fraction < *out_frac && !tr.start_solid) {
|
||||||
|
*out_frac = tr.fraction;
|
||||||
|
*out_normal = tr.normal;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pxl8_vec3 pxl8_bsp_trace(const pxl8_bsp* bsp, pxl8_vec3 from, pxl8_vec3 to, f32 radius) {
|
pxl8_vec3 pxl8_bsp_trace(const pxl8_bsp* bsp, pxl8_vec3 from, pxl8_vec3 to, f32 radius) {
|
||||||
if (!bsp || bsp->num_nodes == 0) return to;
|
if (!bsp || bsp->num_nodes == 0) return to;
|
||||||
|
|
||||||
if (bsp_point_clear(bsp, to.x, to.y, to.z, radius)) {
|
f32 frac;
|
||||||
return to;
|
pxl8_vec3 normal;
|
||||||
}
|
trace_offsets(bsp, from, to, radius, &frac, &normal);
|
||||||
|
if (frac >= 1.0f) return to;
|
||||||
|
|
||||||
bool x_ok = bsp_point_clear(bsp, to.x, from.y, from.z, radius);
|
pxl8_vec3 delta = { to.x - from.x, to.y - from.y, to.z - from.z };
|
||||||
bool y_ok = bsp_point_clear(bsp, from.x, to.y, from.z, radius);
|
pxl8_vec3 hit = {
|
||||||
bool z_ok = bsp_point_clear(bsp, from.x, from.y, to.z, radius);
|
from.x + delta.x * frac,
|
||||||
|
from.y + delta.y * frac,
|
||||||
|
from.z + delta.z * frac,
|
||||||
|
};
|
||||||
|
|
||||||
pxl8_vec3 result = from;
|
f32 remaining = 1.0f - frac;
|
||||||
if (x_ok) result.x = to.x;
|
if (remaining <= 0.0f) return hit;
|
||||||
if (y_ok) result.y = to.y;
|
|
||||||
if (z_ok) result.z = to.z;
|
|
||||||
|
|
||||||
return result;
|
f32 backoff = pxl8_vec3_dot(delta, normal) * remaining;
|
||||||
|
pxl8_vec3 slide_target = {
|
||||||
|
hit.x + delta.x * remaining - normal.x * backoff,
|
||||||
|
hit.y + delta.y * remaining - normal.y * backoff,
|
||||||
|
hit.z + delta.z * remaining - normal.z * backoff,
|
||||||
|
};
|
||||||
|
|
||||||
|
f32 slide_frac;
|
||||||
|
pxl8_vec3 slide_normal;
|
||||||
|
trace_offsets(bsp, hit, slide_target, radius, &slide_frac, &slide_normal);
|
||||||
|
if (slide_frac >= 1.0f) return slide_target;
|
||||||
|
|
||||||
|
pxl8_vec3 slide_delta = {
|
||||||
|
slide_target.x - hit.x,
|
||||||
|
slide_target.y - hit.y,
|
||||||
|
slide_target.z - hit.z,
|
||||||
|
};
|
||||||
|
return (pxl8_vec3){
|
||||||
|
hit.x + slide_delta.x * slide_frac,
|
||||||
|
hit.y + slide_delta.y * slide_frac,
|
||||||
|
hit.z + slide_delta.z * slide_frac,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
static const pxl8_bsp* sim_bsp_at(const pxl8_sim_world* world, f32 x, f32 z) {
|
static const pxl8_bsp* sim_bsp_at(const pxl8_sim_world* world, f32 x, f32 z) {
|
||||||
|
|
@ -79,59 +224,93 @@ static f32 bsp_terrain_height(const pxl8_bsp* bsp, f32 x, f32 z) {
|
||||||
return h0 + (h1 - h0) * fz;
|
return h0 + (h1 - h0) * fz;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool sim_point_solid(const pxl8_sim_world* world, f32 x, f32 y, f32 z) {
|
|
||||||
const pxl8_bsp* bsp = sim_bsp_at(world, x, z);
|
|
||||||
return pxl8_bsp_point_solid(bsp, (pxl8_vec3){x, y, z});
|
|
||||||
}
|
|
||||||
|
|
||||||
static f32 sim_terrain_height(const pxl8_sim_world* world, f32 x, f32 z) {
|
static f32 sim_terrain_height(const pxl8_sim_world* world, f32 x, f32 z) {
|
||||||
const pxl8_bsp* bsp = sim_bsp_at(world, x, z);
|
const pxl8_bsp* bsp = sim_bsp_at(world, x, z);
|
||||||
return bsp_terrain_height(bsp, x, z);
|
return bsp_terrain_height(bsp, x, z);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool sim_point_clear(const pxl8_sim_world* world, f32 x, f32 y, f32 z, f32 radius) {
|
static void sim_trace_offsets(const pxl8_sim_world* world, pxl8_vec3 from, pxl8_vec3 to,
|
||||||
if (sim_point_solid(world, x, y, z)) return false;
|
f32 radius, f32* out_frac, pxl8_vec3* out_normal) {
|
||||||
if (sim_point_solid(world, x + radius, y, z)) return false;
|
f32 d = radius * 0.7071f;
|
||||||
if (sim_point_solid(world, x - radius, y, z)) return false;
|
pxl8_vec3 offsets[9] = {
|
||||||
if (sim_point_solid(world, x, y, z + radius)) return false;
|
{0, 0, 0},
|
||||||
if (sim_point_solid(world, x, y, z - radius)) return false;
|
{radius, 0, 0}, {-radius, 0, 0},
|
||||||
return true;
|
{0, 0, radius}, {0, 0, -radius},
|
||||||
}
|
{d, 0, d}, {d, 0, -d},
|
||||||
|
{-d, 0, d}, {-d, 0, -d},
|
||||||
|
};
|
||||||
|
|
||||||
static f32 find_landing_y(const pxl8_sim_world* world, pxl8_vec3 pos, f32 target_y, f32 radius, f32 height) {
|
*out_frac = 1.0f;
|
||||||
f32 hi = pos.y;
|
*out_normal = (pxl8_vec3){0, 0, 0};
|
||||||
f32 lo = target_y;
|
|
||||||
for (i32 i = 0; i < 8; i++) {
|
for (i32 i = 0; i < 9; i++) {
|
||||||
f32 mid = (hi + lo) * 0.5f;
|
pxl8_vec3 s = { from.x + offsets[i].x, from.y + offsets[i].y, from.z + offsets[i].z };
|
||||||
pxl8_vec3 test = {pos.x, mid, pos.z};
|
pxl8_vec3 e = { to.x + offsets[i].x, to.y + offsets[i].y, to.z + offsets[i].z };
|
||||||
pxl8_vec3 result = pxl8_sim_trace(world, pos, test, radius, height);
|
const pxl8_bsp* bsp_s = sim_bsp_at(world, s.x, s.z);
|
||||||
if (result.y > mid + 0.01f) {
|
const pxl8_bsp* bsp_e = sim_bsp_at(world, e.x, e.z);
|
||||||
lo = mid;
|
if (bsp_s) {
|
||||||
} else {
|
trace_result tr = bsp_trace_line(bsp_s, s, e);
|
||||||
hi = mid;
|
if (tr.fraction < *out_frac && !tr.start_solid) {
|
||||||
|
*out_frac = tr.fraction;
|
||||||
|
*out_normal = tr.normal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (bsp_e && bsp_e != bsp_s) {
|
||||||
|
bool inside_bounds = !(bsp_e->bounds_max_x > bsp_e->bounds_min_x) ||
|
||||||
|
(s.x >= bsp_e->bounds_min_x && s.x < bsp_e->bounds_max_x &&
|
||||||
|
s.z >= bsp_e->bounds_min_z && s.z < bsp_e->bounds_max_z);
|
||||||
|
if (inside_bounds) {
|
||||||
|
trace_result tr = bsp_trace_line(bsp_e, s, e);
|
||||||
|
if (tr.fraction < *out_frac && !tr.start_solid) {
|
||||||
|
*out_frac = tr.fraction;
|
||||||
|
*out_normal = tr.normal;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return hi;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pxl8_vec3 pxl8_sim_trace(const pxl8_sim_world* world, pxl8_vec3 from, pxl8_vec3 to, f32 radius, f32 height) {
|
pxl8_vec3 pxl8_sim_trace(const pxl8_sim_world* world, pxl8_vec3 from, pxl8_vec3 to, f32 radius, f32 height) {
|
||||||
(void)height;
|
(void)height;
|
||||||
if (!world || world->chunk_size <= 0) return to;
|
if (!world || world->chunk_size <= 0) return to;
|
||||||
|
|
||||||
if (sim_point_clear(world, to.x, to.y, to.z, radius)) {
|
f32 frac;
|
||||||
return to;
|
pxl8_vec3 normal;
|
||||||
}
|
sim_trace_offsets(world, from, to, radius, &frac, &normal);
|
||||||
|
if (frac >= 1.0f) return to;
|
||||||
|
|
||||||
bool x_ok = sim_point_clear(world, to.x, from.y, from.z, radius);
|
pxl8_vec3 delta = { to.x - from.x, to.y - from.y, to.z - from.z };
|
||||||
bool y_ok = sim_point_clear(world, from.x, to.y, from.z, radius);
|
pxl8_vec3 hit = {
|
||||||
bool z_ok = sim_point_clear(world, from.x, from.y, to.z, radius);
|
from.x + delta.x * frac,
|
||||||
|
from.y + delta.y * frac,
|
||||||
|
from.z + delta.z * frac,
|
||||||
|
};
|
||||||
|
|
||||||
pxl8_vec3 result = from;
|
f32 remaining = 1.0f - frac;
|
||||||
if (x_ok) result.x = to.x;
|
if (remaining <= 0.0f) return hit;
|
||||||
if (y_ok) result.y = to.y;
|
|
||||||
if (z_ok) result.z = to.z;
|
|
||||||
|
|
||||||
return result;
|
f32 backoff = pxl8_vec3_dot(delta, normal) * remaining;
|
||||||
|
pxl8_vec3 slide_target = {
|
||||||
|
hit.x + delta.x * remaining - normal.x * backoff,
|
||||||
|
hit.y + delta.y * remaining - normal.y * backoff,
|
||||||
|
hit.z + delta.z * remaining - normal.z * backoff,
|
||||||
|
};
|
||||||
|
|
||||||
|
f32 slide_frac;
|
||||||
|
pxl8_vec3 slide_normal;
|
||||||
|
sim_trace_offsets(world, hit, slide_target, radius, &slide_frac, &slide_normal);
|
||||||
|
if (slide_frac >= 1.0f) return slide_target;
|
||||||
|
|
||||||
|
pxl8_vec3 slide_delta = {
|
||||||
|
slide_target.x - hit.x,
|
||||||
|
slide_target.y - hit.y,
|
||||||
|
slide_target.z - hit.z,
|
||||||
|
};
|
||||||
|
return (pxl8_vec3){
|
||||||
|
hit.x + slide_delta.x * slide_frac,
|
||||||
|
hit.y + slide_delta.y * slide_frac,
|
||||||
|
hit.z + slide_delta.z * slide_frac,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
bool pxl8_sim_check_ground(const pxl8_sim_world* world, pxl8_vec3 pos, f32 radius) {
|
bool pxl8_sim_check_ground(const pxl8_sim_world* world, pxl8_vec3 pos, f32 radius) {
|
||||||
|
|
@ -201,10 +380,6 @@ void pxl8_sim_move_player(pxl8_sim_entity* ent, const pxl8_input_msg* input,
|
||||||
|
|
||||||
pxl8_vec3 new_pos = pxl8_sim_trace(world, ent->pos, target, cfg->player_radius, cfg->player_height);
|
pxl8_vec3 new_pos = pxl8_sim_trace(world, ent->pos, target, cfg->player_radius, cfg->player_height);
|
||||||
|
|
||||||
if (ent->vel.y < 0 && new_pos.y > target.y + 0.01f) {
|
|
||||||
new_pos.y = find_landing_y(world, new_pos, target.y, cfg->player_radius, cfg->player_height);
|
|
||||||
}
|
|
||||||
|
|
||||||
f32 th = sim_terrain_height(world, new_pos.x, new_pos.z);
|
f32 th = sim_terrain_height(world, new_pos.x, new_pos.z);
|
||||||
if (th > -1e8f && new_pos.y < th) {
|
if (th > -1e8f && new_pos.y < th) {
|
||||||
new_pos.y = th;
|
new_pos.y = th;
|
||||||
|
|
@ -256,10 +431,6 @@ void pxl8_sim_integrate(pxl8_sim_entity* ent, const pxl8_sim_world* world,
|
||||||
|
|
||||||
pxl8_vec3 new_pos = pxl8_sim_trace(world, ent->pos, target, cfg->player_radius, cfg->player_height);
|
pxl8_vec3 new_pos = pxl8_sim_trace(world, ent->pos, target, cfg->player_radius, cfg->player_height);
|
||||||
|
|
||||||
if (ent->vel.y < 0 && new_pos.y > target.y + 0.01f) {
|
|
||||||
new_pos.y = find_landing_y(world, new_pos, target.y, cfg->player_radius, cfg->player_height);
|
|
||||||
}
|
|
||||||
|
|
||||||
f32 th2 = sim_terrain_height(world, new_pos.x, new_pos.z);
|
f32 th2 = sim_terrain_height(world, new_pos.x, new_pos.z);
|
||||||
if (th2 > -1e8f && new_pos.y < th2) {
|
if (th2 > -1e8f && new_pos.y < th2) {
|
||||||
new_pos.y = th2;
|
new_pos.y = th2;
|
||||||
|
|
|
||||||
|
|
@ -330,8 +330,8 @@ static void compute_edge_leafs(pxl8_loaded_chunk* lc) {
|
||||||
memset(lc->edges, 0, sizeof(lc->edges));
|
memset(lc->edges, 0, sizeof(lc->edges));
|
||||||
|
|
||||||
for (u32 i = 0; i < bsp->num_leafs; i++) {
|
for (u32 i = 0; i < bsp->num_leafs; i++) {
|
||||||
if (bsp->leafs[i].contents == -1) continue;
|
|
||||||
const pxl8_bsp_leaf* leaf = &bsp->leafs[i];
|
const pxl8_bsp_leaf* leaf = &bsp->leafs[i];
|
||||||
|
if (bsp->leafs[i].contents == -1) continue;
|
||||||
|
|
||||||
if ((f32)leaf->mins[2] <= (f32)((i16)cz0) + 1.0f && lc->edges[0].count < 16)
|
if ((f32)leaf->mins[2] <= (f32)((i16)cz0) + 1.0f && lc->edges[0].count < 16)
|
||||||
lc->edges[0].leafs[lc->edges[0].count++] = (u16)i;
|
lc->edges[0].leafs[lc->edges[0].count++] = (u16)i;
|
||||||
|
|
@ -402,13 +402,37 @@ static void world_compute_visibility(pxl8_world* world, pxl8_gfx* gfx, pxl8_vec3
|
||||||
for (u32 i = 0; i < world->loaded_count; i++) {
|
for (u32 i = 0; i < world->loaded_count; i++) {
|
||||||
pxl8_loaded_chunk* lc = &world->loaded[i];
|
pxl8_loaded_chunk* lc = &world->loaded[i];
|
||||||
if (!lc->chunk || !lc->chunk->bsp) continue;
|
if (!lc->chunk || !lc->chunk->bsp) continue;
|
||||||
|
const pxl8_bsp* bsp = lc->chunk->bsp;
|
||||||
f32 cx0 = lc->cx * CHUNK_SIZE;
|
f32 cx0 = lc->cx * CHUNK_SIZE;
|
||||||
f32 cz0 = lc->cz * CHUNK_SIZE;
|
f32 cz0 = lc->cz * CHUNK_SIZE;
|
||||||
if (camera_pos.x < cx0 || camera_pos.x >= cx0 + CHUNK_SIZE ||
|
if (camera_pos.x < cx0 || camera_pos.x >= cx0 + CHUNK_SIZE ||
|
||||||
camera_pos.z < cz0 || camera_pos.z >= cz0 + CHUNK_SIZE) continue;
|
camera_pos.z < cz0 || camera_pos.z >= cz0 + CHUNK_SIZE) continue;
|
||||||
i32 leaf = pxl8_bsp_find_leaf(lc->chunk->bsp, camera_pos);
|
if (bsp->bounds_max_x > bsp->bounds_min_x &&
|
||||||
if (leaf >= 0 && (u32)leaf < lc->chunk->bsp->num_leafs &&
|
(camera_pos.x < bsp->bounds_min_x || camera_pos.x >= bsp->bounds_max_x ||
|
||||||
lc->chunk->bsp->leafs[leaf].contents != -1) {
|
camera_pos.z < bsp->bounds_min_z || camera_pos.z >= bsp->bounds_max_z))
|
||||||
|
continue;
|
||||||
|
i32 leaf = pxl8_bsp_find_leaf(bsp, camera_pos);
|
||||||
|
if (leaf >= 0 && (u32)leaf < bsp->num_leafs &&
|
||||||
|
bsp->leafs[leaf].contents != -1 &&
|
||||||
|
(!(bsp->bounds_max_x > bsp->bounds_min_x) || bsp->leafs[leaf].contents == -2)) {
|
||||||
|
cam_ci = (i32)i;
|
||||||
|
cam_li = leaf;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cam_ci < 0) {
|
||||||
|
for (u32 i = 0; i < world->loaded_count; i++) {
|
||||||
|
pxl8_loaded_chunk* lc = &world->loaded[i];
|
||||||
|
if (!lc->chunk || !lc->chunk->bsp) continue;
|
||||||
|
const pxl8_bsp* bsp = lc->chunk->bsp;
|
||||||
|
if (bsp->bounds_max_x > bsp->bounds_min_x) continue;
|
||||||
|
i32 leaf = pxl8_bsp_find_leaf(bsp, camera_pos);
|
||||||
|
if (leaf < 0 || (u32)leaf >= bsp->num_leafs) continue;
|
||||||
|
const pxl8_bsp_leaf* l = &bsp->leafs[leaf];
|
||||||
|
if (l->contents == -1) continue;
|
||||||
|
if (camera_pos.x < (f32)l->mins[0] || camera_pos.x > (f32)l->maxs[0] ||
|
||||||
|
camera_pos.z < (f32)l->mins[2] || camera_pos.z > (f32)l->maxs[2]) continue;
|
||||||
cam_ci = (i32)i;
|
cam_ci = (i32)i;
|
||||||
cam_li = leaf;
|
cam_li = leaf;
|
||||||
break;
|
break;
|
||||||
|
|
@ -457,6 +481,10 @@ static void world_compute_visibility(pxl8_world* world, pxl8_gfx* gfx, pxl8_vec3
|
||||||
u32 head = 0, tail = 0;
|
u32 head = 0, tail = 0;
|
||||||
|
|
||||||
pxl8_rect full_screen = {-1.0f, -1.0f, 1.0f, 1.0f};
|
pxl8_rect full_screen = {-1.0f, -1.0f, 1.0f, 1.0f};
|
||||||
|
const pxl8_bsp* cam_bsp = world->loaded[cam_ci].chunk->bsp;
|
||||||
|
bool cam_exterior = cam_bsp->leafs[cam_li].contents == 0 &&
|
||||||
|
!(cam_bsp->bounds_max_x > cam_bsp->bounds_min_x);
|
||||||
|
|
||||||
world->vis_ptrs[cam_ci][cam_li >> 3] |= (1 << (cam_li & 7));
|
world->vis_ptrs[cam_ci][cam_li >> 3] |= (1 << (cam_li & 7));
|
||||||
world->vis_win_ptrs[cam_ci][cam_li] = full_screen;
|
world->vis_win_ptrs[cam_ci][cam_li] = full_screen;
|
||||||
world->vis_queue[tail++] = (world_vis_node){(u16)cam_ci, (u16)cam_li, full_screen};
|
world->vis_queue[tail++] = (world_vis_node){(u16)cam_ci, (u16)cam_li, full_screen};
|
||||||
|
|
@ -479,7 +507,7 @@ static void world_compute_visibility(pxl8_world* world, pxl8_gfx* gfx, pxl8_vec3
|
||||||
if (bsp->leafs[target].contents == -1) continue;
|
if (bsp->leafs[target].contents == -1) continue;
|
||||||
if (is_cam_chunk && !pxl8_bsp_is_leaf_visible(bsp, cam_li, (i32)target)) continue;
|
if (is_cam_chunk && !pxl8_bsp_is_leaf_visible(bsp, cam_li, (i32)target)) continue;
|
||||||
|
|
||||||
if (is_cam_leaf) {
|
if (is_cam_leaf || cam_exterior) {
|
||||||
vis_try_enqueue(world->vis_ptrs, world->vis_win_ptrs,
|
vis_try_enqueue(world->vis_ptrs, world->vis_win_ptrs,
|
||||||
world->vis_queue, &tail, PXL8_VIS_MAX_QUEUE,
|
world->vis_queue, &tail, PXL8_VIS_MAX_QUEUE,
|
||||||
cur.chunk_idx, (u16)target, full_screen);
|
cur.chunk_idx, (u16)target, full_screen);
|
||||||
|
|
@ -546,6 +574,13 @@ static void world_compute_visibility(pxl8_world* world, pxl8_gfx* gfx, pxl8_vec3
|
||||||
bpx0 = (f32)xlo; bpx1 = (f32)xhi;
|
bpx0 = (f32)xlo; bpx1 = (f32)xhi;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cam_exterior) {
|
||||||
|
vis_try_enqueue(world->vis_ptrs, world->vis_win_ptrs,
|
||||||
|
world->vis_queue, &tail, PXL8_VIS_MAX_QUEUE,
|
||||||
|
(u16)nci, (u16)nl, full_screen);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
pxl8_rect psr = project_portal(bpx0, bpz0, bpx1, bpz1,
|
pxl8_rect psr = project_portal(bpx0, bpz0, bpx1, bpz1,
|
||||||
0.0f, PORTAL_Y_HI, vp);
|
0.0f, PORTAL_Y_HI, vp);
|
||||||
if (!vr_valid(psr)) continue;
|
if (!vr_valid(psr)) continue;
|
||||||
|
|
@ -558,6 +593,7 @@ static void world_compute_visibility(pxl8_world* world, pxl8_gfx* gfx, pxl8_vec3
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void pxl8_world_render(pxl8_world* world, pxl8_gfx* gfx, pxl8_vec3 camera_pos) {
|
void pxl8_world_render(pxl8_world* world, pxl8_gfx* gfx, pxl8_vec3 camera_pos) {
|
||||||
|
|
|
||||||
|
|
@ -285,6 +285,16 @@ static pxl8_bsp* assembly_to_bsp(pxl8_world_chunk_assembly* a) {
|
||||||
memcpy(&bsp->heightfield_cell_size, &cs_raw, sizeof(f32));
|
memcpy(&bsp->heightfield_cell_size, &cs_raw, sizeof(f32));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u32 raw;
|
||||||
|
raw = pxl8_read_u32_be(&s);
|
||||||
|
memcpy(&bsp->bounds_min_x, &raw, sizeof(f32));
|
||||||
|
raw = pxl8_read_u32_be(&s);
|
||||||
|
memcpy(&bsp->bounds_min_z, &raw, sizeof(f32));
|
||||||
|
raw = pxl8_read_u32_be(&s);
|
||||||
|
memcpy(&bsp->bounds_max_x, &raw, sizeof(f32));
|
||||||
|
raw = pxl8_read_u32_be(&s);
|
||||||
|
memcpy(&bsp->bounds_max_z, &raw, sizeof(f32));
|
||||||
|
|
||||||
return bsp;
|
return bsp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue