mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
More advanced roofs
This commit is contained in:
parent
5a31b17bc3
commit
ee4c6d006f
@ -8,11 +8,8 @@ use common::{
|
|||||||
};
|
};
|
||||||
use enum_map::EnumMap;
|
use enum_map::EnumMap;
|
||||||
use enumset::EnumSet;
|
use enumset::EnumSet;
|
||||||
use hashbrown::{HashMap, HashSet};
|
use hashbrown::HashSet;
|
||||||
use rand::{
|
use rand::{seq::IteratorRandom, Rng};
|
||||||
seq::{IteratorRandom, SliceRandom},
|
|
||||||
Rng, SeedableRng,
|
|
||||||
};
|
|
||||||
use strum::{EnumIter, IntoEnumIterator};
|
use strum::{EnumIter, IntoEnumIterator};
|
||||||
use vek::*;
|
use vek::*;
|
||||||
|
|
||||||
@ -59,6 +56,21 @@ impl Wall {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
enum RoofStyle {
|
||||||
|
Flat,
|
||||||
|
FlatBars { dir: Dir },
|
||||||
|
LeanTo { dir: Dir, max_z: i32 },
|
||||||
|
Gable { dir: Dir, max_z: i32 },
|
||||||
|
Hip { max_z: i32 },
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Roof {
|
||||||
|
bounds: Aabr<i32>,
|
||||||
|
min_z: i32,
|
||||||
|
style: RoofStyle,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, EnumIter, enum_map::Enum)]
|
#[derive(Clone, Copy, EnumIter, enum_map::Enum)]
|
||||||
enum RoomKind {
|
enum RoomKind {
|
||||||
Garden,
|
Garden,
|
||||||
@ -99,6 +111,7 @@ pub struct Room {
|
|||||||
kind: RoomKind,
|
kind: RoomKind,
|
||||||
// stairs: Option<Id<Stairs>>,
|
// stairs: Option<Id<Stairs>>,
|
||||||
walls: EnumMap<Dir, Vec<Id<Wall>>>,
|
walls: EnumMap<Dir, Vec<Id<Wall>>>,
|
||||||
|
roofs: Vec<Id<Roof>>,
|
||||||
// TODO: Remove this, used for debugging
|
// TODO: Remove this, used for debugging
|
||||||
detail_areas: Vec<Aabr<i32>>,
|
detail_areas: Vec<Aabr<i32>>,
|
||||||
pub details: Vec<Detail>,
|
pub details: Vec<Detail>,
|
||||||
@ -109,17 +122,33 @@ impl Room {
|
|||||||
Self {
|
Self {
|
||||||
bounds,
|
bounds,
|
||||||
kind,
|
kind,
|
||||||
|
roofs: Default::default(),
|
||||||
walls: Default::default(),
|
walls: Default::default(),
|
||||||
detail_areas: Default::default(),
|
detail_areas: Default::default(),
|
||||||
details: Default::default(),
|
details: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Are any of this rooms roofs fully covering it?
|
||||||
|
fn is_covered_by_roof(&self, roofs: &Store<Roof>) -> bool {
|
||||||
|
let aabr = Aabr {
|
||||||
|
min: self.bounds.min.xy(),
|
||||||
|
max: self.bounds.max.xy(),
|
||||||
|
};
|
||||||
|
for roof in self.roofs.iter() {
|
||||||
|
if roofs[*roof].bounds.contains_aabr(aabr) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Tavern {
|
pub struct Tavern {
|
||||||
name: String,
|
name: String,
|
||||||
pub rooms: Store<Room>,
|
pub rooms: Store<Room>,
|
||||||
walls: Store<Wall>,
|
walls: Store<Wall>,
|
||||||
|
roofs: Store<Roof>,
|
||||||
/// Tile position of the door tile
|
/// Tile position of the door tile
|
||||||
pub door_tile: Vec2<i32>,
|
pub door_tile: Vec2<i32>,
|
||||||
pub door_wpos: Vec3<i32>,
|
pub door_wpos: Vec3<i32>,
|
||||||
@ -130,7 +159,7 @@ pub struct Tavern {
|
|||||||
impl Tavern {
|
impl Tavern {
|
||||||
pub fn generate(
|
pub fn generate(
|
||||||
land: &Land,
|
land: &Land,
|
||||||
index: IndexRef,
|
_index: IndexRef,
|
||||||
rng: &mut impl Rng,
|
rng: &mut impl Rng,
|
||||||
site: &Site,
|
site: &Site,
|
||||||
door_tile: Vec2<i32>,
|
door_tile: Vec2<i32>,
|
||||||
@ -139,9 +168,9 @@ impl Tavern {
|
|||||||
) -> Self {
|
) -> Self {
|
||||||
let name = namegen::NameGen::location(rng).generate_tavern();
|
let name = namegen::NameGen::location(rng).generate_tavern();
|
||||||
|
|
||||||
let start = std::time::Instant::now();
|
|
||||||
let mut rooms = Store::default();
|
let mut rooms = Store::default();
|
||||||
let mut walls = Store::default();
|
let mut walls = Store::default();
|
||||||
|
let mut roofs = Store::default();
|
||||||
let mut room_counts = EnumMap::<RoomKind, u32>::default();
|
let mut room_counts = EnumMap::<RoomKind, u32>::default();
|
||||||
|
|
||||||
let bounds = Aabr {
|
let bounds = Aabr {
|
||||||
@ -258,14 +287,7 @@ impl Tavern {
|
|||||||
|
|
||||||
room_metas.push(RoomMeta {
|
room_metas.push(RoomMeta {
|
||||||
id: entrance_id,
|
id: entrance_id,
|
||||||
walls: Dir::iter()
|
walls: Dir::iter().filter(|d| *d != door_dir).collect(),
|
||||||
.filter(|d| *d != door_dir)
|
|
||||||
// .map(|d| {
|
|
||||||
// let a = d.rotated_cw().select_aabr(entrance_room_aabr);
|
|
||||||
// let b = d.rotated_ccw().select_aabr(entrance_room_aabr);
|
|
||||||
// (d, a.min(b)..=a.max(b))
|
|
||||||
// })
|
|
||||||
.collect(),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
room_counts[entrance_room] += 1;
|
room_counts[entrance_room] += 1;
|
||||||
@ -281,11 +303,13 @@ impl Tavern {
|
|||||||
max: aabr.max + amount,
|
max: aabr.max + amount,
|
||||||
};
|
};
|
||||||
'room_gen: while room_metas.len() > 0 {
|
'room_gen: while room_metas.len() > 0 {
|
||||||
|
// Continue extending from a random existing room
|
||||||
let mut room_meta = room_metas.swap_remove(rng.gen_range(0..room_metas.len()));
|
let mut room_meta = room_metas.swap_remove(rng.gen_range(0..room_metas.len()));
|
||||||
if room_meta.walls.is_empty() {
|
if room_meta.walls.is_empty() {
|
||||||
continue 'room_gen;
|
continue 'room_gen;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Pick a direction to choose from
|
||||||
let Some(in_dir) = room_meta.walls.into_iter().choose(rng) else {
|
let Some(in_dir) = room_meta.walls.into_iter().choose(rng) else {
|
||||||
continue 'room_gen;
|
continue 'room_gen;
|
||||||
};
|
};
|
||||||
@ -297,6 +321,7 @@ impl Tavern {
|
|||||||
let from_id = room_meta.id;
|
let from_id = room_meta.id;
|
||||||
let from_room = &rooms[from_id];
|
let from_room = &rooms[from_id];
|
||||||
|
|
||||||
|
// If there are more directions to continue from, push this room again.
|
||||||
if !room_meta.walls.is_empty() {
|
if !room_meta.walls.is_empty() {
|
||||||
room_metas.push(room_meta);
|
room_metas.push(room_meta);
|
||||||
}
|
}
|
||||||
@ -309,7 +334,7 @@ impl Tavern {
|
|||||||
max: in_dir.select_aabr_with(ibounds, ibounds.max),
|
max: in_dir.select_aabr_with(ibounds, ibounds.max),
|
||||||
}
|
}
|
||||||
.made_valid();
|
.made_valid();
|
||||||
// Height of the new room
|
// Pick a height of the new room
|
||||||
let room_hgt = rng.gen_range(3..=5);
|
let room_hgt = rng.gen_range(3..=5);
|
||||||
let wanted_alt = land.get_alt_approx(max_bounds.center()) as i32;
|
let wanted_alt = land.get_alt_approx(max_bounds.center()) as i32;
|
||||||
let max_stair_length = (in_dir.select(if wanted_alt < from_room.bounds.min.z {
|
let max_stair_length = (in_dir.select(if wanted_alt < from_room.bounds.min.z {
|
||||||
@ -409,7 +434,7 @@ impl Tavern {
|
|||||||
|
|
||||||
// Pick a room.
|
// Pick a room.
|
||||||
let room_lottery = Lottery::from(room_lottery);
|
let room_lottery = Lottery::from(room_lottery);
|
||||||
let room = *room_lottery.choose_seeded(rng.gen());
|
let room_kind = *room_lottery.choose_seeded(rng.gen());
|
||||||
|
|
||||||
// Select a door position
|
// Select a door position
|
||||||
let mut min = left
|
let mut min = left
|
||||||
@ -428,7 +453,8 @@ impl Tavern {
|
|||||||
let in_pos =
|
let in_pos =
|
||||||
in_dir.select_aabr_with(from_bounds, Vec2::broadcast(in_pos)) + in_dir.to_vec2();
|
in_dir.select_aabr_with(from_bounds, Vec2::broadcast(in_pos)) + in_dir.to_vec2();
|
||||||
|
|
||||||
let Some(bounds) = place_room_in(room, max_bounds, in_dir, in_pos, rng) else {
|
// Place the room in the given max bounds
|
||||||
|
let Some(bounds) = place_room_in(room_kind, max_bounds, in_dir, in_pos, rng) else {
|
||||||
continue 'room_gen;
|
continue 'room_gen;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -436,7 +462,7 @@ impl Tavern {
|
|||||||
min: bounds.min.with_z(alt),
|
min: bounds.min.with_z(alt),
|
||||||
max: bounds.max.with_z(alt + room_hgt),
|
max: bounds.max.with_z(alt + room_hgt),
|
||||||
};
|
};
|
||||||
let id = rooms.insert(Room::new(bounds3, room));
|
let id = rooms.insert(Room::new(bounds3, room_kind));
|
||||||
|
|
||||||
let start = in_dir.select_aabr_with(
|
let start = in_dir.select_aabr_with(
|
||||||
from_bounds,
|
from_bounds,
|
||||||
@ -476,7 +502,7 @@ impl Tavern {
|
|||||||
id,
|
id,
|
||||||
walls: Dir::iter().filter(|d| *d != -in_dir).collect(),
|
walls: Dir::iter().filter(|d| *d != -in_dir).collect(),
|
||||||
});
|
});
|
||||||
room_counts[room] += 1;
|
room_counts[room_kind] += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Place walls where needed.
|
// Place walls where needed.
|
||||||
@ -643,6 +669,7 @@ impl Tavern {
|
|||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let mut x = bounds.min.x;
|
let mut x = bounds.min.x;
|
||||||
|
// Basically greedy meshing, but for aabrs
|
||||||
while x <= bounds.max.x {
|
while x <= bounds.max.x {
|
||||||
let mut y = bounds.min.y;
|
let mut y = bounds.min.y;
|
||||||
'y_loop: while y <= bounds.max.y {
|
'y_loop: while y <= bounds.max.y {
|
||||||
@ -759,11 +786,139 @@ impl Tavern {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("GENERATION TIME: {}μs", start.elapsed().as_micros());
|
for room_id in rooms.ids() {
|
||||||
|
let room = &rooms[room_id];
|
||||||
|
// If a room is already fully covered by a roof, we skip it.
|
||||||
|
if room.is_covered_by_roof(&roofs) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let roof_min_z = room.bounds.max.z + 1;
|
||||||
|
let mut roof_bounds = to_aabr(room.bounds);
|
||||||
|
roof_bounds.min -= 2;
|
||||||
|
roof_bounds.max += 2;
|
||||||
|
let mut dirs = Vec::from(Dir::ALL);
|
||||||
|
|
||||||
|
let mut over_rooms = vec![room_id];
|
||||||
|
// Extend roof over adjecent rooms.
|
||||||
|
while !dirs.is_empty() {
|
||||||
|
let dir = dirs.swap_remove(rng.gen_range(0..dirs.len()));
|
||||||
|
let orth = dir.orthogonal();
|
||||||
|
// Check for room intersections in this direction.
|
||||||
|
for (room_id, room) in rooms.iter() {
|
||||||
|
let room_aabr = to_aabr(room.bounds);
|
||||||
|
if room.bounds.max.z == roof_min_z
|
||||||
|
&& dir.select_aabr(roof_bounds) + dir.signum()
|
||||||
|
== (-dir).select_aabr(room_aabr)
|
||||||
|
&& orth.select_aabr(roof_bounds) <= orth.select_aabr(room_aabr) + 2
|
||||||
|
&& (-orth).select_aabr(roof_bounds) >= (-orth).select_aabr(room_aabr) - 2
|
||||||
|
{
|
||||||
|
// If the room we found is fully covered by a roof already, we don't go in
|
||||||
|
// this direction.
|
||||||
|
if room.is_covered_by_roof(&roofs) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
roof_bounds = dir.extend_aabr(roof_bounds, dir.select(room_aabr.size()));
|
||||||
|
dirs.push(dir);
|
||||||
|
over_rooms.push(room_id);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build a lottery of valid roofs to pick from
|
||||||
|
let mut valid_styles = vec![(0.5, RoofStyle::Flat)];
|
||||||
|
|
||||||
|
let gardens = over_rooms
|
||||||
|
.iter()
|
||||||
|
.filter(|id| matches!(rooms[**id].kind, RoomKind::Garden))
|
||||||
|
.count();
|
||||||
|
|
||||||
|
// If we just have gardens, we can use FlatBars style.
|
||||||
|
if gardens == over_rooms.len() {
|
||||||
|
let ratio = Dir::X.select(roof_bounds.size()) as f32
|
||||||
|
/ Dir::Y.select(roof_bounds.size()) as f32;
|
||||||
|
valid_styles.extend([
|
||||||
|
(5.0 * ratio, RoofStyle::FlatBars { dir: Dir::X }),
|
||||||
|
(5.0 / ratio, RoofStyle::FlatBars { dir: Dir::Y }),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find heights of possible adjecent rooms.
|
||||||
|
let mut dir_zs = EnumMap::default();
|
||||||
|
for dir in Dir::iter() {
|
||||||
|
let orth = dir.orthogonal();
|
||||||
|
for room in rooms.values() {
|
||||||
|
let room_aabr = to_aabr(room.bounds);
|
||||||
|
if room.bounds.max.z > roof_min_z
|
||||||
|
&& dir.select_aabr(roof_bounds) == (-dir).select_aabr(room_aabr)
|
||||||
|
&& orth.select_aabr(roof_bounds) <= orth.select_aabr(room_aabr) + 2
|
||||||
|
&& (-orth).select_aabr(roof_bounds) >= (-orth).select_aabr(room_aabr) - 2
|
||||||
|
{
|
||||||
|
dir_zs[dir] = Some(room.bounds.max.z);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for dir in [Dir::X, Dir::Y] {
|
||||||
|
if dir_zs[dir.orthogonal()].is_none() && dir_zs[-dir.orthogonal()].is_none() {
|
||||||
|
let max_z =
|
||||||
|
roof_min_z + (dir.orthogonal().select(roof_bounds.size()) / 2 - 1).min(7);
|
||||||
|
let max_z = match (dir_zs[dir], dir_zs[-dir]) {
|
||||||
|
(Some(a), Some(b)) => {
|
||||||
|
if a.min(b) >= roof_min_z + 3 {
|
||||||
|
max_z.min(a.min(b))
|
||||||
|
} else {
|
||||||
|
max_z
|
||||||
|
}
|
||||||
|
},
|
||||||
|
(None, None) => max_z,
|
||||||
|
_ => continue,
|
||||||
|
};
|
||||||
|
|
||||||
|
for max_z in roof_min_z + 3..=max_z {
|
||||||
|
valid_styles.push((1.0, RoofStyle::Gable { dir, max_z }))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for dir in Dir::iter() {
|
||||||
|
if let (Some(h), None) = (dir_zs[dir], dir_zs[-dir]) {
|
||||||
|
for max_z in roof_min_z + 2..=h {
|
||||||
|
valid_styles.push((1.0, RoofStyle::LeanTo { dir, max_z }))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if Dir::iter().all(|d| dir_zs[d].is_none()) {
|
||||||
|
for max_z in roof_min_z + 3..=roof_min_z + 7 {
|
||||||
|
valid_styles.push((0.8, RoofStyle::Hip { max_z }))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let style_lottery = Lottery::from(valid_styles);
|
||||||
|
|
||||||
|
debug_assert!(
|
||||||
|
roof_bounds.is_valid(),
|
||||||
|
"Roof bounds aren't valid: {:?}",
|
||||||
|
roof_bounds
|
||||||
|
);
|
||||||
|
let roof_id = roofs.insert(Roof {
|
||||||
|
bounds: roof_bounds,
|
||||||
|
min_z: roof_min_z,
|
||||||
|
style: *style_lottery.choose_seeded(rng.gen()),
|
||||||
|
});
|
||||||
|
|
||||||
|
for room_id in over_rooms {
|
||||||
|
rooms[room_id].roofs.push(roof_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
name,
|
name,
|
||||||
rooms,
|
rooms,
|
||||||
walls,
|
walls,
|
||||||
|
roofs,
|
||||||
door_tile,
|
door_tile,
|
||||||
door_wpos,
|
door_wpos,
|
||||||
bounds,
|
bounds,
|
||||||
@ -825,85 +980,124 @@ impl Structure for Tavern {
|
|||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
enum RoofStyle {
|
for roof in self.roofs.values() {
|
||||||
Flat,
|
match roof.style {
|
||||||
FlatBars(Dir),
|
|
||||||
LeanTo(Dir),
|
|
||||||
Gable(Dir),
|
|
||||||
Hip,
|
|
||||||
}
|
|
||||||
struct Roof {
|
|
||||||
bounds: Aabb<i32>,
|
|
||||||
style: RoofStyle,
|
|
||||||
}
|
|
||||||
let mut roof = Store::default();
|
|
||||||
|
|
||||||
let s = [field.get(self.door_wpos); 8];
|
|
||||||
let rng = &mut rand_chacha::ChaChaRng::from_seed(unsafe { std::mem::transmute(s) });
|
|
||||||
// let mut room_roofs = HashMap::new();
|
|
||||||
|
|
||||||
for room in self.rooms.values() {
|
|
||||||
match room.kind {
|
|
||||||
RoomKind::Garden => {
|
|
||||||
let dir = *[Dir::X, Dir::Y].choose(rng).expect("We have 2 elements");
|
|
||||||
let orth = dir.orthogonal();
|
|
||||||
roof.insert(Roof {
|
|
||||||
bounds: Aabb {
|
|
||||||
min: (room.bounds.min - 1 - orth.to_vec2())
|
|
||||||
.with_z(room.bounds.max.z + 1),
|
|
||||||
max: (room.bounds.max + 1 + orth.to_vec2())
|
|
||||||
.with_z(room.bounds.max.z + 1),
|
|
||||||
},
|
|
||||||
style: RoofStyle::FlatBars(dir),
|
|
||||||
});
|
|
||||||
},
|
|
||||||
_ => {
|
|
||||||
roof.insert(Roof {
|
|
||||||
bounds: Aabb {
|
|
||||||
min: (room.bounds.min - 2).with_z(room.bounds.max.z + 1),
|
|
||||||
max: (room.bounds.max + 2).with_z(room.bounds.max.z + 5),
|
|
||||||
},
|
|
||||||
style: RoofStyle::Hip,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for roof in roof.values() {
|
|
||||||
let roof_aabr = Aabr {
|
|
||||||
min: roof.bounds.min.xy(),
|
|
||||||
max: roof.bounds.max.xy(),
|
|
||||||
};
|
|
||||||
match &roof.style {
|
|
||||||
RoofStyle::Flat => {
|
RoofStyle::Flat => {
|
||||||
painter.aabb(aabb(roof.bounds)).fill(roof_fill.clone());
|
painter
|
||||||
|
.aabb(aabb(Aabb {
|
||||||
|
min: roof.bounds.min.with_z(roof.min_z),
|
||||||
|
max: roof.bounds.max.with_z(roof.min_z),
|
||||||
|
}))
|
||||||
|
.fill(roof_fill.clone());
|
||||||
},
|
},
|
||||||
RoofStyle::FlatBars(dir) => painter
|
RoofStyle::FlatBars { dir } => painter
|
||||||
.aabb(aabb(Aabb {
|
.aabb(aabb(Aabb {
|
||||||
min: dir
|
min: dir
|
||||||
.select_aabr_with(roof_aabr, roof_aabr.min)
|
.select_aabr_with(roof.bounds, roof.bounds.min)
|
||||||
.with_z(roof.bounds.max.z),
|
.with_z(roof.min_z),
|
||||||
max: dir
|
max: dir
|
||||||
.select_aabr_with(roof_aabr, roof_aabr.max)
|
.select_aabr_with(roof.bounds, roof.bounds.max)
|
||||||
.with_z(roof.bounds.max.z),
|
.with_z(roof.min_z),
|
||||||
}))
|
}))
|
||||||
.repeat(
|
.repeat(
|
||||||
-dir.to_vec3() * 2,
|
-dir.to_vec3() * 2,
|
||||||
(dir.select(roof_aabr.size()) as u32 + 3) / 2,
|
(dir.select(roof.bounds.size()) as u32 + 3) / 2,
|
||||||
)
|
)
|
||||||
.fill(roof_fill.clone()),
|
.fill(roof_fill.clone()),
|
||||||
RoofStyle::LeanTo(dir) => {
|
RoofStyle::LeanTo { dir, max_z } => {
|
||||||
painter
|
painter
|
||||||
.ramp(aabb(roof.bounds), *dir)
|
.aabb(aabb(Aabb {
|
||||||
|
min: roof.bounds.min.with_z(roof.min_z),
|
||||||
|
max: roof.bounds.max.with_z(roof.min_z),
|
||||||
|
}))
|
||||||
.fill(roof_fill.clone());
|
.fill(roof_fill.clone());
|
||||||
},
|
|
||||||
RoofStyle::Gable(dir) => {
|
|
||||||
painter
|
painter
|
||||||
.gable(roof.bounds, roof.bounds.size().d, *dir)
|
.ramp(
|
||||||
|
aabb(Aabb {
|
||||||
|
min: roof.bounds.min.with_z(roof.min_z),
|
||||||
|
max: roof.bounds.max.with_z(max_z),
|
||||||
|
}),
|
||||||
|
dir,
|
||||||
|
)
|
||||||
.fill(roof_fill.clone());
|
.fill(roof_fill.clone());
|
||||||
|
for d in [dir.orthogonal(), -dir.orthogonal()] {
|
||||||
|
painter
|
||||||
|
.ramp(
|
||||||
|
aabb(Aabb {
|
||||||
|
min: (d.select_aabr_with(roof.bounds, roof.bounds.min)
|
||||||
|
- d.to_vec2())
|
||||||
|
.with_z(roof.min_z - 1),
|
||||||
|
max: (d.select_aabr_with(roof.bounds, roof.bounds.max)
|
||||||
|
- d.to_vec2())
|
||||||
|
.with_z(max_z - 1),
|
||||||
|
}),
|
||||||
|
dir,
|
||||||
|
)
|
||||||
|
.fill(wall_fill.clone());
|
||||||
|
painter
|
||||||
|
.ramp(
|
||||||
|
aabb(Aabb {
|
||||||
|
min: d
|
||||||
|
.select_aabr_with(roof.bounds, roof.bounds.min)
|
||||||
|
.with_z(roof.min_z - 1),
|
||||||
|
max: d
|
||||||
|
.select_aabr_with(roof.bounds, roof.bounds.max)
|
||||||
|
.with_z(max_z - 1),
|
||||||
|
}),
|
||||||
|
dir,
|
||||||
|
)
|
||||||
|
.clear();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
RoofStyle::Hip => {
|
RoofStyle::Gable { dir, max_z } => {
|
||||||
painter.pyramid(aabb(roof.bounds)).fill(roof_fill.clone());
|
painter
|
||||||
|
.gable(
|
||||||
|
aabb(Aabb {
|
||||||
|
min: roof.bounds.min.with_z(roof.min_z),
|
||||||
|
max: roof.bounds.max.with_z(max_z),
|
||||||
|
}),
|
||||||
|
max_z - roof.min_z + 1,
|
||||||
|
dir,
|
||||||
|
)
|
||||||
|
.fill(roof_fill.clone());
|
||||||
|
for dir in [dir, -dir] {
|
||||||
|
painter
|
||||||
|
.gable(
|
||||||
|
aabb(Aabb {
|
||||||
|
min: (dir.select_aabr_with(roof.bounds, roof.bounds.min + 1)
|
||||||
|
- dir.to_vec2())
|
||||||
|
.with_z(roof.min_z),
|
||||||
|
max: (dir.select_aabr_with(roof.bounds, roof.bounds.max - 1)
|
||||||
|
- dir.to_vec2())
|
||||||
|
.with_z(max_z - 1),
|
||||||
|
}),
|
||||||
|
max_z - roof.min_z,
|
||||||
|
dir,
|
||||||
|
)
|
||||||
|
.fill(wall_fill.clone());
|
||||||
|
painter
|
||||||
|
.gable(
|
||||||
|
aabb(Aabb {
|
||||||
|
min: dir
|
||||||
|
.select_aabr_with(roof.bounds, roof.bounds.min + 1)
|
||||||
|
.with_z(roof.min_z),
|
||||||
|
max: dir
|
||||||
|
.select_aabr_with(roof.bounds, roof.bounds.max - 1)
|
||||||
|
.with_z(max_z - 1),
|
||||||
|
}),
|
||||||
|
max_z - roof.min_z,
|
||||||
|
dir,
|
||||||
|
)
|
||||||
|
.clear();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
RoofStyle::Hip { max_z } => {
|
||||||
|
painter
|
||||||
|
.pyramid(aabb(Aabb {
|
||||||
|
min: roof.bounds.min.with_z(roof.min_z),
|
||||||
|
max: roof.bounds.max.with_z(max_z),
|
||||||
|
}))
|
||||||
|
.fill(roof_fill.clone());
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1001,9 +1195,7 @@ impl Structure for Tavern {
|
|||||||
max: room.bounds.max.xy(),
|
max: room.bounds.max.xy(),
|
||||||
};
|
};
|
||||||
match room.kind {
|
match room.kind {
|
||||||
RoomKind::Garden => {
|
RoomKind::Garden => {},
|
||||||
let dir = Dir::from_vec2(room_aabr.size().into());
|
|
||||||
},
|
|
||||||
RoomKind::StageRoom => {
|
RoomKind::StageRoom => {
|
||||||
for aabr in room.detail_areas.iter().copied() {
|
for aabr in room.detail_areas.iter().copied() {
|
||||||
for dir in Dir::iter().filter(|dir| {
|
for dir in Dir::iter().filter(|dir| {
|
||||||
|
Loading…
Reference in New Issue
Block a user