mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Began work on caves2
This commit is contained in:
parent
61573a7800
commit
2cce44fc36
@ -153,7 +153,7 @@ float lights_at(vec3 wpos, vec3 wnorm, vec3 /*cam_to_frag*/view_dir, vec3 mu, ve
|
|||||||
|
|
||||||
// float strength = attenuation_strength(difference);// pow(attenuation_strength(difference), 0.6);
|
// float strength = attenuation_strength(difference);// pow(attenuation_strength(difference), 0.6);
|
||||||
// NOTE: This normalizes strength to 0.25 at the center of the point source.
|
// NOTE: This normalizes strength to 0.25 at the center of the point source.
|
||||||
float strength = 1.0 / (4 + distance_2);
|
float strength = 3.0 / (5 + distance_2);
|
||||||
|
|
||||||
// Multiply the vec3 only once
|
// Multiply the vec3 only once
|
||||||
const float PI = 3.1415926535897932384626433832795;
|
const float PI = 3.1415926535897932384626433832795;
|
||||||
|
85
world/examples/cave_view.rs
Normal file
85
world/examples/cave_view.rs
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
use rand::thread_rng;
|
||||||
|
use vek::*;
|
||||||
|
use veloren_world::{index::Index, site::Settlement, IndexRef};
|
||||||
|
|
||||||
|
const W: usize = 640;
|
||||||
|
const H: usize = 480;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let seed = 1337;
|
||||||
|
let index = &Index::new(seed);
|
||||||
|
|
||||||
|
let mut win =
|
||||||
|
minifb::Window::new("Cave Viewer", W, H, minifb::WindowOptions::default()).unwrap();
|
||||||
|
|
||||||
|
let settlement = Settlement::generate(Vec2::zero(), None, &mut thread_rng());
|
||||||
|
|
||||||
|
let mut focus = Vec2::<f32>::zero();
|
||||||
|
let mut zoom = 1.0;
|
||||||
|
let mut is_t = false;
|
||||||
|
let colors = &*index.colors();
|
||||||
|
let features = &*index.features();
|
||||||
|
let index = IndexRef {
|
||||||
|
colors,
|
||||||
|
features,
|
||||||
|
index,
|
||||||
|
};
|
||||||
|
|
||||||
|
while win.is_open() {
|
||||||
|
let mut buf = vec![0; W * H];
|
||||||
|
|
||||||
|
let win_to_pos =
|
||||||
|
|wp: Vec2<usize>| (wp.map(|e| e as f32) - Vec2::new(W as f32, H as f32) * 0.5) * zoom;
|
||||||
|
|
||||||
|
for i in 0..W {
|
||||||
|
for j in 0..H {
|
||||||
|
use common::terrain::{quadratic_nearest_point, river_spline_coeffs};
|
||||||
|
|
||||||
|
let pos = focus + win_to_pos(Vec2::new(i, j)) * zoom;
|
||||||
|
|
||||||
|
let a = Vec2::new(1000.0, 0.0);
|
||||||
|
let b = Vec2::new(1100.0, 30.0);
|
||||||
|
let d = Vec2::new(0.0, 0.0);
|
||||||
|
let closest = quadratic_nearest_point(
|
||||||
|
&river_spline_coeffs(a, d, b),
|
||||||
|
pos.map(|e| e as f64),
|
||||||
|
Vec2::new(a, b),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
let color = Lerp::lerp(
|
||||||
|
Rgb::new(1.0, 0.0, 0.0),
|
||||||
|
Rgb::new(0.0, 1.0, 0.0),
|
||||||
|
1.0 / (1.0 + if is_t { closest.0 } else { closest.2 }),
|
||||||
|
);
|
||||||
|
|
||||||
|
let color = Rgba::new(color.r, color.g, color.b, 1.0);
|
||||||
|
buf[j * W + i] = u32::from_le_bytes(color.map(|e| (e * 255.0) as u8).into_array());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let spd = 4.0;
|
||||||
|
if win.is_key_down(minifb::Key::W) {
|
||||||
|
focus.y -= spd * zoom;
|
||||||
|
}
|
||||||
|
if win.is_key_down(minifb::Key::A) {
|
||||||
|
focus.x -= spd * zoom;
|
||||||
|
}
|
||||||
|
if win.is_key_down(minifb::Key::S) {
|
||||||
|
focus.y += spd * zoom;
|
||||||
|
}
|
||||||
|
if win.is_key_down(minifb::Key::D) {
|
||||||
|
focus.x += spd * zoom;
|
||||||
|
}
|
||||||
|
if win.is_key_down(minifb::Key::Q) {
|
||||||
|
zoom *= 1.015;
|
||||||
|
}
|
||||||
|
if win.is_key_down(minifb::Key::E) {
|
||||||
|
zoom /= 1.015;
|
||||||
|
}
|
||||||
|
if win.is_key_down(minifb::Key::Tab) {
|
||||||
|
is_t ^= true;
|
||||||
|
}
|
||||||
|
|
||||||
|
win.update_with_buffer(&buf, W, H).unwrap();
|
||||||
|
}
|
||||||
|
}
|
@ -94,8 +94,8 @@ impl Civs {
|
|||||||
let initial_civ_count = initial_civ_count(sim.map_size_lg());
|
let initial_civ_count = initial_civ_count(sim.map_size_lg());
|
||||||
let mut ctx = GenCtx { sim, rng };
|
let mut ctx = GenCtx { sim, rng };
|
||||||
|
|
||||||
info!("starting cave generation");
|
// info!("starting cave generation");
|
||||||
this.generate_caves(&mut ctx);
|
// this.generate_caves(&mut ctx);
|
||||||
|
|
||||||
info!("starting civilisation creation");
|
info!("starting civilisation creation");
|
||||||
let mut start_locations: Vec<Vec2<i32>> = Vec::new();
|
let mut start_locations: Vec<Vec2<i32>> = Vec::new();
|
||||||
@ -438,7 +438,7 @@ impl Civs {
|
|||||||
&& chunk.alt < cave_max_alt
|
&& chunk.alt < cave_max_alt
|
||||||
&& cave_min_alt < chunk.water_alt
|
&& cave_min_alt < chunk.water_alt
|
||||||
&& chunk.river.near_water()
|
&& chunk.river.near_water()
|
||||||
// Only do this for caves at the sea level for now.
|
// Only do this for caves at the sea level for now.
|
||||||
// The reason being that floodfilling from a water alt to an alt lower than the water alt causes problems.
|
// The reason being that floodfilling from a water alt to an alt lower than the water alt causes problems.
|
||||||
&& chunk.water_alt <= CONFIG.sea_level;
|
&& chunk.water_alt <= CONFIG.sea_level;
|
||||||
if submerged {
|
if submerged {
|
||||||
|
@ -11,6 +11,8 @@ pub struct Land<'a> {
|
|||||||
impl<'a> Land<'a> {
|
impl<'a> Land<'a> {
|
||||||
pub fn empty() -> Self { Self { sim: None } }
|
pub fn empty() -> Self { Self { sim: None } }
|
||||||
|
|
||||||
|
pub fn size(&self) -> Vec2<u32> { self.sim.map_or(Vec2::one(), |s| s.get_size()) }
|
||||||
|
|
||||||
pub fn from_sim(sim: &'a sim::WorldSim) -> Self { Self { sim: Some(sim) } }
|
pub fn from_sim(sim: &'a sim::WorldSim) -> Self { Self { sim: Some(sim) } }
|
||||||
|
|
||||||
pub fn get_alt_approx(&self, wpos: Vec2<i32>) -> f32 {
|
pub fn get_alt_approx(&self, wpos: Vec2<i32>) -> f32 {
|
||||||
|
377
world/src/layer/cave.rs
Normal file
377
world/src/layer/cave.rs
Normal file
@ -0,0 +1,377 @@
|
|||||||
|
use super::scatter::close;
|
||||||
|
use crate::{
|
||||||
|
util::{sampler::Sampler, RandomField, LOCALITY},
|
||||||
|
Canvas, ColumnSample, Land,
|
||||||
|
};
|
||||||
|
use common::{
|
||||||
|
terrain::{
|
||||||
|
quadratic_nearest_point, river_spline_coeffs, Block, BlockKind, SpriteKind,
|
||||||
|
TerrainChunkSize,
|
||||||
|
},
|
||||||
|
vol::RectVolSize,
|
||||||
|
};
|
||||||
|
use noise::{Fbm, NoiseFn};
|
||||||
|
use rand::prelude::*;
|
||||||
|
use std::{
|
||||||
|
f64::consts::PI,
|
||||||
|
ops::{Add, Mul, Range, Sub},
|
||||||
|
};
|
||||||
|
use vek::*;
|
||||||
|
|
||||||
|
const CELL_SIZE: i32 = 1024;
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub struct Node {
|
||||||
|
pub wpos: Vec3<i32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_cell(wpos: Vec2<i32>, level: u32) -> Vec2<i32> {
|
||||||
|
(wpos + (level & 1) as i32 * CELL_SIZE / 2).map(|e| e.div_euclid(CELL_SIZE))
|
||||||
|
}
|
||||||
|
fn to_wpos(cell: Vec2<i32>, level: u32) -> Vec2<i32> {
|
||||||
|
(cell * CELL_SIZE) - (level & 1) as i32 * CELL_SIZE / 2
|
||||||
|
}
|
||||||
|
|
||||||
|
const AVG_LEVEL_DEPTH: i32 = 120;
|
||||||
|
|
||||||
|
fn node_at(cell: Vec2<i32>, level: u32, land: &Land) -> Option<Node> {
|
||||||
|
let rand = RandomField::new(37 + level);
|
||||||
|
|
||||||
|
if rand.chance(cell.with_z(0), 0.5) || level == 0 {
|
||||||
|
let dx = RandomField::new(38 + level);
|
||||||
|
let dy = RandomField::new(39 + level);
|
||||||
|
let wpos = to_wpos(cell, level)
|
||||||
|
+ CELL_SIZE as i32 / 4
|
||||||
|
+ (Vec2::new(dx.get(cell.with_z(0)), dy.get(cell.with_z(0))) % CELL_SIZE as u32 / 2)
|
||||||
|
.map(|e| e as i32);
|
||||||
|
land.get_chunk_wpos(wpos).and_then(|chunk| {
|
||||||
|
let alt = chunk.alt as i32 + 8 - AVG_LEVEL_DEPTH * level as i32;
|
||||||
|
|
||||||
|
if level > 0
|
||||||
|
|| (!chunk.near_cliffs()
|
||||||
|
&& !chunk.river.near_water()
|
||||||
|
&& chunk.sites.is_empty()
|
||||||
|
&& land.get_gradient_approx(wpos) < 0.75)
|
||||||
|
{
|
||||||
|
Some(Node {
|
||||||
|
wpos: wpos.with_z(alt),
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn surface_entrances<'a>(land: &'a Land) -> impl Iterator<Item = Vec2<i32>> + 'a {
|
||||||
|
let sz_cells = to_cell(
|
||||||
|
land.size()
|
||||||
|
.map2(TerrainChunkSize::RECT_SIZE, |e, sz| (e * sz) as i32),
|
||||||
|
0,
|
||||||
|
);
|
||||||
|
(0..sz_cells.x + 1)
|
||||||
|
.flat_map(move |x| (0..sz_cells.y + 1).map(move |y| Vec2::new(x, y)))
|
||||||
|
.filter_map(|cell| {
|
||||||
|
let tunnel = tunnels_below_from_cell(cell, 0, land)?;
|
||||||
|
// Hacky, moves the entrance position closer to the actual entrance
|
||||||
|
Some(Lerp::lerp(tunnel.a.wpos.xy(), tunnel.b.wpos.xy(), 0.25))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Tunnel {
|
||||||
|
a: Node,
|
||||||
|
b: Node,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tunnels_at<'a>(
|
||||||
|
wpos: Vec2<i32>,
|
||||||
|
level: u32,
|
||||||
|
land: &'a Land,
|
||||||
|
) -> impl Iterator<Item = Tunnel> + 'a {
|
||||||
|
let rand = RandomField::new(37 + level);
|
||||||
|
let col_cell = to_cell(wpos, level);
|
||||||
|
LOCALITY
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(move |rpos| {
|
||||||
|
let current_cell_pos = col_cell + rpos;
|
||||||
|
Some(current_cell_pos).zip(node_at(current_cell_pos, level, land))
|
||||||
|
})
|
||||||
|
.flat_map(move |(current_cell_pos, current_cell)| {
|
||||||
|
[Vec2::new(1, 1), Vec2::new(1, -1)]
|
||||||
|
.into_iter()
|
||||||
|
.filter(move |rpos| {
|
||||||
|
let mid = (current_cell_pos * 2 + rpos) / 2;
|
||||||
|
rand.chance(mid.with_z(0), 0.5) ^ (rpos.y == -1)
|
||||||
|
})
|
||||||
|
.chain([Vec2::new(1, 0), Vec2::new(0, 1)])
|
||||||
|
.filter_map(move |rpos| {
|
||||||
|
let other_cell_pos = current_cell_pos + rpos;
|
||||||
|
Some(other_cell_pos).zip(node_at(other_cell_pos, level, land))
|
||||||
|
})
|
||||||
|
.map(move |(other_cell_pos, other_cell)| Tunnel {
|
||||||
|
a: current_cell,
|
||||||
|
b: other_cell,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tunnels_below_from_cell(cell: Vec2<i32>, level: u32, land: &Land) -> Option<Tunnel> {
|
||||||
|
let wpos = to_wpos(cell, level);
|
||||||
|
Some(Tunnel {
|
||||||
|
a: node_at(to_cell(wpos, level), level, land)?,
|
||||||
|
b: node_at(
|
||||||
|
to_cell(wpos + CELL_SIZE as i32 / 2, level + 1),
|
||||||
|
level + 1,
|
||||||
|
land,
|
||||||
|
)?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tunnels_down_from<'a>(
|
||||||
|
wpos: Vec2<i32>,
|
||||||
|
level: u32,
|
||||||
|
land: &'a Land,
|
||||||
|
) -> impl Iterator<Item = Tunnel> + 'a {
|
||||||
|
let col_cell = to_cell(wpos, level);
|
||||||
|
LOCALITY
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(move |rpos| tunnels_below_from_cell(col_cell + rpos, level, land))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn apply_caves_to(canvas: &mut Canvas, rng: &mut impl Rng) {
|
||||||
|
let nz = Fbm::new();
|
||||||
|
let info = canvas.info();
|
||||||
|
canvas.foreach_col(|canvas, wpos2d, col| {
|
||||||
|
let wposf = wpos2d.map(|e| e as f64 + 0.5);
|
||||||
|
let land = info.land();
|
||||||
|
|
||||||
|
for level in 1..4 {
|
||||||
|
let rand = RandomField::new(37 + level);
|
||||||
|
let tunnel_bounds = tunnels_at(wpos2d, level, &land)
|
||||||
|
.chain(tunnels_down_from(wpos2d, level, &land))
|
||||||
|
.filter_map(|tunnel| {
|
||||||
|
let start = tunnel.a.wpos.xy().map(|e| e as f64 + 0.5);
|
||||||
|
let end = tunnel.b.wpos.xy().map(|e| e as f64 + 0.5);
|
||||||
|
let dist = LineSegment2 { start, end }
|
||||||
|
.distance_to_point(wpos2d.map(|e| e as f64 + 0.5));
|
||||||
|
|
||||||
|
let curve = (
|
||||||
|
RandomField::new(13)
|
||||||
|
.get_f32(tunnel.a.wpos.xy().with_z(0))
|
||||||
|
.powf(0.25) as f64,
|
||||||
|
(RandomField::new(14).get_f32(tunnel.a.wpos.xy().with_z(0)) as f64 - 0.5)
|
||||||
|
.signum(),
|
||||||
|
);
|
||||||
|
|
||||||
|
if let Some((t, closest, _)) = quadratic_nearest_point(
|
||||||
|
&river_spline_coeffs(
|
||||||
|
start,
|
||||||
|
((end - start) * 0.5
|
||||||
|
+ ((end - start) * 0.5).rotated_z(PI / 2.0)
|
||||||
|
* 4.0
|
||||||
|
* curve.0
|
||||||
|
* curve.1)
|
||||||
|
.map(|e| e as f32),
|
||||||
|
end,
|
||||||
|
),
|
||||||
|
wposf,
|
||||||
|
Vec2::new(start, end),
|
||||||
|
) {
|
||||||
|
let dist = closest.distance(wposf);
|
||||||
|
if dist < 64.0 {
|
||||||
|
let tunnel_len = tunnel
|
||||||
|
.a
|
||||||
|
.wpos
|
||||||
|
.map(|e| e as f64)
|
||||||
|
.distance(tunnel.b.wpos.map(|e| e as f64));
|
||||||
|
let radius = Lerp::lerp(
|
||||||
|
6.0,
|
||||||
|
32.0,
|
||||||
|
(nz.get((wposf / 200.0).into_array()) * 2.0 * 0.5 + 0.5)
|
||||||
|
.clamped(0.0, 1.0),
|
||||||
|
); // Lerp::lerp(8.0, 24.0, (t * 0.075 * tunnel_len).sin() * 0.5 + 0.5);
|
||||||
|
let height_here = (1.0 - dist / radius).max(0.0).powf(0.3) * radius;
|
||||||
|
if height_here > 0.0 {
|
||||||
|
let z_offs = nz.get((wposf / 512.0).into_array())
|
||||||
|
* 48.0
|
||||||
|
* ((1.0 - (t - 0.5).abs() * 2.0) * 8.0).min(1.0);
|
||||||
|
let depth =
|
||||||
|
Lerp::lerp(tunnel.a.wpos.z as f64, tunnel.b.wpos.z as f64, t)
|
||||||
|
+ z_offs;
|
||||||
|
Some((
|
||||||
|
(depth - height_here * 0.3) as i32,
|
||||||
|
(depth + height_here * 1.35) as i32,
|
||||||
|
z_offs,
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
for (min, max, z_offs) in tunnel_bounds {
|
||||||
|
// Avoid cave entrances intersecting water
|
||||||
|
let z_range = Lerp::lerp(
|
||||||
|
max,
|
||||||
|
min,
|
||||||
|
1.0 - (1.0 - ((col.alt - col.water_level) / 4.0).clamped(0.0, 1.0))
|
||||||
|
* (1.0 - ((col.alt - max as f32) / 8.0).clamped(0.0, 1.0)),
|
||||||
|
)..max;
|
||||||
|
write_column(canvas, col, level, wpos2d, z_range, z_offs, rng);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Biome {
|
||||||
|
humidity: f32,
|
||||||
|
temp: f32,
|
||||||
|
mineral: f32,
|
||||||
|
fungal: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_column(
|
||||||
|
canvas: &mut Canvas,
|
||||||
|
col: &ColumnSample,
|
||||||
|
level: u32,
|
||||||
|
wpos2d: Vec2<i32>,
|
||||||
|
z_range: Range<i32>,
|
||||||
|
z_offs: f64,
|
||||||
|
rng: &mut impl Rng,
|
||||||
|
) {
|
||||||
|
let info = canvas.info();
|
||||||
|
|
||||||
|
let below = ((col.alt - z_range.start as f32) / 50.0).clamped(0.0, 1.0);
|
||||||
|
let biome = Biome {
|
||||||
|
humidity: Lerp::lerp(
|
||||||
|
col.humidity,
|
||||||
|
info.index()
|
||||||
|
.noise
|
||||||
|
.cave_nz
|
||||||
|
.get(wpos2d.map(|e| e as f64 / 1024.0).into_array())
|
||||||
|
.mul(0.5)
|
||||||
|
.add(0.5) as f32,
|
||||||
|
below,
|
||||||
|
),
|
||||||
|
temp: Lerp::lerp(
|
||||||
|
col.temp,
|
||||||
|
info.index()
|
||||||
|
.noise
|
||||||
|
.cave_nz
|
||||||
|
.get(wpos2d.map(|e| e as f64 / 2048.0).into_array())
|
||||||
|
.add(
|
||||||
|
((col.alt as f64 - z_range.start as f64) / (AVG_LEVEL_DEPTH as f64 * 2.0))
|
||||||
|
.clamped(0.0, 2.0),
|
||||||
|
) as f32,
|
||||||
|
below,
|
||||||
|
),
|
||||||
|
mineral: info
|
||||||
|
.index()
|
||||||
|
.noise
|
||||||
|
.cave_nz
|
||||||
|
.get(wpos2d.map(|e| e as f64 / 256.0).into_array())
|
||||||
|
.mul(0.5)
|
||||||
|
.add(0.5) as f32,
|
||||||
|
fungal: info
|
||||||
|
.index()
|
||||||
|
.noise
|
||||||
|
.cave_nz
|
||||||
|
.get(wpos2d.map(|e| e as f64 / 512.0).into_array())
|
||||||
|
.mul(0.5)
|
||||||
|
.add(0.5) as f32,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Exposed to the sky
|
||||||
|
let exposed = z_range.end as f32 > col.alt;
|
||||||
|
|
||||||
|
let rand = RandomField::new(37 + level);
|
||||||
|
|
||||||
|
let stalactite = {
|
||||||
|
let cavern_height = (z_range.end - z_range.start) as f64;
|
||||||
|
info
|
||||||
|
.index()
|
||||||
|
.noise
|
||||||
|
.cave_nz
|
||||||
|
.get(wpos2d.map(|e| e as f64 / 16.0).into_array())
|
||||||
|
.sub(0.5)
|
||||||
|
.max(0.0)
|
||||||
|
.mul(2.0)
|
||||||
|
// No stalactites near entrances
|
||||||
|
.mul(((col.alt as f64 - z_range.end as f64) / 8.0).clamped(0.0, 1.0))
|
||||||
|
.mul(8.0 + cavern_height * 0.4)
|
||||||
|
};
|
||||||
|
|
||||||
|
let lava = {
|
||||||
|
info.index()
|
||||||
|
.noise
|
||||||
|
.cave_nz
|
||||||
|
.get(wpos2d.map(|e| e as f64 / 64.0).into_array())
|
||||||
|
.sub(0.5)
|
||||||
|
.abs()
|
||||||
|
.sub(0.2)
|
||||||
|
.min(0.0)
|
||||||
|
.mul((biome.temp as f64 - 1.5).mul(30.0).clamped(0.0, 1.0))
|
||||||
|
.mul(64.0)
|
||||||
|
.max(-32.0)
|
||||||
|
};
|
||||||
|
|
||||||
|
let dirt = if exposed { 0 } else { 1 };
|
||||||
|
let bedrock = z_range.start + lava as i32;
|
||||||
|
let base = bedrock + (stalactite * 0.4) as i32;
|
||||||
|
let floor = base + dirt;
|
||||||
|
let ceiling = z_range.end - stalactite as i32;
|
||||||
|
for z in bedrock..z_range.end {
|
||||||
|
canvas.map(wpos2d.with_z(z), |block| {
|
||||||
|
if !block.is_filled() {
|
||||||
|
block.into_vacant()
|
||||||
|
} else if z < z_range.start - 4 {
|
||||||
|
Block::new(BlockKind::Lava, Rgb::new(255, 100, 0))
|
||||||
|
} else if z < base || z >= ceiling {
|
||||||
|
Block::new(BlockKind::WeakRock, Rgb::new(80, 100, 150))
|
||||||
|
} else if z >= base && z < floor {
|
||||||
|
let surf_color: Rgb<i16> = Lerp::lerp(
|
||||||
|
Lerp::lerp(Rgb::new(40, 20, 0), Rgb::new(80, 80, 30), col.marble_small),
|
||||||
|
Lerp::lerp(Rgb::new(100, 20, 50), Rgb::new(80, 80, 100), col.marble_mid),
|
||||||
|
((col.alt - z as f32) / 300.0).clamped(0.0, 1.0),
|
||||||
|
);
|
||||||
|
|
||||||
|
Block::new(BlockKind::Sand, surf_color.map(|e| e as u8))
|
||||||
|
} else if let Some(sprite) = (z == floor && !exposed)
|
||||||
|
.then(|| {
|
||||||
|
if rand.chance(
|
||||||
|
wpos2d.with_z(1),
|
||||||
|
close(biome.humidity, 1.0, 0.5) * close(biome.temp, 0.0, 0.75) * 0.02,
|
||||||
|
) {
|
||||||
|
Some(SpriteKind::CaveMushroom)
|
||||||
|
} else if rand.chance(
|
||||||
|
wpos2d.with_z(1),
|
||||||
|
close(biome.humidity, 0.0, 0.5) * biome.mineral * 0.02,
|
||||||
|
) {
|
||||||
|
Some(SpriteKind::CrystalLow)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.flatten()
|
||||||
|
{
|
||||||
|
Block::air(sprite)
|
||||||
|
} else if z == ceiling - 1 && rand.chance(wpos2d.with_z(0), 0.0075) {
|
||||||
|
use SpriteKind::*;
|
||||||
|
Block::air(
|
||||||
|
*[Orb, CavernMycelBlue, CrystalHigh, CeilingMushroom]
|
||||||
|
.choose(rng)
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
Block::air(SpriteKind::Empty)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -1,3 +1,4 @@
|
|||||||
|
pub mod cave;
|
||||||
pub mod rock;
|
pub mod rock;
|
||||||
pub mod scatter;
|
pub mod scatter;
|
||||||
pub mod shrub;
|
pub mod shrub;
|
||||||
@ -6,8 +7,8 @@ pub mod tree;
|
|||||||
pub mod wildlife;
|
pub mod wildlife;
|
||||||
|
|
||||||
pub use self::{
|
pub use self::{
|
||||||
rock::apply_rocks_to, scatter::apply_scatter_to, shrub::apply_shrubs_to, spot::apply_spots_to,
|
cave::apply_caves_to as apply_caves2_to, rock::apply_rocks_to, scatter::apply_scatter_to,
|
||||||
tree::apply_trees_to,
|
shrub::apply_shrubs_to, spot::apply_spots_to, tree::apply_trees_to,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -5,7 +5,7 @@ use rand::prelude::*;
|
|||||||
use std::f32;
|
use std::f32;
|
||||||
use vek::*;
|
use vek::*;
|
||||||
|
|
||||||
fn close(x: f32, tgt: f32, falloff: f32) -> f32 {
|
pub fn close(x: f32, tgt: f32, falloff: f32) -> f32 {
|
||||||
(1.0 - (x - tgt).abs() / falloff).max(0.0).powf(0.125)
|
(1.0 - (x - tgt).abs() / falloff).max(0.0).powf(0.125)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,7 +11,8 @@
|
|||||||
bool_to_option,
|
bool_to_option,
|
||||||
label_break_value,
|
label_break_value,
|
||||||
option_zip,
|
option_zip,
|
||||||
arbitrary_enum_discriminant
|
arbitrary_enum_discriminant,
|
||||||
|
let_else
|
||||||
)]
|
)]
|
||||||
|
|
||||||
mod all;
|
mod all;
|
||||||
@ -180,6 +181,14 @@ impl World {
|
|||||||
wpos: pos,
|
wpos: pos,
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
.chain(layer::cave::surface_entrances(&Land::from_sim(self.sim()))
|
||||||
|
.enumerate()
|
||||||
|
.map(|(i, wpos)| world_msg::SiteInfo {
|
||||||
|
id: 65536 + i as u64, // Generate a fake ID, TODO: don't do this
|
||||||
|
name: None,
|
||||||
|
kind: world_msg::SiteKind::Cave,
|
||||||
|
wpos,
|
||||||
|
}))
|
||||||
.collect(),
|
.collect(),
|
||||||
..self.sim.get_map(index, self.sim().calendar.as_ref())
|
..self.sim.get_map(index, self.sim().calendar.as_ref())
|
||||||
}
|
}
|
||||||
@ -387,6 +396,7 @@ impl World {
|
|||||||
if index.features.spots {
|
if index.features.spots {
|
||||||
layer::apply_spots_to(&mut canvas, &mut dynamic_rng);
|
layer::apply_spots_to(&mut canvas, &mut dynamic_rng);
|
||||||
}
|
}
|
||||||
|
layer::apply_caves2_to(&mut canvas, &mut dynamic_rng);
|
||||||
// layer::apply_coral_to(&mut canvas);
|
// layer::apply_coral_to(&mut canvas);
|
||||||
|
|
||||||
// Apply site generation
|
// Apply site generation
|
||||||
|
Loading…
Reference in New Issue
Block a user