mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Basic region generation
This commit is contained in:
parent
aa28f0b427
commit
451bbe9921
@ -41,7 +41,7 @@ fn get_ao_quad<V: ReadVol>(vol: &V, pos: Vec3<i32>, shift: Vec3<i32>, dirs: &[Ve
|
||||
.unwrap_or(false);
|
||||
// Map both 1 and 2 neighbors to 0.5 occlusion.
|
||||
if s1 || s2 || corner {
|
||||
0.5
|
||||
0.3
|
||||
} else {
|
||||
1.0
|
||||
}
|
||||
|
@ -58,12 +58,10 @@ impl SessionState {
|
||||
}
|
||||
|
||||
// TODO: Get rid of this when we're done with it (we're not yet)
|
||||
/*
|
||||
match self.client.borrow().current_chunk() {
|
||||
Some(chunk) => println!("Chunk location: {:?}", chunk.meta().name()),
|
||||
None => {}
|
||||
}
|
||||
*/
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -15,35 +15,44 @@ fn main() {
|
||||
|
||||
let mut focus = Vec2::zero();
|
||||
let mut gain = 1.0;
|
||||
let mut scale = 4;
|
||||
|
||||
while win.is_open() {
|
||||
let mut buf = vec![0; W * H];
|
||||
|
||||
for i in 0..W {
|
||||
for j in 0..H {
|
||||
let pos = focus + Vec2::new(i as i32, j as i32) * 4;
|
||||
let pos = focus + Vec2::new(i as i32, j as i32) * scale;
|
||||
|
||||
let alt = sampler
|
||||
let (alt, location) = sampler
|
||||
.get(pos)
|
||||
.map(|sample| sample.alt.sub(64.0).add(gain).mul(0.7).max(0.0).min(255.0) as u8)
|
||||
.unwrap_or(0);
|
||||
.map(|sample| (
|
||||
sample.alt.sub(64.0).add(gain).mul(0.7).max(0.0).min(255.0) as u8,
|
||||
sample.location,
|
||||
))
|
||||
.unwrap_or((0, None));
|
||||
|
||||
buf[j * W + i] = u32::from_le_bytes([alt; 4]);
|
||||
let loc_color = location.map(|l| (
|
||||
l.name().bytes().nth(0).unwrap() * 17,
|
||||
l.name().bytes().nth(1).unwrap() * 17,
|
||||
)).unwrap_or((0, 0));
|
||||
|
||||
buf[j * W + i] = u32::from_le_bytes([loc_color.0, loc_color.1, alt, alt]);
|
||||
}
|
||||
}
|
||||
|
||||
let spd = 32;
|
||||
if win.is_key_down(minifb::Key::W) {
|
||||
focus.y -= spd;
|
||||
focus.y -= spd * scale;
|
||||
}
|
||||
if win.is_key_down(minifb::Key::A) {
|
||||
focus.x -= spd;
|
||||
focus.x -= spd * scale;
|
||||
}
|
||||
if win.is_key_down(minifb::Key::S) {
|
||||
focus.y += spd;
|
||||
focus.y += spd * scale;
|
||||
}
|
||||
if win.is_key_down(minifb::Key::D) {
|
||||
focus.x += spd;
|
||||
focus.x += spd * scale;
|
||||
}
|
||||
if win.is_key_down(minifb::Key::Q) {
|
||||
gain += 10.0;
|
||||
@ -51,6 +60,12 @@ fn main() {
|
||||
if win.is_key_down(minifb::Key::E) {
|
||||
gain -= 10.0;
|
||||
}
|
||||
if win.is_key_down(minifb::Key::R) {
|
||||
scale += 1;
|
||||
}
|
||||
if win.is_key_down(minifb::Key::F) {
|
||||
scale -= 1;
|
||||
}
|
||||
|
||||
win.update_with_buffer(&buf).unwrap();
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ use vek::*;
|
||||
|
||||
pub struct BlockGen<'a> {
|
||||
world: &'a World,
|
||||
column_cache: HashCache<Vec2<i32>, Option<ColumnSample>>,
|
||||
column_cache: HashCache<Vec2<i32>, Option<ColumnSample<'a>>>,
|
||||
column_gen: ColumnGen<'a>,
|
||||
}
|
||||
|
||||
@ -53,6 +53,7 @@ impl<'a> SamplerMut for BlockGen<'a> {
|
||||
rock,
|
||||
cliff,
|
||||
temp,
|
||||
..
|
||||
} = self.sample_column(Vec2::from(wpos))?;
|
||||
|
||||
let wposf = wpos.map(|e| e as f64);
|
||||
|
@ -1,10 +1,19 @@
|
||||
use crate::{all::ForestKind, util::Sampler, World, CONFIG};
|
||||
use crate::{
|
||||
all::ForestKind,
|
||||
util::Sampler,
|
||||
sim::Location,
|
||||
World,
|
||||
CONFIG,
|
||||
};
|
||||
use common::{
|
||||
terrain::{Block, TerrainChunkSize},
|
||||
vol::{VolSize, Vox},
|
||||
};
|
||||
use noise::NoiseFn;
|
||||
use std::ops::{Add, Div, Mul, Neg, Sub};
|
||||
use std::{
|
||||
ops::{Add, Div, Mul, Neg, Sub},
|
||||
sync::Arc,
|
||||
};
|
||||
use vek::*;
|
||||
|
||||
pub struct ColumnGen<'a> {
|
||||
@ -19,12 +28,12 @@ impl<'a> ColumnGen<'a> {
|
||||
|
||||
impl<'a> Sampler for ColumnGen<'a> {
|
||||
type Index = Vec2<i32>;
|
||||
type Sample = Option<ColumnSample>;
|
||||
type Sample = Option<ColumnSample<'a>>;
|
||||
|
||||
fn get(&self, wpos: Vec2<i32>) -> Option<ColumnSample> {
|
||||
fn get(&self, wpos: Vec2<i32>) -> Option<ColumnSample<'a>> {
|
||||
let wposf = wpos.map(|e| e as f64);
|
||||
let chunk_pos = wpos.map2(Vec2::from(TerrainChunkSize::SIZE), |e, sz: u32| {
|
||||
e as u32 / sz
|
||||
e / sz as i32
|
||||
});
|
||||
|
||||
let sim = self.world.sim();
|
||||
@ -36,7 +45,7 @@ impl<'a> Sampler for ColumnGen<'a> {
|
||||
let cliffiness = sim.get_interpolated(wpos, |chunk| chunk.cliffiness)?;
|
||||
let tree_density = sim.get_interpolated(wpos, |chunk| chunk.tree_density)?;
|
||||
|
||||
let forest_kind = sim.get(chunk_pos)?.forest_kind;
|
||||
let sim_chunk = sim.get(chunk_pos)?;
|
||||
|
||||
let alt = sim.get_interpolated(wpos, |chunk| chunk.alt)?
|
||||
+ (sim.gen_ctx.small_nz.get((wposf.div(256.0)).into_array()) as f32)
|
||||
@ -140,19 +149,20 @@ impl<'a> Sampler for ColumnGen<'a> {
|
||||
(alt - CONFIG.sea_level - 2.0) / 5.0,
|
||||
),
|
||||
tree_density,
|
||||
forest_kind,
|
||||
forest_kind: sim_chunk.forest_kind,
|
||||
close_trees: sim.gen_ctx.tree_gen.get(wpos),
|
||||
cave_xy,
|
||||
cave_alt,
|
||||
rock,
|
||||
cliff: cliffiness,
|
||||
temp,
|
||||
location: sim_chunk.location.as_ref(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ColumnSample {
|
||||
pub struct ColumnSample<'a> {
|
||||
pub alt: f32,
|
||||
pub chaos: f32,
|
||||
pub surface_color: Rgb<f32>,
|
||||
@ -164,4 +174,5 @@ pub struct ColumnSample {
|
||||
pub rock: f32,
|
||||
pub cliff: f32,
|
||||
pub temp: f32,
|
||||
pub location: Option<&'a Arc<Location>>
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ mod all;
|
||||
mod block;
|
||||
mod column;
|
||||
pub mod config;
|
||||
mod sim;
|
||||
pub mod sim;
|
||||
pub mod util;
|
||||
|
||||
// Reexports
|
||||
@ -62,15 +62,20 @@ impl World {
|
||||
let water = Block::new(5, Rgb::new(100, 150, 255));
|
||||
|
||||
let chunk_size2d = Vec2::from(TerrainChunkSize::SIZE);
|
||||
let base_z = match self.sim.get_interpolated(
|
||||
let (base_z, sim_chunk) = match self.sim.get_interpolated(
|
||||
chunk_pos.map2(chunk_size2d, |e, sz: u32| e * sz as i32 + sz as i32 / 2),
|
||||
|chunk| chunk.get_base_z(),
|
||||
) {
|
||||
Some(base_z) => base_z as i32,
|
||||
).and_then(|base_z| self.sim.get(chunk_pos).map(|sim_chunk| (base_z, sim_chunk))) {
|
||||
Some((base_z, sim_chunk)) => (base_z as i32, sim_chunk),
|
||||
None => return TerrainChunk::new(0, water, air, TerrainChunkMeta::void()),
|
||||
};
|
||||
|
||||
let mut chunk = TerrainChunk::new(base_z - 8, stone, air, TerrainChunkMeta::void());
|
||||
let meta = TerrainChunkMeta::new(
|
||||
sim_chunk.get_name(),
|
||||
sim_chunk.get_biome(),
|
||||
);
|
||||
|
||||
let mut chunk = TerrainChunk::new(base_z - 8, stone, air, meta);
|
||||
|
||||
let mut sampler = self.sample_blocks();
|
||||
|
||||
|
@ -1,17 +1,37 @@
|
||||
use rand::Rng;
|
||||
use vek::*;
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum LocationKind {
|
||||
Settlement,
|
||||
Mountain,
|
||||
Forest,
|
||||
Wildnerness,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Location {
|
||||
name: String,
|
||||
center: Vec2<i32>,
|
||||
kind: LocationKind,
|
||||
kingdom: Kingdom,
|
||||
kingdom: Option<Kingdom>,
|
||||
}
|
||||
|
||||
impl Location {
|
||||
pub fn generate<R: Rng>(center: Vec2<i32>, rng: &mut R) -> Self {
|
||||
Self {
|
||||
name: generate_name(rng),
|
||||
center,
|
||||
kind: LocationKind::Wildnerness,
|
||||
kingdom: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn name(&self) -> &str {
|
||||
&self.name
|
||||
}
|
||||
|
||||
pub fn kingdom(&self) -> Option<&Kingdom> {
|
||||
self.kingdom.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
@ -19,7 +39,7 @@ pub struct Kingdom {
|
||||
name: String,
|
||||
}
|
||||
|
||||
fn generate_name() -> String {
|
||||
fn generate_name<R: Rng>(rng: &mut R) -> String {
|
||||
let consts = [
|
||||
"st", "tr", "b", "n", "p", "ph", "cr", "g", "c", "d", "k", "kr", "kl", "gh", "sl", "st",
|
||||
"cr", "sp", "th", "dr", "pr", "dr", "gr", "br", "ryth", "rh", "sl", "f", "fr", "p", "pr",
|
||||
|
@ -1,14 +1,24 @@
|
||||
mod location;
|
||||
|
||||
use self::location::Location;
|
||||
// Reexports
|
||||
pub use self::location::Location;
|
||||
|
||||
use crate::{all::ForestKind, util::StructureGen2d, CONFIG};
|
||||
use common::{terrain::TerrainChunkSize, vol::VolSize};
|
||||
use common::{
|
||||
terrain::{BiomeKind, TerrainChunkSize},
|
||||
vol::VolSize,
|
||||
};
|
||||
use noise::{BasicMulti, HybridMulti, MultiFractal, NoiseFn, RidgedMulti, Seedable, SuperSimplex};
|
||||
use std::{
|
||||
ops::{Add, Div, Mul, Neg, Sub},
|
||||
sync::Arc,
|
||||
};
|
||||
use vek::*;
|
||||
use rand::{
|
||||
Rng,
|
||||
SeedableRng,
|
||||
prng::XorShiftRng,
|
||||
};
|
||||
|
||||
pub const WORLD_SIZE: Vec2<usize> = Vec2 { x: 1024, y: 1024 };
|
||||
|
||||
@ -35,6 +45,7 @@ pub struct WorldSim {
|
||||
pub seed: u32,
|
||||
pub(crate) chunks: Vec<SimChunk>,
|
||||
pub(crate) gen_ctx: GenCtx,
|
||||
pub rng: XorShiftRng,
|
||||
}
|
||||
|
||||
impl WorldSim {
|
||||
@ -64,8 +75,8 @@ impl WorldSim {
|
||||
};
|
||||
|
||||
let mut chunks = Vec::new();
|
||||
for x in 0..WORLD_SIZE.x as u32 {
|
||||
for y in 0..WORLD_SIZE.y as u32 {
|
||||
for x in 0..WORLD_SIZE.x as i32 {
|
||||
for y in 0..WORLD_SIZE.y as i32 {
|
||||
chunks.push(SimChunk::generate(Vec2::new(x, y), &mut gen_ctx));
|
||||
}
|
||||
}
|
||||
@ -74,20 +85,70 @@ impl WorldSim {
|
||||
seed,
|
||||
chunks,
|
||||
gen_ctx,
|
||||
rng: XorShiftRng::from_seed([
|
||||
(seed >> 0) as u8, 0, 0, 0,
|
||||
(seed >> 8) as u8, 0, 0, 0,
|
||||
(seed >> 16) as u8, 0, 0, 0,
|
||||
(seed >> 24) as u8, 0, 0, 0,
|
||||
]),
|
||||
};
|
||||
|
||||
this.simulate(100);
|
||||
this.seed_elements();
|
||||
this.simulate(200);
|
||||
|
||||
this
|
||||
}
|
||||
|
||||
pub fn simulate(&mut self, cycles: usize) {
|
||||
// TODO
|
||||
/// Prepare the world for simulation
|
||||
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,
|
||||
);
|
||||
|
||||
if let Some(chunk) = self.get_mut(loc_center) {
|
||||
chunk.location = Some(Location::generate(loc_center, &mut rng).into());
|
||||
}
|
||||
}
|
||||
|
||||
self.rng = rng;
|
||||
}
|
||||
|
||||
pub fn get(&self, chunk_pos: Vec2<u32>) -> Option<&SimChunk> {
|
||||
pub fn simulate(&mut self, cycles: usize) {
|
||||
let mut rng = self.rng.clone();
|
||||
|
||||
for _ in 0..cycles {
|
||||
for i in 0..WORLD_SIZE.x as i32 {
|
||||
for j in 0..WORLD_SIZE.y as i32 {
|
||||
let pos = Vec2::new(i, j);
|
||||
|
||||
let location = self.get(pos).unwrap().location.clone();
|
||||
|
||||
let rpos = Vec2::new(
|
||||
rng.gen::<i32>(),
|
||||
rng.gen::<i32>(),
|
||||
).map(|e| e.abs() % 3 - 1);
|
||||
|
||||
if let Some(other) = &mut self.get_mut(pos + rpos) {
|
||||
if other.location.is_none()
|
||||
&& rng.gen::<f32>() > other.chaos * 1.5
|
||||
&& other.alt > CONFIG.sea_level {
|
||||
other.location = location;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.rng = rng;
|
||||
}
|
||||
|
||||
pub fn get(&self, chunk_pos: Vec2<i32>) -> Option<&SimChunk> {
|
||||
if chunk_pos
|
||||
.map2(WORLD_SIZE, |e, sz| e < sz as u32)
|
||||
.map2(WORLD_SIZE, |e, sz| e >= 0 && e < sz as i32)
|
||||
.reduce_and()
|
||||
{
|
||||
Some(&self.chunks[chunk_pos.y as usize * WORLD_SIZE.x + chunk_pos.x as usize])
|
||||
@ -96,7 +157,18 @@ impl WorldSim {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_base_z(&self, chunk_pos: Vec2<u32>) -> Option<f32> {
|
||||
pub fn get_mut(&mut self, chunk_pos: Vec2<i32>) -> Option<&mut SimChunk> {
|
||||
if chunk_pos
|
||||
.map2(WORLD_SIZE, |e, sz| e >= 0 && e < sz as i32)
|
||||
.reduce_and()
|
||||
{
|
||||
Some(&mut self.chunks[chunk_pos.y as usize * WORLD_SIZE.x + chunk_pos.x as usize])
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_base_z(&self, chunk_pos: Vec2<i32>) -> Option<f32> {
|
||||
self.get(chunk_pos).and_then(|_| {
|
||||
(0..2)
|
||||
.map(|i| (0..2).map(move |j| (i, j)))
|
||||
@ -135,10 +207,10 @@ impl WorldSim {
|
||||
|
||||
for (x_idx, j) in (-1..3).enumerate() {
|
||||
let y0 =
|
||||
f(self.get(pos.map2(Vec2::new(j, -1), |e, q| (e.max(0.0) as i32 + q) as u32))?);
|
||||
let y1 = f(self.get(pos.map2(Vec2::new(j, 0), |e, q| (e.max(0.0) as i32 + q) as u32))?);
|
||||
let y2 = f(self.get(pos.map2(Vec2::new(j, 1), |e, q| (e.max(0.0) as i32 + q) as u32))?);
|
||||
let y3 = f(self.get(pos.map2(Vec2::new(j, 2), |e, q| (e.max(0.0) as i32 + q) as u32))?);
|
||||
f(self.get(pos.map2(Vec2::new(j, -1), |e, q| e.max(0.0) as i32 + q))?);
|
||||
let y1 = f(self.get(pos.map2(Vec2::new(j, 0), |e, q| e.max(0.0) as i32 + q))?);
|
||||
let y2 = f(self.get(pos.map2(Vec2::new(j, 1), |e, q| e.max(0.0) as i32 + q))?);
|
||||
let y3 = f(self.get(pos.map2(Vec2::new(j, 2), |e, q| e.max(0.0) as i32 + q))?);
|
||||
|
||||
x[x_idx] = cubic(y0, y1, y2, y3, pos.y.fract() as f32);
|
||||
}
|
||||
@ -162,8 +234,8 @@ pub struct SimChunk {
|
||||
}
|
||||
|
||||
impl SimChunk {
|
||||
fn generate(pos: Vec2<u32>, gen_ctx: &mut GenCtx) -> Self {
|
||||
let wposf = (pos * Vec2::from(TerrainChunkSize::SIZE)).map(|e| e as f64);
|
||||
fn generate(pos: Vec2<i32>, gen_ctx: &mut GenCtx) -> Self {
|
||||
let wposf = (pos * TerrainChunkSize::SIZE.map(|e| e as i32)).map(|e| e as f64);
|
||||
|
||||
let hill = (0.0
|
||||
+ gen_ctx
|
||||
@ -180,6 +252,7 @@ impl SimChunk {
|
||||
let chaos = (gen_ctx.chaos_nz.get((wposf.div(4_000.0)).into_array()) as f32)
|
||||
.add(1.0)
|
||||
.mul(0.5)
|
||||
.mul((gen_ctx.chaos_nz.get((wposf.div(8_000.0)).into_array()) as f32).powf(2.0).add(0.5).min(1.0))
|
||||
.powf(1.4)
|
||||
.add(0.1 * hill);
|
||||
|
||||
@ -263,4 +336,26 @@ impl SimChunk {
|
||||
pub fn get_max_z(&self) -> f32 {
|
||||
(self.alt + Z_TOLERANCE.1).max(CONFIG.sea_level + 1.0)
|
||||
}
|
||||
|
||||
pub fn get_name(&self) -> Option<String> {
|
||||
self.location
|
||||
.as_ref()
|
||||
.map(|l| l.name().to_string())
|
||||
}
|
||||
|
||||
pub fn get_biome(&self) -> BiomeKind {
|
||||
if self.alt < CONFIG.sea_level {
|
||||
BiomeKind::Ocean
|
||||
} else if self.chaos > 0.6 {
|
||||
BiomeKind::Mountain
|
||||
} else if self.temp > CONFIG.desert_temp {
|
||||
BiomeKind::Desert
|
||||
} else if self.temp < CONFIG.snow_temp {
|
||||
BiomeKind::Snowlands
|
||||
} else if self.tree_density > 0.65 {
|
||||
BiomeKind::Forest
|
||||
} else {
|
||||
BiomeKind::Grassland
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user