This commit is contained in:
Arkitu 2024-08-28 14:09:57 +02:00
parent 5cfaf975d1
commit 2fd0fb9fc3
4 changed files with 517 additions and 34 deletions

281
assets/horse.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 468 KiB

View File

@ -7,14 +7,14 @@ use crate::state::State;
#[repr(C)]
#[derive(Clone, Copy, Zeroable, Pod, Debug)]
pub struct Vertex {
pub pos: [f32; 3],
pub pos: [f32; 2],
pub color: [f32; 4]
}
impl Vertex {
const DESC: VertexBufferLayout<'static> = VertexBufferLayout {
array_stride: std::mem::size_of::<Vertex>() as wgpu::BufferAddress,
step_mode: wgpu::VertexStepMode::Vertex,
attributes: &wgpu::vertex_attr_array![0 => Float32x3, 1 => Float32x4],
attributes: &wgpu::vertex_attr_array![0 => Float32x2, 1 => Float32x4],
};
}
@ -33,13 +33,6 @@ impl Default for Uniforms {
}
}
}
impl Uniforms {
const DESC: VertexBufferLayout<'static> = VertexBufferLayout {
array_stride: std::mem::size_of::<Vertex>() as wgpu::BufferAddress,
step_mode: wgpu::VertexStepMode::Vertex,
attributes: &wgpu::vertex_attr_array![0 => Float32x3, 1 => Float32],
};
}
pub struct Graphics<'a> {
state: State,
@ -91,13 +84,13 @@ impl<'a> Graphics<'a> {
let vertex_buf = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some("Vertex Buffer"),
contents: &[bytemuck::cast_slice::<Vertex, _>(&state.vertices), &[0; 1024]].concat(),
contents: &[bytemuck::cast_slice::<Vertex, _>(&state.vertices), &[0; 100000]].concat(),
usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST,
});
let index_buf = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some("Index Buffer"),
contents: &[bytemuck::cast_slice::<u32, _>(&state.indices), &[0; 1024]].concat(),
contents: &[bytemuck::cast_slice::<u32, _>(&state.indices), &[0; 100000]].concat(),
usage: wgpu::BufferUsages::INDEX | wgpu::BufferUsages::COPY_DST,
});

View File

@ -11,13 +11,13 @@ struct VertexOutput {
@vertex
fn vs_main(
@location(0) pos: vec3f,
@location(0) pos: vec2f,
@location(1) color: vec4f
) -> VertexOutput {
var out: VertexOutput;
out.color = color;
// out.color[3] -= uniforms.darkness;
out.pos = vec4f(pos.xy-uniforms.camera.xy, pos.z, uniforms.camera.z);
out.pos = vec4f((pos.xy-uniforms.camera.xy)/uniforms.camera.z, 0, 1);
return out;
}

View File

@ -1,23 +1,23 @@
use std::time::Instant;
use log::info;
use noise::{Fbm, MultiFractal, NoiseFn, Perlin};
use rand::prelude::*;
use voronoice::{BoundingBox, Point, Voronoi, VoronoiBuilder};
use winit::{event::{DeviceEvent, Event, MouseButton, MouseScrollDelta, WindowEvent}, window::Window};
use winit::{event::{DeviceEvent, ElementState, Event, KeyEvent, MouseButton, MouseScrollDelta, RawKeyEvent, WindowEvent}, keyboard::{KeyCode, PhysicalKey}, window::Window};
use crate::graphics::{Uniforms, Vertex};
const FRAMERATE: usize = 10; // Update per second
#[repr(u8)]
#[derive(Debug, Clone, Copy)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum CellKind {
Void,
Sea,
Plain,
Beach,
Forest,
Dirt,
Stone
Stone,
Grass
}
struct CellData {
@ -41,11 +41,11 @@ impl CellData {
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 - (self.moisture*0.4), 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.]
CellKind::Stone => [0.5, 0.5, 0.5, 1.],
CellKind::Grass => [(136./255.) - (self.moisture*0.4), (204./255.) - (self.moisture*0.4), (59./255.) - (self.moisture*0.4), 1.]
}
}
}
@ -105,11 +105,165 @@ impl Map {
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum EntityKind {
Horse
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum EntityState {
Walking(Instant), // Start of walk
Resting
}
#[derive(Debug)]
struct Entity {
pos: [f32; 3],
kind: EntityKind,
start: Instant,
state: EntityState
}
impl Entity {
fn new(pos: [f32; 3], kind: EntityKind) -> Self {
Self {
pos,
kind,
start: Instant::now(),
state: EntityState::Resting
}
}
fn render(&self, vertices: &mut Vec<Vertex>, indices: &mut Vec<u32>) {
match self.kind {
EntityKind::Horse => {
let color = [171./255., 122./255., 50./255., 1.];
let dark = [color[0]-0.3, color[1]-0.3, color[2]-0.3, 1.];
let (vs, is) = match self.state {
EntityState::Walking(now) => {
let now = now.elapsed().as_secs_f32()*5.;
(
[
// back left leg
Vertex { pos: [-0.5, 0.3], color: dark },
Vertex { pos: [-0.4 + (now.sin()*0.1), -0.7 + (now.cos().max(-0.5)*0.1)], color: dark },
Vertex { pos: [-0.25, 0.1], color: dark },
// back right leg
Vertex { pos: [-0.5, 0.3], color },
Vertex { pos: [-0.4 + ((now + 1.).sin()*0.1), -0.7 + ((now + 1.).cos().max(-0.5)*0.1)], color },
Vertex { pos: [-0.25, 0.1], color },
// front left leg
Vertex { pos: [0.3, 0.2], color: dark },
Vertex { pos: [0.4 + ((now-1.).sin()*0.1), -0.7 + ((now-1.).cos().max(-0.5)*0.1)], color: dark },
Vertex { pos: [0.5, 0.3], color: dark },
// front right leg
Vertex { pos: [0.3, 0.2], color },
Vertex { pos: [0.4 + ((now-2.).sin()*0.1), -0.7 + ((now-2.).cos().max(-0.5)*0.1)], color },
Vertex { pos: [0.5, 0.3], color },
// body
// 3
Vertex { pos: [-0.3, 0.], color },
Vertex { pos: [0.4, -0.1], color },
// 11
Vertex { pos: [0.3, 0.4], color },
],
[
0,1,2,
3,4,5,
6,7,8,
9,10,11,
3,12,13,
3,13,11,
3,11,14
]
)
},
EntityState::Resting => {
(
[
// back left leg
Vertex { pos: [-0.5, 0.3], color: dark },
Vertex { pos: [-0.4, -0.75], color: dark },
Vertex { pos: [-0.25, 0.1], color: dark },
// back right leg
Vertex { pos: [-0.5, 0.3], color },
Vertex { pos: [-0.4, -0.75], color },
Vertex { pos: [-0.25, 0.1], color },
// front left leg
Vertex { pos: [0.3, 0.2], color: dark },
Vertex { pos: [0.4, -0.75], color: dark },
Vertex { pos: [0.5, 0.3], color: dark },
// front right leg
Vertex { pos: [0.3, 0.2], color },
Vertex { pos: [0.4, -0.75], color },
Vertex { pos: [0.5, 0.3], color },
// body
// 3
Vertex { pos: [-0.3, 0.], color },
Vertex { pos: [0.4, -0.1], color },
// 11
Vertex { pos: [0.3, 0.4], color },
],
[
0,1,2,
3,4,5,
6,7,8,
9,10,11,
3,12,13,
3,13,11,
3,11,14
]
)
}
};
vertices.reserve(vs.len());
let base = vertices.len() as u32;
for mut v in vs {
v.pos[0] = v.pos[0]/50. + self.pos[0];
v.pos[1] = (v.pos[1] + 0.75)/50. + self.pos[1];
vertices.push(v)
}
indices.reserve(is.len());
for i in is {
indices.push(base + i);
}
// let vs = vec![
// Vertex { pos: [-0.5, 0.3, 0.], color },
// Vertex { pos: [-0.3, 0., 0.], color },
// Vertex { pos: [0.4, -0.1, 0.], color },
// Vertex { pos: [0.5, 0.3, 0.], color },
// Vertex { pos: [0.3, 0.4, 0.], color },
// ];
// let i = self.vertices.len() as u32;
// for v in vs.iter() {
// self.vertices.push(*v);
// }
// for v in 1..(vs.len()-1) as u32 {
// self.indices.push(i);
// self.indices.push(i+v);
// self.indices.push(i+v+1);
// }
}
}
}
}
pub struct State {
pub vertices: Vec<Vertex>,
pub indices: Vec<u32>,
pub uniforms: Uniforms,
map: Map,
entities: Vec<Entity>,
start: Instant,
frame: usize,
selected_tile: usize,
@ -124,6 +278,7 @@ impl State {
start: Instant::now(),
frame: 0,
map: Map::new(0),
entities: Vec::new(),
selected_tile: 0,
mouse_pressed: false
};
@ -153,17 +308,19 @@ impl State {
Event::WindowEvent { event: WindowEvent::CursorMoved { 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)
x: ((2.*position.x/(w_size.width as f64))-1.)*(self.uniforms.camera[2] as f64) + self.uniforms.camera[0] as f64,
y: (1.-(2.*position.y/(w_size.height as f64)))*(self.uniforms.camera[2] as f64) + self.uniforms.camera[1] as f64
};
let c = self.map.voronoi.cell(self.selected_tile);
if self.mouse_pressed {
for i in c.iter_path(pos) {
for i in c.iter_path(pos.clone()) {
self.selected_tile = i;
let cd = &mut self.map.cells_data[self.selected_tile];
if let CellKind::Dirt = cd.kind {
cd.kind = CellKind::Forest;
}
self.entities.push(Entity::new([pos.x as f32, pos.y as f32, 0.9], EntityKind::Horse));
}
} else {
self.selected_tile = c.iter_path(pos).last().unwrap();
@ -174,15 +331,36 @@ impl State {
MouseScrollDelta::PixelDelta(pos) => pos.y as f32,
MouseScrollDelta::LineDelta(_, y) => y
};
self.uniforms.camera[2] = self.uniforms.camera[2].clamp(0.1, 1.);
},
Event::WindowEvent { event: WindowEvent::KeyboardInput { event: KeyEvent { physical_key: PhysicalKey::Code(kc), state, .. }, .. }, .. } => {
if state.is_pressed() {
match kc {
KeyCode::KeyW => {
self.uniforms.camera[1] += 0.1;
},
KeyCode::KeyS => {
self.uniforms.camera[1] -= 0.1;
},
KeyCode::KeyA => {
self.uniforms.camera[0] -= 0.1;
},
KeyCode::KeyD => {
self.uniforms.camera[0] += 0.1;
},
_ => {}
}
}
},
_ => {}
}
}
pub fn render(&mut self) {
info!("render");
self.vertices = Vec::new();
self.indices = Vec::new();
for (c, cd) in self.map.voronoi.iter_cells().zip(self.map.cells_data.iter()) {
for (c, cd) in self.map.voronoi.iter_cells().zip(self.map.cells_data.iter()).filter(|(_,cd)| cd.kind != CellKind::Forest) {
let mut color = cd.color();
if c.site() == self.selected_tile {
color[0] = (color[0]+0.4).clamp(0., 1.);
@ -192,7 +370,30 @@ impl State {
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, cd.z], color });
self.vertices.push(Vertex { pos: [v.x as f32, v.y as f32], 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);
}
}
for e in self.entities.iter() {
e.render(&mut self.vertices, &mut self.indices);
}
for (c, cd) in self.map.voronoi.iter_cells().zip(self.map.cells_data.iter()).filter(|(_,cd)| cd.kind == CellKind::Forest) {
let mut color = cd.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.);
}
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], color });
}
for v in 1..(vs.len()-1) as u32 {
self.indices.push(i);
@ -207,22 +408,30 @@ impl State {
}
}
pub fn update(&mut self) {
info!("update");
let mut rng = thread_rng();
let mut new_forest = Vec::new();
let mut new_kind = Vec::new();
for cd in self.map.cells_data.iter() {
if let CellKind::Forest = cd.kind {
if rng.gen::<f32>() < (0.03*cd.moisture) {
if cd.kind == CellKind::Forest || cd.kind == CellKind::Grass {
let r = rng.gen::<f32>();
if r < (0.035*cd.moisture) {
let c = self.map.voronoi.cell(cd.cell);
let n = c.iter_neighbors().choose(&mut rng).unwrap();
new_forest.push(n);
let k = if r < (0.005*cd.moisture) && (self.map.cells_data[n].kind == CellKind::Dirt || self.map.cells_data[n].kind == CellKind::Grass) && cd.kind == CellKind::Forest {
Some(CellKind::Forest)
} else if self.map.cells_data[n].kind == CellKind::Dirt {
Some(CellKind::Grass)
} else {
None
};
if let Some(k) = k {
new_kind.push((n, k));
}
}
}
}
for i in new_forest {
let cd = &mut self.map.cells_data[i];
if let CellKind::Dirt = cd.kind {
cd.kind = CellKind::Forest;
}
for (n, k) in new_kind {
self.map.cells_data[n].kind = k;
}
self.frame += 1;