mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Implement giant trees in site2
This commit is contained in:
parent
18f6077321
commit
54b69e37a5
@ -44,6 +44,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
- A 'point light glow' effect, making lanterns and other point lights more visually pronounced
|
- A 'point light glow' effect, making lanterns and other point lights more visually pronounced
|
||||||
- Generate random name for site2 sites
|
- Generate random name for site2 sites
|
||||||
- Shader dithering to remove banding from scenes with large colour gradients
|
- Shader dithering to remove banding from scenes with large colour gradients
|
||||||
|
- Convert giant trees to site2
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@ fn main() -> Result {
|
|||||||
CanvasInfo::with_mock_canvas_info(index.as_index_ref(), world.sim(), |canvas| {
|
CanvasInfo::with_mock_canvas_info(index.as_index_ref(), world.sim(), |canvas| {
|
||||||
for plot in site.plots() {
|
for plot in site.plots() {
|
||||||
if let PlotKind::Dungeon(dungeon) = plot.kind() {
|
if let PlotKind::Dungeon(dungeon) = plot.kind() {
|
||||||
let (prim_tree, fills) = dungeon.render_collect(&site, &canvas.land());
|
let (prim_tree, fills) = dungeon.render_collect(&site, canvas);
|
||||||
|
|
||||||
for (prim, fill) in fills {
|
for (prim, fill) in fills {
|
||||||
let aabb = fill.get_bounds(&prim_tree, prim);
|
let aabb = fill.get_bounds(&prim_tree, prim);
|
||||||
|
@ -103,7 +103,13 @@ impl Civs {
|
|||||||
let (kind, size) = match ctx.rng.gen_range(0..64) {
|
let (kind, size) = match ctx.rng.gen_range(0..64) {
|
||||||
0..=4 => (SiteKind::Castle, 3),
|
0..=4 => (SiteKind::Castle, 3),
|
||||||
5..=28 if index.features().site2 => (SiteKind::Refactor, 6),
|
5..=28 if index.features().site2 => (SiteKind::Refactor, 6),
|
||||||
29..=31 => (SiteKind::Tree, 4),
|
29..=31 => {
|
||||||
|
if index.features().site2 {
|
||||||
|
(SiteKind::GiantTree, 4)
|
||||||
|
} else {
|
||||||
|
(SiteKind::Tree, 4)
|
||||||
|
}
|
||||||
|
},
|
||||||
_ => (SiteKind::Dungeon, 0),
|
_ => (SiteKind::Dungeon, 0),
|
||||||
};
|
};
|
||||||
let loc = find_site_loc(&mut ctx, None, size, kind)?;
|
let loc = find_site_loc(&mut ctx, None, size, kind)?;
|
||||||
@ -129,6 +135,7 @@ impl Civs {
|
|||||||
SiteKind::Castle => (16i32, 5.0),
|
SiteKind::Castle => (16i32, 5.0),
|
||||||
SiteKind::Refactor => (0i32, 0.0),
|
SiteKind::Refactor => (0i32, 0.0),
|
||||||
SiteKind::Tree => (12i32, 8.0),
|
SiteKind::Tree => (12i32, 8.0),
|
||||||
|
SiteKind::GiantTree => (12i32, 8.0),
|
||||||
};
|
};
|
||||||
|
|
||||||
let (raise, raise_dist, make_waypoint): (f32, i32, bool) = match &site.kind {
|
let (raise, raise_dist, make_waypoint): (f32, i32, bool) = match &site.kind {
|
||||||
@ -207,6 +214,11 @@ impl Civs {
|
|||||||
SiteKind::Tree => {
|
SiteKind::Tree => {
|
||||||
WorldSite::tree(Tree::generate(wpos, &Land::from_sim(ctx.sim), &mut rng))
|
WorldSite::tree(Tree::generate(wpos, &Land::from_sim(ctx.sim), &mut rng))
|
||||||
},
|
},
|
||||||
|
SiteKind::GiantTree => WorldSite::giant_tree(site2::Site::generate_giant_tree(
|
||||||
|
&Land::from_sim(ctx.sim),
|
||||||
|
&mut rng,
|
||||||
|
wpos,
|
||||||
|
)),
|
||||||
});
|
});
|
||||||
sim_site.site_tmp = Some(site);
|
sim_site.site_tmp = Some(site);
|
||||||
let site_ref = &index.sites[site];
|
let site_ref = &index.sites[site];
|
||||||
@ -1029,6 +1041,7 @@ pub enum SiteKind {
|
|||||||
Castle,
|
Castle,
|
||||||
Refactor,
|
Refactor,
|
||||||
Tree,
|
Tree,
|
||||||
|
GiantTree,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SiteKind {
|
impl SiteKind {
|
||||||
|
@ -275,8 +275,8 @@ pub fn apply_trees_to(
|
|||||||
&& dynamic_rng.gen_range(0..256) == 0
|
&& dynamic_rng.gen_range(0..256) == 0
|
||||||
{
|
{
|
||||||
canvas.set(wpos + Vec3::unit_z(), Block::air(SpriteKind::Lantern));
|
canvas.set(wpos + Vec3::unit_z(), Block::air(SpriteKind::Lantern));
|
||||||
// Add a snow covering to the block above under certain
|
// Add a snow covering to the block above under certain
|
||||||
// circumstances
|
// circumstances
|
||||||
} else if col.snow_cover
|
} else if col.snow_cover
|
||||||
&& ((block.kind() == BlockKind::Leaves && is_leaf_top)
|
&& ((block.kind() == BlockKind::Leaves && is_leaf_top)
|
||||||
|| (is_top && block.is_filled()))
|
|| (is_top && block.is_filled()))
|
||||||
@ -803,47 +803,54 @@ impl ProceduralTree {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Recursively search for branches or leaves by walking the tree's branch graph.
|
// Recursively search for branches or leaves by walking the tree's branch graph.
|
||||||
fn is_branch_or_leaves_at_inner(
|
fn walk_inner(
|
||||||
&self,
|
&self,
|
||||||
pos: Vec3<f32>,
|
descend: &mut impl FnMut(&Branch, &Branch) -> bool,
|
||||||
parent: &Branch,
|
parent: &Branch,
|
||||||
branch_idx: usize,
|
branch_idx: usize,
|
||||||
) -> (bool, bool, bool, bool) {
|
) {
|
||||||
let branch = &self.branches[branch_idx];
|
let branch = &self.branches[branch_idx];
|
||||||
// Always probe the sibling branch, since our AABB doesn't include its bounds
|
// Always probe the sibling branch, since it's not a child of the current
|
||||||
// (it's not one of our children)
|
// branch.
|
||||||
let branch_or_leaves = branch
|
let _branch_or_leaves = branch
|
||||||
.sibling_idx
|
.sibling_idx
|
||||||
.map(|idx| Vec4::<bool>::from(self.is_branch_or_leaves_at_inner(pos, parent, idx)))
|
.map(|idx| self.walk_inner(descend, parent, idx));
|
||||||
.unwrap_or_default();
|
|
||||||
|
|
||||||
// Only continue probing this sub-graph of the tree if the sample position falls
|
|
||||||
// within its AABB
|
|
||||||
if branch.aabb.contains_point(pos) {
|
|
||||||
// Probe this branch
|
|
||||||
let (this, _d2) = branch.is_branch_or_leaves_at(&self.config, pos, parent);
|
|
||||||
|
|
||||||
let siblings = branch_or_leaves | Vec4::from(this);
|
|
||||||
|
|
||||||
|
// Only continue probing this sub-graph of the tree if the branch maches a
|
||||||
|
// criteria (usually that it falls within the region we care about
|
||||||
|
// sampling)
|
||||||
|
if descend(branch, parent) {
|
||||||
// Probe the children of this branch
|
// Probe the children of this branch
|
||||||
let children = branch
|
let _children = branch
|
||||||
.child_idx
|
.child_idx
|
||||||
.map(|idx| Vec4::<bool>::from(self.is_branch_or_leaves_at_inner(pos, branch, idx)))
|
.map(|idx| self.walk_inner(descend, branch, idx));
|
||||||
.unwrap_or_default();
|
|
||||||
|
|
||||||
// Only allow empties for children if there is no solid at the current depth
|
|
||||||
(siblings | children).into_tuple()
|
|
||||||
} else {
|
|
||||||
branch_or_leaves.into_tuple()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Recursively walk the tree's branches, calling the current closure with
|
||||||
|
/// the branch and its parent. If the closure returns `false`, recursion
|
||||||
|
/// into the child branches is skipped.
|
||||||
|
pub fn walk<F: FnMut(&Branch, &Branch) -> bool>(&self, mut f: F) {
|
||||||
|
self.walk_inner(&mut f, &self.branches[self.trunk_idx], self.trunk_idx);
|
||||||
|
}
|
||||||
|
|
||||||
/// Determine whether there are either branches or leaves at the given
|
/// Determine whether there are either branches or leaves at the given
|
||||||
/// position in the tree.
|
/// position in the tree.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn is_branch_or_leaves_at(&self, pos: Vec3<f32>) -> (bool, bool, bool, bool) {
|
pub fn is_branch_or_leaves_at(&self, pos: Vec3<f32>) -> (bool, bool, bool, bool) {
|
||||||
let (log, leaf, platform, air) =
|
let mut flags = Vec4::broadcast(false);
|
||||||
self.is_branch_or_leaves_at_inner(pos, &self.branches[self.trunk_idx], self.trunk_idx);
|
self.walk(|branch, parent| {
|
||||||
|
if branch.aabb.contains_point(pos) {
|
||||||
|
flags |=
|
||||||
|
Vec4::<bool>::from(branch.is_branch_or_leaves_at(&self.config, pos, parent).0);
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let (log, leaf, platform, air) = flags.into_tuple();
|
||||||
|
|
||||||
let root = if self.root_aabb.contains_point(pos) {
|
let root = if self.root_aabb.contains_point(pos) {
|
||||||
self.roots.iter().any(|root| {
|
self.roots.iter().any(|root| {
|
||||||
let p = root.line.projected_point(pos);
|
let p = root.line.projected_point(pos);
|
||||||
@ -867,7 +874,7 @@ impl ProceduralTree {
|
|||||||
// associated with the parent. This means that the entire tree is laid out in a
|
// associated with the parent. This means that the entire tree is laid out in a
|
||||||
// walkable graph where each branch refers only to two other branches. As a
|
// walkable graph where each branch refers only to two other branches. As a
|
||||||
// result, walking the tree is simply a case of performing double recursion.
|
// result, walking the tree is simply a case of performing double recursion.
|
||||||
struct Branch {
|
pub struct Branch {
|
||||||
line: LineSegment3<f32>,
|
line: LineSegment3<f32>,
|
||||||
wood_radius: f32,
|
wood_radius: f32,
|
||||||
leaf_radius: f32,
|
leaf_radius: f32,
|
||||||
@ -969,6 +976,16 @@ impl Branch {
|
|||||||
|
|
||||||
(mask, d2)
|
(mask, d2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This returns an AABB of both the branch and all of the children of that
|
||||||
|
/// branch
|
||||||
|
pub fn get_aabb(&self) -> Aabb<f32> { self.aabb }
|
||||||
|
|
||||||
|
pub fn get_line(&self) -> LineSegment3<f32> { self.line }
|
||||||
|
|
||||||
|
pub fn get_wood_radius(&self) -> f32 { self.wood_radius }
|
||||||
|
|
||||||
|
pub fn get_leaf_radius(&self) -> f32 { self.leaf_radius }
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Root {
|
struct Root {
|
||||||
|
@ -155,7 +155,7 @@ impl World {
|
|||||||
},
|
},
|
||||||
civ::SiteKind::Castle => world_msg::SiteKind::Castle,
|
civ::SiteKind::Castle => world_msg::SiteKind::Castle,
|
||||||
civ::SiteKind::Refactor => world_msg::SiteKind::Town,
|
civ::SiteKind::Refactor => world_msg::SiteKind::Town,
|
||||||
civ::SiteKind::Tree => world_msg::SiteKind::Tree,
|
civ::SiteKind::Tree | civ::SiteKind::GiantTree => world_msg::SiteKind::Tree,
|
||||||
},
|
},
|
||||||
wpos: site.center * TerrainChunkSize::RECT_SIZE.map(|e| e as i32),
|
wpos: site.center * TerrainChunkSize::RECT_SIZE.map(|e| e as i32),
|
||||||
}
|
}
|
||||||
|
@ -198,6 +198,7 @@ fn simulate_return(index: &mut Index, world: &mut WorldSim) -> Result<(), std::i
|
|||||||
let mut castles = EconStatistics::default();
|
let mut castles = EconStatistics::default();
|
||||||
let mut towns = EconStatistics::default();
|
let mut towns = EconStatistics::default();
|
||||||
let mut dungeons = EconStatistics::default();
|
let mut dungeons = EconStatistics::default();
|
||||||
|
let giant_trees = EconStatistics::default();
|
||||||
for site in index.sites.ids() {
|
for site in index.sites.ids() {
|
||||||
let site = &index.sites[site];
|
let site = &index.sites[site];
|
||||||
match site.kind {
|
match site.kind {
|
||||||
@ -206,6 +207,7 @@ fn simulate_return(index: &mut Index, world: &mut WorldSim) -> Result<(), std::i
|
|||||||
SiteKind::Castle(_) => castles += site.economy.pop,
|
SiteKind::Castle(_) => castles += site.economy.pop,
|
||||||
SiteKind::Tree(_) => (),
|
SiteKind::Tree(_) => (),
|
||||||
SiteKind::Refactor(_) => towns += site.economy.pop,
|
SiteKind::Refactor(_) => towns += site.economy.pop,
|
||||||
|
SiteKind::GiantTree(_) => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if towns.valid() {
|
if towns.valid() {
|
||||||
@ -232,6 +234,14 @@ fn simulate_return(index: &mut Index, world: &mut WorldSim) -> Result<(), std::i
|
|||||||
dungeons.sum / (dungeons.count as f32)
|
dungeons.sum / (dungeons.count as f32)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
if giant_trees.valid() {
|
||||||
|
info!(
|
||||||
|
"Giant Trees {:.0}-{:.0} avg {:.0}",
|
||||||
|
giant_trees.min,
|
||||||
|
giant_trees.max,
|
||||||
|
giant_trees.sum / (giant_trees.count as f32)
|
||||||
|
)
|
||||||
|
}
|
||||||
check_money(index);
|
check_money(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,6 +62,7 @@ pub enum SiteKind {
|
|||||||
Castle(Castle),
|
Castle(Castle),
|
||||||
Refactor(site2::Site),
|
Refactor(site2::Site),
|
||||||
Tree(tree::Tree),
|
Tree(tree::Tree),
|
||||||
|
GiantTree(site2::Site),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Site {
|
impl Site {
|
||||||
@ -100,6 +101,13 @@ impl Site {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn giant_tree(gt: site2::Site) -> Self {
|
||||||
|
Self {
|
||||||
|
kind: SiteKind::GiantTree(gt),
|
||||||
|
economy: Economy::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn radius(&self) -> f32 {
|
pub fn radius(&self) -> f32 {
|
||||||
match &self.kind {
|
match &self.kind {
|
||||||
SiteKind::Settlement(s) => s.radius(),
|
SiteKind::Settlement(s) => s.radius(),
|
||||||
@ -107,6 +115,7 @@ impl Site {
|
|||||||
SiteKind::Castle(c) => c.radius(),
|
SiteKind::Castle(c) => c.radius(),
|
||||||
SiteKind::Refactor(s) => s.radius(),
|
SiteKind::Refactor(s) => s.radius(),
|
||||||
SiteKind::Tree(t) => t.radius(),
|
SiteKind::Tree(t) => t.radius(),
|
||||||
|
SiteKind::GiantTree(gt) => gt.radius(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,6 +126,7 @@ impl Site {
|
|||||||
SiteKind::Castle(c) => c.get_origin(),
|
SiteKind::Castle(c) => c.get_origin(),
|
||||||
SiteKind::Refactor(s) => s.origin,
|
SiteKind::Refactor(s) => s.origin,
|
||||||
SiteKind::Tree(t) => t.origin,
|
SiteKind::Tree(t) => t.origin,
|
||||||
|
SiteKind::GiantTree(gt) => gt.origin,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,6 +137,7 @@ impl Site {
|
|||||||
SiteKind::Castle(c) => c.spawn_rules(wpos),
|
SiteKind::Castle(c) => c.spawn_rules(wpos),
|
||||||
SiteKind::Refactor(s) => s.spawn_rules(wpos),
|
SiteKind::Refactor(s) => s.spawn_rules(wpos),
|
||||||
SiteKind::Tree(t) => t.spawn_rules(wpos),
|
SiteKind::Tree(t) => t.spawn_rules(wpos),
|
||||||
|
SiteKind::GiantTree(gt) => gt.spawn_rules(wpos),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,6 +148,7 @@ impl Site {
|
|||||||
SiteKind::Castle(c) => c.name(),
|
SiteKind::Castle(c) => c.name(),
|
||||||
SiteKind::Refactor(s) => s.name(),
|
SiteKind::Refactor(s) => s.name(),
|
||||||
SiteKind::Tree(_) => "Giant Tree",
|
SiteKind::Tree(_) => "Giant Tree",
|
||||||
|
SiteKind::GiantTree(gt) => gt.name(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -169,6 +181,7 @@ impl Site {
|
|||||||
SiteKind::Castle(c) => c.apply_to(canvas.index, canvas.wpos, get_col, canvas.chunk),
|
SiteKind::Castle(c) => c.apply_to(canvas.index, canvas.wpos, get_col, canvas.chunk),
|
||||||
SiteKind::Refactor(s) => s.render(canvas, dynamic_rng),
|
SiteKind::Refactor(s) => s.render(canvas, dynamic_rng),
|
||||||
SiteKind::Tree(t) => t.render(canvas, dynamic_rng),
|
SiteKind::Tree(t) => t.render(canvas, dynamic_rng),
|
||||||
|
SiteKind::GiantTree(gt) => gt.render(canvas, dynamic_rng),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -192,6 +205,7 @@ impl Site {
|
|||||||
SiteKind::Castle(c) => c.apply_supplement(dynamic_rng, wpos2d, get_column, supplement),
|
SiteKind::Castle(c) => c.apply_supplement(dynamic_rng, wpos2d, get_column, supplement),
|
||||||
SiteKind::Refactor(_) => {},
|
SiteKind::Refactor(_) => {},
|
||||||
SiteKind::Tree(_) => {},
|
SiteKind::Tree(_) => {},
|
||||||
|
SiteKind::GiantTree(gt) => gt.apply_supplement(dynamic_rng, wpos2d, supplement),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@ use crate::{
|
|||||||
block::block_from_structure,
|
block::block_from_structure,
|
||||||
site2::util::Dir,
|
site2::util::Dir,
|
||||||
util::{RandomField, Sampler},
|
util::{RandomField, Sampler},
|
||||||
|
CanvasInfo,
|
||||||
};
|
};
|
||||||
use common::{
|
use common::{
|
||||||
store::{Id, Store},
|
store::{Id, Store},
|
||||||
@ -504,6 +505,7 @@ impl Fill {
|
|||||||
pub struct Painter {
|
pub struct Painter {
|
||||||
prims: RefCell<Store<Primitive>>,
|
prims: RefCell<Store<Primitive>>,
|
||||||
fills: RefCell<Vec<(Id<Primitive>, Fill)>>,
|
fills: RefCell<Vec<(Id<Primitive>, Fill)>>,
|
||||||
|
render_area: Aabr<i32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Painter {
|
impl Painter {
|
||||||
@ -789,6 +791,8 @@ impl Painter {
|
|||||||
pub fn fill(&self, prim: impl Into<Id<Primitive>>, fill: Fill) {
|
pub fn fill(&self, prim: impl Into<Id<Primitive>>, fill: Fill) {
|
||||||
self.fills.borrow_mut().push((prim.into(), fill));
|
self.fills.borrow_mut().push((prim.into(), fill));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn render_aabr(&self) -> Aabr<i32> { self.render_area }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
@ -867,14 +871,18 @@ pub trait Structure {
|
|||||||
fn render_collect(
|
fn render_collect(
|
||||||
&self,
|
&self,
|
||||||
site: &Site,
|
site: &Site,
|
||||||
land: &Land,
|
canvas: &CanvasInfo,
|
||||||
) -> (Store<Primitive>, Vec<(Id<Primitive>, Fill)>) {
|
) -> (Store<Primitive>, Vec<(Id<Primitive>, Fill)>) {
|
||||||
let painter = Painter {
|
let painter = Painter {
|
||||||
prims: RefCell::new(Store::default()),
|
prims: RefCell::new(Store::default()),
|
||||||
fills: RefCell::new(Vec::new()),
|
fills: RefCell::new(Vec::new()),
|
||||||
|
render_area: Aabr {
|
||||||
|
min: canvas.wpos,
|
||||||
|
max: canvas.wpos + TerrainChunkSize::RECT_SIZE.map(|e| e as i32),
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
self.render(site, land, &painter);
|
self.render(site, &canvas.land(), &painter);
|
||||||
(painter.prims.into_inner(), painter.fills.into_inner())
|
(painter.prims.into_inner(), painter.fills.into_inner())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -55,7 +55,19 @@ impl Site {
|
|||||||
.map(|e| e.abs())
|
.map(|e| e.abs())
|
||||||
.reduce_max()
|
.reduce_max()
|
||||||
.max(self.tiles.bounds.max.map(|e| e.abs()).reduce_max())
|
.max(self.tiles.bounds.max.map(|e| e.abs()).reduce_max())
|
||||||
+ 1)
|
// Temporary solution for giving giant_tree's leaves enough space to be painted correctly
|
||||||
|
// TODO: This will have to be replaced by a system as described on discord :
|
||||||
|
// https://discord.com/channels/449602562165833758/450064928720814081/937044837461536808
|
||||||
|
+ if self
|
||||||
|
.plots
|
||||||
|
.values()
|
||||||
|
.any(|p| matches!(&p.kind, PlotKind::GiantTree(_)))
|
||||||
|
{
|
||||||
|
// 25 Seems to be big enough for the current scale of 4.0
|
||||||
|
25
|
||||||
|
} else {
|
||||||
|
1
|
||||||
|
})
|
||||||
* tile::TILE_SIZE as i32) as f32
|
* tile::TILE_SIZE as i32) as f32
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -364,6 +376,40 @@ impl Site {
|
|||||||
site
|
site
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn generate_giant_tree(land: &Land, rng: &mut impl Rng, origin: Vec2<i32>) -> Self {
|
||||||
|
let mut rng = reseed(rng);
|
||||||
|
|
||||||
|
let mut site = Site {
|
||||||
|
origin,
|
||||||
|
..Site::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
site.demarcate_obstacles(land);
|
||||||
|
let giant_tree = plot::GiantTree::generate(&site, Vec2::zero(), land, &mut rng);
|
||||||
|
site.name = giant_tree.name().to_string();
|
||||||
|
let size = (giant_tree.radius() / tile::TILE_SIZE as f32).ceil() as i32;
|
||||||
|
|
||||||
|
let aabr = Aabr {
|
||||||
|
min: Vec2::broadcast(-size),
|
||||||
|
max: Vec2::broadcast(size) + 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
let plot = site.create_plot(Plot {
|
||||||
|
kind: PlotKind::GiantTree(giant_tree),
|
||||||
|
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: None,
|
||||||
|
});
|
||||||
|
|
||||||
|
site
|
||||||
|
}
|
||||||
|
|
||||||
pub fn generate_city(land: &Land, rng: &mut impl Rng, origin: Vec2<i32>) -> Self {
|
pub fn generate_city(land: &Land, rng: &mut impl Rng, origin: Vec2<i32>) -> Self {
|
||||||
let mut rng = reseed(rng);
|
let mut rng = reseed(rng);
|
||||||
|
|
||||||
@ -875,6 +921,13 @@ impl Site {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Solve the 'trees are too big' problem and remove this
|
||||||
|
for (id, plot) in self.plots.iter() {
|
||||||
|
if matches!(&plot.kind, PlotKind::GiantTree(_)) {
|
||||||
|
plots.insert(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let mut plots_to_render = plots.into_iter().collect::<Vec<_>>();
|
let mut plots_to_render = plots.into_iter().collect::<Vec<_>>();
|
||||||
plots_to_render.sort_unstable();
|
plots_to_render.sort_unstable();
|
||||||
|
|
||||||
@ -888,10 +941,11 @@ impl Site {
|
|||||||
|
|
||||||
for plot in plots_to_render {
|
for plot in plots_to_render {
|
||||||
let (prim_tree, fills) = match &self.plots[plot].kind {
|
let (prim_tree, fills) = match &self.plots[plot].kind {
|
||||||
PlotKind::House(house) => house.render_collect(self, &canvas.land()),
|
PlotKind::House(house) => house.render_collect(self, canvas),
|
||||||
PlotKind::Workshop(workshop) => workshop.render_collect(self, &canvas.land()),
|
PlotKind::Workshop(workshop) => workshop.render_collect(self, canvas),
|
||||||
PlotKind::Castle(castle) => castle.render_collect(self, &canvas.land()),
|
PlotKind::Castle(castle) => castle.render_collect(self, canvas),
|
||||||
PlotKind::Dungeon(dungeon) => dungeon.render_collect(self, &canvas.land()),
|
PlotKind::Dungeon(dungeon) => dungeon.render_collect(self, canvas),
|
||||||
|
PlotKind::GiantTree(giant_tree) => giant_tree.render_collect(self, canvas),
|
||||||
_ => continue,
|
_ => continue,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
mod castle;
|
mod castle;
|
||||||
pub mod dungeon;
|
pub mod dungeon;
|
||||||
|
mod giant_tree;
|
||||||
mod house;
|
mod house;
|
||||||
mod workshop;
|
mod workshop;
|
||||||
|
|
||||||
pub use self::{castle::Castle, dungeon::Dungeon, house::House, workshop::Workshop};
|
pub use self::{
|
||||||
|
castle::Castle, dungeon::Dungeon, giant_tree::GiantTree, house::House, workshop::Workshop,
|
||||||
|
};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::util::DHashSet;
|
use crate::util::DHashSet;
|
||||||
@ -45,4 +48,5 @@ pub enum PlotKind {
|
|||||||
Castle(Castle),
|
Castle(Castle),
|
||||||
Road(Path<Vec2<i32>>),
|
Road(Path<Vec2<i32>>),
|
||||||
Dungeon(Dungeon),
|
Dungeon(Dungeon),
|
||||||
|
GiantTree(GiantTree),
|
||||||
}
|
}
|
||||||
|
86
world/src/site2/plot/giant_tree.rs
Normal file
86
world/src/site2/plot/giant_tree.rs
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
use crate::{
|
||||||
|
layer::tree::{ProceduralTree, TreeConfig},
|
||||||
|
site::namegen::NameGen,
|
||||||
|
site2::{Fill, Painter, Site, Structure},
|
||||||
|
util::FastNoise,
|
||||||
|
Land, Sampler,
|
||||||
|
};
|
||||||
|
use common::terrain::{Block, BlockKind};
|
||||||
|
use rand::Rng;
|
||||||
|
use vek::*;
|
||||||
|
|
||||||
|
pub struct GiantTree {
|
||||||
|
name: String,
|
||||||
|
wpos: Vec3<i32>,
|
||||||
|
tree: ProceduralTree,
|
||||||
|
seed: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GiantTree {
|
||||||
|
pub fn generate(site: &Site, center_tile: Vec2<i32>, land: &Land, rng: &mut impl Rng) -> Self {
|
||||||
|
let wpos = site.tile_center_wpos(center_tile);
|
||||||
|
Self {
|
||||||
|
name: format!("Tree of {}", NameGen::location(rng).generate()),
|
||||||
|
// Find the tree's altitude
|
||||||
|
wpos: wpos.with_z(land.get_alt_approx(wpos) as i32),
|
||||||
|
tree: {
|
||||||
|
let config = TreeConfig::giant(rng, 4.0, true);
|
||||||
|
ProceduralTree::generate(config, rng)
|
||||||
|
},
|
||||||
|
seed: rng.gen(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn name(&self) -> &str { &self.name }
|
||||||
|
|
||||||
|
pub fn radius(&self) -> f32 { 100.0 }
|
||||||
|
|
||||||
|
pub fn tree(&self) -> &ProceduralTree { &self.tree }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Structure for GiantTree {
|
||||||
|
fn render(&self, _site: &Site, _land: &Land, painter: &Painter) {
|
||||||
|
let fast_noise = FastNoise::new(self.seed);
|
||||||
|
let dark = Rgb::new(10, 70, 50).map(|e| e as f32);
|
||||||
|
let light = Rgb::new(80, 140, 10).map(|e| e as f32);
|
||||||
|
let leaf_col = Lerp::lerp(
|
||||||
|
dark,
|
||||||
|
light,
|
||||||
|
fast_noise.get((self.wpos.map(|e| e as f64) * 0.05) * 0.5 + 0.5),
|
||||||
|
);
|
||||||
|
self.tree.walk(|branch, _| {
|
||||||
|
let aabr = Aabr {
|
||||||
|
min: self.wpos.xy() + branch.get_aabb().min.xy().as_(),
|
||||||
|
max: self.wpos.xy() + branch.get_aabb().max.xy().as_(),
|
||||||
|
};
|
||||||
|
if aabr.collides_with_aabr(painter.render_aabr().as_()) {
|
||||||
|
// TODO : Migrate to using Painter#line() instead
|
||||||
|
painter
|
||||||
|
.line(
|
||||||
|
self.wpos + branch.get_line().start.as_(),
|
||||||
|
self.wpos + branch.get_line().end.as_(),
|
||||||
|
branch.get_wood_radius(),
|
||||||
|
)
|
||||||
|
.fill(Fill::Block(Block::new(
|
||||||
|
BlockKind::Wood,
|
||||||
|
Rgb::new(80, 32, 0),
|
||||||
|
)));
|
||||||
|
if branch.get_leaf_radius() > branch.get_wood_radius() {
|
||||||
|
painter
|
||||||
|
.line(
|
||||||
|
self.wpos + branch.get_line().start.as_(),
|
||||||
|
self.wpos + branch.get_line().end.as_(),
|
||||||
|
branch.get_leaf_radius(),
|
||||||
|
)
|
||||||
|
.fill(Fill::Block(Block::new(
|
||||||
|
BlockKind::Leaves,
|
||||||
|
leaf_col.map(|e| e as u8),
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user