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