2020-11-07 21:50:52 +00:00
|
|
|
use crate::{
|
|
|
|
all::ForestKind,
|
|
|
|
block::block_from_structure,
|
|
|
|
column::ColumnGen,
|
|
|
|
util::{RandomPerm, Sampler, UnitChooser},
|
|
|
|
Canvas, CONFIG,
|
|
|
|
};
|
|
|
|
use common::{
|
2020-11-09 15:06:37 +00:00
|
|
|
terrain::{structure::Structure, Block, BlockKind},
|
2020-11-07 21:50:52 +00:00
|
|
|
vol::ReadVol,
|
|
|
|
};
|
|
|
|
use lazy_static::lazy_static;
|
|
|
|
use std::{collections::HashMap, f32, sync::Arc};
|
|
|
|
use vek::*;
|
|
|
|
|
|
|
|
lazy_static! {
|
2020-11-22 01:37:20 +00:00
|
|
|
pub static ref OAKS: Vec<Arc<Structure>> = Structure::load_group("oaks");
|
2020-11-07 21:50:52 +00:00
|
|
|
pub static ref OAK_STUMPS: Vec<Arc<Structure>> = Structure::load_group("oak_stumps");
|
|
|
|
pub static ref PINES: Vec<Arc<Structure>> = Structure::load_group("pines");
|
|
|
|
pub static ref PALMS: Vec<Arc<Structure>> = Structure::load_group("palms");
|
|
|
|
pub static ref ACACIAS: Vec<Arc<Structure>> = Structure::load_group("acacias");
|
2020-12-08 00:09:37 +00:00
|
|
|
pub static ref BAOBABS: Vec<Arc<Structure>> = Structure::load_group("baobabs");
|
2020-11-07 21:50:52 +00:00
|
|
|
pub static ref FRUIT_TREES: Vec<Arc<Structure>> = Structure::load_group("fruit_trees");
|
|
|
|
pub static ref BIRCHES: Vec<Arc<Structure>> = Structure::load_group("birch");
|
|
|
|
pub static ref MANGROVE_TREES: Vec<Arc<Structure>> = Structure::load_group("mangrove_trees");
|
|
|
|
pub static ref QUIRKY: Vec<Arc<Structure>> = Structure::load_group("quirky");
|
|
|
|
pub static ref QUIRKY_DRY: Vec<Arc<Structure>> = Structure::load_group("quirky_dry");
|
2020-11-17 03:17:03 +00:00
|
|
|
pub static ref SWAMP_TREES: Vec<Arc<Structure>> = Structure::load_group("swamp_trees");
|
2020-11-07 21:50:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static MODEL_RAND: RandomPerm = RandomPerm::new(0xDB21C052);
|
|
|
|
static UNIT_CHOOSER: UnitChooser = UnitChooser::new(0x700F4EC7);
|
|
|
|
static QUIRKY_RAND: RandomPerm = RandomPerm::new(0xA634460F);
|
|
|
|
|
2020-11-23 15:39:03 +00:00
|
|
|
#[allow(clippy::if_same_then_else)]
|
2020-11-08 23:19:07 +00:00
|
|
|
pub fn apply_trees_to(canvas: &mut Canvas) {
|
2020-11-07 21:50:52 +00:00
|
|
|
struct Tree {
|
|
|
|
pos: Vec3<i32>,
|
|
|
|
model: Arc<Structure>,
|
|
|
|
seed: u32,
|
|
|
|
units: (Vec2<i32>, Vec2<i32>),
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut tree_cache = HashMap::new();
|
|
|
|
|
|
|
|
let info = canvas.info();
|
|
|
|
canvas.foreach_col(|canvas, wpos2d, col| {
|
|
|
|
let trees = info.land().get_near_trees(wpos2d);
|
|
|
|
|
|
|
|
for (tree_wpos, seed) in trees {
|
|
|
|
let tree = if let Some(tree) = tree_cache.entry(tree_wpos).or_insert_with(|| {
|
|
|
|
let col = ColumnGen::new(info.land()).get((tree_wpos, info.index()))?;
|
|
|
|
|
2020-11-11 11:42:22 +00:00
|
|
|
let is_quirky = QUIRKY_RAND.chance(seed, 1.0 / 500.0);
|
|
|
|
|
2020-11-23 15:39:03 +00:00
|
|
|
// Ensure that it's valid to place a *thing* here
|
2020-11-11 11:42:22 +00:00
|
|
|
if col.alt < col.water_level
|
2020-11-22 01:37:20 +00:00
|
|
|
|| col.spawn_rate < 0.9
|
2020-11-07 21:50:52 +00:00
|
|
|
|| col.water_dist.map(|d| d < 8.0).unwrap_or(false)
|
|
|
|
|| col.path.map(|(d, _, _, _)| d < 12.0).unwrap_or(false)
|
|
|
|
{
|
|
|
|
return None;
|
2020-11-23 15:39:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Ensure that it's valid to place a tree here
|
|
|
|
if !is_quirky && ((seed.wrapping_mul(13)) & 0xFF) as f32 / 256.0 > col.tree_density
|
2020-11-15 01:40:23 +00:00
|
|
|
{
|
2020-11-11 11:42:22 +00:00
|
|
|
return None;
|
2020-11-07 21:50:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Some(Tree {
|
|
|
|
pos: Vec3::new(tree_wpos.x, tree_wpos.y, col.alt as i32),
|
|
|
|
model: {
|
2020-11-11 11:42:22 +00:00
|
|
|
let models: &'static [_] = if is_quirky {
|
2020-11-07 21:50:52 +00:00
|
|
|
if col.temp > CONFIG.desert_temp {
|
|
|
|
&QUIRKY_DRY
|
|
|
|
} else {
|
|
|
|
&QUIRKY
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
match col.forest_kind {
|
2020-11-15 01:40:23 +00:00
|
|
|
ForestKind::Oak if QUIRKY_RAND.chance(seed + 1, 1.0 / 16.0) => {
|
|
|
|
&OAK_STUMPS
|
|
|
|
},
|
|
|
|
ForestKind::Oak if QUIRKY_RAND.chance(seed + 2, 1.0 / 20.0) => {
|
|
|
|
&FRUIT_TREES
|
|
|
|
},
|
2020-11-09 17:19:29 +00:00
|
|
|
ForestKind::Palm => &PALMS,
|
2020-12-08 00:09:37 +00:00
|
|
|
ForestKind::Acacia => &ACACIAS,
|
|
|
|
ForestKind::Baobab => &BAOBABS,
|
2020-11-07 21:50:52 +00:00
|
|
|
ForestKind::Oak => &OAKS,
|
|
|
|
ForestKind::Pine => &PINES,
|
2020-11-09 22:59:41 +00:00
|
|
|
ForestKind::Birch => &BIRCHES,
|
2020-11-07 21:50:52 +00:00
|
|
|
ForestKind::Mangrove => &MANGROVE_TREES,
|
2020-11-17 03:17:03 +00:00
|
|
|
ForestKind::Swamp => &SWAMP_TREES,
|
2020-11-07 21:50:52 +00:00
|
|
|
}
|
|
|
|
};
|
2020-11-08 23:19:07 +00:00
|
|
|
Arc::clone(
|
|
|
|
&models[(MODEL_RAND.get(seed.wrapping_mul(17)) / 13) as usize
|
|
|
|
% models.len()],
|
|
|
|
)
|
2020-11-07 21:50:52 +00:00
|
|
|
},
|
|
|
|
seed,
|
|
|
|
units: UNIT_CHOOSER.get(seed),
|
|
|
|
})
|
|
|
|
}) {
|
|
|
|
tree
|
|
|
|
} else {
|
|
|
|
continue;
|
|
|
|
};
|
|
|
|
|
|
|
|
let bounds = tree.model.get_bounds();
|
2020-11-09 15:06:37 +00:00
|
|
|
let mut is_top = true;
|
2020-11-09 17:09:33 +00:00
|
|
|
let mut is_leaf_top = true;
|
2020-11-09 15:06:37 +00:00
|
|
|
for z in (bounds.min.z..bounds.max.z).rev() {
|
2020-11-07 21:50:52 +00:00
|
|
|
let wpos = Vec3::new(wpos2d.x, wpos2d.y, tree.pos.z + z);
|
|
|
|
let model_pos = Vec3::from(
|
|
|
|
(wpos - tree.pos)
|
|
|
|
.xy()
|
|
|
|
.map2(Vec2::new(tree.units.0, tree.units.1), |rpos, unit| {
|
|
|
|
unit * rpos
|
|
|
|
})
|
|
|
|
.sum(),
|
|
|
|
) + Vec3::unit_z() * (wpos.z - tree.pos.z);
|
|
|
|
block_from_structure(
|
|
|
|
info.index(),
|
2020-11-08 23:19:07 +00:00
|
|
|
if let Some(block) = tree.model.get(model_pos).ok().copied() {
|
2020-11-07 22:51:12 +00:00
|
|
|
block
|
|
|
|
} else {
|
2020-11-08 23:19:07 +00:00
|
|
|
// If we hit an inaccessible block, we're probably outside the model bounds.
|
|
|
|
// Skip this column.
|
2020-11-07 22:51:12 +00:00
|
|
|
break;
|
|
|
|
},
|
2020-11-07 21:50:52 +00:00
|
|
|
wpos,
|
|
|
|
tree.pos.xy(),
|
|
|
|
tree.seed,
|
|
|
|
col,
|
|
|
|
Block::air,
|
|
|
|
)
|
2020-11-09 15:06:37 +00:00
|
|
|
.map(|block| {
|
2020-11-09 17:09:33 +00:00
|
|
|
// Add a snow covering to the block above under certain circumstances
|
|
|
|
if col.snow_cover
|
|
|
|
&& ((block.kind() == BlockKind::Leaves && is_leaf_top)
|
|
|
|
|| (is_top && block.is_filled()))
|
|
|
|
{
|
2020-11-09 15:06:37 +00:00
|
|
|
canvas.set(
|
|
|
|
wpos + Vec3::unit_z(),
|
|
|
|
Block::new(BlockKind::Snow, Rgb::new(210, 210, 255)),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
canvas.set(wpos, block);
|
2020-11-09 17:09:33 +00:00
|
|
|
is_leaf_top = false;
|
2020-11-09 15:06:37 +00:00
|
|
|
is_top = false;
|
|
|
|
})
|
|
|
|
.unwrap_or_else(|| {
|
2020-11-09 17:09:33 +00:00
|
|
|
is_leaf_top = true;
|
2020-11-09 15:06:37 +00:00
|
|
|
});
|
2020-11-07 21:50:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|