use std::time::Instant; use noise::{Fbm, MultiFractal, NoiseFn, Perlin}; use rand::prelude::*; use voronoice::{BoundingBox, Point, Voronoi, VoronoiBuilder, VoronoiCell}; 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, Plain, Beach, Forest } impl CellKind { const VARIANTS: u8 = 3; fn color(&self) -> [f32; 4] { // let mut rng = thread_rng(); // [rng.gen(), rng.gen(), rng.gen(), 1.] match self { Self::Void => [0.; 4], Self::Sea => [0., 0., 1., 1.], Self::Plain => [0., 1., 0., 1.], Self::Beach => [1., 1., 0., 1.], Self::Forest => [0., 0.5, 0., 1.] } } } impl From for CellKind { fn from(value: u8) -> Self { match value { 0 => Self::Void, 1 => Self::Sea, 2 => Self::Plain, 3 => Self::Beach, 4 => Self::Forest, _ => panic!("Invalid cell kind") } } } struct CellData { kind: CellKind, cell: usize, z: f32 } impl CellData { fn new(kind: CellKind, cell: usize, z: f32) -> Self { Self { kind, cell, z } } } struct Map { voronoi: Voronoi, cells_data: Vec, seed: u32 } impl Map { const HEIGHT: f32 = 2.; const WIDTH: f32 = 2.; const SIZE: usize = 10_000; 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)) .set_lloyd_relaxation_iterations(3) .build() .unwrap(); let mut cells_data = Vec::with_capacity(Self::SIZE); let z_noise = Fbm::::new(seed); let moisture_noise = Fbm::::new(seed+1) .set_frequency(2.); 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 } else if z <= 0.52 { CellKind::Beach } else { 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 } }; cells_data.push(CellData::new(k, i, z as f32)); } Self { voronoi, cells_data, seed } } } pub struct State { pub vertices: Vec, pub indices: Vec, 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(), map: Map::new(0) }; s.update(); s } pub fn input(&mut self, event: Event<()>) { match event { Event::WindowEvent { event: WindowEvent::MouseInput { state, button, ..}, ..} => { if let state = ElementState::Pressed { match button { MouseButton::Left => self.map = Map::new(self.map.seed + 1), MouseButton::Right => self.map = Map::new(self.map.seed - 1), _ => {} }; } }, Event::DeviceEvent { event: DeviceEvent::MouseWheel { delta }, ..} => { self.uniforms.camera[2] -= match delta { MouseScrollDelta::PixelDelta(pos) => pos.y as f32, MouseScrollDelta::LineDelta(_, y) => y }; }, _ => {} } } pub fn update(&mut self) { self.vertices = Vec::new(); self.indices = Vec::new(); 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::>(); 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); } } } }