Paths and smoother region borders

This commit is contained in:
Joshua Barretto 2019-06-22 22:44:27 +01:00
parent 86f13af8cb
commit 216c2583fb
5 changed files with 132 additions and 19 deletions

View File

@ -37,8 +37,8 @@ fn main() {
let loc_color = location
.map(|l| {
(
l.name().bytes().nth(0).unwrap() * 17,
l.name().bytes().nth(1).unwrap() * 17,
l.loc.name().bytes().nth(0).unwrap() * 17,
l.loc.name().bytes().nth(1).unwrap() * 17,
)
})
.unwrap_or((0, 0));
@ -67,10 +67,10 @@ fn main() {
gain -= 10.0;
}
if win.is_key_down(minifb::Key::R) {
scale += 1;
scale += 6;
}
if win.is_key_down(minifb::Key::F) {
scale -= 1;
scale -= 6;
}
win.update_with_buffer(&buf).unwrap();

View File

@ -103,8 +103,7 @@ impl<'a> SamplerMut for BlockGen<'a> {
(true, alt, water_level)
} else {
// Apply warping
let warp = (self
.world
let warp = (world
.sim()
.gen_ctx
.warp_nz

View File

@ -1,4 +1,10 @@
use crate::{all::ForestKind, sim::Location, util::Sampler, World, CONFIG};
use crate::{
all::ForestKind,
sim::{Location, LocationInfo},
util::Sampler,
World,
CONFIG,
};
use common::{
terrain::{Block, TerrainChunkSize},
vol::{VolSize, Vox},
@ -116,6 +122,30 @@ impl<'a> Sampler for ColumnGen<'a> {
temp.sub(CONFIG.desert_temp).mul(32.0),
);
// Work out if we're on a path
let near_0 = sim_chunk.location.as_ref().map(|l| l.near[0].block_pos).unwrap_or(Vec2::zero()).map(|e| e as f32);
let near_1 = sim_chunk.location.as_ref().map(|l| l.near[1].block_pos).unwrap_or(Vec2::zero()).map(|e| e as f32);
let dist_to_path = (0.0
+ (near_1.y - near_0.y) * wposf.x as f32
- (near_1.x - near_0.x) * wposf.y as f32
+ near_1.x * near_0.y
- near_0.x * near_1.y)
.abs()
.div(near_0.distance(near_1));
let alt = if dist_to_path < 15.0 {
alt - 100.0
} else {
alt
};
let ground = if dist_to_path < 5.0 {
Rgb::new(0.0, 0.0, 0.0)
} else {
ground
};
// Caves
let cave_at = |wposf: Vec2<f64>| {
(sim.gen_ctx.cave_0_nz.get(
@ -202,5 +232,5 @@ pub struct ColumnSample<'a> {
pub cliff_hill: f32,
pub close_cliffs: [(Vec2<i32>, u32); 9],
pub temp: f32,
pub location: Option<&'a Arc<Location>>,
pub location: Option<&'a LocationInfo>,
}

View File

@ -1,4 +1,4 @@
#![feature(euclidean_division, bind_by_move_pattern_guards)]
#![feature(euclidean_division, bind_by_move_pattern_guards, option_flattening)]
mod all;
mod block;

View File

@ -3,7 +3,11 @@ mod location;
// Reexports
pub use self::location::Location;
use crate::{all::ForestKind, util::StructureGen2d, CONFIG};
use crate::{
all::ForestKind,
util::{StructureGen2d, Sampler},
CONFIG,
};
use common::{
terrain::{BiomeKind, TerrainChunkSize},
vol::VolSize,
@ -115,14 +119,80 @@ impl WorldSim {
pub fn seed_elements(&mut self) {
let mut rng = self.rng.clone();
for _ in 0..250 {
let loc_center = Vec2::new(
self.rng.gen::<i32>() % WORLD_SIZE.x as i32,
self.rng.gen::<i32>() % WORLD_SIZE.y as i32,
);
let cell_size = 32;
let grid_size = WORLD_SIZE / cell_size;
let loc_count = 250;
if let Some(chunk) = self.get_mut(loc_center) {
chunk.location = Some(Location::generate(loc_center, &mut rng).into());
let mut locations = vec![None; grid_size.product()];
// Seed the world with some locations
for _ in 0..loc_count {
let cell_pos = Vec2::new(
self.rng.gen::<usize>() % grid_size.x,
self.rng.gen::<usize>() % grid_size.y,
);
let wpos = (cell_pos * cell_size)
.map2(
Vec2::from(TerrainChunkSize::SIZE),
|e, sz: u32| e as i32 * sz as i32,
);
locations[cell_pos.y * grid_size.x + cell_pos.x] = Some(Arc::new(Location::generate(wpos, &mut rng)));
}
// Simulate invasion!
let invasion_cycles = 25;
for _ in 0..invasion_cycles {
for i in 0..grid_size.x {
for j in 0..grid_size.y {
if locations[j * grid_size.x + i].is_none() {
const R_COORDS: [i32; 5] = [-1, 0, 1, 0, -1];
let idx = self.rng.gen::<usize>() % 4;
let loc = Vec2::new(
i as i32 + R_COORDS[idx],
j as i32 + R_COORDS[idx + 1],
).map(|e| e as usize);
locations[j * grid_size.x + i] = locations
.get(loc.y * grid_size.x + loc.x)
.cloned()
.flatten();
}
}
}
}
// Place the locations onto the world
let gen = StructureGen2d::new(self.seed, cell_size as u32, cell_size as u32 / 2);
for i in 0..WORLD_SIZE.x {
for j in 0..WORLD_SIZE.y {
let chunk_pos = Vec2::new(i as i32, j as i32);
let cell_pos = Vec2::new(i / cell_size, j / cell_size);
// Find the distance to each region
let near = gen.get(chunk_pos);
let mut near = near
.iter()
.map(|(pos, seed)| RegionInfo {
chunk_pos: *pos,
block_pos: pos.map2(Vec2::from(TerrainChunkSize::SIZE), |e, sz: u32| e * sz as i32),
dist: (pos - chunk_pos).map(|e| e as f32).magnitude(),
seed: *seed,
})
.collect::<Vec<_>>();
// Sort regions based on distance
near.sort_by(|a, b| a.dist.partial_cmp(&b.dist).unwrap());
let nearest_cell_pos = near[0].chunk_pos.map(|e| e as usize) / cell_size;
self.get_mut(chunk_pos).unwrap().location = locations
.get(nearest_cell_pos.y * grid_size.x + nearest_cell_pos.x)
.cloned()
.unwrap_or(None)
.map(|loc| LocationInfo {
loc,
near,
});
}
}
@ -242,7 +312,21 @@ pub struct SimChunk {
pub near_cliffs: bool,
pub tree_density: f32,
pub forest_kind: ForestKind,
pub location: Option<Arc<Location>>,
pub location: Option<LocationInfo>,
}
#[derive(Copy, Clone)]
pub struct RegionInfo {
pub chunk_pos: Vec2<i32>,
pub block_pos: Vec2<i32>,
pub dist: f32,
pub seed: u32,
}
#[derive(Clone)]
pub struct LocationInfo {
pub loc: Arc<Location>,
pub near: Vec<RegionInfo>,
}
impl SimChunk {
@ -367,7 +451,7 @@ impl SimChunk {
}
pub fn get_name(&self) -> Option<String> {
self.location.as_ref().map(|l| l.name().to_string())
self.location.as_ref().map(|l| l.loc.name().to_string())
}
pub fn get_biome(&self) -> BiomeKind {