2024-08-22 17:21:34 +01:00
|
|
|
use std::time::Instant;
|
2024-08-24 21:44:13 +01:00
|
|
|
use noise::{Fbm, MultiFractal, NoiseFn, Perlin};
|
2024-08-22 17:21:34 +01:00
|
|
|
use rand::prelude::*;
|
2024-08-23 17:04:26 +01:00
|
|
|
use voronoice::{BoundingBox, Point, Voronoi, VoronoiBuilder, VoronoiCell};
|
2024-08-22 17:21:34 +01:00
|
|
|
use winit::event::{DeviceEvent, ElementState, Event, MouseButton, MouseScrollDelta, WindowEvent};
|
|
|
|
|
|
|
|
use crate::graphics::{Uniforms, Vertex};
|
|
|
|
|
|
|
|
pub const SQRT_3: f32 = 1.732050807568877293527446341505872367;
|
|
|
|
|
|
|
|
#[repr(u8)]
|
|
|
|
#[derive(Debug, Clone, Copy)]
|
|
|
|
enum CellKind {
|
|
|
|
Void,
|
|
|
|
Sea,
|
2024-08-24 21:44:13 +01:00
|
|
|
Plain,
|
|
|
|
Beach,
|
|
|
|
Forest
|
2024-08-22 17:21:34 +01:00
|
|
|
}
|
|
|
|
impl CellKind {
|
2024-08-23 09:00:33 +01:00
|
|
|
const VARIANTS: u8 = 3;
|
2024-08-22 17:21:34 +01:00
|
|
|
fn color(&self) -> [f32; 4] {
|
2024-08-23 17:04:26 +01:00
|
|
|
// let mut rng = thread_rng();
|
|
|
|
// [rng.gen(), rng.gen(), rng.gen(), 1.]
|
2024-08-22 17:21:34 +01:00
|
|
|
match self {
|
|
|
|
Self::Void => [0.; 4],
|
|
|
|
Self::Sea => [0., 0., 1., 1.],
|
2024-08-24 21:44:13 +01:00
|
|
|
Self::Plain => [0., 1., 0., 1.],
|
|
|
|
Self::Beach => [1., 1., 0., 1.],
|
|
|
|
Self::Forest => [0., 0.5, 0., 1.]
|
2024-08-22 17:21:34 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
impl From<u8> for CellKind {
|
|
|
|
fn from(value: u8) -> Self {
|
|
|
|
match value {
|
|
|
|
0 => Self::Void,
|
|
|
|
1 => Self::Sea,
|
2024-08-24 21:44:13 +01:00
|
|
|
2 => Self::Plain,
|
|
|
|
3 => Self::Beach,
|
|
|
|
4 => Self::Forest,
|
2024-08-22 17:21:34 +01:00
|
|
|
_ => panic!("Invalid cell kind")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-08-23 17:04:26 +01:00
|
|
|
struct CellData {
|
|
|
|
kind: CellKind,
|
|
|
|
cell: usize,
|
|
|
|
z: f32
|
2024-08-22 17:21:34 +01:00
|
|
|
}
|
2024-08-23 17:04:26 +01:00
|
|
|
impl CellData {
|
|
|
|
fn new(kind: CellKind, cell: usize, z: f32) -> Self {
|
2024-08-22 17:21:34 +01:00
|
|
|
Self {
|
2024-08-23 17:04:26 +01:00
|
|
|
kind,
|
|
|
|
cell,
|
|
|
|
z
|
2024-08-22 17:21:34 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct Map {
|
2024-08-23 17:04:26 +01:00
|
|
|
voronoi: Voronoi,
|
|
|
|
cells_data: Vec<CellData>,
|
|
|
|
seed: u32
|
2024-08-22 17:21:34 +01:00
|
|
|
}
|
|
|
|
impl Map {
|
2024-08-23 17:04:26 +01:00
|
|
|
const HEIGHT: f32 = 2.;
|
|
|
|
const WIDTH: f32 = 2.;
|
2024-08-24 21:44:13 +01:00
|
|
|
const SIZE: usize = 10_000;
|
2024-08-23 17:04:26 +01:00
|
|
|
fn new(seed: u32) -> Self {
|
|
|
|
let mut rng = rand::rngs::SmallRng::seed_from_u64(seed as u64);
|
|
|
|
let mut sites = Vec::with_capacity(Self::SIZE);
|
|
|
|
for _ in 0..Self::SIZE {
|
|
|
|
sites.push(Point { x:rng.gen_range(-Self::WIDTH/2.0..Self::WIDTH/2.0) as f64, y:rng.gen_range(-Self::HEIGHT/2.0..Self::HEIGHT/2.0) as f64 })
|
|
|
|
}
|
|
|
|
let voronoi = VoronoiBuilder::default()
|
|
|
|
.set_sites(sites)
|
|
|
|
.set_bounding_box(BoundingBox::new_centered(Self::WIDTH as f64, Self::HEIGHT as f64))
|
2024-08-24 21:44:13 +01:00
|
|
|
.set_lloyd_relaxation_iterations(3)
|
2024-08-23 17:04:26 +01:00
|
|
|
.build()
|
|
|
|
.unwrap();
|
|
|
|
let mut cells_data = Vec::with_capacity(Self::SIZE);
|
|
|
|
let z_noise = Fbm::<Perlin>::new(seed);
|
2024-08-24 21:44:13 +01:00
|
|
|
let moisture_noise = Fbm::<Perlin>::new(seed+1)
|
|
|
|
.set_frequency(2.);
|
2024-08-23 17:04:26 +01:00
|
|
|
for i in 0..Self::SIZE {
|
|
|
|
let c = voronoi.cell(i);
|
|
|
|
let site = c.site_position();
|
|
|
|
let z = (
|
|
|
|
0.3 // Arbitrary value
|
|
|
|
+ ((z_noise.get([site.x, site.y])+1.)/2.) // Noise + [0; 1]
|
|
|
|
- ((site.x.powi(2)+site.y.powi(2)).sqrt()*0.5) // Distance - [0; sqrt(2)] * 0.5
|
|
|
|
).clamp(0., 1.);
|
|
|
|
let k = if z <= 0.5 {
|
|
|
|
CellKind::Sea
|
2024-08-24 21:44:13 +01:00
|
|
|
} else if z <= 0.52 {
|
|
|
|
CellKind::Beach
|
2024-08-23 17:04:26 +01:00
|
|
|
} else {
|
2024-08-24 21:44:13 +01:00
|
|
|
let m = (
|
|
|
|
(moisture_noise.get([site.x, site.y])+1.)/2. // Noise + [0; 1]
|
|
|
|
).clamp(0., 1.);
|
|
|
|
if m > 0.5 {
|
|
|
|
CellKind::Forest
|
|
|
|
} else {
|
|
|
|
CellKind::Plain
|
|
|
|
}
|
2024-08-23 17:04:26 +01:00
|
|
|
};
|
|
|
|
cells_data.push(CellData::new(k, i, z as f32));
|
|
|
|
}
|
2024-08-23 09:00:33 +01:00
|
|
|
Self {
|
2024-08-23 17:04:26 +01:00
|
|
|
voronoi,
|
|
|
|
cells_data,
|
|
|
|
seed
|
2024-08-23 09:00:33 +01:00
|
|
|
}
|
2024-08-22 17:21:34 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct State {
|
|
|
|
pub vertices: Vec<Vertex>,
|
|
|
|
pub indices: Vec<u32>,
|
|
|
|
pub uniforms: Uniforms,
|
|
|
|
start: Instant,
|
|
|
|
map: Map
|
|
|
|
}
|
|
|
|
impl State {
|
|
|
|
pub fn new() -> Self {
|
|
|
|
let mut s = Self {
|
|
|
|
vertices: vec![],
|
|
|
|
indices: vec![],
|
|
|
|
uniforms: Uniforms::default(),
|
|
|
|
start: Instant::now(),
|
2024-08-23 17:04:26 +01:00
|
|
|
map: Map::new(0)
|
2024-08-22 17:21:34 +01:00
|
|
|
};
|
|
|
|
s.update();
|
|
|
|
s
|
|
|
|
}
|
|
|
|
pub fn input(&mut self, event: Event<()>) {
|
|
|
|
match event {
|
|
|
|
Event::WindowEvent { event: WindowEvent::MouseInput { state, button, ..}, ..} => {
|
|
|
|
if let state = ElementState::Pressed {
|
2024-08-23 17:04:26 +01:00
|
|
|
match button {
|
|
|
|
MouseButton::Left => self.map = Map::new(self.map.seed + 1),
|
|
|
|
MouseButton::Right => self.map = Map::new(self.map.seed - 1),
|
|
|
|
_ => {}
|
2024-08-22 17:21:34 +01:00
|
|
|
};
|
|
|
|
}
|
|
|
|
},
|
|
|
|
Event::DeviceEvent { event: DeviceEvent::MouseWheel { delta }, ..} => {
|
2024-08-23 17:04:26 +01:00
|
|
|
self.uniforms.camera[2] -= match delta {
|
2024-08-22 17:21:34 +01:00
|
|
|
MouseScrollDelta::PixelDelta(pos) => pos.y as f32,
|
|
|
|
MouseScrollDelta::LineDelta(_, y) => y
|
|
|
|
};
|
|
|
|
},
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pub fn update(&mut self) {
|
2024-08-23 17:04:26 +01:00
|
|
|
self.vertices = Vec::new();
|
|
|
|
self.indices = Vec::new();
|
2024-08-22 17:21:34 +01:00
|
|
|
|
2024-08-23 17:04:26 +01:00
|
|
|
for (c, data) in self.map.voronoi.iter_cells().zip(self.map.cells_data.iter()) {
|
|
|
|
let color = data.kind.color();
|
|
|
|
let vs = c.iter_vertices().collect::<Vec<_>>();
|
|
|
|
let i = self.vertices.len() as u32;
|
|
|
|
for v in vs.iter() {
|
|
|
|
self.vertices.push(Vertex { pos: [v.x as f32, v.y as f32, data.z], color });
|
|
|
|
}
|
|
|
|
for v in 1..(vs.len()-1) as u32 {
|
|
|
|
self.indices.push(i);
|
|
|
|
self.indices.push(i+v);
|
|
|
|
self.indices.push(i+v+1);
|
|
|
|
}
|
2024-08-22 17:21:34 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|