mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Experimental house towers, wall/roof refactor
This commit is contained in:
parent
a5ccfe3bc9
commit
1b12ab0d29
@ -770,7 +770,7 @@ impl<'a> Sampler<'a> for ColumnGen<'a> {
|
||||
if gouge_factor == 1.0 {
|
||||
return Some((
|
||||
true,
|
||||
None,
|
||||
Some(lake_dist as f32),
|
||||
alt.min(lake_water_alt - 1.0 - river_gouge),
|
||||
downhill_water_alt.max(lake_water_alt)
|
||||
- river_gouge,
|
||||
|
@ -14,8 +14,14 @@ use super::{
|
||||
pub struct House {
|
||||
roof_color: Rgb<u8>,
|
||||
noise: RandomField,
|
||||
chimney: Option<i32>,
|
||||
roof_ribbing: bool,
|
||||
roof_ribbing_diagonal: bool,
|
||||
}
|
||||
|
||||
enum Pillar {
|
||||
None,
|
||||
Chimney(i32),
|
||||
Tower(i32),
|
||||
}
|
||||
|
||||
enum RoofStyle {
|
||||
@ -31,7 +37,7 @@ enum StoreyFill {
|
||||
}
|
||||
|
||||
impl StoreyFill {
|
||||
fn has_lower(&self) -> bool { !if let StoreyFill::None = self { true } else { false } }
|
||||
fn has_lower(&self) -> bool { if let StoreyFill::All = self { true } else { false } }
|
||||
fn has_upper(&self) -> bool { if let StoreyFill::None = self { false } else { true } }
|
||||
}
|
||||
|
||||
@ -40,10 +46,11 @@ pub struct Attr {
|
||||
storey_fill: StoreyFill,
|
||||
roof_style: RoofStyle,
|
||||
mansard: i32,
|
||||
pillar: Pillar,
|
||||
}
|
||||
|
||||
impl Attr {
|
||||
fn generate<R: Rng>(rng: &mut R) -> Self {
|
||||
fn generate<R: Rng>(rng: &mut R, locus: i32) -> Self {
|
||||
Self {
|
||||
central_supports: rng.gen(),
|
||||
storey_fill: match rng.gen_range(0, 2) {
|
||||
@ -56,7 +63,11 @@ impl Attr {
|
||||
1 => RoofStyle::Gable,
|
||||
_ => RoofStyle::Rounded,
|
||||
},
|
||||
mansard: rng.gen_range(-8, 6).max(0),
|
||||
mansard: rng.gen_range(-7, 4).max(0),
|
||||
pillar: match rng.gen_range(0, 4) {
|
||||
0 => Pillar::Chimney(9 + locus + rng.gen_range(0, 4)),
|
||||
_ => Pillar::None,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -76,7 +87,12 @@ impl Archetype for House {
|
||||
attr: Attr {
|
||||
storey_fill: StoreyFill::All,
|
||||
mansard: 0,
|
||||
..Attr::generate(rng)
|
||||
pillar: match rng.gen_range(0, 3) {
|
||||
0 => Pillar::Chimney(9 + locus + rng.gen_range(0, 4)),
|
||||
1 => Pillar::Tower(15 + locus + rng.gen_range(0, 4)),
|
||||
_ => Pillar::None,
|
||||
},
|
||||
..Attr::generate(rng, locus)
|
||||
},
|
||||
locus,
|
||||
border: 4,
|
||||
@ -86,8 +102,8 @@ impl Archetype for House {
|
||||
.flatten()
|
||||
.filter_map(|(i, flip)| if rng.gen() {
|
||||
Some((i as i32 * len / (branches_per_side - 1).max(1) as i32, Branch {
|
||||
len: rng.gen_range(5, 16) * flip,
|
||||
attr: Attr::generate(rng),
|
||||
len: rng.gen_range(8, 16) * flip,
|
||||
attr: Attr::generate(rng, locus),
|
||||
locus: (6 + rng.gen_range(0, 3)).min(locus),
|
||||
border: 4,
|
||||
children: Vec::new(),
|
||||
@ -106,8 +122,8 @@ impl Archetype for House {
|
||||
rng.gen_range(50, 200),
|
||||
),
|
||||
noise: RandomField::new(rng.gen()),
|
||||
chimney: if rng.gen() { Some(8 + skel.root.locus + rng.gen_range(1, 5)) } else { None },
|
||||
roof_ribbing: rng.gen(),
|
||||
roof_ribbing_diagonal: rng.gen(),
|
||||
};
|
||||
|
||||
(this, skel)
|
||||
@ -144,7 +160,7 @@ impl Archetype for House {
|
||||
let foundation_height = 0 - (dist - width - 1).max(0);
|
||||
let roof_top = 8 + width;
|
||||
|
||||
if let Some(chimney_top) = self.chimney {
|
||||
if let Pillar::Chimney(chimney_top) = branch.attr.pillar {
|
||||
// Chimney shaft
|
||||
if center_offset.map(|e| e.abs()).reduce_max() == 0 && profile.y >= foundation_height + 1 {
|
||||
return if profile.y == foundation_height + 1 {
|
||||
@ -181,97 +197,115 @@ impl Archetype for House {
|
||||
}
|
||||
}
|
||||
|
||||
let do_roof = |profile: Vec2<i32>, dist, roof_top, roof_width, mansard| {
|
||||
if profile.y > roof_top - profile.x.max(mansard) && profile.y >= roof_top - roof_width { // Air above roof
|
||||
return Some(empty);
|
||||
// Roofs and walls
|
||||
let do_roof_wall = |profile: Vec2<i32>, width, dist, bound_offset: Vec2<i32>, roof_top, mansard| {
|
||||
// Roof
|
||||
|
||||
let (roof_profile, roof_dist) = match &branch.attr.roof_style {
|
||||
RoofStyle::Hip => (Vec2::new(dist, profile.y), dist),
|
||||
RoofStyle::Gable => (profile, dist),
|
||||
RoofStyle::Rounded => {
|
||||
let circular_dist = (bound_offset.map(|e| e.pow(4) as f32).sum().powf(0.25) + 0.5).ceil() as i32;
|
||||
(Vec2::new(circular_dist, profile.y), circular_dist)
|
||||
},
|
||||
};
|
||||
|
||||
let roof_level = roof_top - roof_profile.x.max(mansard);
|
||||
|
||||
if profile.y > roof_level {
|
||||
return None;
|
||||
}
|
||||
|
||||
// Roof
|
||||
if profile.y == roof_top - profile.x.max(mansard)
|
||||
&& dist <= roof_width
|
||||
{
|
||||
let is_ribbing = (profile.y - ceil_height) % 3 == 0 && self.roof_ribbing;
|
||||
if (profile.x == 0 && mansard == 0) || dist == roof_width|| is_ribbing { // Eaves
|
||||
return Some(log.with_priority(1));
|
||||
if profile.y == roof_level && roof_dist <= width + 2 {
|
||||
let is_ribbing = ((profile.y - ceil_height) % 3 == 0 && self.roof_ribbing)
|
||||
|| (bound_offset.x == bound_offset.y && self.roof_ribbing_diagonal);
|
||||
if (roof_profile.x == 0 && mansard == 0) || roof_dist == width + 2 || is_ribbing { // Eaves
|
||||
return Some(log);
|
||||
} else {
|
||||
return Some(roof.with_priority(1));
|
||||
return Some(roof);
|
||||
}
|
||||
}
|
||||
|
||||
// Wall
|
||||
|
||||
if dist == width && profile.y < roof_level {
|
||||
if bound_offset.x == bound_offset.y || profile.y == ceil_height { // Support beams
|
||||
return Some(log);
|
||||
} else if !branch.attr.storey_fill.has_lower() && profile.y < ceil_height {
|
||||
return Some(empty);
|
||||
} else if !branch.attr.storey_fill.has_upper() {
|
||||
return Some(empty);
|
||||
} else {
|
||||
let frame_bounds = if profile.y >= ceil_height {
|
||||
Aabr {
|
||||
min: Vec2::new(-1, ceil_height + 2),
|
||||
max: Vec2::new(1, ceil_height + 5),
|
||||
}
|
||||
} else {
|
||||
Aabr {
|
||||
min: Vec2::new(2, foundation_height + 2),
|
||||
max: Vec2::new(width - 2, ceil_height - 2),
|
||||
}
|
||||
};
|
||||
let window_bounds = Aabr {
|
||||
min: (frame_bounds.min + 1).map2(frame_bounds.center(), |a, b| a.min(b)),
|
||||
max: (frame_bounds.max - 1).map2(frame_bounds.center(), |a, b| a.max(b)),
|
||||
};
|
||||
|
||||
// Window
|
||||
if (frame_bounds.size() + 1).reduce_min() > 2 { // Window frame is large enough for a window
|
||||
let surface_pos = Vec2::new(bound_offset.x, profile.y);
|
||||
if window_bounds.contains_point(surface_pos) {
|
||||
return Some(internal);
|
||||
} else if frame_bounds.contains_point(surface_pos) {
|
||||
return Some(log.with_priority(3));
|
||||
};
|
||||
}
|
||||
|
||||
// Wall
|
||||
return Some(if branch.attr.central_supports && profile.x == 0 { // Support beams
|
||||
log.with_priority(4)
|
||||
} else {
|
||||
wall
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if dist < width { // Internals
|
||||
if profile.y == ceil_height {
|
||||
if profile.x == 0 {// Rafters
|
||||
return Some(log);
|
||||
} else if branch.attr.storey_fill.has_upper() { // Ceiling
|
||||
return Some(floor);
|
||||
}
|
||||
} else if (!branch.attr.storey_fill.has_lower() && profile.y < ceil_height)
|
||||
|| (!branch.attr.storey_fill.has_upper() && profile.y >= ceil_height)
|
||||
{
|
||||
return Some(empty);
|
||||
} else {
|
||||
return Some(internal);
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
};
|
||||
|
||||
if let Some(block) = match &branch.attr.roof_style {
|
||||
RoofStyle::Hip => do_roof(Vec2::new(dist, profile.y), dist, roof_top, width + 2, branch.attr.mansard),
|
||||
RoofStyle::Gable => do_roof(profile, dist, roof_top, width + 2, branch.attr.mansard),
|
||||
RoofStyle::Rounded => {
|
||||
let circular_dist = (bound_offset.map(|e| e.pow(4) as f32).sum().powf(0.25) + 0.5).ceil() as i32;
|
||||
do_roof(Vec2::new(circular_dist, profile.y), circular_dist, roof_top, width + 2, branch.attr.mansard)
|
||||
},
|
||||
} {
|
||||
return block;
|
||||
let mut cblock = empty;
|
||||
|
||||
if let Some(block) = do_roof_wall(profile, width, dist, bound_offset, roof_top, branch.attr.mansard) {
|
||||
cblock = cblock.resolve_with(block);
|
||||
}
|
||||
|
||||
// Walls
|
||||
if dist == width {
|
||||
if bound_offset.x == bound_offset.y || profile.y == ceil_height { // Support beams
|
||||
return log;
|
||||
} else if !branch.attr.storey_fill.has_lower() && profile.y < ceil_height {
|
||||
return empty;
|
||||
} else if !branch.attr.storey_fill.has_upper() {
|
||||
return empty;
|
||||
} else {
|
||||
let frame_bounds = if profile.y >= ceil_height {
|
||||
Aabr {
|
||||
min: Vec2::new(-1, ceil_height + 2),
|
||||
max: Vec2::new(1, ceil_height + 5),
|
||||
}
|
||||
} else {
|
||||
Aabr {
|
||||
min: Vec2::new(2, foundation_height + 2),
|
||||
max: Vec2::new(width - 2, ceil_height - 2),
|
||||
}
|
||||
};
|
||||
let window_bounds = Aabr {
|
||||
min: (frame_bounds.min + 1).map2(frame_bounds.center(), |a, b| a.min(b)),
|
||||
max: (frame_bounds.max - 1).map2(frame_bounds.center(), |a, b| a.max(b)),
|
||||
};
|
||||
if let Pillar::Tower(tower_top) = branch.attr.pillar {
|
||||
let profile = Vec2::new(center_offset.x.abs(), profile.y);
|
||||
let dist = center_offset.map(|e| e.abs()).reduce_max();
|
||||
|
||||
// Window
|
||||
if (frame_bounds.size() + 1).reduce_min() > 2 { // Window frame is large enough for a window
|
||||
let surface_pos = Vec2::new(bound_offset.x, profile.y);
|
||||
if window_bounds.contains_point(surface_pos) {
|
||||
return internal;
|
||||
} else if frame_bounds.contains_point(surface_pos) {
|
||||
return log.with_priority(3);
|
||||
};
|
||||
}
|
||||
|
||||
// Wall
|
||||
return if branch.attr.central_supports && profile.x == 0 { // Support beams
|
||||
log.with_priority(4)
|
||||
} else {
|
||||
wall
|
||||
};
|
||||
if let Some(block) = do_roof_wall(profile, 4, dist, center_offset.map(|e| e.abs()), tower_top, branch.attr.mansard) {
|
||||
cblock = cblock.resolve_with(block);
|
||||
}
|
||||
}
|
||||
|
||||
if dist < width { // Internals
|
||||
if profile.y == ceil_height {
|
||||
if profile.x == 0 {// Rafters
|
||||
return log;
|
||||
} else if branch.attr.storey_fill.has_upper() { // Ceiling
|
||||
return floor;
|
||||
}
|
||||
} else if (!branch.attr.storey_fill.has_lower() && profile.y < ceil_height)
|
||||
|| (!branch.attr.storey_fill.has_upper() && profile.y >= ceil_height)
|
||||
{
|
||||
return empty;
|
||||
} else {
|
||||
return internal;
|
||||
}
|
||||
}
|
||||
|
||||
empty
|
||||
cblock
|
||||
}
|
||||
}
|
||||
|
@ -29,14 +29,8 @@ impl BlockMask {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn resolve_with(self, dist_self: i32, other: Self, dist_other: i32) -> Self {
|
||||
if self.priority == other.priority {
|
||||
if dist_self <= dist_other {
|
||||
self
|
||||
} else {
|
||||
other
|
||||
}
|
||||
} else if self.priority >= other.priority {
|
||||
pub fn resolve_with(self, other: Self) -> Self {
|
||||
if self.priority >= other.priority {
|
||||
self
|
||||
} else {
|
||||
other
|
||||
|
@ -83,9 +83,9 @@ impl<T> Skeleton<T> {
|
||||
)
|
||||
}.map(|e| e.abs());
|
||||
let center_offset = if ori == Ori::East {
|
||||
Vec2::new(pos.y, pos.x)
|
||||
Vec2::new(pos.y - bounds.center().y, pos.x - bounds.center().x)
|
||||
} else {
|
||||
Vec2::new(pos.x, pos.y)
|
||||
Vec2::new(pos.x - bounds.center().x, pos.y - bounds.center().y)
|
||||
};
|
||||
let dist = bound_offset.reduce_max();
|
||||
let dist_locus = dist - branch.locus;
|
||||
@ -95,7 +95,7 @@ impl<T> Skeleton<T> {
|
||||
} || true {
|
||||
let new_bm = f(dist, bound_offset, center_offset, branch);
|
||||
min = min
|
||||
.map(|(min_dist_locus, bm)| (dist_locus, bm.resolve_with(min_dist_locus, new_bm, dist_locus)))
|
||||
.map(|(_, bm)| (dist_locus, bm.resolve_with(new_bm)))
|
||||
.or(Some((dist_locus, new_bm)));
|
||||
}
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user