More tree variety, denser forests

This commit is contained in:
Joshua Barretto 2021-02-06 23:53:25 +00:00
parent 8ed16ccb07
commit ac5a60d260
7 changed files with 199 additions and 146 deletions

View File

@ -31,7 +31,13 @@ impl<T> PartialEq for Id<T> {
} }
impl<T> fmt::Debug for Id<T> { impl<T> fmt::Debug for Id<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Id<{}>({}, {})", std::any::type_name::<T>(), self.idx, self.gen) write!(
f,
"Id<{}>({}, {})",
std::any::type_name::<T>(),
self.idx,
self.gen
)
} }
} }
impl<T> hash::Hash for Id<T> { impl<T> hash::Hash for Id<T> {
@ -69,9 +75,7 @@ impl<T> Store<T> {
} }
pub fn get(&self, id: Id<T>) -> &T { pub fn get(&self, id: Id<T>) -> &T {
let entry = self.entries let entry = self.entries.get(id.idx as usize).unwrap();
.get(id.idx as usize)
.unwrap();
if entry.gen == id.gen { if entry.gen == id.gen {
entry.item.as_ref().unwrap() entry.item.as_ref().unwrap()
} else { } else {
@ -80,9 +84,7 @@ impl<T> Store<T> {
} }
pub fn get_mut(&mut self, id: Id<T>) -> &mut T { pub fn get_mut(&mut self, id: Id<T>) -> &mut T {
let entry = self.entries let entry = self.entries.get_mut(id.idx as usize).unwrap();
.get_mut(id.idx as usize)
.unwrap();
if entry.gen == id.gen { if entry.gen == id.gen {
entry.item.as_mut().unwrap() entry.item.as_mut().unwrap()
} else { } else {
@ -90,13 +92,9 @@ impl<T> Store<T> {
} }
} }
pub fn ids(&self) -> impl Iterator<Item = Id<T>> + '_ { pub fn ids(&self) -> impl Iterator<Item = Id<T>> + '_ { self.iter().map(|(id, _)| id) }
self.iter().map(|(id, _)| id)
}
pub fn values(&self) -> impl Iterator<Item = &T> + '_ { pub fn values(&self) -> impl Iterator<Item = &T> + '_ { self.iter().map(|(_, item)| item) }
self.iter().map(|(_, item)| item)
}
pub fn values_mut(&mut self) -> impl Iterator<Item = &mut T> + '_ { pub fn values_mut(&mut self) -> impl Iterator<Item = &mut T> + '_ {
self.iter_mut().map(|(_, item)| item) self.iter_mut().map(|(_, item)| item)
@ -111,7 +109,8 @@ impl<T> Store<T> {
idx: idx as u32, idx: idx as u32,
gen: entry.gen, gen: entry.gen,
phantom: PhantomData, phantom: PhantomData,
}).zip(entry.item.as_ref()) })
.zip(entry.item.as_ref())
}) })
} }
@ -124,14 +123,16 @@ impl<T> Store<T> {
idx: idx as u32, idx: idx as u32,
gen: entry.gen, gen: entry.gen,
phantom: PhantomData, phantom: PhantomData,
}).zip(entry.item.as_mut()) })
.zip(entry.item.as_mut())
}) })
} }
pub fn insert(&mut self, item: T) -> Id<T> { pub fn insert(&mut self, item: T) -> Id<T> {
if self.len < self.entries.len() { if self.len < self.entries.len() {
// TODO: Make this more efficient with a lookahead system // TODO: Make this more efficient with a lookahead system
let (idx, entry) = self.entries let (idx, entry) = self
.entries
.iter_mut() .iter_mut()
.enumerate() .enumerate()
.find(|(_, e)| e.item.is_none()) .find(|(_, e)| e.item.is_none())
@ -161,13 +162,10 @@ impl<T> Store<T> {
} }
pub fn remove(&mut self, id: Id<T>) -> Option<T> { pub fn remove(&mut self, id: Id<T>) -> Option<T> {
if let Some(item) = self.entries if let Some(item) = self
.entries
.get_mut(id.idx as usize) .get_mut(id.idx as usize)
.and_then(|e| if e.gen == id.gen { .and_then(|e| if e.gen == id.gen { e.item.take() } else { None })
e.item.take()
} else {
None
})
{ {
self.len -= 1; self.len -= 1;
Some(item) Some(item)

View File

@ -5,7 +5,10 @@ use veloren_world::site2::test_site;
fn main() { fn main() {
let site = test_site(); let site = test_site();
let size = site.bounds().size(); let size = site.bounds().size();
println!("{}", BeginSvg { w: size.w as f32, h: size.h as f32 }); println!("{}", BeginSvg {
w: size.w as f32,
h: size.h as f32
});
for plot in site.plots() { for plot in site.plots() {
let bounds = plot.find_bounds(); let bounds = plot.find_bounds();
@ -15,7 +18,11 @@ fn main() {
w: bounds.size().w as f32, w: bounds.size().w as f32,
h: bounds.size().h as f32, h: bounds.size().h as f32,
style: Style { style: Style {
fill: Fill::Color(Color { r: 50, g: 50, b: 50 }), fill: Fill::Color(Color {
r: 50,
g: 50,
b: 50
}),
stroke: Stroke::Color(Color { r: 0, g: 0, b: 0 }, 1.0), stroke: Stroke::Color(Color { r: 0, g: 0, b: 0 }, 1.0),
opacity: 1.0, opacity: 1.0,
stroke_opacity: 1.0, stroke_opacity: 1.0,

View File

@ -7,14 +7,17 @@ use crate::{
}; };
use common::{ use common::{
assets::AssetHandle, assets::AssetHandle,
terrain::{Block, BlockKind, structure::{Structure, StructureBlock, StructuresGroup}}, terrain::{
structure::{Structure, StructureBlock, StructuresGroup},
Block, BlockKind,
},
vol::ReadVol, vol::ReadVol,
}; };
use hashbrown::HashMap; use hashbrown::HashMap;
use lazy_static::lazy_static; use lazy_static::lazy_static;
use rand::prelude::*;
use std::{f32, ops::Range}; use std::{f32, ops::Range};
use vek::*; use vek::*;
use rand::prelude::*;
lazy_static! { lazy_static! {
static ref OAKS: AssetHandle<StructuresGroup> = Structure::load_group("oaks"); static ref OAKS: AssetHandle<StructuresGroup> = Structure::load_group("oaks");
@ -99,15 +102,25 @@ pub fn apply_trees_to(canvas: &mut Canvas) {
ForestKind::Acacia => *ACACIAS, ForestKind::Acacia => *ACACIAS,
ForestKind::Baobab => *BAOBABS, ForestKind::Baobab => *BAOBABS,
// ForestKind::Oak => *OAKS, // ForestKind::Oak => *OAKS,
ForestKind::Oak => break 'model TreeModel::Procedural( ForestKind::Oak => {
ProceduralTree::generate(TreeConfig::OAK, seed), break 'model TreeModel::Procedural(
StructureBlock::TemperateLeaves, ProceduralTree::generate(
), TreeConfig::oak(&mut RandomPerm::new(seed)),
&mut RandomPerm::new(seed),
),
StructureBlock::TemperateLeaves,
);
},
//ForestKind::Pine => *PINES, //ForestKind::Pine => *PINES,
ForestKind::Pine => break 'model TreeModel::Procedural( ForestKind::Pine => {
ProceduralTree::generate(TreeConfig::PINE, seed), break 'model TreeModel::Procedural(
StructureBlock::PineLeaves, ProceduralTree::generate(
), TreeConfig::pine(&mut RandomPerm::new(seed)),
&mut RandomPerm::new(seed),
),
StructureBlock::PineLeaves,
);
},
ForestKind::Birch => *BIRCHES, ForestKind::Birch => *BIRCHES,
ForestKind::Mangrove => *MANGROVE_TREES, ForestKind::Mangrove => *MANGROVE_TREES,
ForestKind::Swamp => *SWAMP_TREES, ForestKind::Swamp => *SWAMP_TREES,
@ -115,8 +128,11 @@ pub fn apply_trees_to(canvas: &mut Canvas) {
}; };
let models = models.read(); let models = models.read();
TreeModel::Structure(models[(MODEL_RAND.get(seed.wrapping_mul(17)) / 13) as usize % models.len()] TreeModel::Structure(
.clone()) models[(MODEL_RAND.get(seed.wrapping_mul(17)) / 13) as usize
% models.len()]
.clone(),
)
}, },
seed, seed,
units: UNIT_CHOOSER.get(seed), units: UNIT_CHOOSER.get(seed),
@ -133,9 +149,7 @@ pub fn apply_trees_to(canvas: &mut Canvas) {
}; };
let rpos2d = (wpos2d - tree.pos.xy()) let rpos2d = (wpos2d - tree.pos.xy())
.map2(Vec2::new(tree.units.0, tree.units.1), |p, unit| { .map2(Vec2::new(tree.units.0, tree.units.1), |p, unit| unit * p)
unit * p
})
.sum(); .sum();
if !Aabr::from(bounds).contains_point(rpos2d) { if !Aabr::from(bounds).contains_point(rpos2d) {
// Skip this column // Skip this column
@ -158,15 +172,17 @@ pub fn apply_trees_to(canvas: &mut Canvas) {
info.index(), info.index(),
if let Some(block) = match &tree.model { if let Some(block) = match &tree.model {
TreeModel::Structure(s) => s.get(model_pos).ok().copied(), TreeModel::Structure(s) => s.get(model_pos).ok().copied(),
TreeModel::Procedural(t, leaf_block) => Some(match t.is_branch_or_leaves_at(model_pos.map(|e| e as f32 + 0.5)) { TreeModel::Procedural(t, leaf_block) => Some(
(true, _) => StructureBlock::Normal(Rgb::new(60, 30, 0)), match t.is_branch_or_leaves_at(model_pos.map(|e| e as f32 + 0.5)) {
(_, true) => *leaf_block, (true, _) => StructureBlock::Normal(Rgb::new(60, 30, 0)),
(_, _) => StructureBlock::None, (_, true) => *leaf_block,
}), (_, _) => StructureBlock::None,
},
),
} { } {
block block
} else { } else {
break break;
}, },
wpos, wpos,
tree.pos.xy(), tree.pos.xy(),
@ -215,50 +231,62 @@ pub struct TreeConfig {
pub max_depth: usize, pub max_depth: usize,
/// The number of branches that form from each branch. /// The number of branches that form from each branch.
pub splits: usize, pub splits: usize,
/// The range of proportions along a branch at which a split into another branch might occur. /// The range of proportions along a branch at which a split into another
/// This value is clamped between 0 and 1, but a wider range may bias the results towards branch ends. /// branch might occur. This value is clamped between 0 and 1, but a
/// wider range may bias the results towards branch ends.
pub split_range: Range<f32>, pub split_range: Range<f32>,
/// The bias applied to the length of branches based on the proportion along their parent that they eminate from. /// The bias applied to the length of branches based on the proportion along
/// -1.0 = negative bias (branches at ends are longer, branches at the start are shorter) /// their parent that they eminate from. -1.0 = negative bias (branches
/// 0.0 = no bias (branches do not change their length with regard to parent branch proportion) /// at ends are longer, branches at the start are shorter) 0.0 = no bias
/// 1.0 = positive bias (branches at ends are shorter, branches at the start are longer) /// (branches do not change their length with regard to parent branch
/// proportion) 1.0 = positive bias (branches at ends are shorter,
/// branches at the start are longer)
pub branch_len_bias: f32, pub branch_len_bias: f32,
/// The scale of leaves in the vertical plane. Less than 1.0 implies a flattening of the leaves. /// The scale of leaves in the vertical plane. Less than 1.0 implies a
/// flattening of the leaves.
pub leaf_vertical_scale: f32, pub leaf_vertical_scale: f32,
/// How evenly spaced (vs random) sub-branches are along their parent. /// How evenly spaced (vs random) sub-branches are along their parent.
pub proportionality: f32, pub proportionality: f32,
} }
impl TreeConfig { impl TreeConfig {
pub const OAK: Self = Self { pub fn oak(rng: &mut impl Rng) -> Self {
trunk_len: 12.0, let scale = Lerp::lerp(0.8, 1.5, rng.gen::<f32>().powi(4));
trunk_radius: 3.0,
branch_child_len: 0.8,
branch_child_radius: 0.6,
leaf_radius: 3.0..5.0,
straightness: 0.5,
max_depth: 4,
splits: 3,
split_range: 0.5..1.5,
branch_len_bias: 0.0,
leaf_vertical_scale: 1.0,
proportionality: 0.0,
};
pub const PINE: Self = Self { Self {
trunk_len: 32.0, trunk_len: 12.0 * scale,
trunk_radius: 1.5, trunk_radius: 3.0 * scale,
branch_child_len: 0.3, branch_child_len: 0.8,
branch_child_radius: 0.0, branch_child_radius: 0.6,
leaf_radius: 2.0..2.5, leaf_radius: 3.0 * scale..4.0 * scale,
straightness: 0.0, straightness: 0.5,
max_depth: 1, max_depth: 4,
splits: 56, splits: 3,
split_range: 0.2..1.2, split_range: 0.5..1.5,
branch_len_bias: 0.75, branch_len_bias: 0.0,
leaf_vertical_scale: 0.3, leaf_vertical_scale: 1.0,
proportionality: 1.0, proportionality: 0.0,
}; }
}
pub fn pine(rng: &mut impl Rng) -> Self {
let scale = Lerp::lerp(1.0, 2.0, rng.gen::<f32>().powi(4));
Self {
trunk_len: 32.0 * scale,
trunk_radius: 1.5 * scale,
branch_child_len: 0.3,
branch_child_radius: 0.0,
leaf_radius: 2.0 * scale..2.5 * scale,
straightness: 0.0,
max_depth: 1,
splits: 56,
split_range: 0.2..1.2,
branch_len_bias: 0.75,
leaf_vertical_scale: 0.3,
proportionality: 1.0,
}
}
} }
// TODO: Rename this to `Tree` when the name conflict is gone // TODO: Rename this to `Tree` when the name conflict is gone
@ -269,9 +297,7 @@ pub struct ProceduralTree {
impl ProceduralTree { impl ProceduralTree {
/// Generate a new tree using the given configuration and seed. /// Generate a new tree using the given configuration and seed.
pub fn generate(config: TreeConfig, seed: u32) -> Self { pub fn generate(config: TreeConfig, rng: &mut impl Rng) -> Self {
let mut rng = RandomPerm::new(seed);
let mut this = Self { let mut this = Self {
branches: Vec::new(), branches: Vec::new(),
trunk_idx: 0, // Gets replaced later trunk_idx: 0, // Gets replaced later
@ -283,20 +309,21 @@ impl ProceduralTree {
// Our trunk starts at the origin... // Our trunk starts at the origin...
Vec3::zero(), Vec3::zero(),
// ...and has a roughly upward direction // ...and has a roughly upward direction
Vec3::new(rng.gen_range(-1.0..1.0), rng.gen_range(-1.0..1.0), 5.0).normalized(), Vec3::new(rng.gen_range(-1.0..1.0), rng.gen_range(-1.0..1.0), 10.0).normalized(),
config.trunk_len, config.trunk_len,
config.trunk_radius, config.trunk_radius,
0, 0,
None, None,
&mut rng, rng,
); );
this.trunk_idx = trunk_idx; this.trunk_idx = trunk_idx;
this this
} }
// Recursively add a branch (with sub-branches) to the tree's branch graph, returning the index and AABB of the // Recursively add a branch (with sub-branches) to the tree's branch graph,
// branch. This AABB gets propagated down to the parent and is used later during sampling to cull the branches to // returning the index and AABB of the branch. This AABB gets propagated
// down to the parent and is used later during sampling to cull the branches to
// be sampled. // be sampled.
fn add_branch( fn add_branch(
&mut self, &mut self,
@ -318,7 +345,8 @@ impl ProceduralTree {
0.0 0.0
}; };
// The AABB that covers this branch, along with wood and leaves that eminate from it // The AABB that covers this branch, along with wood and leaves that eminate
// from it
let mut aabb = Aabb { let mut aabb = Aabb {
min: Vec3::partial_min(start, end) - wood_radius.max(leaf_radius), min: Vec3::partial_min(start, end) - wood_radius.max(leaf_radius),
max: Vec3::partial_max(start, end) + wood_radius.max(leaf_radius), max: Vec3::partial_max(start, end) + wood_radius.max(leaf_radius),
@ -327,31 +355,43 @@ impl ProceduralTree {
let mut child_idx = None; let mut child_idx = None;
// Don't add child branches if we're already enough layers into the tree // Don't add child branches if we're already enough layers into the tree
if depth < config.max_depth { if depth < config.max_depth {
let x_axis = dir.cross(Vec3::<f32>::zero().map(|_| rng.gen_range(-1.0..1.0))).normalized(); let x_axis = dir
.cross(Vec3::<f32>::zero().map(|_| rng.gen_range(-1.0..1.0)))
.normalized();
let y_axis = dir.cross(x_axis).normalized(); let y_axis = dir.cross(x_axis).normalized();
let screw_shift = rng.gen_range(0.0..f32::consts::TAU); let screw_shift = rng.gen_range(0.0..f32::consts::TAU);
for i in 0..config.splits { for i in 0..config.splits {
let dist = Lerp::lerp(i as f32 / (config.splits - 1) as f32, rng.gen_range(0.0..1.0), config.proportionality); let dist = Lerp::lerp(
i as f32 / (config.splits - 1) as f32,
rng.gen_range(0.0..1.0),
config.proportionality,
);
const PHI: f32 = 0.618; const PHI: f32 = 0.618;
const RAD_PER_BRANCH: f32 = f32::consts::TAU * PHI; const RAD_PER_BRANCH: f32 = f32::consts::TAU * PHI;
let screw = let screw = (screw_shift + dist * config.splits as f32 * RAD_PER_BRANCH).sin()
(screw_shift + dist * config.splits as f32 * RAD_PER_BRANCH).sin() * x_axis + * x_axis
(screw_shift + dist * config.splits as f32 * RAD_PER_BRANCH).cos() * y_axis; + (screw_shift + dist * config.splits as f32 * RAD_PER_BRANCH).cos() * y_axis;
// Choose a point close to the branch to act as the target direction for the branch to grow in // Choose a point close to the branch to act as the target direction for the
// let split_factor = rng.gen_range(config.split_range.start, config.split_range.end).clamped(0.0, 1.0); // branch to grow in let split_factor =
let split_factor = Lerp::lerp(config.split_range.start, config.split_range.end, dist); // rng.gen_range(config.split_range.start, config.split_range.end).clamped(0.0,
let tgt = Lerp::lerp_unclamped( // 1.0);
start, let split_factor =
end, Lerp::lerp(config.split_range.start, config.split_range.end, dist);
split_factor, let tgt = Lerp::lerp_unclamped(start, end, split_factor)
) + Lerp::lerp(Vec3::<f32>::zero().map(|_| rng.gen_range(-1.0..1.0)), screw, config.proportionality); + Lerp::lerp(
Vec3::<f32>::zero().map(|_| rng.gen_range(-1.0..1.0)),
screw,
config.proportionality,
);
// Start the branch at the closest point to the target // Start the branch at the closest point to the target
let branch_start = line.projected_point(tgt); let branch_start = line.projected_point(tgt);
// Now, interpolate between the target direction and the parent branch's direction to find a direction // Now, interpolate between the target direction and the parent branch's
let branch_dir = Lerp::lerp(tgt - branch_start, dir, config.straightness).normalized(); // direction to find a direction
let branch_dir =
Lerp::lerp(tgt - branch_start, dir, config.straightness).normalized();
let (branch_idx, branch_aabb) = self.add_branch( let (branch_idx, branch_aabb) = self.add_branch(
config, config,
@ -359,14 +399,18 @@ impl ProceduralTree {
branch_dir, branch_dir,
branch_len branch_len
* config.branch_child_len * config.branch_child_len
* (1.0 - (split_factor - 0.5) * 2.0 * config.branch_len_bias.clamped(-1.0, 1.0)), * (1.0
- (split_factor - 0.5)
* 2.0
* config.branch_len_bias.clamped(-1.0, 1.0)),
branch_radius * config.branch_child_radius, branch_radius * config.branch_child_radius,
depth + 1, depth + 1,
child_idx, child_idx,
rng, rng,
); );
child_idx = Some(branch_idx); child_idx = Some(branch_idx);
// Parent branches AABBs include the AABBs of child branches to allow for culling during sampling // Parent branches AABBs include the AABBs of child branches to allow for
// culling during sampling
aabb.expand_to_contain(branch_aabb); aabb.expand_to_contain(branch_aabb);
} }
} }
@ -386,19 +430,20 @@ impl ProceduralTree {
} }
/// Get the bounding box that covers the tree (all branches and leaves) /// Get the bounding box that covers the tree (all branches and leaves)
pub fn get_bounds(&self) -> Aabb<f32> { pub fn get_bounds(&self) -> Aabb<f32> { self.branches[self.trunk_idx].aabb }
self.branches[self.trunk_idx].aabb
}
// 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(&self, pos: Vec3<f32>, branch_idx: usize) -> (bool, bool) { fn is_branch_or_leaves_at_inner(&self, pos: Vec3<f32>, branch_idx: usize) -> (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 (it's not one of our children) // Always probe the sibling branch, since our AABB doesn't include its bounds
let branch_or_leaves = branch.sibling_idx // (it's not one of our children)
let branch_or_leaves = branch
.sibling_idx
.map(|idx| Vec2::from(self.is_branch_or_leaves_at_inner(pos, idx))) .map(|idx| Vec2::from(self.is_branch_or_leaves_at_inner(pos, idx)))
.unwrap_or_default(); .unwrap_or_default();
// Only continue probing this sub-graph of the tree if the sample position falls within its AABB // Only continue probing this sub-graph of the tree if the sample position falls
// within its AABB
if branch.aabb.contains_point(pos) { if branch.aabb.contains_point(pos) {
(branch_or_leaves (branch_or_leaves
// Probe this branch // Probe this branch
@ -407,23 +452,25 @@ impl ProceduralTree {
| branch.child_idx | branch.child_idx
.map(|idx| Vec2::from(self.is_branch_or_leaves_at_inner(pos, idx))) .map(|idx| Vec2::from(self.is_branch_or_leaves_at_inner(pos, idx)))
.unwrap_or_default()) .unwrap_or_default())
.into_tuple() .into_tuple()
} else { } else {
branch_or_leaves.into_tuple() branch_or_leaves.into_tuple()
} }
} }
/// Determine whether there are either branches or leaves at the given position in the tree. /// Determine whether there are either branches or leaves at the given
/// position in the tree.
#[inline(always)] #[inline(always)]
pub fn is_branch_or_leaves_at(&self, pos: Vec3<f32>) -> (bool, bool) { pub fn is_branch_or_leaves_at(&self, pos: Vec3<f32>) -> (bool, bool) {
self.is_branch_or_leaves_at_inner(pos, self.trunk_idx) self.is_branch_or_leaves_at_inner(pos, self.trunk_idx)
} }
} }
// Branches are arranged in a graph shape. Each branch points to both its first child (if any) and also to the next // Branches are arranged in a graph shape. Each branch points to both its first
// branch in the list of child branches associated with the parent. This means that the entire tree is laid out in a // child (if any) and also to the next branch in the list of child branches
// walkable graph where each branch refers only to two other branches. As a result, walking the tree is simply a case // associated with the parent. This means that the entire tree is laid out in a
// of performing double recursion. // 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.
struct Branch { struct Branch {
line: LineSegment3<f32>, line: LineSegment3<f32>,
wood_radius: f32, wood_radius: f32,
@ -436,7 +483,8 @@ struct Branch {
} }
impl Branch { impl Branch {
/// Determine whether there are either branches or leaves at the given position in the branch. /// Determine whether there are either branches or leaves at the given
/// position in the branch.
pub fn is_branch_or_leaves_at(&self, pos: Vec3<f32>) -> (bool, bool) { pub fn is_branch_or_leaves_at(&self, pos: Vec3<f32>) -> (bool, bool) {
// fn finvsqrt(x: f32) -> f32 { // fn finvsqrt(x: f32) -> f32 {
// let y = f32::from_bits(0x5f375a86 - (x.to_bits() >> 1)); // let y = f32::from_bits(0x5f375a86 - (x.to_bits() >> 1));

View File

@ -516,7 +516,7 @@ impl WorldSim {
cave_0_nz: SuperSimplex::new().set_seed(rng.gen()), cave_0_nz: SuperSimplex::new().set_seed(rng.gen()),
cave_1_nz: SuperSimplex::new().set_seed(rng.gen()), cave_1_nz: SuperSimplex::new().set_seed(rng.gen()),
structure_gen: StructureGen2d::new(rng.gen(), 32, 16), structure_gen: StructureGen2d::new(rng.gen(), 24, 8),
region_gen: StructureGen2d::new(rng.gen(), 400, 96), region_gen: StructureGen2d::new(rng.gen(), 400, 96),
humid_nz: Billow::new() humid_nz: Billow::new()
.set_octaves(9) .set_octaves(9)

View File

@ -1,14 +1,14 @@
mod tile;
mod plot; mod plot;
mod tile;
use vek::*;
use common::store::{Store, Id};
use crate::util::Grid;
use self::{ use self::{
tile::TileGrid,
plot::{Plot, PlotKind}, plot::{Plot, PlotKind},
tile::TileGrid,
}; };
use crate::util::Grid;
use common::store::{Id, Store};
use rand::prelude::*; use rand::prelude::*;
use vek::*;
#[derive(Default)] #[derive(Default)]
pub struct Site { pub struct Site {
@ -25,19 +25,17 @@ impl Site {
} }
} }
pub fn plots(&self) -> impl Iterator<Item=&Plot> + '_ { pub fn plots(&self) -> impl Iterator<Item = &Plot> + '_ { self.plots.values() }
self.plots.values()
}
pub fn create_plot(&mut self, plot: Plot) -> Id<Plot> { pub fn create_plot(&mut self, plot: Plot) -> Id<Plot> { self.plots.insert(plot) }
self.plots.insert(plot)
}
pub fn generate(rng: &mut impl Rng) -> Self { pub fn generate(rng: &mut impl Rng) -> Self {
let mut site = Site::default(); let mut site = Site::default();
for i in 0..10 { for i in 0..10 {
let dir = Vec2::<f32>::zero().map(|_| rng.gen_range(-1.0..1.0)).normalized(); let dir = Vec2::<f32>::zero()
.map(|_| rng.gen_range(-1.0..1.0))
.normalized();
let search_pos = (dir * 32.0).map(|e| e as i32); let search_pos = (dir * 32.0).map(|e| e as i32);
site.tiles site.tiles
@ -51,6 +49,4 @@ impl Site {
} }
} }
pub fn test_site() -> Site { pub fn test_site() -> Site { Site::generate(&mut thread_rng()) }
Site::generate(&mut thread_rng())
}

View File

@ -1,5 +1,5 @@
use vek::*;
use crate::util::DHashSet; use crate::util::DHashSet;
use vek::*;
pub struct Plot { pub struct Plot {
kind: PlotKind, kind: PlotKind,
@ -11,7 +11,9 @@ impl Plot {
pub fn find_bounds(&self) -> Aabr<i32> { pub fn find_bounds(&self) -> Aabr<i32> {
self.tiles self.tiles
.iter() .iter()
.fold(Aabr::new_empty(self.root_tile), |b, t| b.expanded_to_contain_point(*t)) .fold(Aabr::new_empty(self.root_tile), |b, t| {
b.expanded_to_contain_point(*t)
})
} }
} }

View File

@ -23,18 +23,22 @@ impl TileGrid {
let tpos = tpos + TILE_RADIUS as i32; let tpos = tpos + TILE_RADIUS as i32;
self.zones self.zones
.get(tpos) .get(tpos)
.and_then(|zone| zone.as_ref()?.get(tpos.map(|e| e.rem_euclid(ZONE_SIZE as i32)))) .and_then(|zone| {
zone.as_ref()?
.get(tpos.map(|e| e.rem_euclid(ZONE_SIZE as i32)))
})
.and_then(|tile| tile.as_ref()) .and_then(|tile| tile.as_ref())
} }
pub fn get_mut(&mut self, tpos: Vec2<i32>) -> Option<&mut Tile> { pub fn get_mut(&mut self, tpos: Vec2<i32>) -> Option<&mut Tile> {
let tpos = tpos + TILE_RADIUS as i32; let tpos = tpos + TILE_RADIUS as i32;
self.zones self.zones.get_mut(tpos).and_then(|zone| {
.get_mut(tpos) zone.get_or_insert_with(|| {
.and_then(|zone| zone Grid::populate_from(Vec2::broadcast(ZONE_RADIUS as i32 * 2 + 1), |_| None)
.get_or_insert_with(|| Grid::populate_from(Vec2::broadcast(ZONE_RADIUS as i32 * 2 + 1), |_| None)) })
.get_mut(tpos.map(|e| e.rem_euclid(ZONE_SIZE as i32))) .get_mut(tpos.map(|e| e.rem_euclid(ZONE_SIZE as i32)))
.map(|tile| tile.get_or_insert_with(|| Tile::empty()))) .map(|tile| tile.get_or_insert_with(|| Tile::empty()))
})
} }
pub fn find_near(&self, tpos: Vec2<i32>, f: impl Fn(&Tile) -> bool) -> Option<Vec2<i32>> { pub fn find_near(&self, tpos: Vec2<i32>, f: impl Fn(&Tile) -> bool) -> Option<Vec2<i32>> {
@ -62,7 +66,5 @@ impl Tile {
} }
} }
pub fn is_empty(&self) -> bool { pub fn is_empty(&self) -> bool { self.kind == TileKind::Empty }
self.kind == TileKind::Empty
}
} }