mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Cleaned up shrub implementation
This commit is contained in:
parent
c399fe9a39
commit
e8021fab2c
@ -6,27 +6,27 @@
|
|||||||
center: (6, 6, 2),
|
center: (6, 6, 2),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
specifier: "world.shrub.jungle-bush-0",
|
specifier: "world.shrub.jungle.bush-0",
|
||||||
center: (5, 5, 3),
|
center: (5, 5, 3),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
specifier: "world.shrub.jungle-bush-1",
|
specifier: "world.shrub.jungle.bush-1",
|
||||||
center: (5, 5, 2),
|
center: (5, 5, 2),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
specifier: "world.shrub.jungle-bush-2",
|
specifier: "world.shrub.jungle.bush-2",
|
||||||
center: (5, 5, 3),
|
center: (5, 5, 3),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
specifier: "world.shrub.jungle-bush-3",
|
specifier: "world.shrub.jungle.bush-3",
|
||||||
center: (5, 5, 3),
|
center: (5, 5, 3),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
specifier: "world.shrub.jungle-bush-4",
|
specifier: "world.shrub.jungle.bush-4",
|
||||||
center: (5, 5, 4),
|
center: (5, 5, 4),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
specifier: "world.shrub.jungle-bush-5",
|
specifier: "world.shrub.jungle.bush-5",
|
||||||
center: (5, 5, 5),
|
center: (5, 5, 5),
|
||||||
),
|
),
|
||||||
]
|
]
|
@ -551,8 +551,11 @@ impl<'a> MapConfig<'a> {
|
|||||||
downhill_wpos,
|
downhill_wpos,
|
||||||
);
|
);
|
||||||
let (_t, _pt, dist) = if let Some((t, pt, dist)) =
|
let (_t, _pt, dist) = if let Some((t, pt, dist)) =
|
||||||
quadratic_nearest_point(&coeffs, wposf, Vec2::new(neighbor_wpos, downhill_wpos))
|
quadratic_nearest_point(
|
||||||
{
|
&coeffs,
|
||||||
|
wposf,
|
||||||
|
Vec2::new(neighbor_wpos, downhill_wpos),
|
||||||
|
) {
|
||||||
(t, pt, dist)
|
(t, pt, dist)
|
||||||
} else {
|
} else {
|
||||||
let ndist = wposf.distance_squared(neighbor_wpos);
|
let ndist = wposf.distance_squared(neighbor_wpos);
|
||||||
|
@ -304,9 +304,9 @@ pub fn quadratic_nearest_point(
|
|||||||
// end: line.y,
|
// end: line.y,
|
||||||
// };
|
// };
|
||||||
// let len_sq = line.start.distance_squared(line.end);
|
// let len_sq = line.start.distance_squared(line.end);
|
||||||
// let t = ((point - line.start).dot(line.end - line.start) / len_sq).clamped(0.0, 1.0);
|
// let t = ((point - line.start).dot(line.end - line.start) /
|
||||||
// let pos = line.start + (line.end - line.start) * t;
|
// len_sq).clamped(0.0, 1.0); let pos = line.start + (line.end - line.start)
|
||||||
// return Some((t, pos, pos.distance_squared(point)));
|
// * t; return Some((t, pos, pos.distance_squared(point)));
|
||||||
|
|
||||||
// Quadratic
|
// Quadratic
|
||||||
|
|
||||||
@ -406,9 +406,9 @@ pub fn quadratic_nearest_point(
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
});
|
});
|
||||||
min_root
|
min_root
|
||||||
// .map(|(t, pt, dist)| {
|
// .map(|(t, pt, dist)| {
|
||||||
// let t = t.clamped(0.0, 1.0);
|
// let t = t.clamped(0.0, 1.0);
|
||||||
// let pos = spline.x * t * t + spline.y * t + spline.z;
|
// let pos = spline.x * t * t + spline.y * t + spline.z;
|
||||||
// (t, pos, pos.distance_squared(point))
|
// (t, pos, pos.distance_squared(point))
|
||||||
// })
|
// })
|
||||||
}
|
}
|
||||||
|
@ -309,7 +309,7 @@ impl<'a> Sampler<'a> for ColumnGen<'a> {
|
|||||||
// },
|
// },
|
||||||
);
|
);
|
||||||
|
|
||||||
let river_width = river_width.max(2.0f64.sqrt() + 0.1) * (1.0 + river_width_noise * 0.3);
|
let river_width = river_width.max(2.0) * (1.0 + river_width_noise * 0.3);
|
||||||
// To find the distance, we just evaluate the quadratic equation at river_t and
|
// To find the distance, we just evaluate the quadratic equation at river_t and
|
||||||
// see if it's within width (but we should be able to use it for a
|
// see if it's within width (but we should be able to use it for a
|
||||||
// lot more, and this probably isn't the very best approach anyway
|
// lot more, and this probably isn't the very best approach anyway
|
||||||
@ -344,7 +344,12 @@ impl<'a> Sampler<'a> for ColumnGen<'a> {
|
|||||||
.unwrap_or(CONFIG.sea_level);
|
.unwrap_or(CONFIG.sea_level);
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct WeightedSum<T> { sum: T, weight: T, min: Option<T>, max: Option<T> }
|
struct WeightedSum<T> {
|
||||||
|
sum: T,
|
||||||
|
weight: T,
|
||||||
|
min: Option<T>,
|
||||||
|
max: Option<T>,
|
||||||
|
}
|
||||||
impl WeightedSum<f32> {
|
impl WeightedSum<f32> {
|
||||||
fn with(self, value: f32, weight: f32) -> Self {
|
fn with(self, value: f32, weight: f32) -> Self {
|
||||||
Self {
|
Self {
|
||||||
@ -353,14 +358,23 @@ impl<'a> Sampler<'a> for ColumnGen<'a> {
|
|||||||
..self
|
..self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// With an upper bound
|
/// With an upper bound
|
||||||
fn with_min(self, min: f32) -> Self {
|
fn with_min(self, min: f32) -> Self {
|
||||||
Self { min: Some(self.min.unwrap_or(min).min(min)), ..self }
|
Self {
|
||||||
|
min: Some(self.min.unwrap_or(min).min(min)),
|
||||||
|
..self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// With a lower bound
|
/// With a lower bound
|
||||||
fn with_max(self, max: f32) -> Self {
|
fn with_max(self, max: f32) -> Self {
|
||||||
Self { max: Some(self.max.unwrap_or(max).max(max)), ..self }
|
Self {
|
||||||
|
max: Some(self.max.unwrap_or(max).max(max)),
|
||||||
|
..self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval(&self) -> Option<f32> {
|
fn eval(&self) -> Option<f32> {
|
||||||
if self.weight > 0.0 {
|
if self.weight > 0.0 {
|
||||||
let res = self.sum / self.weight;
|
let res = self.sum / self.weight;
|
||||||
@ -370,8 +384,8 @@ impl<'a> Sampler<'a> for ColumnGen<'a> {
|
|||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval_or(&self, default: f32) -> f32 {
|
fn eval_or(&self, default: f32) -> f32 {
|
||||||
let res = if self.weight > 0.0 {
|
let res = if self.weight > 0.0 {
|
||||||
self.sum / self.weight
|
self.sum / self.weight
|
||||||
@ -384,8 +398,17 @@ impl<'a> Sampler<'a> for ColumnGen<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_waterfall(chunk_pos: Vec2<i32>, river_chunk: &SimChunk, downhill_chunk: &SimChunk) -> bool {
|
fn is_waterfall(
|
||||||
(chunk_pos.sum() as u32 % 19 < 2 || matches!(downhill_chunk.river.river_kind, Some(RiverKind::Lake { .. }))) && (river_chunk.water_alt > downhill_chunk.water_alt + 8.0)
|
chunk_pos: Vec2<i32>,
|
||||||
|
river_chunk: &SimChunk,
|
||||||
|
downhill_chunk: &SimChunk,
|
||||||
|
) -> bool {
|
||||||
|
(chunk_pos.sum() as u32 % 19 < 2
|
||||||
|
|| matches!(
|
||||||
|
downhill_chunk.river.river_kind,
|
||||||
|
Some(RiverKind::Lake { .. })
|
||||||
|
))
|
||||||
|
&& (river_chunk.water_alt > downhill_chunk.water_alt + 8.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn river_water_alt(a: f32, b: f32, t: f32, is_waterfall: bool) -> f32 {
|
fn river_water_alt(a: f32, b: f32, t: f32, is_waterfall: bool) -> f32 {
|
||||||
@ -501,17 +524,28 @@ impl<'a> Sampler<'a> for ColumnGen<'a> {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
let unbounded_water_level = unbounded_water_level.eval_or(actual_sea_level);
|
let unbounded_water_level = unbounded_water_level.eval_or(actual_sea_level);
|
||||||
let water_level = match (river_water_level.eval(), lake_water_level.eval().filter(|_| lake_dist <= 0.0 || in_river)) {
|
let water_level = match (
|
||||||
|
river_water_level.eval(),
|
||||||
|
lake_water_level
|
||||||
|
.eval()
|
||||||
|
.filter(|_| lake_dist <= 0.0 || in_river),
|
||||||
|
) {
|
||||||
(Some(r), Some(l)) => r.max(l),
|
(Some(r), Some(l)) => r.max(l),
|
||||||
(r, l) => r.or(l).unwrap_or(actual_sea_level).max(unbounded_water_level),
|
(r, l) => r
|
||||||
|
.or(l)
|
||||||
|
.unwrap_or(actual_sea_level)
|
||||||
|
.max(unbounded_water_level),
|
||||||
};
|
};
|
||||||
|
|
||||||
let riverless_alt = alt;
|
let riverless_alt = alt;
|
||||||
let alt = neighbor_river_data.clone().fold(
|
let alt = neighbor_river_data.clone().fold(
|
||||||
WeightedSum::default().with(riverless_alt, 1.0),
|
WeightedSum::default().with(riverless_alt, 1.0),
|
||||||
|alt, (river_chunk_idx, river_chunk, river, dist_info)| match (river.river_kind, dist_info) {
|
|alt, (river_chunk_idx, river_chunk, river, dist_info)| match (
|
||||||
|
river.river_kind,
|
||||||
|
dist_info,
|
||||||
|
) {
|
||||||
(
|
(
|
||||||
Some(kind/*RiverKind::River { cross_section }*/),
|
Some(kind /* RiverKind::River { cross_section } */),
|
||||||
Some((_, dist, river_width, (river_t, (river_pos, _), downhill_chunk))),
|
Some((_, dist, river_width, (river_t, (river_pos, _), downhill_chunk))),
|
||||||
) => {
|
) => {
|
||||||
// Distance from river center
|
// Distance from river center
|
||||||
@ -519,7 +553,12 @@ impl<'a> Sampler<'a> for ColumnGen<'a> {
|
|||||||
// Distance from edge of river
|
// Distance from edge of river
|
||||||
let river_edge_dist = (river_dist - river_width * 0.5).max(0.0) as f32;
|
let river_edge_dist = (river_dist - river_width * 0.5).max(0.0) as f32;
|
||||||
// 0.0 = not near river, 1.0 = in middle of river
|
// 0.0 = not near river, 1.0 = in middle of river
|
||||||
let near_river = ((river_dist / river_width) as f32).min(1.0).mul(f32::consts::PI).cos().add(1.0).mul(0.5);
|
let near_river = ((river_dist / river_width) as f32)
|
||||||
|
.min(1.0)
|
||||||
|
.mul(f32::consts::PI)
|
||||||
|
.cos()
|
||||||
|
.add(1.0)
|
||||||
|
.mul(0.5);
|
||||||
|
|
||||||
let water_alt = match kind {
|
let water_alt = match kind {
|
||||||
RiverKind::River { cross_section } => {
|
RiverKind::River { cross_section } => {
|
||||||
@ -540,11 +579,25 @@ impl<'a> Sampler<'a> for ColumnGen<'a> {
|
|||||||
is_waterfall(river_chunk_idx, river_chunk, downhill_chunk),
|
is_waterfall(river_chunk_idx, river_chunk, downhill_chunk),
|
||||||
);
|
);
|
||||||
|
|
||||||
let depth = water_level - Lerp::lerp(riverless_alt.min(water_level), water_level - 4.0, 0.5);
|
let depth = water_level
|
||||||
|
- Lerp::lerp(
|
||||||
|
riverless_alt.min(water_level),
|
||||||
|
water_level - 4.0,
|
||||||
|
0.5,
|
||||||
|
);
|
||||||
|
|
||||||
let min_alt = Lerp::lerp(riverless_alt, lake_water_alt, ((river_dist - 8.5) / (river_width * 0.5 - 8.5).max(0.01)).clamped(0.0, 1.0) as f32);
|
let min_alt = Lerp::lerp(
|
||||||
|
riverless_alt,
|
||||||
|
lake_water_alt,
|
||||||
|
((river_dist - 8.5) / (river_width * 0.5 - 8.5).max(0.01))
|
||||||
|
.clamped(0.0, 1.0) as f32,
|
||||||
|
);
|
||||||
|
|
||||||
Some((lake_water_alt, /*river_width as f32 * 0.15*/ depth, Some(min_alt)))
|
Some((
|
||||||
|
lake_water_alt,
|
||||||
|
/* river_width as f32 * 0.15 */ depth,
|
||||||
|
Some(min_alt),
|
||||||
|
))
|
||||||
},
|
},
|
||||||
RiverKind::Ocean => None,
|
RiverKind::Ocean => None,
|
||||||
};
|
};
|
||||||
@ -553,29 +606,48 @@ impl<'a> Sampler<'a> for ColumnGen<'a> {
|
|||||||
if let Some((water_alt, water_depth, min_alt)) = water_alt {
|
if let Some((water_alt, water_depth, min_alt)) = water_alt {
|
||||||
if river_edge_dist <= 0.0 {
|
if river_edge_dist <= 0.0 {
|
||||||
const MIN_DEPTH: f32 = 1.0;
|
const MIN_DEPTH: f32 = 1.0;
|
||||||
let near_centre = ((river_dist / (river_width * 0.5)) as f32).min(1.0).mul(f32::consts::PI).cos().add(1.0).mul(0.5);
|
let near_centre = ((river_dist / (river_width * 0.5)) as f32)
|
||||||
let waterfall_boost = if is_waterfall(river_chunk_idx, river_chunk, downhill_chunk) {
|
.min(1.0)
|
||||||
(river_chunk.alt - downhill_chunk.alt).max(0.0).powf(2.0) * (1.0 - (river_t as f32 - 0.5).abs() * 2.0).powf(3.5) / 20.0
|
.mul(f32::consts::PI)
|
||||||
} else {
|
.cos()
|
||||||
0.0
|
.add(1.0)
|
||||||
};
|
.mul(0.5);
|
||||||
// let river_depth = cross_section.y as f32 /*river_width as f32 * 0.15*/;
|
let waterfall_boost =
|
||||||
let riverbed_depth = near_centre * water_depth + MIN_DEPTH + waterfall_boost;
|
if is_waterfall(river_chunk_idx, river_chunk, downhill_chunk) {
|
||||||
// Handle rivers debouching into the ocean nicely by 'flattening' their bottom
|
(river_chunk.alt - downhill_chunk.alt).max(0.0).powf(2.0)
|
||||||
let riverbed_alt = (water_alt - riverbed_depth).max(riverless_alt.min(CONFIG.sea_level - MIN_DEPTH));
|
* (1.0 - (river_t as f32 - 0.5).abs() * 2.0).powf(3.5)
|
||||||
alt
|
/ 20.0
|
||||||
.with(min_alt.unwrap_or(riverbed_alt).min(riverbed_alt), near_centre * BANK_STRENGTH)
|
} else {
|
||||||
.with_min(min_alt.unwrap_or(riverbed_alt).min(riverbed_alt))
|
0.0
|
||||||
|
};
|
||||||
|
// let river_depth = cross_section.y as f32 /*river_width as f32 *
|
||||||
|
// 0.15*/;
|
||||||
|
let riverbed_depth =
|
||||||
|
near_centre * water_depth + MIN_DEPTH + waterfall_boost;
|
||||||
|
// Handle rivers debouching into the ocean nicely by 'flattening' their
|
||||||
|
// bottom
|
||||||
|
let riverbed_alt = (water_alt - riverbed_depth)
|
||||||
|
.max(riverless_alt.min(CONFIG.sea_level - MIN_DEPTH));
|
||||||
|
alt.with(
|
||||||
|
min_alt.unwrap_or(riverbed_alt).min(riverbed_alt),
|
||||||
|
near_centre * BANK_STRENGTH,
|
||||||
|
)
|
||||||
|
.with_min(min_alt.unwrap_or(riverbed_alt).min(riverbed_alt))
|
||||||
} else {
|
} else {
|
||||||
const GORGE: f32 = 0.5;
|
const GORGE: f32 = 0.5;
|
||||||
const BANK_SCALE: f32 = 24.0;
|
const BANK_SCALE: f32 = 24.0;
|
||||||
// Weighting of this riverbank on nearby terrain (higher when closer to the river). This
|
// Weighting of this riverbank on nearby terrain (higher when closer to
|
||||||
// 'pulls' the riverbank toward the river's altitude to make sure that we get a smooth
|
// the river). This 'pulls' the riverbank
|
||||||
|
// toward the river's altitude to make sure that we get a smooth
|
||||||
// transition from normal terrain to the water.
|
// transition from normal terrain to the water.
|
||||||
let weight = Lerp::lerp(
|
let weight = Lerp::lerp(
|
||||||
BANK_STRENGTH / (1.0 + (river_edge_dist as f32 - 3.0).max(0.0) * BANK_STRENGTH / BANK_SCALE),
|
BANK_STRENGTH
|
||||||
|
/ (1.0
|
||||||
|
+ (river_edge_dist as f32 - 3.0).max(0.0) * BANK_STRENGTH
|
||||||
|
/ BANK_SCALE),
|
||||||
0.0,
|
0.0,
|
||||||
// cubic((river_edge_dist / BANK_SCALE).clamped(0.0, 1.0) as f64) as f32,
|
// cubic((river_edge_dist / BANK_SCALE).clamped(0.0, 1.0) as f64)
|
||||||
|
// as f32,
|
||||||
(river_edge_dist / BANK_SCALE).clamped(0.0, 1.0),
|
(river_edge_dist / BANK_SCALE).clamped(0.0, 1.0),
|
||||||
);
|
);
|
||||||
let alt = alt.with(water_alt + GORGE, weight);
|
let alt = alt.with(water_alt + GORGE, weight);
|
||||||
@ -586,8 +658,8 @@ impl<'a> Sampler<'a> for ColumnGen<'a> {
|
|||||||
alt
|
alt
|
||||||
};
|
};
|
||||||
// let alt = if !in_river && lake_dist > 0.0 {
|
// let alt = if !in_river && lake_dist > 0.0 {
|
||||||
// alt.with_max(water_alt + GORGE - river_edge_dist.powf(2.0) / 10.0)
|
// alt.with_max(water_alt + GORGE - river_edge_dist.powf(2.0) /
|
||||||
// } else {
|
// 10.0) } else {
|
||||||
// alt
|
// alt
|
||||||
// };
|
// };
|
||||||
alt
|
alt
|
||||||
@ -758,11 +830,11 @@ impl<'a> Sampler<'a> for ColumnGen<'a> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let alt_for_river = alt;
|
let alt_for_river = alt;
|
||||||
// + if overlap_count == 0.0 {
|
// + if overlap_count == 0.0 {
|
||||||
// 0.0
|
// 0.0
|
||||||
// } else {
|
// } else {
|
||||||
// river_overlap_distance_product / overlap_count
|
// river_overlap_distance_product / overlap_count
|
||||||
// } as f32;
|
// } as f32;
|
||||||
|
|
||||||
let riverless_alt_delta = (sim.gen_ctx.small_nz.get(
|
let riverless_alt_delta = (sim.gen_ctx.small_nz.get(
|
||||||
(wposf_turb.div(200.0 * (32.0 / TerrainChunkSize::RECT_SIZE.x as f64))).into_array(),
|
(wposf_turb.div(200.0 * (32.0 / TerrainChunkSize::RECT_SIZE.x as f64))).into_array(),
|
||||||
@ -802,261 +874,238 @@ impl<'a> Sampler<'a> for ColumnGen<'a> {
|
|||||||
let riverless_alt_delta = riverless_alt_delta + (cliff - 0.5) * cliff_height;
|
let riverless_alt_delta = riverless_alt_delta + (cliff - 0.5) * cliff_height;
|
||||||
|
|
||||||
let river_gouge = 0.5;
|
let river_gouge = 0.5;
|
||||||
let (_in_water, old_water_dist, alt_, old_water_level, _riverless_alt, warp_factor) = if let Some(
|
let (_in_water, old_water_dist, alt_, old_water_level, _riverless_alt, warp_factor) =
|
||||||
(max_border_river_pos, river_chunk, max_border_river, max_border_river_dist),
|
if let Some((
|
||||||
) =
|
max_border_river_pos,
|
||||||
max_river
|
river_chunk,
|
||||||
{
|
max_border_river,
|
||||||
// This is flowing into a lake, or a lake, or is at least a non-ocean tile.
|
max_border_river_dist,
|
||||||
//
|
)) = max_river
|
||||||
// If we are <= water_alt, we are in the lake; otherwise, we are flowing into
|
{
|
||||||
// it.
|
// This is flowing into a lake, or a lake, or is at least a non-ocean tile.
|
||||||
match max_border_river.river_kind {
|
//
|
||||||
Some(RiverKind::River { cross_section }) => 'block: {
|
// If we are <= water_alt, we are in the lake; otherwise, we are flowing into
|
||||||
if max_border_river_dist.map(|(_, dist, _, _)| dist)
|
// it.
|
||||||
!= Some(Vec2::zero())
|
match max_border_river.river_kind {
|
||||||
{
|
Some(RiverKind::River { cross_section }) => 'block: {
|
||||||
let (_, _, river_width, (_, (river_pos, _), _)) =
|
if max_border_river_dist.map(|(_, dist, _, _)| dist) != Some(Vec2::zero()) {
|
||||||
max_border_river_dist.unwrap();
|
let (_, _, river_width, (_, (river_pos, _), _)) =
|
||||||
let river_dist = wposf.distance(river_pos);
|
max_border_river_dist.unwrap();
|
||||||
|
let river_dist = wposf.distance(river_pos);
|
||||||
|
|
||||||
// FIXME: Make water altitude accurate.
|
// FIXME: Make water altitude accurate.
|
||||||
break 'block (
|
|
||||||
river_scale_factor <= 1.0,
|
|
||||||
Some((river_dist - river_width * 0.5) as f32),
|
|
||||||
alt_for_river - max_dip,//alt_for_river,
|
|
||||||
downhill_water_alt,
|
|
||||||
alt, //alt_for_river,
|
|
||||||
river_scale_factor as f32,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
let (
|
|
||||||
_,
|
|
||||||
_,
|
|
||||||
river_width,
|
|
||||||
(river_t, (river_pos, _), downhill_river_chunk),
|
|
||||||
) = max_border_river_dist.unwrap();
|
|
||||||
let river_alt = Lerp::lerp(
|
|
||||||
river_chunk.alt.max(river_chunk.water_alt),
|
|
||||||
downhill_river_chunk.alt.max(downhill_river_chunk.water_alt),
|
|
||||||
river_t as f32,
|
|
||||||
);
|
|
||||||
let new_alt = river_alt - river_gouge;
|
|
||||||
let river_dist = wposf.distance(river_pos);
|
|
||||||
let river_height_factor = river_dist / (river_width * 0.5);
|
|
||||||
|
|
||||||
// This is not a good way to determine river depth, but we do it
|
|
||||||
// anyway. TODO: Make the erosion
|
|
||||||
// sim output better river depths through `cross_section`.
|
|
||||||
let river_depth = river_width as f32 * 0.5;
|
|
||||||
|
|
||||||
let valley_alt = Lerp::lerp(
|
|
||||||
new_alt - (cross_section.y * river_depth).max(1.0),
|
|
||||||
new_alt - 1.0,
|
|
||||||
(river_height_factor * river_height_factor) as f32,
|
|
||||||
);
|
|
||||||
|
|
||||||
(
|
|
||||||
true,
|
|
||||||
Some((river_dist - river_width * 0.5) as f32),
|
|
||||||
alt_for_river - max_dip,//valley_alt.min(alt),
|
|
||||||
new_alt.max(valley_alt.min(alt) + 1.0),
|
|
||||||
alt, //river_alt + cross_section.y.max(1.0),
|
|
||||||
river_scale_factor as f32,//0.0,
|
|
||||||
)
|
|
||||||
},
|
|
||||||
Some(RiverKind::Ocean) => 'block: {
|
|
||||||
let (
|
|
||||||
_,
|
|
||||||
dist,
|
|
||||||
river_width,
|
|
||||||
(river_t, (river_pos, _), downhill_river_chunk),
|
|
||||||
) = if let Some(dist) = max_border_river_dist {
|
|
||||||
dist
|
|
||||||
} else {
|
|
||||||
error!(
|
|
||||||
?max_border_river,
|
|
||||||
?chunk_pos,
|
|
||||||
?max_border_river_pos,
|
|
||||||
"downhill error details"
|
|
||||||
);
|
|
||||||
panic!(
|
|
||||||
"Oceans should definitely have a downhill! \
|
|
||||||
...Right?"
|
|
||||||
);
|
|
||||||
};
|
|
||||||
let lake_water_alt = Lerp::lerp(
|
|
||||||
river_chunk.alt.max(river_chunk.water_alt),
|
|
||||||
downhill_river_chunk
|
|
||||||
.alt
|
|
||||||
.max(downhill_river_chunk.water_alt),
|
|
||||||
river_t as f32,
|
|
||||||
) + 1.0;
|
|
||||||
|
|
||||||
if dist == Vec2::zero() {
|
|
||||||
let river_dist = wposf.distance(river_pos);
|
|
||||||
let _river_height_factor =
|
|
||||||
river_dist / (river_width * 0.5);
|
|
||||||
break 'block (
|
|
||||||
true,
|
|
||||||
Some((river_dist - river_width * 0.5) as f32),
|
|
||||||
alt_for_river - max_dip,//alt_for_river,
|
|
||||||
// .min(lake_water_alt - 1.0 - river_gouge),
|
|
||||||
lake_water_alt,
|
|
||||||
alt, //alt_for_river.max(lake_water_alt),
|
|
||||||
0.0,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
(
|
|
||||||
river_scale_factor <= 1.0,
|
|
||||||
Some(
|
|
||||||
(wposf.distance(river_pos) - river_width * 0.5)
|
|
||||||
as f32,
|
|
||||||
),
|
|
||||||
alt_for_river - max_dip,//alt_for_river,
|
|
||||||
downhill_water_alt + 1.0,
|
|
||||||
alt, //alt_for_river,
|
|
||||||
river_scale_factor as f32,
|
|
||||||
)
|
|
||||||
},
|
|
||||||
Some(RiverKind::Lake { .. }) => 'block: {
|
|
||||||
let lake_chunk = max_border_river_pos.map(|e| e as f64);
|
|
||||||
let lake_aabr = Aabr {
|
|
||||||
min: lake_chunk * neighbor_coef,
|
|
||||||
max: (lake_chunk + 1.0) * neighbor_coef,
|
|
||||||
};
|
|
||||||
let lake_dist = lake_aabr.distance_to_point(wposf);
|
|
||||||
let downhill_river_chunk = max_border_river_pos;
|
|
||||||
let lake_id_dist = downhill_river_chunk - chunk_pos;
|
|
||||||
let in_bounds = lake_id_dist.x >= -1
|
|
||||||
&& lake_id_dist.y >= -1
|
|
||||||
&& lake_id_dist.x <= 1
|
|
||||||
&& lake_id_dist.y <= 1;
|
|
||||||
let in_bounds = in_bounds
|
|
||||||
&& (lake_id_dist.x >= 0 && lake_id_dist.y >= 0);
|
|
||||||
let (_, dist, _, (river_t, _, downhill_river_chunk)) =
|
|
||||||
if let Some(dist) = max_border_river_dist {
|
|
||||||
dist
|
|
||||||
} else if lake_dist
|
|
||||||
<= TerrainChunkSize::RECT_SIZE.x as f64 * 1.0
|
|
||||||
|| in_bounds
|
|
||||||
{
|
|
||||||
let gouge_factor = 0.0;
|
|
||||||
break 'block (
|
break 'block (
|
||||||
in_bounds
|
river_scale_factor <= 1.0,
|
||||||
|| downhill_water_alt
|
Some((river_dist - river_width * 0.5) as f32),
|
||||||
.max(river_chunk.water_alt)
|
alt_for_river - max_dip, //alt_for_river,
|
||||||
> alt_for_river,
|
|
||||||
Some(lake_dist as f32),
|
|
||||||
alt_for_river - max_dip,//alt_for_river,
|
|
||||||
(downhill_water_alt.max(river_chunk.water_alt)
|
|
||||||
- river_gouge),
|
|
||||||
alt_for_river,
|
|
||||||
river_scale_factor as f32
|
|
||||||
* (1.0 - gouge_factor),
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
break 'block (
|
|
||||||
false,
|
|
||||||
Some(lake_dist as f32),
|
|
||||||
alt_for_river - max_dip,//alt_for_river,
|
|
||||||
downhill_water_alt,
|
downhill_water_alt,
|
||||||
alt_for_river,
|
alt, //alt_for_river,
|
||||||
river_scale_factor as f32,
|
river_scale_factor as f32,
|
||||||
);
|
);
|
||||||
};
|
}
|
||||||
|
let (_, _, river_width, (river_t, (river_pos, _), downhill_river_chunk)) =
|
||||||
|
max_border_river_dist.unwrap();
|
||||||
|
let river_alt = Lerp::lerp(
|
||||||
|
river_chunk.alt.max(river_chunk.water_alt),
|
||||||
|
downhill_river_chunk.alt.max(downhill_river_chunk.water_alt),
|
||||||
|
river_t as f32,
|
||||||
|
);
|
||||||
|
let new_alt = river_alt - river_gouge;
|
||||||
|
let river_dist = wposf.distance(river_pos);
|
||||||
|
let river_height_factor = river_dist / (river_width * 0.5);
|
||||||
|
|
||||||
let lake_dist = dist.y;
|
// This is not a good way to determine river depth, but we do it
|
||||||
let lake_water_alt = Lerp::lerp(
|
// anyway. TODO: Make the erosion
|
||||||
river_chunk.alt.max(river_chunk.water_alt),
|
// sim output better river depths through `cross_section`.
|
||||||
downhill_river_chunk
|
let river_depth = river_width as f32 * 0.5;
|
||||||
.alt
|
|
||||||
.max(downhill_river_chunk.water_alt),
|
let valley_alt = Lerp::lerp(
|
||||||
river_t as f32,
|
new_alt - (cross_section.y * river_depth).max(1.0),
|
||||||
);
|
new_alt - 1.0,
|
||||||
// if dist == Vec2::zero() {
|
(river_height_factor * river_height_factor) as f32,
|
||||||
// return (
|
);
|
||||||
// true,
|
|
||||||
// Some(lake_dist as f32),
|
(
|
||||||
// alt_for_river,
|
true,
|
||||||
// // .min(lake_water_alt - 1.0 - river_gouge),
|
Some((river_dist - river_width * 0.5) as f32),
|
||||||
// lake_water_alt - river_gouge,
|
alt_for_river - max_dip, //valley_alt.min(alt),
|
||||||
// alt_for_river.max(lake_water_alt),
|
new_alt.max(valley_alt.min(alt) + 1.0),
|
||||||
// 0.0,
|
alt, //river_alt + cross_section.y.max(1.0),
|
||||||
// );
|
river_scale_factor as f32, //0.0,
|
||||||
// }
|
)
|
||||||
if lake_dist <= TerrainChunkSize::RECT_SIZE.x as f64 * 1.0
|
},
|
||||||
|| in_bounds
|
Some(RiverKind::Ocean) => 'block: {
|
||||||
{
|
let (_, dist, river_width, (river_t, (river_pos, _), downhill_river_chunk)) =
|
||||||
let gouge_factor = if in_bounds && lake_dist <= 1.0 {
|
if let Some(dist) = max_border_river_dist {
|
||||||
1.0
|
dist
|
||||||
} else {
|
} else {
|
||||||
0.0
|
error!(
|
||||||
};
|
?max_border_river,
|
||||||
let in_bounds_ = lake_dist
|
?chunk_pos,
|
||||||
<= TerrainChunkSize::RECT_SIZE.x as f64 * 0.5;
|
?max_border_river_pos,
|
||||||
if gouge_factor == 1.0 {
|
"downhill error details"
|
||||||
|
);
|
||||||
|
panic!("Oceans should definitely have a downhill! ...Right?");
|
||||||
|
};
|
||||||
|
let lake_water_alt = Lerp::lerp(
|
||||||
|
river_chunk.alt.max(river_chunk.water_alt),
|
||||||
|
downhill_river_chunk.alt.max(downhill_river_chunk.water_alt),
|
||||||
|
river_t as f32,
|
||||||
|
) + 1.0;
|
||||||
|
|
||||||
|
if dist == Vec2::zero() {
|
||||||
|
let river_dist = wposf.distance(river_pos);
|
||||||
|
let _river_height_factor = river_dist / (river_width * 0.5);
|
||||||
break 'block (
|
break 'block (
|
||||||
true,
|
true,
|
||||||
Some(lake_dist as f32),
|
Some((river_dist - river_width * 0.5) as f32),
|
||||||
alt_for_river - max_dip,//alt_for_river,
|
alt_for_river - max_dip, //alt_for_river,
|
||||||
// .min(lake_water_alt - 1.0 - river_gouge),
|
// .min(lake_water_alt - 1.0 - river_gouge),
|
||||||
downhill_water_alt.max(lake_water_alt)
|
lake_water_alt,
|
||||||
- river_gouge,
|
alt, //alt_for_river.max(lake_water_alt),
|
||||||
alt.max(lake_water_alt),
|
0.0,
|
||||||
0.0,// river_scale_factor as f32* (1.0 - gouge_factor),
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
break 'block (
|
|
||||||
true,
|
|
||||||
Some(lake_dist as f32),
|
|
||||||
alt_for_river - max_dip,//alt_for_river,
|
|
||||||
if in_bounds_ {
|
|
||||||
downhill_water_alt.max(lake_water_alt)
|
|
||||||
} else {
|
|
||||||
downhill_water_alt//.max(lake_water_alt)
|
|
||||||
}.max(river_chunk.water_alt) - river_gouge,
|
|
||||||
alt_for_river,
|
|
||||||
river_scale_factor as f32
|
|
||||||
* (1.0 - gouge_factor),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
(
|
(
|
||||||
river_scale_factor <= 1.0,
|
river_scale_factor <= 1.0,
|
||||||
Some(lake_dist as f32),
|
Some((wposf.distance(river_pos) - river_width * 0.5) as f32),
|
||||||
alt_for_river - max_dip,//alt_for_river.max(lake_water_alt).max(river_chunk.water_alt),
|
alt_for_river - max_dip, //alt_for_river,
|
||||||
|
downhill_water_alt + 1.0,
|
||||||
|
alt, //alt_for_river,
|
||||||
|
river_scale_factor as f32,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
Some(RiverKind::Lake { .. }) => 'block: {
|
||||||
|
let lake_chunk = max_border_river_pos.map(|e| e as f64);
|
||||||
|
let lake_aabr = Aabr {
|
||||||
|
min: lake_chunk * neighbor_coef,
|
||||||
|
max: (lake_chunk + 1.0) * neighbor_coef,
|
||||||
|
};
|
||||||
|
let lake_dist = lake_aabr.distance_to_point(wposf);
|
||||||
|
let downhill_river_chunk = max_border_river_pos;
|
||||||
|
let lake_id_dist = downhill_river_chunk - chunk_pos;
|
||||||
|
let in_bounds = lake_id_dist.x >= -1
|
||||||
|
&& lake_id_dist.y >= -1
|
||||||
|
&& lake_id_dist.x <= 1
|
||||||
|
&& lake_id_dist.y <= 1;
|
||||||
|
let in_bounds = in_bounds && (lake_id_dist.x >= 0 && lake_id_dist.y >= 0);
|
||||||
|
let (_, dist, _, (river_t, _, downhill_river_chunk)) =
|
||||||
|
if let Some(dist) = max_border_river_dist {
|
||||||
|
dist
|
||||||
|
} else if lake_dist <= TerrainChunkSize::RECT_SIZE.x as f64 * 1.0
|
||||||
|
|| in_bounds
|
||||||
|
{
|
||||||
|
let gouge_factor = 0.0;
|
||||||
|
break 'block (
|
||||||
|
in_bounds
|
||||||
|
|| downhill_water_alt.max(river_chunk.water_alt)
|
||||||
|
> alt_for_river,
|
||||||
|
Some(lake_dist as f32),
|
||||||
|
alt_for_river - max_dip, //alt_for_river,
|
||||||
|
(downhill_water_alt.max(river_chunk.water_alt) - river_gouge),
|
||||||
|
alt_for_river,
|
||||||
|
river_scale_factor as f32 * (1.0 - gouge_factor),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
break 'block (
|
||||||
|
false,
|
||||||
|
Some(lake_dist as f32),
|
||||||
|
alt_for_river - max_dip, //alt_for_river,
|
||||||
|
downhill_water_alt,
|
||||||
|
alt_for_river,
|
||||||
|
river_scale_factor as f32,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
let lake_dist = dist.y;
|
||||||
|
let lake_water_alt = Lerp::lerp(
|
||||||
|
river_chunk.alt.max(river_chunk.water_alt),
|
||||||
|
downhill_river_chunk.alt.max(downhill_river_chunk.water_alt),
|
||||||
|
river_t as f32,
|
||||||
|
);
|
||||||
|
// if dist == Vec2::zero() {
|
||||||
|
// return (
|
||||||
|
// true,
|
||||||
|
// Some(lake_dist as f32),
|
||||||
|
// alt_for_river,
|
||||||
|
// // .min(lake_water_alt - 1.0 - river_gouge),
|
||||||
|
// lake_water_alt - river_gouge,
|
||||||
|
// alt_for_river.max(lake_water_alt),
|
||||||
|
// 0.0,
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
if lake_dist <= TerrainChunkSize::RECT_SIZE.x as f64 * 1.0 || in_bounds {
|
||||||
|
let gouge_factor = if in_bounds && lake_dist <= 1.0 {
|
||||||
|
1.0
|
||||||
|
} else {
|
||||||
|
0.0
|
||||||
|
};
|
||||||
|
let in_bounds_ =
|
||||||
|
lake_dist <= TerrainChunkSize::RECT_SIZE.x as f64 * 0.5;
|
||||||
|
if gouge_factor == 1.0 {
|
||||||
|
break 'block (
|
||||||
|
true,
|
||||||
|
Some(lake_dist as f32),
|
||||||
|
alt_for_river - max_dip, //alt_for_river,
|
||||||
|
// .min(lake_water_alt - 1.0 - river_gouge),
|
||||||
|
downhill_water_alt.max(lake_water_alt) - river_gouge,
|
||||||
|
alt.max(lake_water_alt),
|
||||||
|
0.0, // river_scale_factor as f32* (1.0 - gouge_factor),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
break 'block (
|
||||||
|
true,
|
||||||
|
Some(lake_dist as f32),
|
||||||
|
alt_for_river - max_dip, //alt_for_river,
|
||||||
|
if in_bounds_ {
|
||||||
|
downhill_water_alt.max(lake_water_alt)
|
||||||
|
} else {
|
||||||
|
downhill_water_alt //.max(lake_water_alt)
|
||||||
|
}
|
||||||
|
.max(river_chunk.water_alt)
|
||||||
|
- river_gouge,
|
||||||
|
alt_for_river,
|
||||||
|
river_scale_factor as f32 * (1.0 - gouge_factor),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(
|
||||||
|
river_scale_factor <= 1.0,
|
||||||
|
Some(lake_dist as f32),
|
||||||
|
alt_for_river - max_dip, /* alt_for_river.max(lake_water_alt).
|
||||||
|
* max(river_chunk.water_alt), */
|
||||||
|
downhill_water_alt,
|
||||||
|
alt_for_river,
|
||||||
|
river_scale_factor as f32,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
None => (
|
||||||
|
false,
|
||||||
|
None,
|
||||||
|
alt_for_river - max_dip, //alt_for_river,
|
||||||
downhill_water_alt,
|
downhill_water_alt,
|
||||||
alt_for_river,
|
alt, //alt_for_river,
|
||||||
river_scale_factor as f32,
|
1.0,
|
||||||
)
|
),
|
||||||
},
|
}
|
||||||
None => (
|
} else {
|
||||||
|
(
|
||||||
false,
|
false,
|
||||||
None,
|
None,
|
||||||
alt_for_river - max_dip,//alt_for_river,
|
alt_for_river - max_dip, //alt_for_river,
|
||||||
downhill_water_alt,
|
downhill_water_alt,
|
||||||
alt, //alt_for_river,
|
alt, //alt_for_river,
|
||||||
1.0,
|
1.0,
|
||||||
),
|
)
|
||||||
}
|
};
|
||||||
} else {
|
|
||||||
(
|
|
||||||
false,
|
|
||||||
None,
|
|
||||||
alt_for_river - max_dip,//alt_for_river,
|
|
||||||
downhill_water_alt,
|
|
||||||
alt, //alt_for_river,
|
|
||||||
1.0,
|
|
||||||
)
|
|
||||||
};
|
|
||||||
// NOTE: To disable warp, uncomment this line.
|
// NOTE: To disable warp, uncomment this line.
|
||||||
// let warp_factor = 0.0;
|
// let warp_factor = 0.0;
|
||||||
|
|
||||||
let warp_factor = warp_factor.min(water_dist.map_or(1.0, |d| d.max(0.0) / 64.0));
|
let warp_factor = warp_factor.min(water_dist.map_or(1.0, |d| d.max(0.0) / 64.0));
|
||||||
let riverless_alt_delta = Lerp::lerp(0.0, riverless_alt_delta, warp_factor);
|
let riverless_alt_delta = Lerp::lerp(0.0, riverless_alt_delta, warp_factor);
|
||||||
// let riverless_alt = alt + riverless_alt_delta; //riverless_alt + riverless_alt_delta;
|
// let riverless_alt = alt + riverless_alt_delta; //riverless_alt +
|
||||||
|
// riverless_alt_delta;
|
||||||
let alt = alt/*alt_*/ + riverless_alt_delta;
|
let alt = alt/*alt_*/ + riverless_alt_delta;
|
||||||
let basement =
|
let basement =
|
||||||
alt + sim.get_interpolated_monotone(wpos, |chunk| chunk.basement.sub(chunk.alt))?;
|
alt + sim.get_interpolated_monotone(wpos, |chunk| chunk.basement.sub(chunk.alt))?;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
|
all::ForestKind,
|
||||||
util::{seed_expan, RandomPerm, Sampler, StructureGen2d, UnitChooser},
|
util::{seed_expan, RandomPerm, Sampler, StructureGen2d, UnitChooser},
|
||||||
Canvas,
|
Canvas,
|
||||||
};
|
};
|
||||||
@ -14,12 +15,13 @@ use rand_chacha::ChaChaRng;
|
|||||||
use vek::*;
|
use vek::*;
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref SHRUBS: AssetHandle<StructuresGroup> = Structure::load_group("shrubs");
|
static ref JUNGLE_SHRUBS: AssetHandle<StructuresGroup> = Structure::load_group("shrubs.jungle");
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Shrub {
|
struct Shrub {
|
||||||
wpos: Vec3<i32>,
|
wpos: Vec3<i32>,
|
||||||
seed: u32,
|
seed: u32,
|
||||||
|
kind: ForestKind,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn apply_shrubs_to(canvas: &mut Canvas, rng: &mut impl Rng) {
|
pub fn apply_shrubs_to(canvas: &mut Canvas, rng: &mut impl Rng) {
|
||||||
@ -33,7 +35,10 @@ pub fn apply_shrubs_to(canvas: &mut Canvas, rng: &mut impl Rng) {
|
|||||||
shrub_cache.entry(wpos).or_insert_with(|| {
|
shrub_cache.entry(wpos).or_insert_with(|| {
|
||||||
let col = info.col_or_gen(wpos)?;
|
let col = info.col_or_gen(wpos)?;
|
||||||
|
|
||||||
if RandomPerm::new(seed).chance(37, col.tree_density * 0.3)
|
let mut rng = ChaChaRng::from_seed(seed_expan::rng_state(seed));
|
||||||
|
|
||||||
|
const BASE_SHRUB_DENSITY: f64 = 0.15;
|
||||||
|
if rng.gen_bool((BASE_SHRUB_DENSITY * col.tree_density as f64).clamped(0.0, 1.0))
|
||||||
&& col.water_dist.map_or(true, |d| d > 8.0)
|
&& col.water_dist.map_or(true, |d| d > 8.0)
|
||||||
&& col.alt > col.water_level
|
&& col.alt > col.water_level
|
||||||
&& col.spawn_rate > 0.9
|
&& col.spawn_rate > 0.9
|
||||||
@ -42,6 +47,11 @@ pub fn apply_shrubs_to(canvas: &mut Canvas, rng: &mut impl Rng) {
|
|||||||
Some(Shrub {
|
Some(Shrub {
|
||||||
wpos: wpos.with_z(col.alt as i32),
|
wpos: wpos.with_z(col.alt as i32),
|
||||||
seed,
|
seed,
|
||||||
|
kind: *info
|
||||||
|
.chunks()
|
||||||
|
.make_forest_lottery(wpos)
|
||||||
|
.choose_seeded(seed)
|
||||||
|
.as_ref()?,
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
@ -55,7 +65,12 @@ pub fn apply_shrubs_to(canvas: &mut Canvas, rng: &mut impl Rng) {
|
|||||||
|
|
||||||
let units = UnitChooser::new(shrub.seed).get(shrub.seed).into();
|
let units = UnitChooser::new(shrub.seed).get(shrub.seed).into();
|
||||||
|
|
||||||
let shrubs = SHRUBS.read();
|
let shrubs = match shrub.kind {
|
||||||
|
ForestKind::Mangrove => &JUNGLE_SHRUBS,
|
||||||
|
_ => continue, // TODO: Add more shrub varieties
|
||||||
|
}
|
||||||
|
.read();
|
||||||
|
|
||||||
let structure = shrubs.choose(&mut rng).unwrap();
|
let structure = shrubs.choose(&mut rng).unwrap();
|
||||||
canvas.blit_structure(shrub.wpos, structure, shrub.seed, units, true);
|
canvas.blit_structure(shrub.wpos, structure, shrub.seed, units, true);
|
||||||
}
|
}
|
||||||
|
@ -2056,47 +2056,45 @@ impl WorldSim {
|
|||||||
self.get_nearest_way(wpos, |chunk| Some(chunk.cave))
|
self.get_nearest_way(wpos, |chunk| Some(chunk.cave))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a [`Lottery<Option<ForestKind>>`] that generates [`ForestKind`]s
|
||||||
|
/// according to the conditions at the given position. If no or fewer
|
||||||
|
/// trees are appropriate for the conditions, `None` may be generated.
|
||||||
|
pub fn make_forest_lottery(&self, wpos: Vec2<i32>) -> Lottery<Option<ForestKind>> {
|
||||||
|
let chunk = if let Some(chunk) = self.get_wpos(wpos) {
|
||||||
|
chunk
|
||||||
|
} else {
|
||||||
|
return Lottery::from(vec![(1.0, None)]);
|
||||||
|
};
|
||||||
|
let env = chunk.get_environment();
|
||||||
|
Lottery::from(
|
||||||
|
ForestKind::into_enum_iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(i, fk)| {
|
||||||
|
const CLUSTER_SIZE: f64 = 48.0;
|
||||||
|
let nz = (FastNoise2d::new(i as u32 * 37)
|
||||||
|
.get(wpos.map(|e| e as f64) / CLUSTER_SIZE)
|
||||||
|
+ 1.0)
|
||||||
|
/ 2.0;
|
||||||
|
(fk.proclivity(&env) * nz, Some(fk))
|
||||||
|
})
|
||||||
|
.chain(std::iter::once((0.001, None)))
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/// Return an iterator over candidate tree positions (note that only some of
|
/// Return an iterator over candidate tree positions (note that only some of
|
||||||
/// these will become trees since environmental parameters may forbid
|
/// these will become trees since environmental parameters may forbid
|
||||||
/// them spawning).
|
/// them spawning).
|
||||||
pub fn get_near_trees(&self, wpos: Vec2<i32>) -> impl Iterator<Item = TreeAttr> + '_ {
|
pub fn get_near_trees(&self, wpos: Vec2<i32>) -> impl Iterator<Item = TreeAttr> + '_ {
|
||||||
// Deterministic based on wpos
|
// Deterministic based on wpos
|
||||||
let normal_trees = std::array::IntoIter::new(self.gen_ctx.structure_gen.get(wpos))
|
let normal_trees = std::array::IntoIter::new(self.gen_ctx.structure_gen.get(wpos))
|
||||||
.filter_map(move |(pos, seed)| {
|
.filter_map(move |(wpos, seed)| {
|
||||||
let chunk = self.get_wpos(pos)?;
|
let lottery = self.make_forest_lottery(wpos);
|
||||||
let env = Environment {
|
|
||||||
humid: chunk.humidity,
|
|
||||||
temp: chunk.temp,
|
|
||||||
near_water: if chunk.river.is_lake()
|
|
||||||
|| chunk.river.near_river()
|
|
||||||
|| chunk.alt < CONFIG.sea_level + 6.0
|
|
||||||
// Close to sea in altitude
|
|
||||||
{
|
|
||||||
1.0
|
|
||||||
} else {
|
|
||||||
0.0
|
|
||||||
},
|
|
||||||
};
|
|
||||||
Some(TreeAttr {
|
Some(TreeAttr {
|
||||||
pos,
|
pos: wpos,
|
||||||
seed,
|
seed,
|
||||||
scale: 1.0,
|
scale: 1.0,
|
||||||
forest_kind: *Lottery::from(
|
forest_kind: *lottery.choose_seeded(seed).as_ref()?,
|
||||||
ForestKind::into_enum_iter()
|
|
||||||
.enumerate()
|
|
||||||
.map(|(i, fk)| {
|
|
||||||
const CLUSTER_SIZE: f64 = 48.0;
|
|
||||||
let nz = (FastNoise2d::new(i as u32 * 37)
|
|
||||||
.get(pos.map(|e| e as f64) / CLUSTER_SIZE)
|
|
||||||
+ 1.0)
|
|
||||||
/ 2.0;
|
|
||||||
(fk.proclivity(&env) * nz, Some(fk))
|
|
||||||
})
|
|
||||||
.chain(std::iter::once((0.001, None)))
|
|
||||||
.collect::<Vec<_>>(),
|
|
||||||
)
|
|
||||||
.choose_seeded(seed)
|
|
||||||
.as_ref()?,
|
|
||||||
inhabited: false,
|
inhabited: false,
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
@ -2222,8 +2220,7 @@ impl SimChunk {
|
|||||||
Some(
|
Some(
|
||||||
uniform_idx_as_vec2(map_size_lg, downhill_pre as usize)
|
uniform_idx_as_vec2(map_size_lg, downhill_pre as usize)
|
||||||
* TerrainChunkSize::RECT_SIZE.map(|e| e as i32)
|
* TerrainChunkSize::RECT_SIZE.map(|e| e as i32)
|
||||||
+ TerrainChunkSize::RECT_SIZE.map(|e| e as i32 / 2)
|
+ TerrainChunkSize::RECT_SIZE.map(|e| e as i32 / 2),
|
||||||
,
|
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -2424,4 +2421,20 @@ impl SimChunk {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn near_cliffs(&self) -> bool { self.cliff_height > 0.0 }
|
pub fn near_cliffs(&self) -> bool { self.cliff_height > 0.0 }
|
||||||
|
|
||||||
|
pub fn get_environment(&self) -> Environment {
|
||||||
|
Environment {
|
||||||
|
humid: self.humidity,
|
||||||
|
temp: self.temp,
|
||||||
|
near_water: if self.river.is_lake()
|
||||||
|
|| self.river.near_river()
|
||||||
|
|| self.alt < CONFIG.sea_level + 6.0
|
||||||
|
// Close to sea in altitude
|
||||||
|
{
|
||||||
|
1.0
|
||||||
|
} else {
|
||||||
|
0.0
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user