From 91ed3c6a84bc4692b02824cf6dfaf5ab5509c6a7 Mon Sep 17 00:00:00 2001 From: IsseW Date: Thu, 29 Sep 2022 17:35:48 +0200 Subject: [PATCH] draw on map --- world/examples/water.rs | 1 + world/src/civ/mod.rs | 2 + world/src/sim/map.rs | 20 +++- world/src/sim/mod.rs | 4 +- world/src/site2/mod.rs | 34 ------ world/src/site2/plot/bridge.rs | 191 ++++++++++++++++++++++++++++++++- world/src/site2/util/mod.rs | 16 ++- 7 files changed, 224 insertions(+), 44 deletions(-) diff --git a/world/examples/water.rs b/world/examples/water.rs index dfbab57437..1a023d2ecb 100644 --- a/world/examples/water.rs +++ b/world/examples/water.rs @@ -81,6 +81,7 @@ fn main() { sample_pos( config, sampler, + index, samples, uniform_idx_as_vec2(map_size_lg, posi), ) diff --git a/world/src/civ/mod.rs b/world/src/civ/mod.rs index 782885cac0..6f926830a8 100644 --- a/world/src/civ/mod.rs +++ b/world/src/civ/mod.rs @@ -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)] diff --git a/world/src/sim/map.rs b/world/src/sim/map.rs index a2b340f55d..d6184bc156 100644 --- a/world/src/sim/map.rs +++ b/world/src/sim/map.rs @@ -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) -> f pub fn sample_pos( config: &MapConfig, sampler: &WorldSim, + index: IndexRef, samples: Option<&[Option]>, pos: Vec2, ) -> 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 diff --git a/world/src/sim/mod.rs b/world/src/sim/mod.rs index aa0f981fe0..ea27af8096 100644 --- a/world/src/sim/mod.rs +++ b/world/src/sim/mod.rs @@ -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 diff --git a/world/src/site2/mod.rs b/world/src/site2/mod.rs index 44f310db54..274388c59c 100644 --- a/world/src/site2/mod.rs +++ b/world/src/site2/mod.rs @@ -1058,40 +1058,6 @@ impl Site { hard_alt: None, }); - - let size = (1.5 + rng.gen::().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 } diff --git a/world/src/site2/plot/bridge.rs b/world/src/site2/plot/bridge.rs index 4d87f1dc84..4aa6c74857 100644 --- a/world/src/site2/plot/bridge.rs +++ b/world/src/site2/plot/bridge.rs @@ -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, max: Vec3) -> Aabb { @@ -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, 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), } } } diff --git a/world/src/site2/util/mod.rs b/world/src/site2/util/mod.rs index a296936eb8..89b64de88f 100644 --- a/world/src/site2/util/mod.rs +++ b/world/src/site2/util/mod.rs @@ -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 { + pub fn select(self, vec: impl Into>) -> 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, other: Vec2) -> Vec2 { + pub fn select_with(self, vec: impl Into>, other: impl Into>) -> Vec2 { + 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 { + pub fn select_aabr(self, aabr: Aabr) -> 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, other: Vec2) -> Vec2 { + pub fn select_aabr_with(self, aabr: Aabr, other: impl Into>) -> Vec2 { + 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, offset: i32) -> [Aabr; 2] { + pub fn split_aabr(self, aabr: Aabr, offset: T) -> [Aabr; 2] where T: Copy + PartialOrd + Add + Sub { match self { Dir::X => aabr.split_at_x(aabr.min.x + offset), Dir::Y => aabr.split_at_y(aabr.min.y + offset),