mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Merge branch 'imbris/worldgen-speedup' into 'master'
Worldgen Speedup See merge request veloren/veloren!507
This commit is contained in:
commit
1936224901
22
Cargo.lock
generated
22
Cargo.lock
generated
@ -93,6 +93,25 @@ dependencies = [
|
||||
"num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "arr_macro"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"arr_macro_impl 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro-hack 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "arr_macro_impl"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro-hack 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "arrayref"
|
||||
version = "0.3.5"
|
||||
@ -3733,6 +3752,7 @@ dependencies = [
|
||||
name = "veloren-world"
|
||||
version = "0.3.0"
|
||||
dependencies = [
|
||||
"arr_macro 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"hashbrown 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"minifb 0.12.0 (git+https://github.com/emoon/rust_minifb.git)",
|
||||
@ -3943,6 +3963,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
"checksum anymap 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "33954243bd79057c2de7338850b85983a44588021f8a5fee574a8888c6de4344"
|
||||
"checksum approx 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "08abcc3b4e9339e33a3d0a5ed15d84a687350c05689d825e0f6655eef9e76a94"
|
||||
"checksum approx 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f0e60b75072ecd4168020818c0107f2857bb6c4e64252d8d3983f6263b40a5c3"
|
||||
"checksum arr_macro 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d262b83f2f573121554ad6e764cd444303df85d86e5fcebc81903ddcf8dd3a97"
|
||||
"checksum arr_macro_impl 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8decbe97ffec939e44228d91e5d0829ceb1616c6ed0984c09df164b1e7ebaafc"
|
||||
"checksum arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee"
|
||||
"checksum arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b8d73f9beda665eaa98ab9e4f7442bd4e7de6652587de55b2525e52e29c1b0ba"
|
||||
"checksum ascii 0.8.7 (registry+https://github.com/rust-lang/crates.io-index)" = "97be891acc47ca214468e09425d02cef3af2c94d0d82081cd02061f996802f14"
|
||||
|
@ -12,6 +12,7 @@ hashbrown = { version = "0.6.0", features = ["serde"] }
|
||||
lazy_static = "1.4.0"
|
||||
rand = "0.7.2"
|
||||
rand_chacha = "0.2.1"
|
||||
arr_macro = "0.1.2"
|
||||
|
||||
[dev-dependencies]
|
||||
minifb = { git = "https://github.com/emoon/rust_minifb.git" }
|
||||
|
@ -3,7 +3,7 @@ mod natural;
|
||||
use crate::{
|
||||
column::{ColumnGen, ColumnSample},
|
||||
generator::{Generator, TownGen},
|
||||
util::{HashCache, RandomField, Sampler, SamplerMut},
|
||||
util::{RandomField, Sampler, SmallCache},
|
||||
World, CONFIG,
|
||||
};
|
||||
use common::{
|
||||
@ -16,7 +16,7 @@ use vek::*;
|
||||
|
||||
pub struct BlockGen<'a> {
|
||||
world: &'a World,
|
||||
column_cache: HashCache<Vec2<i32>, Option<ColumnSample<'a>>>,
|
||||
column_cache: SmallCache<Option<ColumnSample<'a>>>,
|
||||
column_gen: ColumnGen<'a>,
|
||||
}
|
||||
|
||||
@ -24,14 +24,14 @@ impl<'a> BlockGen<'a> {
|
||||
pub fn new(world: &'a World, column_gen: ColumnGen<'a>) -> Self {
|
||||
Self {
|
||||
world,
|
||||
column_cache: HashCache::with_capacity(64),
|
||||
column_cache: SmallCache::default(),
|
||||
column_gen,
|
||||
}
|
||||
}
|
||||
|
||||
fn sample_column(
|
||||
column_gen: &ColumnGen<'a>,
|
||||
cache: &mut HashCache<Vec2<i32>, Option<ColumnSample<'a>>>,
|
||||
cache: &mut SmallCache<Option<ColumnSample<'a>>>,
|
||||
wpos: Vec2<i32>,
|
||||
) -> Option<ColumnSample<'a>> {
|
||||
cache
|
||||
@ -41,10 +41,11 @@ impl<'a> BlockGen<'a> {
|
||||
|
||||
fn get_cliff_height(
|
||||
column_gen: &ColumnGen<'a>,
|
||||
cache: &mut HashCache<Vec2<i32>, Option<ColumnSample<'a>>>,
|
||||
cache: &mut SmallCache<Option<ColumnSample<'a>>>,
|
||||
wpos: Vec2<f32>,
|
||||
close_cliffs: &[(Vec2<i32>, u32); 9],
|
||||
cliff_hill: f32,
|
||||
tolerance: f32,
|
||||
) -> f32 {
|
||||
close_cliffs.iter().fold(
|
||||
0.0f32,
|
||||
@ -61,7 +62,7 @@ impl<'a> BlockGen<'a> {
|
||||
|
||||
max_height.max(
|
||||
if cliff_pos.map(|e| e as f32).distance_squared(wpos)
|
||||
< (radius * radius) as f32
|
||||
< (radius as f32 + tolerance).powf(2.0)
|
||||
{
|
||||
cliff_sample.alt
|
||||
+ height as f32 * (1.0 - cliff_sample.chaos)
|
||||
@ -84,7 +85,7 @@ impl<'a> BlockGen<'a> {
|
||||
} = self;
|
||||
|
||||
// Main sample
|
||||
let sample = Self::sample_column(column_gen, column_cache, wpos)?;
|
||||
let sample = column_gen.get(wpos)?;
|
||||
|
||||
// Tree samples
|
||||
let mut structure_samples = [None, None, None, None, None, None, None, None, None];
|
||||
@ -129,7 +130,12 @@ impl<'a> BlockGen<'a> {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get_with_z_cache(&mut self, wpos: Vec3<i32>, z_cache: Option<&ZCache>) -> Option<Block> {
|
||||
pub fn get_with_z_cache(
|
||||
&mut self,
|
||||
wpos: Vec3<i32>,
|
||||
z_cache: Option<&ZCache>,
|
||||
only_structures: bool,
|
||||
) -> Option<Block> {
|
||||
let BlockGen {
|
||||
world,
|
||||
column_cache,
|
||||
@ -165,195 +171,199 @@ impl<'a> BlockGen<'a> {
|
||||
|
||||
let wposf = wpos.map(|e| e as f64);
|
||||
|
||||
let (_definitely_underground, height, water_height) =
|
||||
if (wposf.z as f32) < alt - 64.0 * chaos {
|
||||
// Shortcut warping
|
||||
(true, alt, CONFIG.sea_level /*water_level*/)
|
||||
} else {
|
||||
// Apply warping
|
||||
let warp = (world.sim().gen_ctx.warp_nz.get(wposf.div(48.0)) as f32)
|
||||
.mul((chaos - 0.1).max(0.0))
|
||||
.mul(48.0)
|
||||
+ (world.sim().gen_ctx.warp_nz.get(wposf.div(15.0)) as f32)
|
||||
.mul((chaos - 0.1).max(0.0))
|
||||
.mul(24.0);
|
||||
|
||||
let height = if (wposf.z as f32) < alt + warp - 10.0 {
|
||||
// Shortcut cliffs
|
||||
alt + warp
|
||||
let (block, height) = if !only_structures {
|
||||
let (_definitely_underground, height, water_height) =
|
||||
if (wposf.z as f32) < alt - 64.0 * chaos {
|
||||
// Shortcut warping
|
||||
(true, alt, CONFIG.sea_level /*water_level*/)
|
||||
} else {
|
||||
let turb = Vec2::new(
|
||||
world.sim().gen_ctx.fast_turb_x_nz.get(wposf.div(25.0)) as f32,
|
||||
world.sim().gen_ctx.fast_turb_y_nz.get(wposf.div(25.0)) as f32,
|
||||
) * 8.0;
|
||||
// Apply warping
|
||||
let warp = (world.sim().gen_ctx.warp_nz.get(wposf.div(48.0)) as f32)
|
||||
.mul((chaos - 0.1).max(0.0))
|
||||
.mul(48.0)
|
||||
+ (world.sim().gen_ctx.warp_nz.get(wposf.div(15.0)) as f32)
|
||||
.mul((chaos - 0.1).max(0.0))
|
||||
.mul(24.0);
|
||||
|
||||
let wpos_turb = Vec2::from(wpos).map(|e: i32| e as f32) + turb;
|
||||
let cliff_height = Self::get_cliff_height(
|
||||
column_gen,
|
||||
column_cache,
|
||||
wpos_turb,
|
||||
&close_cliffs,
|
||||
cliff_hill,
|
||||
);
|
||||
let height = if (wposf.z as f32) < alt + warp - 10.0 {
|
||||
// Shortcut cliffs
|
||||
alt + warp
|
||||
} else {
|
||||
let turb = Vec2::new(
|
||||
world.sim().gen_ctx.fast_turb_x_nz.get(wposf.div(25.0)) as f32,
|
||||
world.sim().gen_ctx.fast_turb_y_nz.get(wposf.div(25.0)) as f32,
|
||||
) * 8.0;
|
||||
|
||||
(alt + warp).max(cliff_height)
|
||||
let wpos_turb = Vec2::from(wpos).map(|e: i32| e as f32) + turb;
|
||||
let cliff_height = Self::get_cliff_height(
|
||||
column_gen,
|
||||
column_cache,
|
||||
wpos_turb,
|
||||
&close_cliffs,
|
||||
cliff_hill,
|
||||
0.0,
|
||||
);
|
||||
|
||||
(alt + warp).max(cliff_height)
|
||||
};
|
||||
|
||||
(
|
||||
false,
|
||||
height,
|
||||
/*(water_level + warp).max(*/ CONFIG.sea_level, /*)*/
|
||||
)
|
||||
};
|
||||
|
||||
(
|
||||
false,
|
||||
height,
|
||||
/*(water_level + warp).max(*/ CONFIG.sea_level, /*)*/
|
||||
)
|
||||
};
|
||||
// Sample blocks
|
||||
|
||||
// Sample blocks
|
||||
// let stone_col = Rgb::new(240, 230, 220);
|
||||
let stone_col = Rgb::new(195, 187, 201);
|
||||
|
||||
// let stone_col = Rgb::new(240, 230, 220);
|
||||
let stone_col = Rgb::new(195, 187, 201);
|
||||
// let dirt_col = Rgb::new(79, 67, 60);
|
||||
|
||||
// let dirt_col = Rgb::new(79, 67, 60);
|
||||
let _air = Block::empty();
|
||||
// let stone = Block::new(2, stone_col);
|
||||
// let surface_stone = Block::new(1, Rgb::new(200, 220, 255));
|
||||
// let dirt = Block::new(1, dirt_col);
|
||||
// let sand = Block::new(1, Rgb::new(180, 150, 50));
|
||||
// let warm_stone = Block::new(1, Rgb::new(165, 165, 130));
|
||||
|
||||
let _air = Block::empty();
|
||||
// let stone = Block::new(2, stone_col);
|
||||
// let surface_stone = Block::new(1, Rgb::new(200, 220, 255));
|
||||
// let dirt = Block::new(1, dirt_col);
|
||||
// let sand = Block::new(1, Rgb::new(180, 150, 50));
|
||||
// let warm_stone = Block::new(1, Rgb::new(165, 165, 130));
|
||||
let water = Block::new(BlockKind::Water, Rgb::new(60, 90, 190));
|
||||
|
||||
let water = Block::new(BlockKind::Water, Rgb::new(60, 90, 190));
|
||||
let grass_depth = 1.5 + 2.0 * chaos;
|
||||
let block = if (wposf.z as f32) < height - grass_depth {
|
||||
let col = Lerp::lerp(
|
||||
saturate_srgb(sub_surface_color, 0.45).map(|e| (e * 255.0) as u8),
|
||||
stone_col,
|
||||
(height - grass_depth - wposf.z as f32) * 0.15,
|
||||
);
|
||||
|
||||
let grass_depth = 1.5 + 2.0 * chaos;
|
||||
let block = if (wposf.z as f32) < height - grass_depth {
|
||||
let col = Lerp::lerp(
|
||||
saturate_srgb(sub_surface_color, 0.45).map(|e| (e * 255.0) as u8),
|
||||
stone_col,
|
||||
(height - grass_depth - wposf.z as f32) * 0.15,
|
||||
);
|
||||
|
||||
// Underground
|
||||
if (wposf.z as f32) > alt - 32.0 * chaos {
|
||||
Some(Block::new(BlockKind::Normal, col))
|
||||
} else {
|
||||
Some(Block::new(BlockKind::Dense, col))
|
||||
}
|
||||
} else if (wposf.z as f32) < height {
|
||||
let col = Lerp::lerp(
|
||||
sub_surface_color,
|
||||
surface_color,
|
||||
(wposf.z as f32 - (height - grass_depth))
|
||||
.div(grass_depth)
|
||||
.powf(0.5),
|
||||
);
|
||||
// Surface
|
||||
Some(Block::new(
|
||||
BlockKind::Normal,
|
||||
saturate_srgb(col, 0.45).map(|e| (e * 255.0) as u8),
|
||||
))
|
||||
} else if (wposf.z as f32) < height + 0.9
|
||||
&& temp < CONFIG.desert_temp
|
||||
&& (wposf.z as f32 > water_height + 3.0)
|
||||
&& marble > 0.68
|
||||
&& marble_small > 0.65
|
||||
&& (marble * 3173.7).fract() < 0.5
|
||||
{
|
||||
let flowers = [
|
||||
BlockKind::BlueFlower,
|
||||
BlockKind::PinkFlower,
|
||||
BlockKind::PurpleFlower,
|
||||
BlockKind::RedFlower,
|
||||
BlockKind::WhiteFlower,
|
||||
BlockKind::YellowFlower,
|
||||
BlockKind::Sunflower,
|
||||
BlockKind::Mushroom,
|
||||
];
|
||||
|
||||
let grasses = [
|
||||
BlockKind::LongGrass,
|
||||
BlockKind::MediumGrass,
|
||||
BlockKind::ShortGrass,
|
||||
];
|
||||
|
||||
Some(Block::new(
|
||||
if (height * 1271.0).fract() < 0.15 {
|
||||
flowers[(height * 0.2) as usize % flowers.len()]
|
||||
// Underground
|
||||
if (wposf.z as f32) > alt - 32.0 * chaos {
|
||||
Some(Block::new(BlockKind::Normal, col))
|
||||
} else {
|
||||
grasses[(height * 0.3) as usize % grasses.len()]
|
||||
},
|
||||
Rgb::broadcast(0),
|
||||
))
|
||||
} else if (wposf.z as f32) < height + 0.9
|
||||
&& temp > CONFIG.desert_temp
|
||||
&& (marble * 4423.5).fract() < 0.0005
|
||||
{
|
||||
let large_cacti = [BlockKind::LargeCactus, BlockKind::MedFlatCactus];
|
||||
|
||||
let small_cacti = [
|
||||
BlockKind::BarrelCactus,
|
||||
BlockKind::RoundCactus,
|
||||
BlockKind::ShortCactus,
|
||||
BlockKind::ShortFlatCactus,
|
||||
];
|
||||
|
||||
Some(Block::new(
|
||||
if (height * 1271.0).fract() < 0.5 {
|
||||
large_cacti[(height * 0.2) as usize % large_cacti.len()]
|
||||
} else {
|
||||
small_cacti[(height * 0.3) as usize % small_cacti.len()]
|
||||
},
|
||||
Rgb::broadcast(0),
|
||||
))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
// Caves
|
||||
let block = block.and_then(|block| {
|
||||
// Underground
|
||||
let cave = cave_xy.powf(2.0)
|
||||
* (wposf.z as f32 - cave_alt)
|
||||
.div(40.0)
|
||||
.powf(4.0)
|
||||
.neg()
|
||||
.add(1.0)
|
||||
> 0.9993;
|
||||
|
||||
if cave {
|
||||
None
|
||||
} else {
|
||||
Some(block)
|
||||
}
|
||||
});
|
||||
|
||||
// Rocks
|
||||
let block = block.or_else(|| {
|
||||
if (height + 2.5 - wposf.z as f32).div(7.5).abs().powf(2.0) < rock {
|
||||
let field0 = RandomField::new(world.sim().seed + 0);
|
||||
let field1 = RandomField::new(world.sim().seed + 1);
|
||||
let field2 = RandomField::new(world.sim().seed + 2);
|
||||
|
||||
Some(Block::new(BlockKind::Dense, col))
|
||||
}
|
||||
} else if (wposf.z as f32) < height {
|
||||
let col = Lerp::lerp(
|
||||
sub_surface_color,
|
||||
surface_color,
|
||||
(wposf.z as f32 - (height - grass_depth))
|
||||
.div(grass_depth)
|
||||
.powf(0.5),
|
||||
);
|
||||
// Surface
|
||||
Some(Block::new(
|
||||
BlockKind::Normal,
|
||||
stone_col
|
||||
- Rgb::new(
|
||||
field0.get(wpos) as u8 % 16,
|
||||
field1.get(wpos) as u8 % 16,
|
||||
field2.get(wpos) as u8 % 16,
|
||||
),
|
||||
saturate_srgb(col, 0.45).map(|e| (e * 255.0) as u8),
|
||||
))
|
||||
} else if (wposf.z as f32) < height + 0.9
|
||||
&& temp < CONFIG.desert_temp
|
||||
&& (wposf.z as f32 > water_height + 3.0)
|
||||
&& marble > 0.68
|
||||
&& marble_small > 0.65
|
||||
&& (marble * 3173.7).fract() < 0.5
|
||||
{
|
||||
let flowers = [
|
||||
BlockKind::BlueFlower,
|
||||
BlockKind::PinkFlower,
|
||||
BlockKind::PurpleFlower,
|
||||
BlockKind::RedFlower,
|
||||
BlockKind::WhiteFlower,
|
||||
BlockKind::YellowFlower,
|
||||
BlockKind::Sunflower,
|
||||
BlockKind::Mushroom,
|
||||
];
|
||||
|
||||
let grasses = [
|
||||
BlockKind::LongGrass,
|
||||
BlockKind::MediumGrass,
|
||||
BlockKind::ShortGrass,
|
||||
];
|
||||
|
||||
Some(Block::new(
|
||||
if (height * 1271.0).fract() < 0.15 {
|
||||
flowers[(height * 0.2) as usize % flowers.len()]
|
||||
} else {
|
||||
grasses[(height * 0.3) as usize % grasses.len()]
|
||||
},
|
||||
Rgb::broadcast(0),
|
||||
))
|
||||
} else if (wposf.z as f32) < height + 0.9
|
||||
&& temp > CONFIG.desert_temp
|
||||
&& (marble * 4423.5).fract() < 0.0005
|
||||
{
|
||||
let large_cacti = [BlockKind::LargeCactus, BlockKind::MedFlatCactus];
|
||||
|
||||
let small_cacti = [
|
||||
BlockKind::BarrelCactus,
|
||||
BlockKind::RoundCactus,
|
||||
BlockKind::ShortCactus,
|
||||
BlockKind::ShortFlatCactus,
|
||||
];
|
||||
|
||||
Some(Block::new(
|
||||
if (height * 1271.0).fract() < 0.5 {
|
||||
large_cacti[(height * 0.2) as usize % large_cacti.len()]
|
||||
} else {
|
||||
small_cacti[(height * 0.3) as usize % small_cacti.len()]
|
||||
},
|
||||
Rgb::broadcast(0),
|
||||
))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
.or_else(|| {
|
||||
// Rocks
|
||||
if (height + 2.5 - wposf.z as f32).div(7.5).abs().powf(2.0) < rock {
|
||||
let field0 = RandomField::new(world.sim().seed + 0);
|
||||
let field1 = RandomField::new(world.sim().seed + 1);
|
||||
let field2 = RandomField::new(world.sim().seed + 2);
|
||||
|
||||
// Water
|
||||
let block = block.or_else(|| {
|
||||
if (wposf.z as f32) < water_height {
|
||||
// Ocean
|
||||
Some(water)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
Some(Block::new(
|
||||
BlockKind::Normal,
|
||||
stone_col
|
||||
- Rgb::new(
|
||||
field0.get(wpos) as u8 % 16,
|
||||
field1.get(wpos) as u8 % 16,
|
||||
field2.get(wpos) as u8 % 16,
|
||||
),
|
||||
))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.and_then(|block| {
|
||||
// Caves
|
||||
// Underground
|
||||
let cave = cave_xy.powf(2.0)
|
||||
* (wposf.z as f32 - cave_alt)
|
||||
.div(40.0)
|
||||
.powf(4.0)
|
||||
.neg()
|
||||
.add(1.0)
|
||||
> 0.9993;
|
||||
|
||||
if cave {
|
||||
None
|
||||
} else {
|
||||
Some(block)
|
||||
}
|
||||
})
|
||||
.or_else(|| {
|
||||
// Water
|
||||
if (wposf.z as f32) < water_height {
|
||||
// Ocean
|
||||
Some(water)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
|
||||
(block, height)
|
||||
} else {
|
||||
(None, sample.alt)
|
||||
};
|
||||
|
||||
// Structures (like towns)
|
||||
let block = chunk
|
||||
@ -383,7 +393,7 @@ pub struct ZCache<'a> {
|
||||
}
|
||||
|
||||
impl<'a> ZCache<'a> {
|
||||
pub fn get_z_limits(&self) -> (f32, f32) {
|
||||
pub fn get_z_limits(&self, block_gen: &mut BlockGen) -> (f32, f32, f32) {
|
||||
let cave_depth = if self.sample.cave_xy.abs() > 0.9 {
|
||||
(self.sample.alt - self.sample.cave_alt + 8.0).max(0.0)
|
||||
} else {
|
||||
@ -392,8 +402,18 @@ impl<'a> ZCache<'a> {
|
||||
|
||||
let min = self.sample.alt - (self.sample.chaos * 48.0 + cave_depth) - 4.0;
|
||||
|
||||
let cliff = if self.sample.near_cliffs { 48.0 } else { 0.0 };
|
||||
let warp = self.sample.chaos * 48.0;
|
||||
let cliff = BlockGen::get_cliff_height(
|
||||
&mut block_gen.column_gen,
|
||||
&mut block_gen.column_cache,
|
||||
self.wpos.map(|e| e as f32),
|
||||
&self.sample.close_cliffs,
|
||||
self.sample.cliff_hill,
|
||||
32.0,
|
||||
);
|
||||
|
||||
let rocks = if self.sample.rock > 0.0 { 12.0 } else { 0.0 };
|
||||
|
||||
let warp = self.sample.chaos * 24.0;
|
||||
let (structure_min, structure_max) = self
|
||||
.structures
|
||||
.iter()
|
||||
@ -412,8 +432,10 @@ impl<'a> ZCache<'a> {
|
||||
}
|
||||
});
|
||||
|
||||
let ground_max = (self.sample.alt + 2.0 + warp + rocks).max(cliff);
|
||||
|
||||
let min = min + structure_min;
|
||||
let max = (self.sample.alt + cliff + structure_max + warp + 8.0)
|
||||
let max = (ground_max + structure_max)
|
||||
.max(self.sample.water_level)
|
||||
.max(CONFIG.sea_level + 2.0);
|
||||
|
||||
@ -430,17 +452,11 @@ impl<'a> ZCache<'a> {
|
||||
})
|
||||
.unwrap_or((min, max));
|
||||
|
||||
(min, max)
|
||||
}
|
||||
}
|
||||
let structures_only_min_z = ground_max
|
||||
.max(self.sample.water_level)
|
||||
.max(CONFIG.sea_level + 2.0);
|
||||
|
||||
impl<'a> SamplerMut<'static> for BlockGen<'a> {
|
||||
type Index = Vec3<i32>;
|
||||
type Sample = Option<Block>;
|
||||
|
||||
fn get(&mut self, wpos: Vec3<i32>) -> Option<Block> {
|
||||
let z_cache = self.get_z_cache(wpos.into());
|
||||
self.get_with_z_cache(wpos, z_cache.as_ref())
|
||||
(min, structures_only_min_z, max)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,7 @@ use super::{BlockGen, StructureInfo, StructureMeta};
|
||||
use crate::{
|
||||
all::ForestKind,
|
||||
column::{ColumnGen, ColumnSample},
|
||||
util::{HashCache, RandomPerm, Sampler, UnitChooser},
|
||||
util::{RandomPerm, Sampler, SmallCache, UnitChooser},
|
||||
CONFIG,
|
||||
};
|
||||
use common::{assets, terrain::Structure};
|
||||
@ -17,7 +17,7 @@ static QUIRKY_RAND: RandomPerm = RandomPerm::new(0xA634460F);
|
||||
|
||||
pub fn structure_gen<'a>(
|
||||
column_gen: &ColumnGen<'a>,
|
||||
column_cache: &mut HashCache<Vec2<i32>, Option<ColumnSample<'a>>>,
|
||||
column_cache: &mut SmallCache<Option<ColumnSample<'a>>>,
|
||||
idx: usize,
|
||||
st_pos: Vec2<i32>,
|
||||
st_seed: u32,
|
||||
@ -41,6 +41,7 @@ pub fn structure_gen<'a>(
|
||||
st_pos.map(|e| e as f32),
|
||||
&st_sample.close_cliffs,
|
||||
st_sample.cliff_hill,
|
||||
0.0,
|
||||
);
|
||||
|
||||
let wheight = st_sample.alt.max(cliff_height);
|
||||
|
@ -116,7 +116,7 @@ impl World {
|
||||
None => continue,
|
||||
};
|
||||
|
||||
let (min_z, max_z) = z_cache.get_z_limits();
|
||||
let (min_z, only_structures_min_z, max_z) = z_cache.get_z_limits(&mut sampler);
|
||||
|
||||
for z in base_z..min_z as i32 {
|
||||
let _ = chunk.set(Vec3::new(x, y, z), stone);
|
||||
@ -125,8 +125,11 @@ impl World {
|
||||
for z in min_z as i32..max_z as i32 {
|
||||
let lpos = Vec3::new(x, y, z);
|
||||
let wpos = chunk_block_pos + lpos;
|
||||
let only_structures = lpos.z >= only_structures_min_z as i32;
|
||||
|
||||
if let Some(block) = sampler.get_with_z_cache(wpos, Some(&z_cache)) {
|
||||
if let Some(block) =
|
||||
sampler.get_with_z_cache(wpos, Some(&z_cache), only_structures)
|
||||
{
|
||||
let _ = chunk.set(lpos, block);
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
use super::{RandomField, Sampler};
|
||||
use std::f32;
|
||||
use std::{f32, ops::Add};
|
||||
use vek::*;
|
||||
|
||||
pub struct FastNoise {
|
||||
@ -34,16 +34,19 @@ impl Sampler<'static> for FastNoise {
|
||||
let v011 = self.noise_at(near_pos + Vec3::new(0, 1, 1));
|
||||
let v111 = self.noise_at(near_pos + Vec3::new(1, 1, 1));
|
||||
|
||||
let factor = pos.map(|e| 0.5 - (e.fract() as f32 * f32::consts::PI).cos() * 0.5);
|
||||
let factor = pos.map(|e| {
|
||||
let f = e.fract().add(1.0).fract() as f32;
|
||||
f.powf(2.0) * (3.0 - 2.0 * f)
|
||||
});
|
||||
|
||||
let x00 = Lerp::lerp(v000, v100, factor.x);
|
||||
let x10 = Lerp::lerp(v010, v110, factor.x);
|
||||
let x01 = Lerp::lerp(v001, v101, factor.x);
|
||||
let x11 = Lerp::lerp(v011, v111, factor.x);
|
||||
let x00 = v000 + factor.x * (v100 - v000);
|
||||
let x10 = v010 + factor.x * (v110 - v010);
|
||||
let x01 = v001 + factor.x * (v101 - v001);
|
||||
let x11 = v011 + factor.x * (v111 - v011);
|
||||
|
||||
let y0 = Lerp::lerp(x00, x10, factor.y);
|
||||
let y1 = Lerp::lerp(x01, x11, factor.y);
|
||||
let y0 = x00 + factor.y * (x10 - x00);
|
||||
let y1 = x01 + factor.y * (x11 - x01);
|
||||
|
||||
Lerp::lerp(y0, y1, factor.z) * 2.0 - 1.0
|
||||
(y0 + factor.z * (y1 - y0)) * 2.0 - 1.0
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ pub mod hash_cache;
|
||||
pub mod random;
|
||||
pub mod sampler;
|
||||
pub mod seed_expan;
|
||||
pub mod small_cache;
|
||||
pub mod structure;
|
||||
pub mod unit_chooser;
|
||||
|
||||
@ -14,6 +15,7 @@ pub use self::{
|
||||
hash_cache::HashCache,
|
||||
random::{RandomField, RandomPerm},
|
||||
sampler::{Sampler, SamplerMut},
|
||||
small_cache::SmallCache,
|
||||
structure::StructureGen2d,
|
||||
unit_chooser::UnitChooser,
|
||||
};
|
||||
|
71
world/src/util/small_cache.rs
Normal file
71
world/src/util/small_cache.rs
Normal file
@ -0,0 +1,71 @@
|
||||
use arr_macro::arr;
|
||||
use vek::*;
|
||||
|
||||
fn calc_idx(v: Vec2<i32>) -> usize {
|
||||
let mut x = v.x as u32;
|
||||
let mut y = v.y as u32;
|
||||
x = x.wrapping_mul(0x6eed0e9d);
|
||||
y = y.wrapping_mul(0x2f72b421);
|
||||
(x ^ y) as usize
|
||||
}
|
||||
|
||||
const CACHE_LEN: usize = 32;
|
||||
|
||||
pub struct SmallCache<V: Default> {
|
||||
index: [Option<Vec2<i32>>; CACHE_LEN + 9],
|
||||
data: [V; CACHE_LEN + 9],
|
||||
random: u32,
|
||||
}
|
||||
impl<V: Default> Default for SmallCache<V> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
index: [None; CACHE_LEN + 9],
|
||||
data: arr![V::default(); 41], // TODO: Use CACHE_LEN
|
||||
random: 1,
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<V: Default> SmallCache<V> {
|
||||
pub fn get<F: FnOnce(Vec2<i32>) -> V>(&mut self, key: Vec2<i32>, f: F) -> &V {
|
||||
let idx = calc_idx(key) % CACHE_LEN;
|
||||
|
||||
// Search
|
||||
if self.index[idx].as_ref().map(|k| k == &key).unwrap_or(false) {
|
||||
return &self.data[idx];
|
||||
} else if self.index[idx + 1]
|
||||
.as_ref()
|
||||
.map(|k| k == &key)
|
||||
.unwrap_or(false)
|
||||
{
|
||||
return &self.data[idx + 1];
|
||||
} else if self.index[idx + 4]
|
||||
.as_ref()
|
||||
.map(|k| k == &key)
|
||||
.unwrap_or(false)
|
||||
{
|
||||
return &self.data[idx + 4];
|
||||
} else if self.index[idx + 9]
|
||||
.as_ref()
|
||||
.map(|k| k == &key)
|
||||
.unwrap_or(false)
|
||||
{
|
||||
return &self.data[idx + 9];
|
||||
}
|
||||
// Not present so insert
|
||||
for i in 0..4 {
|
||||
let idx = idx + i * i;
|
||||
if self.index[idx].is_none() {
|
||||
self.index[idx] = Some(key.clone());
|
||||
self.data[idx] = f(key);
|
||||
return &self.data[idx];
|
||||
}
|
||||
}
|
||||
// No space randomly remove someone
|
||||
let step = super::seed_expan::diffuse(self.random) as usize % 4;
|
||||
let idx = step * step + idx;
|
||||
self.random = self.random.wrapping_add(1);
|
||||
self.index[idx] = Some(key.clone());
|
||||
self.data[idx] = f(key);
|
||||
&self.data[idx]
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user