mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
working rooms
This commit is contained in:
parent
eb2395a401
commit
9903b53105
@ -227,7 +227,7 @@ fn render_flat(bridge: &Bridge, painter: &Painter) {
|
||||
}
|
||||
.made_valid();
|
||||
|
||||
let [ramp_aabr, aabr] = bridge.dir.split_aabr(aabr, height);
|
||||
let [ramp_aabr, aabr] = bridge.dir.split_aabr_offset(aabr, height);
|
||||
|
||||
let ramp_prim = |ramp_aabr: Aabr<i32>, offset: i32| {
|
||||
painter
|
||||
@ -254,7 +254,7 @@ fn render_flat(bridge: &Bridge, painter: &Painter) {
|
||||
let vault_offset = 5;
|
||||
let bridge_thickness = 4;
|
||||
|
||||
let [vault, _] = bridge.dir.split_aabr(aabr, vault_width);
|
||||
let [vault, _] = bridge.dir.split_aabr_offset(aabr, vault_width);
|
||||
|
||||
let len = bridge.dir.select(aabr.size());
|
||||
let true_offset = vault_width + vault_offset;
|
||||
@ -321,8 +321,11 @@ fn render_heightened_viaduct(bridge: &Bridge, painter: &Painter, data: &Heighten
|
||||
}
|
||||
.made_valid();
|
||||
|
||||
let [_start_aabr, rest] = bridge.dir.split_aabr(aabr, bridge_start_z - bridge.start.z);
|
||||
let [_end_aabr, bridge_aabr] = (-bridge.dir).split_aabr(rest, bridge_start_z - bridge.end.z);
|
||||
let [_start_aabr, rest] = bridge
|
||||
.dir
|
||||
.split_aabr_offset(aabr, bridge_start_z - bridge.start.z);
|
||||
let [_end_aabr, bridge_aabr] =
|
||||
(-bridge.dir).split_aabr_offset(rest, bridge_start_z - bridge.end.z);
|
||||
let under = bridge.center.z - 15;
|
||||
|
||||
let bridge_prim = |bridge_width: i32| {
|
||||
@ -334,11 +337,14 @@ fn render_heightened_viaduct(bridge: &Bridge, painter: &Painter, data: &Heighten
|
||||
}
|
||||
.made_valid();
|
||||
|
||||
let [start_aabr, rest] = bridge.dir.split_aabr(aabr, bridge_start_z - bridge.start.z);
|
||||
let [end_aabr, bridge_aabr] = (-bridge.dir).split_aabr(rest, bridge_start_z - bridge.end.z);
|
||||
let [start_aabr, rest] = bridge
|
||||
.dir
|
||||
.split_aabr_offset(aabr, bridge_start_z - bridge.start.z);
|
||||
let [end_aabr, bridge_aabr] =
|
||||
(-bridge.dir).split_aabr_offset(rest, bridge_start_z - bridge.end.z);
|
||||
let [bridge_start, bridge_end] = bridge
|
||||
.dir
|
||||
.split_aabr(bridge_aabr, bridge.dir.select(bridge_aabr.size()) / 2);
|
||||
.split_aabr_offset(bridge_aabr, bridge.dir.select(bridge_aabr.size()) / 2);
|
||||
|
||||
let ramp_in_aabr = |aabr: Aabr<i32>, dir: Dir, zmin, zmax| {
|
||||
let inset = dir.select(aabr.size());
|
||||
@ -592,7 +598,7 @@ fn render_tower(bridge: &Bridge, painter: &Painter, roof_kind: &RoofKind) {
|
||||
let aabr = bridge
|
||||
.dir
|
||||
.rotated_cw()
|
||||
.split_aabr(tower_aabr, stair_thickness + 1)[1];
|
||||
.split_aabr_offset(tower_aabr, stair_thickness + 1)[1];
|
||||
|
||||
painter
|
||||
.aabb(aabb(
|
||||
@ -748,7 +754,7 @@ fn render_hang(bridge: &Bridge, painter: &Painter) {
|
||||
let top_offset = 4;
|
||||
let top = bridge.end.z + top_offset;
|
||||
|
||||
let [ramp_f, aabr] = bridge.dir.split_aabr(aabr, top - bridge.start.z + 1);
|
||||
let [ramp_f, aabr] = bridge.dir.split_aabr_offset(aabr, top - bridge.start.z + 1);
|
||||
|
||||
painter
|
||||
.aabb(aabb(
|
||||
@ -764,7 +770,7 @@ fn render_hang(bridge: &Bridge, painter: &Painter) {
|
||||
)
|
||||
.fill(rock.clone());
|
||||
|
||||
let [ramp_b, aabr] = (-bridge.dir).split_aabr(aabr, top_offset + 1);
|
||||
let [ramp_b, aabr] = (-bridge.dir).split_aabr_offset(aabr, top_offset + 1);
|
||||
painter
|
||||
.aabb(aabb(
|
||||
ramp_b.min.with_z(bridge.end.z - 10),
|
||||
|
@ -1,12 +1,12 @@
|
||||
use std::{mem::swap, ops::RangeInclusive};
|
||||
use std::{cmp::Ordering, mem::swap, ops::RangeInclusive};
|
||||
|
||||
use common::{
|
||||
lottery::Lottery,
|
||||
store::{Id, Store},
|
||||
terrain::{Block, BlockKind},
|
||||
terrain::{Block, BlockKind, SpriteKind},
|
||||
};
|
||||
use enum_map::EnumMap;
|
||||
use fxhash::hash;
|
||||
use hashbrown::HashSet;
|
||||
use rand::Rng;
|
||||
use strum::{EnumIter, IntoEnumIterator};
|
||||
use vek::*;
|
||||
@ -25,7 +25,7 @@ struct Wall {
|
||||
top_alt: i32,
|
||||
from: Neighbor,
|
||||
to: Neighbor,
|
||||
out_dir: Dir,
|
||||
to_dir: Dir,
|
||||
door: Option<i32>,
|
||||
}
|
||||
|
||||
@ -54,7 +54,8 @@ struct Room {
|
||||
bounds: Aabb<i32>,
|
||||
kind: RoomKind,
|
||||
// stairs: Option<Id<Stairs>>,
|
||||
// walls: Vec<Wall>,
|
||||
walls: EnumMap<Dir, Vec<Id<Wall>>>,
|
||||
detail_areas: Vec<Aabr<i32>>,
|
||||
}
|
||||
|
||||
struct Stairs {
|
||||
@ -183,6 +184,8 @@ impl Tavern {
|
||||
let entrance_id = rooms.insert(Room {
|
||||
bounds: entrance_room_aabb,
|
||||
kind: entrance_room,
|
||||
walls: EnumMap::default(),
|
||||
detail_areas: Vec::new(),
|
||||
});
|
||||
|
||||
let start = door_dir.select_aabr_with(
|
||||
@ -190,7 +193,7 @@ impl Tavern {
|
||||
Vec2::broadcast(door_dir.rotated_cw().select_aabr(entrance_room_aabr)),
|
||||
) + door_dir.rotated_cw().to_vec2()
|
||||
+ door_dir.to_vec2();
|
||||
walls.insert(Wall {
|
||||
let wall_id = walls.insert(Wall {
|
||||
start,
|
||||
end: door_dir.select_aabr_with(
|
||||
entrance_room_aabr,
|
||||
@ -201,9 +204,10 @@ impl Tavern {
|
||||
top_alt: entrance_room_aabb.max.z,
|
||||
from: None,
|
||||
to: Some(entrance_id),
|
||||
out_dir: -door_dir,
|
||||
to_dir: door_dir,
|
||||
door: Some(door_dir.rotated_cw().select(door_wpos.xy() - start).abs()),
|
||||
});
|
||||
rooms[entrance_id].walls[door_dir].push(wall_id);
|
||||
|
||||
room_metas.push(RoomMeta {
|
||||
id: entrance_id,
|
||||
@ -224,6 +228,11 @@ impl Tavern {
|
||||
min: aabb.min.xy(),
|
||||
max: aabb.max.xy(),
|
||||
};
|
||||
// Extend a valid aabr
|
||||
let extend_aabr = |aabr: Aabr<i32>, amount: i32| Aabr {
|
||||
min: aabr.min - amount,
|
||||
max: aabr.max + amount,
|
||||
};
|
||||
'room_gen: while room_metas.len() > 0 {
|
||||
let mut room_meta = room_metas.swap_remove(rng.gen_range(0..room_metas.len()));
|
||||
if room_meta.walls.is_empty() {
|
||||
@ -260,9 +269,8 @@ impl Tavern {
|
||||
&& room.bounds.min.z <= from_room.bounds.max.z
|
||||
&& room.bounds.max.z >= from_room.bounds.min.z
|
||||
}) {
|
||||
let mut bounds = to_aabr(room.bounds);
|
||||
bounds.min -= 2;
|
||||
bounds.max += 2;
|
||||
let bounds = to_aabr(room.bounds);
|
||||
let bounds = extend_aabr(bounds, 2);
|
||||
let intersection = bounds.intersection(max_bounds);
|
||||
if intersection.is_valid() {
|
||||
let Some(bounds) = Dir::iter()
|
||||
@ -368,6 +376,8 @@ impl Tavern {
|
||||
let id = rooms.insert(Room {
|
||||
bounds: bounds3,
|
||||
kind: room,
|
||||
walls: EnumMap::default(),
|
||||
detail_areas: Vec::new(),
|
||||
});
|
||||
|
||||
let start = in_dir.select_aabr_with(
|
||||
@ -386,21 +396,198 @@ impl Tavern {
|
||||
) + in_dir.to_vec2()
|
||||
+ right.to_vec2();
|
||||
|
||||
walls.insert(Wall {
|
||||
let wall_id = walls.insert(Wall {
|
||||
start,
|
||||
end,
|
||||
base_alt: bounds3.min.z,
|
||||
top_alt: bounds3.max.z,
|
||||
from: Some(from_id),
|
||||
to: Some(id),
|
||||
out_dir: in_dir,
|
||||
to_dir: in_dir,
|
||||
door: Some(right.select(in_pos - start)),
|
||||
});
|
||||
|
||||
rooms[id].walls[-in_dir].push(wall_id);
|
||||
rooms[from_id].walls[in_dir].push(wall_id);
|
||||
|
||||
room_metas.push(RoomMeta {
|
||||
id,
|
||||
walls: Dir::iter().filter(|d| *d != -in_dir).collect(),
|
||||
});
|
||||
room_counts[room] += 1;
|
||||
}
|
||||
|
||||
// Place walls where needed.
|
||||
for from_id in rooms.ids() {
|
||||
let room_bounds = to_aabr(rooms[from_id].bounds);
|
||||
let mut skip = HashSet::new();
|
||||
skip.insert(from_id);
|
||||
let mut wall_ranges = EnumMap::<Dir, Vec<_>>::default();
|
||||
for dir in Dir::iter() {
|
||||
let orth = dir.orthogonal();
|
||||
let range = (orth.select(room_bounds.min), orth.select(room_bounds.max));
|
||||
wall_ranges[dir].push(range);
|
||||
}
|
||||
let mut split_range = |dir: Dir, min: i32, max: i32| {
|
||||
debug_assert!(min <= max);
|
||||
let Ok(i) = wall_ranges[dir].binary_search_by(|(r_min, r_max)| {
|
||||
match (min.cmp(r_min), min.cmp(r_max)) {
|
||||
(Ordering::Less, _) => Ordering::Greater,
|
||||
(Ordering::Greater | Ordering::Equal, Ordering::Less | Ordering::Equal) => {
|
||||
Ordering::Equal
|
||||
},
|
||||
(_, Ordering::Greater) => Ordering::Less,
|
||||
}
|
||||
}) else {
|
||||
// TODO: Don't panic here.
|
||||
dbg!((min, max));
|
||||
dbg!(&wall_ranges[dir]);
|
||||
panic!("Couldn't find range");
|
||||
};
|
||||
|
||||
let range = &mut wall_ranges[dir][i];
|
||||
debug_assert!(range.0 <= min);
|
||||
debug_assert!(range.1 >= max);
|
||||
|
||||
match (range.0 == min, range.1 == max) {
|
||||
(true, true) => {
|
||||
wall_ranges[dir].remove(i);
|
||||
},
|
||||
(true, false) => *range = (max + 1, range.1),
|
||||
(false, true) => *range = (range.0, min - 1),
|
||||
(false, false) => {
|
||||
let tmp = range.1;
|
||||
*range = (range.0, min - 1);
|
||||
debug_assert!(range.0 <= range.1);
|
||||
let m = (max + 1, tmp);
|
||||
debug_assert!(m.0 <= m.1, "{m:?}");
|
||||
wall_ranges[dir].insert(i + 1, m);
|
||||
},
|
||||
}
|
||||
};
|
||||
for dir in Dir::iter() {
|
||||
let connected_walls = &mut rooms[from_id].walls[dir];
|
||||
skip.extend(
|
||||
connected_walls
|
||||
.iter()
|
||||
.flat_map(|wall| walls[*wall].from.into_iter().chain(walls[*wall].to)),
|
||||
);
|
||||
let orth = dir.orthogonal();
|
||||
// Divide wall ranges by existing walls.
|
||||
for wall in connected_walls.iter() {
|
||||
let wall = &walls[*wall];
|
||||
let mut min = orth.select(wall.start);
|
||||
let mut max = orth.select(wall.end);
|
||||
if min > max {
|
||||
swap(&mut min, &mut max);
|
||||
}
|
||||
min += 1;
|
||||
max -= 1;
|
||||
split_range(dir, min, max);
|
||||
}
|
||||
}
|
||||
|
||||
// Divide wall ranges by neighbouring rooms
|
||||
for to_id in rooms.ids().filter(|id| !skip.contains(id)) {
|
||||
let a_min_z = rooms[from_id].bounds.min.z;
|
||||
let a_max_z = rooms[from_id].bounds.max.z;
|
||||
let b_min_z = rooms[to_id].bounds.min.z;
|
||||
let b_max_z = rooms[to_id].bounds.max.z;
|
||||
if a_min_z > b_max_z || a_max_z < b_min_z {
|
||||
// We are not at the same altitude.
|
||||
continue;
|
||||
}
|
||||
let min_z = a_min_z.min(b_min_z);
|
||||
let max_z = a_max_z.max(b_max_z);
|
||||
let n_room_bounds = to_aabr(rooms[to_id].bounds);
|
||||
|
||||
let p1 = n_room_bounds.projected_point(room_bounds.center());
|
||||
let p0 = room_bounds.projected_point(p1);
|
||||
|
||||
let to_dir = Dir::from_vector(p1 - p0);
|
||||
|
||||
let intersection = to_dir
|
||||
.extend_aabr(room_bounds, 1)
|
||||
.intersection(to_dir.opposite().extend_aabr(n_room_bounds, 1));
|
||||
|
||||
if intersection.is_valid() {
|
||||
let start = intersection.min;
|
||||
let end = intersection.max;
|
||||
|
||||
let orth = to_dir.orthogonal();
|
||||
|
||||
let min = orth.select(start);
|
||||
let max = orth.select(end);
|
||||
split_range(to_dir, min, max);
|
||||
let door = if max - min >= 3 && rng.gen_bool(0.8) {
|
||||
Some(rng.gen_range(1..=max - min))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let id = walls.insert(Wall {
|
||||
start: start - orth.to_vec2(),
|
||||
end: end + orth.to_vec2(),
|
||||
base_alt: min_z,
|
||||
top_alt: max_z,
|
||||
from: Some(from_id),
|
||||
to: Some(to_id),
|
||||
to_dir,
|
||||
door,
|
||||
});
|
||||
|
||||
rooms[from_id].walls[to_dir].push(id);
|
||||
rooms[to_id].walls[-to_dir].push(id);
|
||||
}
|
||||
}
|
||||
// Place remaining walls.
|
||||
for (dir, ranges) in wall_ranges {
|
||||
for (min, max) in ranges {
|
||||
let start =
|
||||
dir.select_aabr_with(room_bounds, Vec2::broadcast(min - 1)) + dir.to_vec2();
|
||||
let end =
|
||||
dir.select_aabr_with(room_bounds, Vec2::broadcast(max + 1)) + dir.to_vec2();
|
||||
|
||||
let wall_id = walls.insert(Wall {
|
||||
start,
|
||||
end,
|
||||
base_alt: rooms[from_id].bounds.min.z,
|
||||
top_alt: rooms[from_id].bounds.max.z,
|
||||
from: Some(from_id),
|
||||
to: None,
|
||||
to_dir: dir,
|
||||
door: None,
|
||||
});
|
||||
|
||||
rooms[from_id].walls[dir].push(wall_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Compute detail areas
|
||||
for room in rooms.values_mut() {
|
||||
room.detail_areas.push(to_aabr(room.bounds));
|
||||
for (dir, dir_walls) in room.walls.iter() {
|
||||
for door_pos in dir_walls.iter().filter_map(|wall_id| {
|
||||
let wall = &walls[*wall_id];
|
||||
|
||||
wall.door.map(|door| {
|
||||
let wall_dir = Dir::from_vector(wall.end - wall.start);
|
||||
wall.start + wall_dir.to_vec2() * door
|
||||
})
|
||||
}) {
|
||||
let orth = dir.orthogonal();
|
||||
for i in 0..room.detail_areas.len() {
|
||||
if let Some([a, b]) =
|
||||
orth.try_split_aabr(room.detail_areas[i], orth.select(door_pos))
|
||||
{
|
||||
room.detail_areas[i] = a;
|
||||
room.detail_areas.push(b);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
room.detail_areas.retain(|area| area.size().product() >= 4);
|
||||
}
|
||||
|
||||
Self {
|
||||
@ -441,18 +628,30 @@ impl Structure for Tavern {
|
||||
}))
|
||||
.fill(stone.clone());
|
||||
|
||||
for (id, room) in self.rooms.iter() {
|
||||
for (_, room) in self.rooms.iter() {
|
||||
painter.aabb(aabb(room.bounds)).clear();
|
||||
let hash = hash(&id).to_le_bytes();
|
||||
painter
|
||||
.aabb(aabb(Aabb {
|
||||
min: room.bounds.min.with_z(room.bounds.min.z - 1),
|
||||
max: room.bounds.max.with_z(room.bounds.min.z - 1),
|
||||
}))
|
||||
.fill(Fill::Block(Block::new(
|
||||
BlockKind::Wood,
|
||||
Rgb::new(hash[0], hash[1], hash[2]),
|
||||
)));
|
||||
.fill(wood.clone());
|
||||
|
||||
match room.kind {
|
||||
RoomKind::Garden => {
|
||||
for aabr in room.detail_areas.iter() {
|
||||
painter
|
||||
.aabb(aabb(Aabb {
|
||||
min: aabr.min.with_z(room.bounds.min.z),
|
||||
max: aabr.max.with_z(room.bounds.min.z),
|
||||
}))
|
||||
.fill(Fill::Sprite(SpriteKind::Apple))
|
||||
}
|
||||
},
|
||||
RoomKind::StageRoom => {},
|
||||
RoomKind::BarRoom => {},
|
||||
RoomKind::EntranceRoom => {},
|
||||
}
|
||||
}
|
||||
|
||||
for (_, wall) in self.walls.iter() {
|
||||
@ -485,11 +684,11 @@ impl Structure for Tavern {
|
||||
if let Some(door) = wall.door {
|
||||
let door_pos = wall.start + wall_dir.to_vec2() * door;
|
||||
let min = match wall.from {
|
||||
None => door_pos - wall.out_dir.to_vec2(),
|
||||
None => door_pos - wall.to_dir.to_vec2(),
|
||||
Some(_) => door_pos,
|
||||
};
|
||||
let max = match wall.to {
|
||||
None => door_pos + wall.out_dir.to_vec2(),
|
||||
None => door_pos + wall.to_dir.to_vec2(),
|
||||
Some(_) => door_pos,
|
||||
};
|
||||
painter
|
||||
|
@ -223,7 +223,7 @@ impl Dir {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn split_aabr<T>(self, aabr: Aabr<T>, offset: T) -> [Aabr<T>; 2]
|
||||
pub fn split_aabr_offset<T>(self, aabr: Aabr<T>, offset: T) -> [Aabr<T>; 2]
|
||||
where
|
||||
T: Copy + PartialOrd + Add<T, Output = T> + Sub<T, Output = T>,
|
||||
{
|
||||
@ -241,6 +241,29 @@ impl Dir {
|
||||
}
|
||||
}
|
||||
|
||||
/// Try to split an aabr in a certain direction
|
||||
pub fn try_split_aabr<T>(self, aabr: Aabr<T>, sp: T) -> Option<[Aabr<T>; 2]>
|
||||
where
|
||||
T: Copy + PartialOrd + Add<T, Output = T> + Sub<T, Output = T>,
|
||||
{
|
||||
match self {
|
||||
Dir::NegX | Dir::X => {
|
||||
if aabr.min.x <= sp && sp <= aabr.max.x {
|
||||
Some(aabr.split_at_x(sp))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
},
|
||||
Dir::NegY | Dir::Y => {
|
||||
if aabr.min.y <= sp && sp <= aabr.max.y {
|
||||
Some(aabr.split_at_y(sp))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn trim_aabr(self, aabr: Aabr<i32>, offset: i32) -> Aabr<i32> {
|
||||
Aabr {
|
||||
min: aabr.min + self.abs().to_vec2() * offset,
|
||||
|
Loading…
Reference in New Issue
Block a user