mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
simple hang bridge
This commit is contained in:
@ -15,7 +15,7 @@ use common::{
|
|||||||
vol::ReadVol,
|
vol::ReadVol,
|
||||||
};
|
};
|
||||||
use num::cast::AsPrimitive;
|
use num::cast::AsPrimitive;
|
||||||
use std::{cell::RefCell, sync::Arc};
|
use std::{cell::RefCell, sync::Arc, ops::RangeBounds};
|
||||||
use vek::*;
|
use vek::*;
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
@ -289,13 +289,10 @@ impl Fill {
|
|||||||
- ((pos.z - aabb.min.z) as f32 + 0.5) / (aabb.max.z - aabb.min.z) as f32
|
- ((pos.z - aabb.min.z) as f32 + 0.5) / (aabb.max.z - aabb.min.z) as f32
|
||||||
},
|
},
|
||||||
Primitive::Cylinder(aabb) => {
|
Primitive::Cylinder(aabb) => {
|
||||||
|
let fpos = pos.as_::<f32>().xy() - aabb.as_::<f32>().center().xy();
|
||||||
|
let size = Vec3::from(aabb.size().as_::<f32>()).xy();
|
||||||
(aabb.min.z..aabb.max.z).contains(&pos.z)
|
(aabb.min.z..aabb.max.z).contains(&pos.z)
|
||||||
&& (pos
|
&& (2.0 * fpos / size).magnitude_squared() <= 1.0
|
||||||
.xy()
|
|
||||||
.as_()
|
|
||||||
.distance_squared(aabb.as_().center().xy() - 0.5)
|
|
||||||
as f32)
|
|
||||||
< (aabb.size().w.min(aabb.size().h) as f32 / 2.0).powi(2)
|
|
||||||
},
|
},
|
||||||
Primitive::Cone(aabb) => {
|
Primitive::Cone(aabb) => {
|
||||||
(aabb.min.z..aabb.max.z).contains(&pos.z)
|
(aabb.min.z..aabb.max.z).contains(&pos.z)
|
||||||
@ -390,9 +387,9 @@ impl Fill {
|
|||||||
},
|
},
|
||||||
Primitive::Scale(prim, vec) => {
|
Primitive::Scale(prim, vec) => {
|
||||||
let center =
|
let center =
|
||||||
Self::get_bounds(tree, *prim).center().as_::<f32>() - Vec3::broadcast(0.5);
|
Self::get_bounds(tree, *prim).as_::<f32>().center();
|
||||||
let fpos = pos.as_::<f32>();
|
let fpos = pos.as_::<f32>();
|
||||||
let spos = (center + ((center - fpos) / vec))
|
let spos = (center + ((fpos - center) / vec))
|
||||||
.map(|x| x.round())
|
.map(|x| x.round())
|
||||||
.as_::<i32>();
|
.as_::<i32>();
|
||||||
Self::contains_at(tree, *prim, spos)
|
Self::contains_at(tree, *prim, spos)
|
||||||
@ -782,6 +779,20 @@ impl Painter {
|
|||||||
self.prim(Primitive::Cylinder(aabb.made_valid()))
|
self.prim(Primitive::Cylinder(aabb.made_valid()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Returns a `PrimitiveRef` of the largest horizontal cylinder that fits in the
|
||||||
|
/// provided Aabb.
|
||||||
|
pub fn horizontal_cylinder(&self, aabb: Aabb<i32>, dir: Dir) -> PrimitiveRef {
|
||||||
|
let aabr = Aabr::from(aabb);
|
||||||
|
let length = dir.select(aabr.size());
|
||||||
|
let height = aabb.max.z - aabb.min.z;
|
||||||
|
let aabb = Aabb {
|
||||||
|
min: (aabr.min - dir.abs().to_vec2() * height).with_z(aabb.min.z),
|
||||||
|
max: (dir.abs().select_with(aabr.min, aabr.max)).with_z(aabb.min.z + length),
|
||||||
|
};
|
||||||
|
self.cylinder(aabb).rotate_about((-dir.abs()).from_z_mat3(), aabr.min.with_z(aabb.min.z))
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns a `PrimitiveRef` of a cylinder using a radius check where a
|
/// Returns a `PrimitiveRef` of a cylinder using a radius check where a
|
||||||
/// radius and origin are parameters instead of a bounding box.
|
/// radius and origin are parameters instead of a bounding box.
|
||||||
pub fn cylinder_with_radius(
|
pub fn cylinder_with_radius(
|
||||||
@ -1169,6 +1180,21 @@ impl Painter {
|
|||||||
prim
|
prim
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn column(&self, point: Vec2<i32>, range: impl RangeBounds<i32>) -> PrimitiveRef {
|
||||||
|
self.aabb(Aabb {
|
||||||
|
min: point.with_z(match range.start_bound() {
|
||||||
|
std::ops::Bound::Included(n) => *n,
|
||||||
|
std::ops::Bound::Excluded(n) => n + 1,
|
||||||
|
std::ops::Bound::Unbounded => i32::MIN,
|
||||||
|
}),
|
||||||
|
max: (point + 1).with_z(match range.end_bound() {
|
||||||
|
std::ops::Bound::Included(n) => n + 1,
|
||||||
|
std::ops::Bound::Excluded(n) => *n,
|
||||||
|
std::ops::Bound::Unbounded => i32::MAX,
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/// The area that the canvas is currently rendering.
|
/// The area that the canvas is currently rendering.
|
||||||
pub fn render_aabr(&self) -> Aabr<i32> { self.render_area }
|
pub fn render_aabr(&self) -> Aabr<i32> { self.render_area }
|
||||||
|
|
||||||
@ -1250,7 +1276,7 @@ pub trait PrimitiveTransform {
|
|||||||
/// Scales the primitive along each axis by the x, y, and z components of
|
/// Scales the primitive along each axis by the x, y, and z components of
|
||||||
/// the `scale` vector respectively.
|
/// the `scale` vector respectively.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn scale(self, scale: Vec3<f32>) -> Self;
|
fn scale(self, scale: Vec3<impl AsPrimitive<f32>>) -> Self;
|
||||||
/// Returns a `PrimitiveRef` of the primitive in addition to the same
|
/// Returns a `PrimitiveRef` of the primitive in addition to the same
|
||||||
/// primitive translated by `offset` and repeated `count` times, each time
|
/// primitive translated by `offset` and repeated `count` times, each time
|
||||||
/// translated by an additional offset.
|
/// translated by an additional offset.
|
||||||
@ -1267,7 +1293,7 @@ impl<'a> PrimitiveTransform for PrimitiveRef<'a> {
|
|||||||
self.painter.prim(Primitive::rotate_about(self, rot, point))
|
self.painter.prim(Primitive::rotate_about(self, rot, point))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn scale(self, scale: Vec3<f32>) -> Self { self.painter.prim(Primitive::scale(self, scale)) }
|
fn scale(self, scale: Vec3<impl AsPrimitive<f32>>) -> Self { self.painter.prim(Primitive::scale(self, scale.as_())) }
|
||||||
|
|
||||||
fn repeat(self, offset: Vec3<i32>, count: u32) -> Self {
|
fn repeat(self, offset: Vec3<i32>, count: u32) -> Self {
|
||||||
self.painter.prim(Primitive::repeat(self, offset, count))
|
self.painter.prim(Primitive::repeat(self, offset, count))
|
||||||
@ -1289,7 +1315,7 @@ impl<'a, const N: usize> PrimitiveTransform for [PrimitiveRef<'a>; N] {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
fn scale(mut self, scale: Vec3<f32>) -> Self {
|
fn scale(mut self, scale: Vec3<impl AsPrimitive<f32>>) -> Self {
|
||||||
for prim in &mut self {
|
for prim in &mut self {
|
||||||
*prim = prim.scale(scale);
|
*prim = prim.scale(scale);
|
||||||
}
|
}
|
||||||
|
@ -1024,7 +1024,7 @@ impl Site {
|
|||||||
let start_tile = site.wpos_tile_pos(bridge.start.xy());
|
let start_tile = site.wpos_tile_pos(bridge.start.xy());
|
||||||
let end_tile = site.wpos_tile_pos(bridge.end.xy());
|
let end_tile = site.wpos_tile_pos(bridge.end.xy());
|
||||||
|
|
||||||
let width = (bridge.width + TILE_SIZE as i32 / 2) / TILE_SIZE as i32;
|
let width = (bridge.width() + TILE_SIZE as i32 / 2) / TILE_SIZE as i32;
|
||||||
let aabr = Aabr {
|
let aabr = Aabr {
|
||||||
min: start_tile.map2(end_tile, |a, b| a.min(b)) - orth * width,
|
min: start_tile.map2(end_tile, |a, b| a.min(b)) - orth * width,
|
||||||
max: start_tile.map2(end_tile, |a, b| a.max(b)) + 1 + orth * width,
|
max: start_tile.map2(end_tile, |a, b| a.max(b)) + 1 + orth * width,
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
use crate::{site2::gen::PrimitiveTransform, Land};
|
use crate::{site2::gen::PrimitiveTransform, Land};
|
||||||
use common::terrain::{BiomeKind, Block, BlockKind};
|
use common::{
|
||||||
|
generation::EntityInfo,
|
||||||
|
terrain::{BiomeKind, Block, BlockKind},
|
||||||
|
};
|
||||||
|
use num::integer::Roots;
|
||||||
use rand::prelude::*;
|
use rand::prelude::*;
|
||||||
use vek::*;
|
use vek::*;
|
||||||
|
|
||||||
@ -26,7 +30,9 @@ impl HeightenedViaduct {
|
|||||||
slope_inv: rng.gen_range(6..=8),
|
slope_inv: rng.gen_range(6..=8),
|
||||||
bridge_start_offset: rng.gen_range(5..=12),
|
bridge_start_offset: rng.gen_range(5..=12),
|
||||||
vault_spacing: rng.gen_range(3..=4),
|
vault_spacing: rng.gen_range(3..=4),
|
||||||
vault_size: *[(3, 16), (1, 4), (1, 4), (1, 4), (5, 32), (5, 32)].choose(rng).unwrap(),
|
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(),
|
side_vault_size: *[(4, 5), (7, 10), (7, 10), (13, 20)].choose(rng).unwrap(),
|
||||||
holes: rng.gen_bool(0.5),
|
holes: rng.gen_bool(0.5),
|
||||||
}
|
}
|
||||||
@ -38,6 +44,42 @@ enum BridgeKind {
|
|||||||
Tower(RoofKind),
|
Tower(RoofKind),
|
||||||
Short,
|
Short,
|
||||||
HeightenedViaduct(HeightenedViaduct),
|
HeightenedViaduct(HeightenedViaduct),
|
||||||
|
HangBridge,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BridgeKind {
|
||||||
|
fn random(
|
||||||
|
rng: &mut impl Rng,
|
||||||
|
start: Vec3<i32>,
|
||||||
|
center: Vec3<i32>,
|
||||||
|
end: Vec3<i32>,
|
||||||
|
) -> BridgeKind {
|
||||||
|
let len = (start.xy() - end.xy()).map(|e| e.abs()).reduce_max();
|
||||||
|
(0..=3)
|
||||||
|
.filter_map(|bridge| match bridge {
|
||||||
|
0 if end.z - start.z > 17 => Some(BridgeKind::Tower(match rng.gen_range(0..=2) {
|
||||||
|
0 => RoofKind::Crenelated,
|
||||||
|
_ => RoofKind::Hipped,
|
||||||
|
})),
|
||||||
|
1 if len < 40 => Some(BridgeKind::Short),
|
||||||
|
2 if end.z - start.z < 5 && start.z - center.z < 16 => Some(
|
||||||
|
BridgeKind::HeightenedViaduct(HeightenedViaduct::random(rng)),
|
||||||
|
),
|
||||||
|
3 if end.z - start.z < 9 && start.z - center.z > 10 => Some(BridgeKind::HangBridge),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.into_iter()
|
||||||
|
.choose(rng)
|
||||||
|
.unwrap_or(BridgeKind::Flat)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn width(&self) -> i32 {
|
||||||
|
match self {
|
||||||
|
BridgeKind::HangBridge => 2,
|
||||||
|
_ => 8,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn aabb(min: Vec3<i32>, max: Vec3<i32>) -> Aabb<i32> {
|
fn aabb(min: Vec3<i32>, max: Vec3<i32>) -> Aabb<i32> {
|
||||||
@ -162,7 +204,7 @@ fn render_flat(bridge: &Bridge, painter: &Painter) {
|
|||||||
let size = tweak!(8);
|
let size = tweak!(8);
|
||||||
let hole = painter
|
let hole = painter
|
||||||
.cylinder(aabb(
|
.cylinder(aabb(
|
||||||
bridge.center.with_z(bridge.end.z - 3 - bridge.width * 2) - Vec2::broadcast(size),
|
bridge.center.with_z(bridge.end.z - 3 - bridge.width() * 2) - Vec2::broadcast(size),
|
||||||
bridge.center.with_z(bridge.end.z + 2) + Vec2::broadcast(size),
|
bridge.center.with_z(bridge.end.z + 2) + Vec2::broadcast(size),
|
||||||
))
|
))
|
||||||
.rotate_about(
|
.rotate_about(
|
||||||
@ -170,7 +212,7 @@ fn render_flat(bridge: &Bridge, painter: &Painter) {
|
|||||||
bridge
|
bridge
|
||||||
.center
|
.center
|
||||||
.as_()
|
.as_()
|
||||||
.with_z(bridge.end.z as f32 - 1.5 - bridge.width as f32),
|
.with_z(bridge.end.z as f32 - 1.5 - bridge.width() as f32),
|
||||||
)
|
)
|
||||||
.scale(
|
.scale(
|
||||||
bridge.dir.abs().to_vec3().as_()
|
bridge.dir.abs().to_vec3().as_()
|
||||||
@ -182,9 +224,9 @@ fn render_flat(bridge: &Bridge, painter: &Painter) {
|
|||||||
.ramp(
|
.ramp(
|
||||||
aabb(
|
aabb(
|
||||||
bridge.start.with_z(bridge.start.z - inset)
|
bridge.start.with_z(bridge.start.z - inset)
|
||||||
- orthogonal * bridge.width
|
- orthogonal * bridge.width()
|
||||||
- forward * inset,
|
- forward * inset,
|
||||||
bridge.start.with_z(bridge.end.z) + orthogonal * bridge.width + forward * dz,
|
bridge.start.with_z(bridge.end.z) + orthogonal * bridge.width() + forward * dz,
|
||||||
),
|
),
|
||||||
dz + inset + 1,
|
dz + inset + 1,
|
||||||
bridge.dir,
|
bridge.dir,
|
||||||
@ -192,10 +234,10 @@ fn render_flat(bridge: &Bridge, painter: &Painter) {
|
|||||||
.union(
|
.union(
|
||||||
painter
|
painter
|
||||||
.aabb(aabb(
|
.aabb(aabb(
|
||||||
bridge.start.with_z(bridge.end.z - 3 - size) - orthogonal * bridge.width
|
bridge.start.with_z(bridge.end.z - 3 - size) - orthogonal * bridge.width()
|
||||||
+ forward * dz,
|
+ forward * dz,
|
||||||
bridge.start.with_z(bridge.end.z)
|
bridge.start.with_z(bridge.end.z)
|
||||||
+ orthogonal * bridge.width
|
+ orthogonal * bridge.width()
|
||||||
+ forward * forward * (bridge.end.xy() - bridge.start.xy()),
|
+ forward * forward * (bridge.end.xy() - bridge.start.xy()),
|
||||||
))
|
))
|
||||||
.without(hole),
|
.without(hole),
|
||||||
@ -226,7 +268,7 @@ fn render_heightened_viaduct(bridge: &Bridge, painter: &Painter, data: &Heighten
|
|||||||
// bridge.start.z)).with_z(bridge_start_z), ), bridge_start_z -
|
// bridge.start.z)).with_z(bridge_start_z), ), bridge_start_z -
|
||||||
// bridge.start.z, bridge.dir).fill(rock);
|
// bridge.start.z, bridge.dir).fill(rock);
|
||||||
|
|
||||||
let bridge_width = bridge.width;
|
let bridge_width = bridge.width();
|
||||||
let side = orthogonal * bridge_width;
|
let side = orthogonal * bridge_width;
|
||||||
|
|
||||||
let aabr = Aabr {
|
let aabr = Aabr {
|
||||||
@ -317,6 +359,14 @@ fn render_heightened_viaduct(bridge: &Bridge, painter: &Painter, data: &Heighten
|
|||||||
orth_dir,
|
orth_dir,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let mut rng = thread_rng();
|
||||||
|
if rng.gen_bool(0.1) {
|
||||||
|
painter.spawn(
|
||||||
|
EntityInfo::at(c.with_z(bridge.center.z).as_())
|
||||||
|
.with_asset_expect("common.entity.wild.aggressive.swamp_troll", &mut rng),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if side_vault * 2 + side_vault_offset < len / 2 + 5 {
|
if side_vault * 2 + side_vault_offset < len / 2 + 5 {
|
||||||
remove = remove.union(
|
remove = remove.union(
|
||||||
painter
|
painter
|
||||||
@ -342,32 +392,49 @@ fn render_heightened_viaduct(bridge: &Bridge, painter: &Painter, data: &Heighten
|
|||||||
|
|
||||||
if data.holes {
|
if data.holes {
|
||||||
remove = remove.union(
|
remove = remove.union(
|
||||||
painter.vault(aabb(
|
painter
|
||||||
|
.vault(
|
||||||
|
aabb(
|
||||||
(c - side + forward * (vault_size + 1)).with_z(side_vault_top - 4),
|
(c - side + forward * (vault_size + 1)).with_z(side_vault_top - 4),
|
||||||
(c + side + forward * (vault_size + spacing)).with_z(side_vault_top + 2),
|
(c + side + forward * (vault_size + spacing))
|
||||||
), orth_dir).union(
|
.with_z(side_vault_top + 2),
|
||||||
painter.vault(aabb(
|
),
|
||||||
(c - side - forward * (vault_size + 1)).with_z(side_vault_top - 4),
|
orth_dir,
|
||||||
(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)
|
bridge_prim(bridge_width).without(remove).fill(rock.clone());
|
||||||
.without(remove)
|
|
||||||
.fill(rock.clone());
|
|
||||||
b.translate(-Vec3::unit_z()).fill(light_rock.clone());
|
b.translate(-Vec3::unit_z()).fill(light_rock.clone());
|
||||||
|
|
||||||
br.translate(Vec3::unit_z() * 5)
|
br.translate(Vec3::unit_z() * 5)
|
||||||
.without(br.translate(-Vec3::unit_z()))
|
.without(br.translate(-Vec3::unit_z()))
|
||||||
.clear();
|
.clear();
|
||||||
|
|
||||||
|
|
||||||
let place_lights = |center: Vec3<i32>| {
|
let place_lights = |center: Vec3<i32>| {
|
||||||
painter.sprite(orth_dir.select_aabr_with(bridge_aabr, center.xy()).with_z(center.z), SpriteKind::FireBowlGround);
|
painter.sprite(
|
||||||
painter.sprite((-orth_dir).select_aabr_with(bridge_aabr, center.xy()).with_z(center.z), SpriteKind::FireBowlGround);
|
orth_dir
|
||||||
|
.select_aabr_with(bridge_aabr, center.xy())
|
||||||
|
.with_z(center.z),
|
||||||
|
SpriteKind::FireBowlGround,
|
||||||
|
);
|
||||||
|
painter.sprite(
|
||||||
|
(-orth_dir)
|
||||||
|
.select_aabr_with(bridge_aabr, center.xy())
|
||||||
|
.with_z(center.z),
|
||||||
|
SpriteKind::FireBowlGround,
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
place_lights(bridge_aabr.center().with_z(bridge_top + 1));
|
place_lights(bridge_aabr.center().with_z(bridge_top + 1));
|
||||||
@ -377,10 +444,20 @@ fn render_heightened_viaduct(bridge: &Bridge, painter: &Painter, data: &Heighten
|
|||||||
|
|
||||||
let place_lights = |i: i32| {
|
let place_lights = |i: i32| {
|
||||||
let offset = i * light_spacing;
|
let offset = i * light_spacing;
|
||||||
let z = bridge_start_z + 1 + (offset + if len / 2 % 2 == 0 { 4 } else { 3 }) / (slope_inv - 1);
|
let z =
|
||||||
|
bridge_start_z + 1 + (offset + if len / 2 % 2 == 0 { 4 } else { 3 }) / (slope_inv - 1);
|
||||||
|
|
||||||
place_lights((bridge.dir.select_aabr_with(bridge_aabr, bridge_aabr.center()) - forward * offset).with_z(z));
|
place_lights(
|
||||||
place_lights(((-bridge.dir).select_aabr_with(bridge_aabr, bridge_aabr.center()) + forward * offset).with_z(z));
|
(bridge
|
||||||
|
.dir
|
||||||
|
.select_aabr_with(bridge_aabr, bridge_aabr.center())
|
||||||
|
- forward * offset)
|
||||||
|
.with_z(z),
|
||||||
|
);
|
||||||
|
place_lights(
|
||||||
|
((-bridge.dir).select_aabr_with(bridge_aabr, bridge_aabr.center()) + forward * offset)
|
||||||
|
.with_z(z),
|
||||||
|
);
|
||||||
};
|
};
|
||||||
for i in 0..num_lights {
|
for i in 0..num_lights {
|
||||||
place_lights(i);
|
place_lights(i);
|
||||||
@ -603,10 +680,112 @@ fn render_tower(bridge: &Bridge, painter: &Painter, roof_kind: &RoofKind) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn render_hang(bridge: &Bridge, painter: &Painter) {
|
||||||
|
let orth_dir = bridge.dir.orthogonal();
|
||||||
|
|
||||||
|
let orthogonal = orth_dir.to_vec2();
|
||||||
|
let forward = bridge.dir.to_vec2();
|
||||||
|
|
||||||
|
let rock = Fill::Block(Block::new(BlockKind::Rock, Rgb::gray(50)));
|
||||||
|
let wood = Fill::Block(Block::new(BlockKind::Wood, Rgb::new(133, 94, 66)));
|
||||||
|
|
||||||
|
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 top_offset = 4;
|
||||||
|
let top = bridge.end.z + top_offset;
|
||||||
|
|
||||||
|
let [ramp_f, aabr] = bridge.dir.split_aabr(aabr, top - bridge.start.z + 1);
|
||||||
|
|
||||||
|
painter
|
||||||
|
.aabb(aabb(
|
||||||
|
ramp_f.min.with_z(bridge.start.z - 10),
|
||||||
|
ramp_f.max.with_z(bridge.start.z),
|
||||||
|
))
|
||||||
|
.fill(rock.clone());
|
||||||
|
painter
|
||||||
|
.ramp(
|
||||||
|
aabb(ramp_f.min.with_z(bridge.start.z), ramp_f.max.with_z(top)),
|
||||||
|
top - bridge.start.z + 1,
|
||||||
|
bridge.dir,
|
||||||
|
)
|
||||||
|
.fill(rock.clone());
|
||||||
|
|
||||||
|
let [ramp_b, aabr] = (-bridge.dir).split_aabr(aabr, top_offset + 1);
|
||||||
|
painter
|
||||||
|
.aabb(aabb(
|
||||||
|
ramp_b.min.with_z(bridge.end.z - 10),
|
||||||
|
ramp_b.max.with_z(bridge.end.z),
|
||||||
|
))
|
||||||
|
.fill(rock.clone());
|
||||||
|
painter
|
||||||
|
.ramp(
|
||||||
|
aabb(ramp_b.min.with_z(bridge.end.z), ramp_b.max.with_z(top)),
|
||||||
|
top - bridge.end.z,
|
||||||
|
-bridge.dir,
|
||||||
|
)
|
||||||
|
.fill(rock.clone());
|
||||||
|
|
||||||
|
let len = bridge.dir.select(aabr.size());
|
||||||
|
|
||||||
|
let h = 3 * len.sqrt() / 4;
|
||||||
|
|
||||||
|
let x = len / 2;
|
||||||
|
|
||||||
|
let xsqr = (x * x) as f32;
|
||||||
|
let hsqr = (h * h) as f32;
|
||||||
|
let w = ((xsqr + (xsqr * (4.0 * hsqr + xsqr)).sqrt()) / 2.0).sqrt().ceil() + 1.0;
|
||||||
|
|
||||||
|
|
||||||
|
let bottom = top - (h - (hsqr - hsqr * x as f32 / w).sqrt().ceil() as i32);
|
||||||
|
|
||||||
|
let w = w as i32;
|
||||||
|
let c = aabr.center();
|
||||||
|
|
||||||
|
let cylinder = painter
|
||||||
|
.horizontal_cylinder(
|
||||||
|
aabb(
|
||||||
|
(c - forward * w - side).with_z(bottom),
|
||||||
|
(c + forward * w + side).with_z(bottom + h * 2),
|
||||||
|
),
|
||||||
|
orth_dir,
|
||||||
|
)
|
||||||
|
.intersect(painter.aabb(aabb(aabr.min.with_z(bottom), aabr.max.with_z(bottom + h * 2))));
|
||||||
|
|
||||||
|
cylinder.fill(wood.clone());
|
||||||
|
|
||||||
|
cylinder.translate(Vec3::unit_z()).clear();
|
||||||
|
|
||||||
|
let edges = cylinder
|
||||||
|
.without(cylinder.translate(Vec3::unit_z()))
|
||||||
|
.without(painter.aabb(aabb(
|
||||||
|
(c - forward * w - orthogonal * (bridge_width - 1)).with_z(bottom),
|
||||||
|
(c + forward * w + orthogonal * (bridge_width - 1)).with_z(bottom + h * 2),
|
||||||
|
)));
|
||||||
|
|
||||||
|
edges
|
||||||
|
.translate(Vec3::unit_z())
|
||||||
|
.fill(Fill::Sprite(SpriteKind::Rope));
|
||||||
|
|
||||||
|
edges.translate(Vec3::unit_z() * 2).fill(wood.clone());
|
||||||
|
|
||||||
|
let column_height = 3;
|
||||||
|
let column_range = top..=top + column_height;
|
||||||
|
painter.column(bridge.dir.select_aabr_with(ramp_f, ramp_f.min), column_range.clone()).fill(rock.clone());
|
||||||
|
painter.column(bridge.dir.select_aabr_with(ramp_f, ramp_f.max), column_range.clone()).fill(rock.clone());
|
||||||
|
painter.column((-bridge.dir).select_aabr_with(ramp_b, ramp_b.min), column_range.clone()).fill(rock.clone());
|
||||||
|
painter.column((-bridge.dir).select_aabr_with(ramp_b, ramp_b.max), column_range.clone()).fill(rock.clone());
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Bridge {
|
pub struct Bridge {
|
||||||
pub(crate) start: Vec3<i32>,
|
pub(crate) start: Vec3<i32>,
|
||||||
pub(crate) end: Vec3<i32>,
|
pub(crate) end: Vec3<i32>,
|
||||||
pub(crate) width: i32,
|
|
||||||
pub(crate) dir: Dir,
|
pub(crate) dir: Dir,
|
||||||
center: Vec3<i32>,
|
center: Vec3<i32>,
|
||||||
kind: BridgeKind,
|
kind: BridgeKind,
|
||||||
@ -658,17 +837,6 @@ impl Bridge {
|
|||||||
} else {
|
} else {
|
||||||
break test_start.with_z(last_alt);
|
break test_start.with_z(last_alt);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
let alt = land.get_alt_approx(test_start + dir);
|
|
||||||
let is_water = land.get_chunk_wpos(test_start + dir * 5).map_or(false, |chunk| chunk.river.river_kind.is_some());
|
|
||||||
if is_water || last_alt - alt as i32 > 1 || start.z - alt as i32 > 5 {
|
|
||||||
break test_start.with_z(last_alt);
|
|
||||||
}
|
|
||||||
last_alt = alt as i32;
|
|
||||||
|
|
||||||
test_start += dir;
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -684,32 +852,20 @@ impl Bridge {
|
|||||||
|
|
||||||
let center = (start.xy() + end.xy()) / 2;
|
let center = (start.xy() + end.xy()) / 2;
|
||||||
let center = center.with_z(land.get_alt_approx(center) as i32);
|
let center = center.with_z(land.get_alt_approx(center) as i32);
|
||||||
|
let bridge = BridgeKind::random(rng, start, center, end);
|
||||||
let len = (start.xy() - end.xy()).map(|e| e.abs()).reduce_max();
|
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
start,
|
start,
|
||||||
end,
|
end,
|
||||||
center,
|
center,
|
||||||
dir: Dir::from_vector(end.xy() - start.xy()),
|
dir: Dir::from_vector(end.xy() - start.xy()),
|
||||||
kind: if end.z - start.z > 17 {
|
kind: bridge,
|
||||||
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
|
|
||||||
},
|
|
||||||
width: 8,
|
|
||||||
biome: land
|
biome: land
|
||||||
.get_chunk_wpos(center.xy())
|
.get_chunk_wpos(center.xy())
|
||||||
.map_or(BiomeKind::Void, |chunk| chunk.get_biome()),
|
.map_or(BiomeKind::Void, |chunk| chunk.get_biome()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn width(&self) -> i32 { self.kind.width() }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Structure for Bridge {
|
impl Structure for Bridge {
|
||||||
@ -719,6 +875,7 @@ impl Structure for Bridge {
|
|||||||
BridgeKind::Tower(roof) => render_tower(self, painter, roof),
|
BridgeKind::Tower(roof) => render_tower(self, painter, roof),
|
||||||
BridgeKind::Short => render_short(self, painter),
|
BridgeKind::Short => render_short(self, painter),
|
||||||
BridgeKind::HeightenedViaduct(data) => render_heightened_viaduct(self, painter, data),
|
BridgeKind::HeightenedViaduct(data) => render_heightened_viaduct(self, painter, data),
|
||||||
|
BridgeKind::HangBridge => render_hang(self, painter),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user