forestiles/src/state.rs

215 lines
7.1 KiB
Rust
Raw Normal View History

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-26 09:57:49 +01:00
use winit::{event::{DeviceEvent, ElementState, Event, MouseButton, MouseScrollDelta, WindowEvent}, window::Window};
2024-08-22 17:21:34 +01:00
use crate::graphics::{Uniforms, Vertex};
2024-08-26 09:57:49 +01:00
const SQRT_3: f32 = 1.732050807568877293527446341505872367;
const FRAMERATE: usize = 10; // Update per second
2024-08-22 17:21:34 +01:00
#[repr(u8)]
#[derive(Debug, Clone, Copy)]
enum CellKind {
Void,
Sea,
2024-08-24 21:44:13 +01:00
Plain,
Beach,
2024-08-26 09:57:49 +01:00
Forest,
Dirt,
Stone
2024-08-22 17:21:34 +01:00
}
2024-08-23 17:04:26 +01:00
struct CellData {
kind: CellKind,
cell: usize,
2024-08-26 09:57:49 +01:00
z: f32,
moisture: f32
2024-08-22 17:21:34 +01:00
}
2024-08-23 17:04:26 +01:00
impl CellData {
2024-08-26 09:57:49 +01:00
fn new(kind: CellKind, cell: usize, z: f32, moisture: f32) -> Self {
2024-08-22 17:21:34 +01:00
Self {
2024-08-23 17:04:26 +01:00
kind,
cell,
2024-08-26 09:57:49 +01:00
z,
moisture
}
}
fn color(&self) -> [f32; 4] {
// let mut rng = thread_rng();
// [rng.gen(), rng.gen(), rng.gen(), 1.]
match self.kind {
CellKind::Void => [0.; 4],
CellKind::Sea => [0., 0., 1., 1.],
CellKind::Plain => [0., 1., 0., 1.],
CellKind::Beach => [0.82, 0.84, 0.51, 1.],
CellKind::Forest => [0., 0.5, 0., 1.],
CellKind::Dirt => [0.53 - (self.moisture*0.4), 0.38-(self.moisture*0.4), 0.29-(self.moisture*0.4), 1.],
CellKind::Stone => [0.5, 0.5, 0.5, 1.]
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.);
2024-08-26 09:57:49 +01:00
let m = (
(moisture_noise.get([site.x, site.y])+1.)/2. // Noise + [0; 1]
).clamp(0., 1.) as f32;
2024-08-23 17:04:26 +01:00
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-26 09:57:49 +01:00
} else if z < 0.8 {
CellKind::Dirt
2024-08-23 17:04:26 +01:00
} else {
2024-08-26 09:57:49 +01:00
CellKind::Stone
2024-08-23 17:04:26 +01:00
};
2024-08-26 09:57:49 +01:00
cells_data.push(CellData::new(k, i, z as f32, m));
2024-08-23 17:04:26 +01:00
}
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,
2024-08-26 09:57:49 +01:00
map: Map,
2024-08-22 17:21:34 +01:00
start: Instant,
2024-08-26 09:57:49 +01:00
frame: usize,
selected_tile: usize,
mouse_pressed: bool
2024-08-22 17:21:34 +01:00
}
impl State {
pub fn new() -> Self {
let mut s = Self {
vertices: vec![],
indices: vec![],
uniforms: Uniforms::default(),
start: Instant::now(),
2024-08-26 09:57:49 +01:00
frame: 0,
map: Map::new(0),
selected_tile: 0,
mouse_pressed: false
2024-08-22 17:21:34 +01:00
};
2024-08-26 09:57:49 +01:00
s.render();
2024-08-22 17:21:34 +01:00
s
}
2024-08-26 09:57:49 +01:00
pub fn input(&mut self, event: Event<()>, window: &Window) {
2024-08-22 17:21:34 +01:00
match event {
Event::WindowEvent { event: WindowEvent::MouseInput { state, button, ..}, ..} => {
2024-08-26 09:57:49 +01:00
if state.is_pressed() {
2024-08-23 17:04:26 +01:00
match button {
2024-08-26 09:57:49 +01:00
MouseButton::Left => {
self.mouse_pressed = true;
},
MouseButton::Right => self.map = Map::new(self.map.seed + 1),
2024-08-23 17:04:26 +01:00
_ => {}
2024-08-22 17:21:34 +01:00
};
2024-08-26 09:57:49 +01:00
} else {
match button {
MouseButton::Left => {
self.mouse_pressed = false;
},
_ => {}
}
}
},
Event::WindowEvent { event: WindowEvent::CursorMoved { position, .. }, ..} => {
dbg!(&position);
let w_size = window.inner_size();
let pos = Point {
x: ((2.*position.x/(w_size.width as f64))-1.)*(self.uniforms.camera[2] as f64),
y: (1.-(2.*position.y/(w_size.height as f64)))*(self.uniforms.camera[2] as f64)
};
let c = self.map.voronoi.cell(self.selected_tile);
if self.mouse_pressed {
for i in c.iter_path(pos) {
self.selected_tile = i;
let c = &mut self.map.cells_data[self.selected_tile];
if let CellKind::Dirt = c.kind {
c.kind = CellKind::Forest;
}
}
} else {
self.selected_tile = c.iter_path(pos).last().unwrap();
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
};
},
_ => {}
}
}
2024-08-26 09:57:49 +01:00
pub fn render(&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()) {
2024-08-26 09:57:49 +01:00
let mut color = data.color();
if c.site() == self.selected_tile {
color[0] = (color[0]+0.4).clamp(0., 1.);
color[1] = (color[1]+0.4).clamp(0., 1.);
color[2] = (color[2]+0.4).clamp(0., 1.);
}
2024-08-23 17:04:26 +01:00
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
}
}
2024-08-26 09:57:49 +01:00
pub fn update_if_needed(&mut self) {
while self.start.elapsed().as_secs_f32() > (self.frame as f32) / (FRAMERATE as f32) {
self.update();
}
}
pub fn update(&mut self) {
self.frame += 1;
}
2024-08-22 17:21:34 +01:00
}