mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Merge branch 'treeco/lod-models' into 'master'
Overhaul of LOD models See merge request veloren/veloren!4390
This commit is contained in:
commit
e22cbab7ce
@ -53,6 +53,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- Allow moving and resizing the chat with left and right mouse button respectively.
|
||||
- Missing plugins are requested from the server and cached locally.
|
||||
- Support for adding spots in plugins.
|
||||
- Added real colours to LOD trees and rooftops, unique models for most tree kinds, and models for several buildings
|
||||
|
||||
### Changed
|
||||
|
||||
|
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -7316,6 +7316,7 @@ version = "0.15.0"
|
||||
dependencies = [
|
||||
"assets_manager",
|
||||
"backtrace",
|
||||
"bitflags 2.5.0",
|
||||
"bytemuck",
|
||||
"chrono",
|
||||
"chumsky",
|
||||
|
BIN
assets/voxygen/lod/acacia.obj
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/lod/acacia.obj
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/lod/arena.obj
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/lod/arena.obj
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/lod/baobab.obj
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/lod/baobab.obj
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/lod/birch.obj
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/lod/birch.obj
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/lod/dead.obj
(Stored with Git LFS)
BIN
assets/voxygen/lod/dead.obj
(Stored with Git LFS)
Binary file not shown.
BIN
assets/voxygen/lod/desert_houses.obj
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/lod/desert_houses.obj
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/lod/frostpine.obj
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/lod/frostpine.obj
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/lod/giant_tree.obj
(Stored with Git LFS)
BIN
assets/voxygen/lod/giant_tree.obj
(Stored with Git LFS)
Binary file not shown.
BIN
assets/voxygen/lod/haniwa.obj
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/lod/haniwa.obj
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/lod/house.obj
(Stored with Git LFS)
BIN
assets/voxygen/lod/house.obj
(Stored with Git LFS)
Binary file not shown.
BIN
assets/voxygen/lod/mangrove.obj
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/lod/mangrove.obj
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/lod/oak.obj
(Stored with Git LFS)
BIN
assets/voxygen/lod/oak.obj
(Stored with Git LFS)
Binary file not shown.
BIN
assets/voxygen/lod/palm.obj
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/lod/palm.obj
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/lod/pine.obj
(Stored with Git LFS)
BIN
assets/voxygen/lod/pine.obj
(Stored with Git LFS)
Binary file not shown.
BIN
assets/voxygen/lod/redwood.obj
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/lod/redwood.obj
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -25,8 +25,7 @@ layout(location = 3) in vec3 model_pos;
|
||||
layout(location = 4) flat in uint f_flags;
|
||||
|
||||
const uint FLAG_SNOW_COVERED = 1;
|
||||
const uint FLAG_IS_BUILDING = 2;
|
||||
const uint FLAG_IS_GIANT_TREE = 4;
|
||||
const uint FLAG_GLOW = 2;
|
||||
|
||||
layout(location = 0) out vec4 tgt_color;
|
||||
layout(location = 1) out uvec4 tgt_mat;
|
||||
@ -84,13 +83,6 @@ void main() {
|
||||
vec3 k_d = vec3(1.0);
|
||||
vec3 k_s = vec3(R_s);
|
||||
|
||||
// Tree trunks
|
||||
if ((f_flags & FLAG_IS_GIANT_TREE) > 0u) {
|
||||
if (dot(abs(model_pos.xyz) * vec3(1.0, 1.0, 2.0), vec3(1)) < 430.0) { surf_color = vec3(0.05, 0.02, 0.0); }
|
||||
} else {
|
||||
if (model_pos.z < 25.0 && dot(abs(model_pos.xy), vec2(1)) < 6.0) { surf_color = vec3(0.05, 0.02, 0.0); }
|
||||
}
|
||||
|
||||
vec3 voxel_norm = f_norm;
|
||||
float my_alt = f_pos.z + focus_off.z;
|
||||
float f_ao = 1.0;
|
||||
@ -138,13 +130,8 @@ void main() {
|
||||
reflected_light *= f_ao;
|
||||
|
||||
vec3 glow = vec3(0);
|
||||
if ((f_flags & FLAG_IS_BUILDING) > 0u && abs(f_norm.z) < 0.1) {
|
||||
ivec3 wpos = ivec3((f_pos.xyz + focus_off.xyz) * 0.2);
|
||||
if (((wpos.x & wpos.y & wpos.z) & 1) == 1) {
|
||||
if ((f_flags & FLAG_GLOW) > 0u) {
|
||||
glow += vec3(1, 0.7, 0.3) * 2;
|
||||
} else {
|
||||
reflected_light += vec3(1, 0.7, 0.3) * 0.9;
|
||||
}
|
||||
}
|
||||
|
||||
vec3 side_color = surf_color;
|
||||
|
@ -20,9 +20,13 @@
|
||||
layout(location = 0) in vec3 v_pos;
|
||||
layout(location = 1) in vec3 v_norm;
|
||||
layout(location = 2) in vec3 v_col;
|
||||
layout(location = 3) in vec3 inst_pos;
|
||||
layout(location = 4) in uvec3 inst_col;
|
||||
layout(location = 5) in uint inst_flags;
|
||||
layout(location = 3) in uint v_flags;
|
||||
layout(location = 4) in vec3 inst_pos;
|
||||
layout(location = 5) in vec3 inst_col;
|
||||
layout(location = 6) in uint inst_flags;
|
||||
|
||||
const uint FLAG_INST_COLOR = 1;
|
||||
const uint FLAG_INST_GLOW = 2;
|
||||
|
||||
layout(location = 0) out vec3 f_pos;
|
||||
layout(location = 1) out vec3 f_norm;
|
||||
@ -47,8 +51,13 @@ void main() {
|
||||
#endif
|
||||
|
||||
f_norm = v_norm;
|
||||
f_col = vec4(vec3(inst_col) * (1.0 / 255.0) * v_col * (hash(inst_pos.xyxy) * 0.4 + 0.6), 1.0);
|
||||
f_flags = inst_flags;
|
||||
|
||||
if ((v_flags & FLAG_INST_COLOR) > 0u) {
|
||||
f_col = vec4(inst_col, 1.0);
|
||||
} else {
|
||||
f_col = vec4(v_col, 1.0);
|
||||
}
|
||||
f_flags = inst_flags | (v_flags & FLAG_INST_GLOW);
|
||||
|
||||
gl_Position =
|
||||
all_mat *
|
||||
|
@ -8,31 +8,38 @@ pub const ZONE_SIZE: u32 = 32;
|
||||
|
||||
bitflags::bitflags! {
|
||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
|
||||
pub struct Flags: u8 {
|
||||
pub struct InstFlags: u8 {
|
||||
const SNOW_COVERED = 0b00000001;
|
||||
const IS_BUILDING = 0b00000010;
|
||||
const IS_GIANT_TREE = 0b00000100;
|
||||
const GLOW = 0b00000010;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Hash, PartialEq, Eq, Debug, Serialize, Deserialize, EnumIter)]
|
||||
#[repr(u16)]
|
||||
pub enum ObjectKind {
|
||||
Oak,
|
||||
GenericTree,
|
||||
Pine,
|
||||
Dead,
|
||||
House,
|
||||
GiantTree,
|
||||
MapleTree,
|
||||
Cherry,
|
||||
AutumnTree,
|
||||
Mangrove,
|
||||
Acacia,
|
||||
Birch,
|
||||
Redwood,
|
||||
Baobab,
|
||||
Frostpine,
|
||||
Haniwa,
|
||||
Desert,
|
||||
Palm,
|
||||
Arena,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct Object {
|
||||
pub kind: ObjectKind,
|
||||
pub pos: Vec3<i16>,
|
||||
pub flags: Flags,
|
||||
pub flags: InstFlags,
|
||||
pub color: Rgb<u8>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
|
@ -128,6 +128,7 @@ num_cpus = "1.0"
|
||||
inline_tweak = { workspace = true }
|
||||
itertools = { workspace = true }
|
||||
sha2 = { workspace = true }
|
||||
bitflags = { workspace = true, features = ["serde"] }
|
||||
|
||||
# Discord RPC
|
||||
discord-sdk = { version = "0.3.0", optional = true }
|
||||
|
@ -1,5 +1,6 @@
|
||||
use super::super::{AaMode, GlobalsLayouts, Vertex as VertexTrait};
|
||||
use bytemuck::{Pod, Zeroable};
|
||||
use common::util::srgb_to_linear;
|
||||
use std::mem;
|
||||
use vek::*;
|
||||
|
||||
@ -9,20 +10,27 @@ pub struct Vertex {
|
||||
pos: [f32; 3],
|
||||
norm: [f32; 3],
|
||||
col: [f32; 3],
|
||||
flags: u32,
|
||||
}
|
||||
|
||||
impl Vertex {
|
||||
pub fn new(pos: Vec3<f32>, norm: Vec3<f32>, col: Rgb<f32>) -> Self {
|
||||
pub fn new(
|
||||
pos: Vec3<f32>,
|
||||
norm: Vec3<f32>,
|
||||
col: Rgb<f32>,
|
||||
flags: crate::scene::lod::VertexFlags,
|
||||
) -> Self {
|
||||
Self {
|
||||
pos: pos.into_array(),
|
||||
norm: norm.into_array(),
|
||||
col: col.into_array(),
|
||||
flags: flags.bits() as u32,
|
||||
}
|
||||
}
|
||||
|
||||
fn desc<'a>() -> wgpu::VertexBufferLayout<'a> {
|
||||
const ATTRIBUTES: [wgpu::VertexAttribute; 3] =
|
||||
wgpu::vertex_attr_array![0 => Float32x3, 1 => Float32x3, 2 => Float32x3];
|
||||
const ATTRIBUTES: [wgpu::VertexAttribute; 4] =
|
||||
wgpu::vertex_attr_array![0 => Float32x3, 1 => Float32x3, 2 => Float32x3, 3 => Uint32];
|
||||
wgpu::VertexBufferLayout {
|
||||
array_stride: Self::STRIDE,
|
||||
step_mode: wgpu::VertexStepMode::Vertex,
|
||||
@ -40,24 +48,24 @@ impl VertexTrait for Vertex {
|
||||
#[derive(Copy, Clone, Debug, Zeroable, Pod)]
|
||||
pub struct Instance {
|
||||
inst_pos: [f32; 3],
|
||||
inst_col: [u8; 4],
|
||||
inst_col: [f32; 3],
|
||||
flags: u32,
|
||||
}
|
||||
|
||||
impl Instance {
|
||||
pub fn new(inst_pos: Vec3<f32>, col: Rgb<u8>, flags: common::lod::Flags) -> Self {
|
||||
pub fn new(inst_pos: Vec3<f32>, col: Rgb<u8>, flags: common::lod::InstFlags) -> Self {
|
||||
Self {
|
||||
inst_pos: inst_pos.into_array(),
|
||||
inst_col: Rgba::new(col.r, col.g, col.b, 255).into_array(),
|
||||
inst_col: srgb_to_linear(col.map(|c| c as f32 / 255.0)).into_array(),
|
||||
flags: flags.bits() as u32,
|
||||
}
|
||||
}
|
||||
|
||||
fn desc<'a>() -> wgpu::VertexBufferLayout<'a> {
|
||||
const ATTRIBUTES: [wgpu::VertexAttribute; 3] = wgpu::vertex_attr_array![
|
||||
3 => Float32x3,
|
||||
4 => Uint8x4,
|
||||
5 => Uint32,
|
||||
4 => Float32x3,
|
||||
5 => Float32x3,
|
||||
6 => Uint32,
|
||||
];
|
||||
wgpu::VertexBufferLayout {
|
||||
array_stride: mem::size_of::<Self>() as wgpu::BufferAddress,
|
||||
|
@ -12,7 +12,7 @@ use common::{
|
||||
assets::{AssetExt, ObjAsset},
|
||||
lod,
|
||||
spiral::Spiral2d,
|
||||
util::srgba_to_linear,
|
||||
util::{srgb_to_linear, srgba_to_linear},
|
||||
weather,
|
||||
};
|
||||
use hashbrown::HashMap;
|
||||
@ -23,6 +23,16 @@ use vek::*;
|
||||
// For culling
|
||||
const MAX_OBJECT_RADIUS: i32 = 64;
|
||||
|
||||
bitflags::bitflags! {
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct VertexFlags: u8 {
|
||||
// Use instance not vertex colour
|
||||
const INST_COLOR = 0b00000001;
|
||||
// Glow!
|
||||
const GLOW = 0b00000010;
|
||||
}
|
||||
}
|
||||
|
||||
struct ObjectGroup {
|
||||
instances: Instances<LodObjectInstance>,
|
||||
// None implies no instances
|
||||
@ -63,7 +73,10 @@ impl Lod {
|
||||
data,
|
||||
zone_objects: HashMap::new(),
|
||||
object_data: [
|
||||
(lod::ObjectKind::Oak, make_lod_object("oak", renderer)),
|
||||
(
|
||||
lod::ObjectKind::GenericTree,
|
||||
make_lod_object("oak", renderer),
|
||||
),
|
||||
(lod::ObjectKind::Pine, make_lod_object("pine", renderer)),
|
||||
(lod::ObjectKind::Dead, make_lod_object("dead", renderer)),
|
||||
(lod::ObjectKind::House, make_lod_object("house", renderer)),
|
||||
@ -71,15 +84,30 @@ impl Lod {
|
||||
lod::ObjectKind::GiantTree,
|
||||
make_lod_object("giant_tree", renderer),
|
||||
),
|
||||
(lod::ObjectKind::MapleTree, make_lod_object("oak", renderer)),
|
||||
(lod::ObjectKind::Cherry, make_lod_object("oak", renderer)),
|
||||
(
|
||||
lod::ObjectKind::AutumnTree,
|
||||
make_lod_object("oak", renderer),
|
||||
lod::ObjectKind::Mangrove,
|
||||
make_lod_object("mangrove", renderer),
|
||||
),
|
||||
(lod::ObjectKind::Acacia, make_lod_object("acacia", renderer)),
|
||||
(lod::ObjectKind::Birch, make_lod_object("birch", renderer)),
|
||||
(
|
||||
lod::ObjectKind::Redwood,
|
||||
make_lod_object("redwood", renderer),
|
||||
),
|
||||
(lod::ObjectKind::Baobab, make_lod_object("baobab", renderer)),
|
||||
(
|
||||
lod::ObjectKind::Frostpine,
|
||||
make_lod_object("frostpine", renderer),
|
||||
),
|
||||
(lod::ObjectKind::Haniwa, make_lod_object("haniwa", renderer)),
|
||||
(
|
||||
lod::ObjectKind::Desert,
|
||||
make_lod_object("desert_houses", renderer),
|
||||
),
|
||||
(lod::ObjectKind::Palm, make_lod_object("palm", renderer)),
|
||||
(lod::ObjectKind::Arena, make_lod_object("arena", renderer)),
|
||||
]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
.into(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -127,21 +155,10 @@ impl Lod {
|
||||
z_range.start.min(pos.z as i32)..z_range.end.max(pos.z as i32)
|
||||
},
|
||||
));
|
||||
// TODO: Put this somewhere more easily configurable, like a manifest
|
||||
let color = match object.kind {
|
||||
lod::ObjectKind::Pine => Rgb::new(0, 25, 12),
|
||||
lod::ObjectKind::Oak => Rgb::new(10, 50, 5),
|
||||
lod::ObjectKind::Dead => Rgb::new(20, 10, 2),
|
||||
lod::ObjectKind::House => Rgb::new(20, 15, 0),
|
||||
lod::ObjectKind::GiantTree => Rgb::new(8, 35, 5),
|
||||
lod::ObjectKind::MapleTree => Rgb::new(20, 0, 5),
|
||||
lod::ObjectKind::Cherry => Rgb::new(70, 40, 70),
|
||||
lod::ObjectKind::AutumnTree => Rgb::new(60, 25, 0),
|
||||
};
|
||||
objects
|
||||
.entry(object.kind)
|
||||
.or_default()
|
||||
.push(LodObjectInstance::new(pos, color, object.flags));
|
||||
.push(LodObjectInstance::new(pos, object.color, object.flags));
|
||||
}
|
||||
objects
|
||||
.into_iter()
|
||||
@ -257,18 +274,31 @@ fn make_lod_object(name: &str, renderer: &mut Renderer) -> Model<LodObjectVertex
|
||||
let mesh = model
|
||||
.read()
|
||||
.0
|
||||
.triangles()
|
||||
.map(|vs| {
|
||||
.objects()
|
||||
.flat_map(|(objname, obj)| {
|
||||
let mut color = objname.split('_').filter_map(|x| x.parse::<u8>().ok());
|
||||
let color = color
|
||||
.next()
|
||||
.and_then(|r| Some(Rgb::new(r, color.next()?, color.next()?)))
|
||||
.unwrap_or(Rgb::broadcast(127));
|
||||
let color = srgb_to_linear(color.map(|c| (c as f32 / 255.0)));
|
||||
let flags = match objname {
|
||||
"InstCol" => VertexFlags::INST_COLOR,
|
||||
"Glow" => VertexFlags::GLOW,
|
||||
_ => VertexFlags::empty(),
|
||||
};
|
||||
obj.triangles().map(move |vs| {
|
||||
let [a, b, c] = vs.map(|v| {
|
||||
LodObjectVertex::new(
|
||||
v.position().into(),
|
||||
v.normal().unwrap_or([0.0, 0.0, 1.0]).into(),
|
||||
Rgb::broadcast(1.0),
|
||||
//v.color().unwrap_or([1.0; 3]).into(),
|
||||
color,
|
||||
flags,
|
||||
)
|
||||
});
|
||||
Tri::new(a, b, c)
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
renderer.create_model(&mesh).expect("Mesh was empty!")
|
||||
}
|
||||
|
@ -1,7 +1,11 @@
|
||||
use crate::util::math::close;
|
||||
use crate::{
|
||||
util::{math::close, sampler::Sampler},
|
||||
IndexRef,
|
||||
};
|
||||
use common::terrain::structure::StructureBlock;
|
||||
use std::ops::Range;
|
||||
use strum::EnumIter;
|
||||
use vek::Vec2;
|
||||
use vek::*;
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter)]
|
||||
pub enum ForestKind {
|
||||
@ -126,6 +130,28 @@ impl ForestKind {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn leaf_block(&self) -> StructureBlock {
|
||||
match self {
|
||||
ForestKind::Palm => StructureBlock::PalmLeavesOuter,
|
||||
ForestKind::Acacia => StructureBlock::Acacia,
|
||||
ForestKind::Baobab => StructureBlock::Baobab,
|
||||
ForestKind::Oak => StructureBlock::TemperateLeaves,
|
||||
ForestKind::Chestnut => StructureBlock::Chestnut,
|
||||
ForestKind::Cedar => StructureBlock::PineLeaves,
|
||||
ForestKind::Pine => StructureBlock::PineLeaves,
|
||||
ForestKind::Redwood => StructureBlock::PineLeaves,
|
||||
ForestKind::Birch => StructureBlock::TemperateLeaves,
|
||||
ForestKind::Mangrove => StructureBlock::Mangrove,
|
||||
ForestKind::Giant => StructureBlock::TemperateLeaves,
|
||||
ForestKind::Swamp => StructureBlock::TemperateLeaves,
|
||||
ForestKind::Frostpine => StructureBlock::FrostpineLeaves,
|
||||
ForestKind::Dead => StructureBlock::TemperateLeaves,
|
||||
ForestKind::Mapletree => StructureBlock::MapleLeaves,
|
||||
ForestKind::Cherry => StructureBlock::CherryLeaves,
|
||||
ForestKind::AutumnTree => StructureBlock::AutumnLeaves,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn proclivity(&self, env: &Environment) -> f32 {
|
||||
self.ideal_proclivity()
|
||||
* close(env.humid, self.humid_range())
|
||||
@ -136,6 +162,30 @@ impl ForestKind {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn leaf_color(
|
||||
index: IndexRef,
|
||||
seed: u32,
|
||||
lerp: f32,
|
||||
sblock: &StructureBlock,
|
||||
) -> Option<Rgb<u8>> {
|
||||
let ranges = sblock
|
||||
.elim_case_pure(&index.colors.block.structure_blocks)
|
||||
.as_ref()
|
||||
.map(Vec::as_slice)
|
||||
.unwrap_or(&[]);
|
||||
|
||||
ranges
|
||||
.get(crate::util::RandomPerm::new(seed).get(seed) as usize % ranges.len())
|
||||
.map(|range| {
|
||||
Rgb::<f32>::lerp(
|
||||
Rgb::<u8>::from(range.start).map(f32::from),
|
||||
Rgb::<u8>::from(range.end).map(f32::from),
|
||||
lerp,
|
||||
)
|
||||
.map(|e| e as u8)
|
||||
})
|
||||
}
|
||||
|
||||
/// Not currently used with trees generated by the tree layer, needs to be
|
||||
/// reworked
|
||||
pub struct TreeAttr {
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::{
|
||||
column::{ColumnGen, ColumnSample},
|
||||
util::{FastNoise, RandomField, RandomPerm, Sampler, SmallCache},
|
||||
util::{FastNoise, RandomField, Sampler, SmallCache},
|
||||
IndexRef, CONFIG,
|
||||
};
|
||||
use common::{
|
||||
@ -212,8 +212,7 @@ pub fn block_from_structure(
|
||||
) -> Option<(Block, Option<SpriteCfg>)> {
|
||||
let field = RandomField::new(structure_seed);
|
||||
|
||||
let lerp = ((field.get(Vec3::from(structure_pos)).rem_euclid(256)) as f32 / 255.0) * 0.8
|
||||
+ ((field.get(pos + i32::MAX / 2).rem_euclid(256)) as f32 / 255.0) * 0.2;
|
||||
let lerp = field.get_f32(Vec3::from(structure_pos)) * 0.8 + field.get_f32(pos) * 0.2;
|
||||
|
||||
let block = match sblock {
|
||||
StructureBlock::None => None,
|
||||
@ -284,49 +283,21 @@ pub fn block_from_structure(
|
||||
| StructureBlock::MapleLeaves
|
||||
| StructureBlock::CherryLeaves
|
||||
| StructureBlock::AutumnLeaves => {
|
||||
let ranges = sblock
|
||||
.elim_case_pure(&index.colors.block.structure_blocks)
|
||||
.as_ref()
|
||||
.map(Vec::as_slice)
|
||||
.unwrap_or(&[]);
|
||||
let range = if ranges.is_empty() {
|
||||
None
|
||||
} else {
|
||||
ranges.get(
|
||||
RandomPerm::new(structure_seed).get(structure_seed) as usize % ranges.len(),
|
||||
)
|
||||
};
|
||||
|
||||
range.map(|range| {
|
||||
if calendar.map_or(false, |c| c.is_event(CalendarEvent::Christmas))
|
||||
&& field.chance(pos + structure_pos, 0.025)
|
||||
{
|
||||
Block::new(BlockKind::GlowingWeakRock, Rgb::new(255, 0, 0))
|
||||
Some(Block::new(BlockKind::GlowingWeakRock, Rgb::new(255, 0, 0)))
|
||||
} else if calendar.map_or(false, |c| c.is_event(CalendarEvent::Halloween))
|
||||
&& *sblock != StructureBlock::PineLeaves
|
||||
&& (*sblock == StructureBlock::TemperateLeaves
|
||||
|| *sblock == StructureBlock::Chestnut
|
||||
|| *sblock == StructureBlock::CherryLeaves)
|
||||
{
|
||||
let (c0, c1) = match structure_seed % 6 {
|
||||
0 => (Rgb::new(165.0, 150.0, 11.0), Rgb::new(170.0, 165.0, 16.0)),
|
||||
1 | 2 => (Rgb::new(218.0, 53.0, 3.0), Rgb::new(226.0, 62.0, 5.0)),
|
||||
_ => (Rgb::new(230.0, 120.0, 20.0), Rgb::new(242.0, 130.0, 25.0)),
|
||||
};
|
||||
|
||||
Block::new(
|
||||
BlockKind::Leaves,
|
||||
Rgb::<f32>::lerp(c0, c1, lerp).map(|e| e as u8),
|
||||
)
|
||||
crate::all::leaf_color(index, structure_seed, lerp, &StructureBlock::AutumnLeaves)
|
||||
.map(|col| Block::new(BlockKind::Leaves, col))
|
||||
} else {
|
||||
Block::new(
|
||||
BlockKind::Leaves,
|
||||
Rgb::<f32>::lerp(
|
||||
Rgb::<u8>::from(range.start).map(f32::from),
|
||||
Rgb::<u8>::from(range.end).map(f32::from),
|
||||
lerp,
|
||||
)
|
||||
.map(|e| e as u8),
|
||||
)
|
||||
crate::all::leaf_color(index, structure_seed, lerp, sblock)
|
||||
.map(|col| Block::new(BlockKind::Leaves, col))
|
||||
}
|
||||
})
|
||||
},
|
||||
StructureBlock::BirchWood => {
|
||||
let wpos = pos + structure_pos;
|
||||
|
@ -69,12 +69,13 @@ pub fn apply_trees_to(
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
enum TreeModel {
|
||||
Structure(Structure),
|
||||
Procedural(ProceduralTree, StructureBlock),
|
||||
Procedural(ProceduralTree),
|
||||
}
|
||||
|
||||
struct Tree {
|
||||
pos: Vec3<i32>,
|
||||
model: TreeModel,
|
||||
leaf_block: StructureBlock,
|
||||
seed: u32,
|
||||
units: (Vec2<i32>, Vec2<i32>),
|
||||
lights: bool,
|
||||
@ -105,151 +106,103 @@ pub fn apply_trees_to(
|
||||
let models: AssetHandle<_> = match forest_kind {
|
||||
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) => {
|
||||
break 'model TreeModel::Procedural(
|
||||
ProceduralTree::generate(
|
||||
break 'model TreeModel::Procedural(ProceduralTree::generate(
|
||||
TreeConfig::apple(&mut RandomPerm::new(seed), scale),
|
||||
&mut RandomPerm::new(seed),
|
||||
),
|
||||
StructureBlock::TemperateLeaves,
|
||||
);
|
||||
));
|
||||
},
|
||||
ForestKind::Palm => *PALMS,
|
||||
ForestKind::Acacia => {
|
||||
break 'model TreeModel::Procedural(
|
||||
ProceduralTree::generate(
|
||||
break 'model TreeModel::Procedural(ProceduralTree::generate(
|
||||
TreeConfig::acacia(&mut RandomPerm::new(seed), scale),
|
||||
&mut RandomPerm::new(seed),
|
||||
),
|
||||
StructureBlock::Acacia,
|
||||
);
|
||||
));
|
||||
},
|
||||
ForestKind::Baobab => {
|
||||
break 'model TreeModel::Procedural(
|
||||
ProceduralTree::generate(
|
||||
break 'model TreeModel::Procedural(ProceduralTree::generate(
|
||||
TreeConfig::baobab(&mut RandomPerm::new(seed), scale),
|
||||
&mut RandomPerm::new(seed),
|
||||
),
|
||||
StructureBlock::Baobab,
|
||||
);
|
||||
));
|
||||
},
|
||||
ForestKind::Oak => {
|
||||
break 'model TreeModel::Procedural(
|
||||
ProceduralTree::generate(
|
||||
break 'model TreeModel::Procedural(ProceduralTree::generate(
|
||||
TreeConfig::oak(&mut RandomPerm::new(seed), scale),
|
||||
&mut RandomPerm::new(seed),
|
||||
),
|
||||
StructureBlock::TemperateLeaves,
|
||||
);
|
||||
));
|
||||
},
|
||||
ForestKind::Dead => {
|
||||
break 'model TreeModel::Procedural(
|
||||
ProceduralTree::generate(
|
||||
break 'model TreeModel::Procedural(ProceduralTree::generate(
|
||||
TreeConfig::dead(&mut RandomPerm::new(seed), scale),
|
||||
&mut RandomPerm::new(seed),
|
||||
),
|
||||
StructureBlock::TemperateLeaves,
|
||||
);
|
||||
));
|
||||
},
|
||||
ForestKind::Chestnut => {
|
||||
break 'model TreeModel::Procedural(
|
||||
ProceduralTree::generate(
|
||||
break 'model TreeModel::Procedural(ProceduralTree::generate(
|
||||
TreeConfig::chestnut(&mut RandomPerm::new(seed), scale),
|
||||
&mut RandomPerm::new(seed),
|
||||
),
|
||||
StructureBlock::Chestnut,
|
||||
);
|
||||
));
|
||||
},
|
||||
ForestKind::Pine => {
|
||||
break 'model TreeModel::Procedural(
|
||||
ProceduralTree::generate(
|
||||
break 'model TreeModel::Procedural(ProceduralTree::generate(
|
||||
TreeConfig::pine(&mut RandomPerm::new(seed), scale, calendar),
|
||||
&mut RandomPerm::new(seed),
|
||||
),
|
||||
StructureBlock::PineLeaves,
|
||||
);
|
||||
));
|
||||
},
|
||||
ForestKind::Cedar => {
|
||||
break 'model TreeModel::Procedural(
|
||||
ProceduralTree::generate(
|
||||
break 'model TreeModel::Procedural(ProceduralTree::generate(
|
||||
TreeConfig::cedar(&mut RandomPerm::new(seed), scale),
|
||||
&mut RandomPerm::new(seed),
|
||||
),
|
||||
StructureBlock::PineLeaves,
|
||||
);
|
||||
));
|
||||
},
|
||||
ForestKind::Redwood => {
|
||||
break 'model TreeModel::Procedural(
|
||||
ProceduralTree::generate(
|
||||
break 'model TreeModel::Procedural(ProceduralTree::generate(
|
||||
TreeConfig::redwood(&mut RandomPerm::new(seed), scale),
|
||||
&mut RandomPerm::new(seed),
|
||||
),
|
||||
StructureBlock::PineLeaves,
|
||||
);
|
||||
));
|
||||
},
|
||||
ForestKind::Birch => {
|
||||
break 'model TreeModel::Procedural(
|
||||
ProceduralTree::generate(
|
||||
break 'model TreeModel::Procedural(ProceduralTree::generate(
|
||||
TreeConfig::birch(&mut RandomPerm::new(seed), scale),
|
||||
&mut RandomPerm::new(seed),
|
||||
),
|
||||
StructureBlock::TemperateLeaves,
|
||||
);
|
||||
));
|
||||
},
|
||||
ForestKind::Frostpine => {
|
||||
break 'model TreeModel::Procedural(
|
||||
ProceduralTree::generate(
|
||||
break 'model TreeModel::Procedural(ProceduralTree::generate(
|
||||
TreeConfig::frostpine(&mut RandomPerm::new(seed), scale),
|
||||
&mut RandomPerm::new(seed),
|
||||
),
|
||||
StructureBlock::FrostpineLeaves,
|
||||
);
|
||||
));
|
||||
},
|
||||
|
||||
ForestKind::Mangrove => {
|
||||
break 'model TreeModel::Procedural(
|
||||
ProceduralTree::generate(
|
||||
break 'model TreeModel::Procedural(ProceduralTree::generate(
|
||||
TreeConfig::jungle(&mut RandomPerm::new(seed), scale),
|
||||
&mut RandomPerm::new(seed),
|
||||
),
|
||||
StructureBlock::Mangrove,
|
||||
);
|
||||
));
|
||||
},
|
||||
ForestKind::Swamp => *SWAMP_TREES,
|
||||
ForestKind::Giant => {
|
||||
break 'model TreeModel::Procedural(
|
||||
ProceduralTree::generate(
|
||||
break 'model TreeModel::Procedural(ProceduralTree::generate(
|
||||
TreeConfig::giant(&mut RandomPerm::new(seed), scale, inhabited),
|
||||
&mut RandomPerm::new(seed),
|
||||
),
|
||||
StructureBlock::TemperateLeaves,
|
||||
);
|
||||
));
|
||||
},
|
||||
ForestKind::Mapletree => {
|
||||
break 'model TreeModel::Procedural(
|
||||
ProceduralTree::generate(
|
||||
break 'model TreeModel::Procedural(ProceduralTree::generate(
|
||||
TreeConfig::oak(&mut RandomPerm::new(seed), scale),
|
||||
&mut RandomPerm::new(seed),
|
||||
),
|
||||
StructureBlock::MapleLeaves,
|
||||
);
|
||||
));
|
||||
},
|
||||
ForestKind::Cherry => {
|
||||
break 'model TreeModel::Procedural(
|
||||
ProceduralTree::generate(
|
||||
break 'model TreeModel::Procedural(ProceduralTree::generate(
|
||||
TreeConfig::cherry(&mut RandomPerm::new(seed), scale),
|
||||
&mut RandomPerm::new(seed),
|
||||
),
|
||||
StructureBlock::CherryLeaves,
|
||||
);
|
||||
));
|
||||
},
|
||||
ForestKind::AutumnTree => {
|
||||
break 'model TreeModel::Procedural(
|
||||
ProceduralTree::generate(
|
||||
break 'model TreeModel::Procedural(ProceduralTree::generate(
|
||||
TreeConfig::autumn_tree(&mut RandomPerm::new(seed), scale),
|
||||
&mut RandomPerm::new(seed),
|
||||
),
|
||||
StructureBlock::AutumnLeaves,
|
||||
);
|
||||
));
|
||||
},
|
||||
};
|
||||
|
||||
@ -260,6 +213,7 @@ pub fn apply_trees_to(
|
||||
.clone(),
|
||||
)
|
||||
},
|
||||
leaf_block: forest_kind.leaf_block(),
|
||||
seed,
|
||||
units: UNIT_CHOOSER.get(seed),
|
||||
lights: inhabited,
|
||||
@ -269,7 +223,7 @@ pub fn apply_trees_to(
|
||||
for tree in trees {
|
||||
let bounds = match &tree.model {
|
||||
TreeModel::Structure(s) => s.get_bounds(),
|
||||
TreeModel::Procedural(t, _) => t.get_bounds().map(|e| e as i32),
|
||||
TreeModel::Procedural(t) => t.get_bounds().map(|e| e as i32),
|
||||
};
|
||||
|
||||
let rpos2d = (wpos2d - tree.pos.xy())
|
||||
@ -282,7 +236,7 @@ pub fn apply_trees_to(
|
||||
|
||||
let hanging_sprites = match &tree.model {
|
||||
TreeModel::Structure(_) => [(0.0004, SpriteKind::Beehive)].as_ref(),
|
||||
TreeModel::Procedural(t, _) => t.config.hanging_sprites,
|
||||
TreeModel::Procedural(t) => t.config.hanging_sprites,
|
||||
};
|
||||
|
||||
let mut is_top = true;
|
||||
@ -303,7 +257,7 @@ pub fn apply_trees_to(
|
||||
info.index(),
|
||||
if let Some(block) = match &tree.model {
|
||||
TreeModel::Structure(s) => s.get(model_pos).ok(),
|
||||
TreeModel::Procedural(t, leaf_block) => Some(
|
||||
TreeModel::Procedural(t) => Some(
|
||||
match t.is_branch_or_leaves_at(model_pos.map(|e| e as f32 + 0.5)) {
|
||||
(_, _, true, _) => {
|
||||
sblock = StructureBlock::Filled(
|
||||
@ -314,7 +268,7 @@ pub fn apply_trees_to(
|
||||
},
|
||||
(_, _, _, true) => &StructureBlock::None,
|
||||
(true, _, _, _) => &t.config.trunk_block,
|
||||
(_, true, _, _) => leaf_block,
|
||||
(_, true, _, _) => &tree.leaf_block,
|
||||
_ => &StructureBlock::None,
|
||||
},
|
||||
),
|
||||
@ -578,20 +532,20 @@ impl TreeConfig {
|
||||
let log_scale = 1.0 + scale.log2().max(0.0);
|
||||
|
||||
Self {
|
||||
trunk_len: 9.0 * scale,
|
||||
trunk_radius: 2.0 * scale,
|
||||
branch_child_len: 0.9,
|
||||
branch_child_radius: 0.75,
|
||||
trunk_len: 45.0 * scale,
|
||||
trunk_radius: 1.8 * scale,
|
||||
branch_child_len: 0.4,
|
||||
branch_child_radius: 0.6,
|
||||
branch_child_radius_lerp: true,
|
||||
leaf_radius: 4.0 * log_scale..5.0 * log_scale,
|
||||
leaf_radius: 2.0 * log_scale..2.5 * log_scale,
|
||||
leaf_radius_scaled: 0.0,
|
||||
straightness: 0.4,
|
||||
max_depth: 4,
|
||||
splits: 1.75..2.0,
|
||||
split_range: 0.75..1.5,
|
||||
branch_len_bias: 0.0,
|
||||
leaf_vertical_scale: 0.4,
|
||||
proportionality: 0.0,
|
||||
straightness: 0.3,
|
||||
max_depth: 2,
|
||||
splits: 16.0..18.0,
|
||||
split_range: 0.2..1.2,
|
||||
branch_len_bias: 0.7,
|
||||
leaf_vertical_scale: 0.3,
|
||||
proportionality: 0.7,
|
||||
inhabited: false,
|
||||
hanging_sprites: &[(0.00007, SpriteKind::Beehive)],
|
||||
trunk_block: StructureBlock::Filled(BlockKind::Wood, Rgb::new(110, 68, 65)),
|
||||
|
127
world/src/lib.rs
127
world/src/lib.rs
@ -608,7 +608,7 @@ impl World {
|
||||
|
||||
// Add trees
|
||||
prof_span!(guard, "add trees");
|
||||
objects.append(
|
||||
objects.extend(
|
||||
&mut self
|
||||
.sim()
|
||||
.get_area_trees(min_wpos, max_wpos)
|
||||
@ -621,15 +621,16 @@ impl World {
|
||||
.filter_map(|(col, tree)| {
|
||||
Some(lod::Object {
|
||||
kind: match tree.forest_kind {
|
||||
all::ForestKind::Oak => lod::ObjectKind::Oak,
|
||||
all::ForestKind::Dead => lod::ObjectKind::Dead,
|
||||
all::ForestKind::Pine
|
||||
| all::ForestKind::Frostpine
|
||||
| all::ForestKind::Redwood => lod::ObjectKind::Pine,
|
||||
all::ForestKind::Mapletree => lod::ObjectKind::MapleTree,
|
||||
all::ForestKind::Cherry => lod::ObjectKind::Cherry,
|
||||
all::ForestKind::AutumnTree => lod::ObjectKind::AutumnTree,
|
||||
_ => lod::ObjectKind::Oak,
|
||||
all::ForestKind::Pine => lod::ObjectKind::Pine,
|
||||
all::ForestKind::Mangrove => lod::ObjectKind::Mangrove,
|
||||
all::ForestKind::Acacia => lod::ObjectKind::Acacia,
|
||||
all::ForestKind::Birch => lod::ObjectKind::Birch,
|
||||
all::ForestKind::Redwood => lod::ObjectKind::Redwood,
|
||||
all::ForestKind::Baobab => lod::ObjectKind::Baobab,
|
||||
all::ForestKind::Frostpine => lod::ObjectKind::Frostpine,
|
||||
all::ForestKind::Palm => lod::ObjectKind::Palm,
|
||||
_ => lod::ObjectKind::GenericTree,
|
||||
},
|
||||
pos: {
|
||||
let rpos = tree.pos - min_wpos;
|
||||
@ -639,19 +640,26 @@ impl World {
|
||||
rpos.map(|e| e as i16).with_z(col.alt as i16)
|
||||
}
|
||||
},
|
||||
flags: lod::Flags::empty()
|
||||
flags: lod::InstFlags::empty()
|
||||
| if col.snow_cover {
|
||||
lod::Flags::SNOW_COVERED
|
||||
lod::InstFlags::SNOW_COVERED
|
||||
} else {
|
||||
lod::Flags::empty()
|
||||
lod::InstFlags::empty()
|
||||
},
|
||||
color: {
|
||||
let field = crate::util::RandomField::new(tree.seed);
|
||||
let lerp = field.get_f32(Vec3::from(tree.pos)) * 0.8 + 0.1;
|
||||
let sblock = tree.forest_kind.leaf_block();
|
||||
|
||||
crate::all::leaf_color(index, tree.seed, lerp, &sblock)
|
||||
.unwrap_or(Rgb::black())
|
||||
},
|
||||
})
|
||||
})
|
||||
.collect(),
|
||||
}),
|
||||
);
|
||||
drop(guard);
|
||||
|
||||
// Add buildings
|
||||
// Add structures
|
||||
objects.extend(
|
||||
index
|
||||
.sites
|
||||
@ -661,68 +669,55 @@ impl World {
|
||||
.map2(min_wpos.zip(max_wpos), |e, (min, max)| e >= min && e < max)
|
||||
.reduce_and()
|
||||
})
|
||||
.filter_map(|(_, site)| match &site.kind {
|
||||
SiteKind::Refactor(site) => {
|
||||
Some(site.plots().filter_map(|plot| match &plot.kind {
|
||||
site2::plot::PlotKind::House(_) => Some(site.tile_wpos(plot.root_tile)),
|
||||
_ => None,
|
||||
}))
|
||||
},
|
||||
.filter_map(|(_, site)| {
|
||||
site.site2().map(|site| {
|
||||
site.plots().filter_map(|plot| match &plot.kind {
|
||||
site2::plot::PlotKind::House(h) => Some((
|
||||
site.tile_wpos(plot.root_tile),
|
||||
h.roof_color(),
|
||||
lod::ObjectKind::House,
|
||||
)),
|
||||
site2::plot::PlotKind::GiantTree(t) => Some((
|
||||
site.tile_wpos(plot.root_tile),
|
||||
t.leaf_color(),
|
||||
lod::ObjectKind::GiantTree,
|
||||
)),
|
||||
site2::plot::PlotKind::Haniwa(_) => Some((
|
||||
site.tile_wpos(plot.root_tile),
|
||||
Rgb::black(),
|
||||
lod::ObjectKind::Haniwa,
|
||||
)),
|
||||
site2::plot::PlotKind::DesertCityMultiPlot(_) => Some((
|
||||
site.tile_wpos(plot.root_tile),
|
||||
Rgb::black(),
|
||||
lod::ObjectKind::Desert,
|
||||
)),
|
||||
site2::plot::PlotKind::DesertCityArena(_) => Some((
|
||||
site.tile_wpos(plot.root_tile),
|
||||
Rgb::black(),
|
||||
lod::ObjectKind::Arena,
|
||||
)),
|
||||
_ => None,
|
||||
})
|
||||
})
|
||||
})
|
||||
.flatten()
|
||||
.filter_map(|wpos2d| {
|
||||
.filter_map(|(wpos2d, color, model)| {
|
||||
ColumnGen::new(self.sim())
|
||||
.get((wpos2d, index, self.sim().calendar.as_ref()))
|
||||
.zip(Some(wpos2d))
|
||||
.zip(Some((wpos2d, color, model)))
|
||||
})
|
||||
.map(|(col, wpos2d)| lod::Object {
|
||||
kind: lod::ObjectKind::House,
|
||||
.map(|(column, (wpos2d, color, model))| lod::Object {
|
||||
kind: model,
|
||||
pos: (wpos2d - min_wpos)
|
||||
.map(|e| e as i16)
|
||||
.with_z(self.sim().get_alt_approx(wpos2d).unwrap_or(0.0) as i16),
|
||||
flags: lod::Flags::IS_BUILDING
|
||||
| if col.snow_cover {
|
||||
lod::Flags::SNOW_COVERED
|
||||
flags: if column.snow_cover {
|
||||
lod::InstFlags::SNOW_COVERED
|
||||
} else {
|
||||
lod::Flags::empty()
|
||||
lod::InstFlags::empty()
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
// Add giant trees
|
||||
objects.extend(
|
||||
index
|
||||
.sites
|
||||
.iter()
|
||||
.filter(|(_, site)| {
|
||||
site.get_origin()
|
||||
.map2(min_wpos.zip(max_wpos), |e, (min, max)| e >= min && e < max)
|
||||
.reduce_and()
|
||||
})
|
||||
.filter(|(_, site)| matches!(&site.kind, SiteKind::GiantTree(_)))
|
||||
.filter_map(|(_, site)| {
|
||||
let wpos2d = site.get_origin();
|
||||
let col = ColumnGen::new(self.sim()).get((
|
||||
wpos2d,
|
||||
index,
|
||||
self.sim().calendar.as_ref(),
|
||||
))?;
|
||||
Some(lod::Object {
|
||||
kind: lod::ObjectKind::GiantTree,
|
||||
pos: {
|
||||
(wpos2d - min_wpos)
|
||||
.map(|e| e as i16)
|
||||
.with_z(self.sim().get_alt_approx(wpos2d).unwrap_or(0.0) as i16)
|
||||
},
|
||||
flags: lod::Flags::empty()
|
||||
| lod::Flags::IS_GIANT_TREE
|
||||
| if col.snow_cover {
|
||||
lod::Flags::SNOW_COVERED
|
||||
} else {
|
||||
lod::Flags::empty()
|
||||
},
|
||||
})
|
||||
color,
|
||||
}),
|
||||
);
|
||||
|
||||
|
@ -80,6 +80,18 @@ impl GiantTree {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn leaf_color(&self) -> Rgb<u8> {
|
||||
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);
|
||||
Lerp::lerp(
|
||||
dark,
|
||||
light,
|
||||
fast_noise.get((self.wpos.map(|e| e as f64) * 0.05) * 0.5 + 0.5),
|
||||
)
|
||||
.map(|e| e as u8)
|
||||
}
|
||||
}
|
||||
|
||||
impl Structure for GiantTree {
|
||||
@ -88,14 +100,7 @@ impl Structure for GiantTree {
|
||||
|
||||
#[cfg_attr(feature = "be-dyn-lib", export_name = "render_gianttree")]
|
||||
fn render_inner(&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),
|
||||
);
|
||||
let leaf_col = self.leaf_color();
|
||||
let mut rng = rand::thread_rng();
|
||||
self.tree.walk(|branch, parent| {
|
||||
let aabr = Aabr {
|
||||
@ -122,10 +127,7 @@ impl Structure for GiantTree {
|
||||
parent.get_leaf_radius(),
|
||||
branch.get_leaf_radius(),
|
||||
)
|
||||
.fill(Fill::Block(Block::new(
|
||||
BlockKind::Leaves,
|
||||
leaf_col.map(|e| e as u8),
|
||||
)));
|
||||
.fill(Fill::Block(Block::new(BlockKind::Leaves, leaf_col)));
|
||||
// Calculate direction of the branch
|
||||
let branch_start = branch.get_line().start;
|
||||
let branch_end = branch.get_line().end;
|
||||
|
@ -95,6 +95,8 @@ impl House {
|
||||
}
|
||||
|
||||
pub fn z_range(&self) -> Range<i32> { self.alt..self.alt + self.levels as i32 * STOREY }
|
||||
|
||||
pub fn roof_color(&self) -> Rgb<u8> { self.roof_color }
|
||||
}
|
||||
|
||||
const STOREY: i32 = 5;
|
||||
|
Loading…
Reference in New Issue
Block a user