draw on map

This commit is contained in:
IsseW 2022-09-29 17:35:48 +02:00 committed by Isse
parent 31b56b03b5
commit 91ed3c6a84
7 changed files with 224 additions and 44 deletions

View File

@ -81,6 +81,7 @@ fn main() {
sample_pos(
config,
sampler,
index,
samples,
uniform_idx_as_vec2(map_size_lg, posi),
)

View File

@ -1626,6 +1626,8 @@ impl Site {
}
pub fn is_castle(&self) -> bool { matches!(self.kind, SiteKind::Castle) }
pub fn is_bridge(&self) -> bool { matches!(self.kind, SiteKind::Bridge(_, _)) }
}
#[derive(PartialEq, Eq, Debug, Clone)]

View File

@ -1,7 +1,7 @@
use crate::{
column::ColumnSample,
sim::{RiverKind, WorldSim},
CONFIG,
CONFIG, IndexRef, site::SiteKind,
};
use common::{
terrain::{
@ -71,6 +71,7 @@ pub fn sample_wpos(config: &MapConfig, sampler: &WorldSim, wpos: Vec2<i32>) -> f
pub fn sample_pos(
config: &MapConfig,
sampler: &WorldSim,
index: IndexRef,
samples: Option<&[Option<ColumnSample>]>,
pos: Vec2<i32>,
) -> MapSample {
@ -102,6 +103,7 @@ pub fn sample_pos(
river_kind,
spline_derivative,
is_path,
is_bridge,
) = sampler
.get(pos)
.map(|sample| {
@ -116,6 +118,17 @@ pub fn sample_pos(
sample.river.river_kind,
sample.river.spline_derivative,
sample.path.0.is_way(),
sample.sites.iter().any(|site| match &index.sites.get(*site).kind {
SiteKind::Bridge(bridge) => if let Some(plot) = bridge.wpos_tile(TerrainChunkSize::center_wpos(pos)).plot {
match bridge.plot(plot).kind {
crate::site2::PlotKind::Bridge(_) => true,
_ => false
}
} else {
false
},
_ => false,
}),
)
})
.unwrap_or((
@ -129,6 +142,7 @@ pub fn sample_pos(
None,
Vec2::zero(),
false,
false,
));
let humidity = humidity.clamp(0.0, 1.0);
@ -246,7 +260,9 @@ pub fn sample_pos(
}
};
// TODO: Make principled.
let rgb = if is_path {
let rgb = if is_bridge {
Rgb::new(0x80, 0x80, 0x80)
} else if is_path {
Rgb::new(0x37, 0x29, 0x23)
} else {
rgb

View File

@ -28,7 +28,7 @@ pub(crate) use self::{
use crate::{
all::{Environment, ForestKind, TreeAttr},
block::BlockGen,
civ::{Place, PointOfInterest},
civ::{Place, PointOfInterest, self},
column::ColumnGen,
layer::spot::Spot,
site::Site,
@ -1657,7 +1657,7 @@ impl WorldSim {
map_config.is_shaded = false;
map_config.generate(
|pos| sample_pos(&map_config, self, Some(&samples_data), pos),
|pos| sample_pos(&map_config, self, index, Some(&samples_data), pos),
|pos| sample_wpos(&map_config, self, pos),
|pos, (r, g, b, _a)| {
// We currently ignore alpha and replace it with the height at pos, scaled to

View File

@ -1058,40 +1058,6 @@ impl Site {
hard_alt: None,
});
let size = (1.5 + rng.gen::<f32>().powf(5.0) * 1.0).round() as u32;
if let Some((aabr, door_tile, door_dir)) = attempt(32, || {
site.find_roadside_aabr(
&mut rng,
4..(size + 1).pow(2),
Extent2::broadcast(size),
)
}) {
let house = plot::House::generate(
land,
&mut reseed(&mut rng),
&site,
door_tile,
door_dir,
aabr,
);
let house_alt = house.alt;
let plot = site.create_plot(Plot {
kind: PlotKind::House(house),
root_tile: aabr.center(),
tiles: aabr_tiles(aabr).collect(),
seed: rng.gen(),
});
site.blit_aabr(aabr, Tile {
kind: TileKind::Building,
plot: Some(plot),
hard_alt: Some(house_alt),
});
} else {
site.make_plaza(land, &mut rng);
}
site
}

View File

@ -11,10 +11,33 @@ enum RoofKind {
Hipped,
}
struct HeightenedViaduct {
slope_inv: i32,
bridge_start_offset: i32,
vault_spacing: i32,
vault_size: (i32, i32),
side_vault_size: (i32, i32),
holes: bool,
}
impl HeightenedViaduct {
fn random(rng: &mut impl Rng) -> Self {
Self {
slope_inv: rng.gen_range(6..=8),
bridge_start_offset: rng.gen_range(5..=12),
vault_spacing: rng.gen_range(3..=4),
vault_size: *[(3, 16), (1, 4), (1, 4), (1, 4), (5, 32), (5, 32)].choose(rng).unwrap(),
side_vault_size: *[(4, 5), (7, 10), (7, 10), (13, 20)].choose(rng).unwrap(),
holes: rng.gen_bool(0.5),
}
}
}
enum BridgeKind {
Flat,
Tower(RoofKind),
Short,
HeightenedViaduct(HeightenedViaduct),
}
fn aabb(min: Vec3<i32>, max: Vec3<i32>) -> Aabb<i32> {
@ -180,6 +203,169 @@ fn render_flat(bridge: &Bridge, painter: &Painter) {
.fill(rock);
}
fn render_heightened_viaduct(bridge: &Bridge, painter: &Painter, data: &HeightenedViaduct) {
let rock = Fill::Block(Block::new(BlockKind::Rock, Rgb::gray(50)));
let light_rock = Fill::Block(Block::new(BlockKind::Rock, Rgb::gray(130)));
let orth_dir = bridge.dir.orthogonal();
let orthogonal = orth_dir.to_vec2();
let forward = bridge.dir.to_vec2();
let slope_inv = data.slope_inv;
let len = (bridge.start.xy() - bridge.end.xy())
.map(|e| e.abs())
.reduce_max();
let bridge_start_z = bridge.end.z + data.bridge_start_offset;
let bridge_top = bridge_start_z + len / slope_inv / 2;
// painter.ramp(aabb(
// bridge.start - side,
// (bridge.start.xy() + side + forward * (bridge_start_z -
// bridge.start.z)).with_z(bridge_start_z), ), bridge_start_z -
// bridge.start.z, bridge.dir).fill(rock);
let bridge_width = bridge.width;
let side = orthogonal * bridge_width;
let aabr = Aabr {
min: bridge.start.xy() - side,
max: bridge.end.xy() + side,
}
.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 under = bridge.center.z - 15;
let bridge_prim = |bridge_width: i32| {
let side = orthogonal * bridge_width;
let aabr = Aabr {
min: bridge.start.xy() - side,
max: bridge.end.xy() + side,
}
.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 [bridge_start, bridge_end] = bridge
.dir
.split_aabr(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());
painter.ramp(
aabb(aabr.min.with_z(zmin), aabr.max.with_z(zmax)),
inset,
dir,
)
};
ramp_in_aabr(start_aabr, bridge.dir, bridge.start.z, bridge_start_z)
.union(
ramp_in_aabr(end_aabr, -bridge.dir, bridge.end.z, bridge_start_z)
.union(ramp_in_aabr(
bridge_start,
bridge.dir,
bridge_start_z + 1,
bridge_top,
))
.union(ramp_in_aabr(
bridge_end,
-bridge.dir,
bridge_start_z + 1,
bridge_top,
)),
)
.union(
painter
.aabb(aabb(
start_aabr.min.with_z(under),
start_aabr.max.with_z(bridge.start.z - 1),
))
.union(painter.aabb(aabb(
end_aabr.min.with_z(under),
end_aabr.max.with_z(bridge.end.z - 1),
))),
)
.union(painter.aabb(aabb(
bridge_aabr.min.with_z(under),
bridge_aabr.max.with_z(bridge_start_z),
)))
};
let b = bridge_prim(bridge_width - 1);
let b = b.without(b.translate(-Vec3::unit_z()));
let c = bridge_aabr.center();
let len = bridge.dir.select(bridge_aabr.size());
let vault_size = data.vault_size.0 * len / data.vault_size.1;
let side_vault = data.side_vault_size.0 * vault_size / data.side_vault_size.1;
let vertical = 5;
let spacing = data.vault_spacing;
let vault_top = bridge_top - vertical;
let side_vault_top = vault_top - (vault_size + spacing + 1 + side_vault) / slope_inv;
let side_vault_offset = vault_size + spacing + 1;
let mut remove = painter.vault(
aabb(
(c - side - forward * vault_size).with_z(under),
(c + side + forward * vault_size).with_z(vault_top),
),
orth_dir,
);
if side_vault * 2 + side_vault_offset < len / 2 + 5 {
remove = remove.union(
painter
.vault(
aabb(
(c - side + forward * side_vault_offset).with_z(under),
(c + side + forward * (side_vault * 2 + side_vault_offset))
.with_z(side_vault_top),
),
orth_dir,
)
.union(
painter.vault(
aabb(
(c - side - forward * side_vault_offset).with_z(under),
(c + side - forward * (side_vault * 2 + side_vault_offset))
.with_z(side_vault_top),
),
orth_dir,
),
),
);
if data.holes {
remove = remove.union(
painter.vault(aabb(
(c - side + forward * (vault_size + 1)).with_z(side_vault_top - 4),
(c + side + forward * (vault_size + spacing)).with_z(side_vault_top + 2),
), orth_dir).union(
painter.vault(aabb(
(c - side - forward * (vault_size + 1)).with_z(side_vault_top - 4),
(c + side - forward * (vault_size + spacing)).with_z(side_vault_top + 2),
), orth_dir)
)
);
}
}
bridge_prim(bridge_width)
.without(b)
.without(remove)
.fill(rock.clone());
b.translate(-Vec3::unit_z()).fill(light_rock.clone());
b.translate(Vec3::unit_z() * 5)
.without(b.translate(-Vec3::unit_z()))
.clear();
}
fn render_tower(bridge: &Bridge, painter: &Painter, roof_kind: &RoofKind) {
let rock = Fill::Block(Block::new(BlockKind::Rock, Rgb::gray(50)));
let wood = Fill::Block(Block::new(BlockKind::Wood, Rgb::new(40, 28, 20)));
@ -485,13 +671,15 @@ impl Bridge {
end,
center,
dir: Dir::from_vector(end.xy() - start.xy()),
kind: if end.z - start.z > 14 {
kind: if end.z - start.z > 17 {
BridgeKind::Tower(match rng.gen_range(0..=2) {
0 => RoofKind::Crenelated,
_ => RoofKind::Hipped,
})
} else if len < 40 {
BridgeKind::Short
} else if end.z - start.z < 5 && start.z - center.z < 16 {
BridgeKind::HeightenedViaduct(HeightenedViaduct::random(rng))
} else {
BridgeKind::Flat
},
@ -509,6 +697,7 @@ impl Structure for Bridge {
BridgeKind::Flat => render_flat(self, painter),
BridgeKind::Tower(roof) => render_tower(self, painter, roof),
BridgeKind::Short => render_short(self, painter),
BridgeKind::HeightenedViaduct(data) => render_heightened_viaduct(self, painter, data),
}
}
}

View File

@ -1,5 +1,7 @@
pub mod gradient;
use std::ops::{Add, Sub};
use rand::Rng;
use vek::*;
@ -168,7 +170,8 @@ impl Dir {
pub fn is_y(self) -> bool { matches!(self, Dir::Y | Dir::NegY) }
/// Returns the component that the direction is parallell to
pub fn select(self, vec: Vec2<i32>) -> i32 {
pub fn select(self, vec: impl Into<Vec2<i32>>) -> i32 {
let vec = vec.into();
match self {
Dir::X | Dir::NegX => vec.x,
Dir::Y | Dir::NegY => vec.y,
@ -177,7 +180,9 @@ impl Dir {
/// Select one component the direction is parallel to from vec and select
/// the other component from other
pub fn select_with(self, vec: Vec2<i32>, other: Vec2<i32>) -> Vec2<i32> {
pub fn select_with(self, vec: impl Into<Vec2<i32>>, other: impl Into<Vec2<i32>>) -> Vec2<i32> {
let vec = vec.into();
let other = other.into();
match self {
Dir::X | Dir::NegX => Vec2::new(vec.x, other.y),
Dir::Y | Dir::NegY => Vec2::new(other.x, vec.y),
@ -185,7 +190,7 @@ impl Dir {
}
/// Returns the side of an aabr that the direction is pointing to
pub fn select_aabr(self, aabr: Aabr<i32>) -> i32 {
pub fn select_aabr<T>(self, aabr: Aabr<T>) -> T {
match self {
Dir::X => aabr.max.x,
Dir::NegX => aabr.min.x,
@ -196,7 +201,8 @@ impl Dir {
/// Select one component from the side the direction is pointing to from
/// aabr and select the other component from other
pub fn select_aabr_with(self, aabr: Aabr<i32>, other: Vec2<i32>) -> Vec2<i32> {
pub fn select_aabr_with<T>(self, aabr: Aabr<T>, other: impl Into<Vec2<T>>) -> Vec2<T> {
let other = other.into();
match self {
Dir::X => Vec2::new(aabr.max.x, other.y),
Dir::NegX => Vec2::new(aabr.min.x, other.y),
@ -215,7 +221,7 @@ impl Dir {
}
}
pub fn split_aabr(self, aabr: Aabr<i32>, offset: i32) -> [Aabr<i32>; 2] {
pub fn split_aabr<T>(self, aabr: Aabr<T>, offset: T) -> [Aabr<T>; 2] where T: Copy + PartialOrd + Add<T, Output = T> + Sub<T, Output = T> {
match self {
Dir::X => aabr.split_at_x(aabr.min.x + offset),
Dir::Y => aabr.split_at_y(aabr.min.y + offset),