Add world generation, better fps stats, multiple chunks, grass/stone blocks

This commit is contained in:
Sijmen 2021-05-30 13:25:47 +02:00
parent 248a634ecb
commit 61ec4c4da5
Signed by: vijfhoek
GPG key ID: 82D05C89B28B0DAE
12 changed files with 415 additions and 127 deletions

89
Cargo.lock generated
View file

@ -24,7 +24,7 @@ version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43bb833f0bf979d8475d38fbf09ed3b8a55e1885fe93ad3f93239fc6a4f17b98"
dependencies = [
"getrandom",
"getrandom 0.2.3",
"once_cell",
"version_check",
]
@ -616,6 +616,17 @@ dependencies = [
"byteorder",
]
[[package]]
name = "getrandom"
version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce"
dependencies = [
"cfg-if 1.0.0",
"libc",
"wasi 0.9.0+wasi-snapshot-preview1",
]
[[package]]
name = "getrandom"
version = "0.2.3"
@ -624,7 +635,7 @@ checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753"
dependencies = [
"cfg-if 1.0.0",
"libc",
"wasi",
"wasi 0.10.2+wasi-snapshot-preview1",
]
[[package]]
@ -1150,6 +1161,17 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c44922cb3dbb1c70b5e5f443d63b64363a898564d739ba5198e3a9138442868d"
[[package]]
name = "noise"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "82051dd6745d5184c6efb7bc8be14892a7f6d4f3ad6dbf754d1c7d7d5fe24b43"
dependencies = [
"image",
"rand",
"rand_xorshift",
]
[[package]]
name = "ntapi"
version = "0.3.6"
@ -1328,6 +1350,12 @@ dependencies = [
"miniz_oxide 0.3.7",
]
[[package]]
name = "ppv-lite86"
version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
[[package]]
name = "proc-macro-crate"
version = "0.1.5"
@ -1373,6 +1401,56 @@ dependencies = [
"proc-macro2",
]
[[package]]
name = "rand"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
dependencies = [
"getrandom 0.1.16",
"libc",
"rand_chacha",
"rand_core",
"rand_hc",
]
[[package]]
name = "rand_chacha"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
dependencies = [
"ppv-lite86",
"rand_core",
]
[[package]]
name = "rand_core"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
dependencies = [
"getrandom 0.1.16",
]
[[package]]
name = "rand_hc"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
dependencies = [
"rand_core",
]
[[package]]
name = "rand_xorshift"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77d416b86801d23dde1aa643023b775c3a462efc0ed96443add11546cdf1dca8"
dependencies = [
"rand_core",
]
[[package]]
name = "range-alloc"
version = "0.1.2"
@ -1451,6 +1529,7 @@ dependencies = [
"futures",
"image",
"log",
"noise",
"wgpu",
"winit",
]
@ -1611,6 +1690,12 @@ version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
[[package]]
name = "wasi"
version = "0.9.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
[[package]]
name = "wasi"
version = "0.10.2+wasi-snapshot-preview1"

View file

@ -15,5 +15,9 @@ env_logger = "0.8.3"
futures = "0.3.15"
image = "0.23.14"
log = "0.4.14"
noise = "0.7.0"
wgpu = "0.8.1"
winit = { version = "0.25.0", default_features = false, features = ["x11"] }
[profile.release]
debug = true

BIN
assets/block_temp/grass.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
assets/block_temp/grass.xcf (Stored with Git LFS) Normal file

Binary file not shown.

View file

@ -1,11 +1,17 @@
use crate::instance::Instance;
use ahash::AHashMap;
use cgmath::{InnerSpace, Vector3};
use noise::{
utils::{NoiseMapBuilder, PlaneMapBuilder},
Fbm,
};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum BlockType {
Dirt,
Cobblestone,
Dirt,
Grass,
Stone,
}
#[derive(Debug, Clone, Copy)]
@ -15,22 +21,87 @@ pub struct Block {
const CHUNK_SIZE: usize = 16;
type ChunkBlocks = [[[Option<Block>; CHUNK_SIZE]; CHUNK_SIZE]; CHUNK_SIZE];
pub struct Chunk {
pub blocks: [[[Option<Block>; CHUNK_SIZE]; CHUNK_SIZE]; CHUNK_SIZE],
pub blocks: ChunkBlocks,
pub highlighted: Option<Vector3<usize>>,
}
impl Chunk {
pub fn to_instances(&self) -> Vec<(BlockType, Vec<Instance>)> {
pub fn generate(chunk_x: i32, chunk_y: i32, chunk_z: i32) -> Self {
let fbm = Fbm::new();
let builder = PlaneMapBuilder::new(&fbm)
.set_size(16, 16)
.set_x_bounds(chunk_x as f64 * 0.2, chunk_x as f64 * 0.2 + 0.2)
.set_y_bounds(chunk_z as f64 * 0.2, chunk_z as f64 * 0.2 + 0.2)
.build();
let mut blocks: ChunkBlocks = Default::default();
for z in 0..CHUNK_SIZE {
for x in 0..CHUNK_SIZE {
let v = builder.get_value(x, z) * 10.0 + 64.0;
let v = v.round() as i32;
let stone_max = (v - 4 - chunk_y * 16).min(CHUNK_SIZE as i32);
for y in 0..stone_max {
blocks[y as usize][z][x] = Some(Block {
block_type: BlockType::Stone,
});
}
let dirt_max = (v - chunk_y * 16).min(CHUNK_SIZE as i32);
for y in stone_max.max(0)..dirt_max {
blocks[y as usize][z][x] = Some(Block {
block_type: BlockType::Dirt,
});
}
if dirt_max >= 0 && dirt_max < CHUNK_SIZE as i32 {
blocks[dirt_max as usize][z][x] = Some(Block {
block_type: BlockType::Grass,
});
}
}
}
Self {
blocks,
highlighted: None,
}
}
fn check_visible(&self, x: usize, y: usize, z: usize) -> bool {
(x > 0 && y > 0 && z > 0 && self.get_block(x - 1, y - 1, z - 1).is_some())
&& (y > 0 && z > 0 && self.get_block(x + 1, y - 1, z - 1).is_some())
&& (x > 0 && z > 0 && self.get_block(x - 1, y + 1, z - 1).is_some())
&& (z > 0 && self.get_block(x + 1, y + 1, z - 1).is_some())
&& (x > 0 && y > 0 && self.get_block(x - 1, y - 1, z + 1).is_some())
&& (y > 0 && self.get_block(x + 1, y - 1, z + 1).is_some())
&& (x > 0 && self.get_block(x - 1, y + 1, z + 1).is_some())
&& (x > 0 && y > 0 && z > 0 && self.get_block(x + 1, y + 1, z + 1).is_some())
}
pub fn to_instances(&self, offset: Vector3<i32>) -> Vec<(BlockType, Vec<Instance>)> {
let mut map: AHashMap<BlockType, Vec<Instance>> = AHashMap::new();
for (y, y_blocks) in self.blocks.iter().enumerate() {
for (z, z_blocks) in y_blocks.iter().enumerate() {
for (x, block) in z_blocks.iter().enumerate() {
if let Some(block) = block {
let position = Vector3::new(x as f32, y as f32, z as f32);
let instances = map.entry(block.block_type).or_default();
let position = Vector3::new(
(x as i32 + offset.x * 16) as f32,
(y as i32 + offset.y * 16) as f32,
(z as i32 + offset.z * 16) as f32,
);
// Don't add the block if it's not visible
if self.check_visible(x, y, z) {
continue;
}
let instances = map.entry(block.block_type).or_default();
instances.push(Instance {
position: position.into(),
highlighted: (self.highlighted == Some(Vector3::new(x, y, z))) as i32,
@ -120,11 +191,14 @@ impl Chunk {
return None;
}
if let Some(_) = self.get_block(
position.x as usize,
position.y as usize,
position.z as usize,
) {
if self
.get_block(
position.x as usize,
position.y as usize,
position.z as usize,
)
.is_some()
{
// Intersection occurred
return Some((position.map(|x| x as usize), face));
}

View file

@ -39,6 +39,45 @@ pub const VERTICES: &[Vertex] = &[
Vertex { position: [1.0, 1.0, 0.0], texture_coordinates: [1.0, 0.0], normal: [ 0.0, 1.0, 0.0] },
];
#[rustfmt::skip]
pub const VERTICES_GRASS: &[Vertex] = &[
// Left
Vertex { position: [0.0, 0.0, 0.0], texture_coordinates: [0.5, 0.5], normal: [-1.0, 0.0, 0.0] },
Vertex { position: [0.0, 0.0, 1.0], texture_coordinates: [0.0, 0.5], normal: [-1.0, 0.0, 0.0] },
Vertex { position: [0.0, 1.0, 1.0], texture_coordinates: [0.0, 0.0], normal: [-1.0, 0.0, 0.0] },
Vertex { position: [0.0, 1.0, 0.0], texture_coordinates: [0.5, 0.0], normal: [-1.0, 0.0, 0.0] },
// Right
Vertex { position: [1.0, 0.0, 0.0], texture_coordinates: [0.0, 0.5], normal: [ 1.0, 0.0, 0.0] },
Vertex { position: [1.0, 0.0, 1.0], texture_coordinates: [0.5, 0.5], normal: [ 1.0, 0.0, 0.0] },
Vertex { position: [1.0, 1.0, 1.0], texture_coordinates: [0.5, 0.0], normal: [ 1.0, 0.0, 0.0] },
Vertex { position: [1.0, 1.0, 0.0], texture_coordinates: [0.0, 0.0], normal: [ 1.0, 0.0, 0.0] },
// Back
Vertex { position: [0.0, 0.0, 0.0], texture_coordinates: [0.5, 0.5], normal: [ 0.0, 0.0, -1.0] },
Vertex { position: [0.0, 1.0, 0.0], texture_coordinates: [0.5, 0.0], normal: [ 0.0, 0.0, -1.0] },
Vertex { position: [1.0, 1.0, 0.0], texture_coordinates: [0.0, 0.0], normal: [ 0.0, 0.0, -1.0] },
Vertex { position: [1.0, 0.0, 0.0], texture_coordinates: [0.0, 0.5], normal: [ 0.0, 0.0, -1.0] },
// Front
Vertex { position: [0.0, 0.0, 1.0], texture_coordinates: [0.0, 0.5], normal: [ 0.0, 0.0, 1.0] },
Vertex { position: [0.0, 1.0, 1.0], texture_coordinates: [0.0, 0.0], normal: [ 0.0, 0.0, 1.0] },
Vertex { position: [1.0, 1.0, 1.0], texture_coordinates: [0.5, 0.0], normal: [ 0.0, 0.0, 1.0] },
Vertex { position: [1.0, 0.0, 1.0], texture_coordinates: [0.5, 0.5], normal: [ 0.0, 0.0, 1.0] },
// Bottom
Vertex { position: [0.0, 0.0, 0.0], texture_coordinates: [0.5, 0.5], normal: [ 0.0, -1.0, 0.0] },
Vertex { position: [0.0, 0.0, 1.0], texture_coordinates: [0.5, 1.0], normal: [ 0.0, -1.0, 0.0] },
Vertex { position: [1.0, 0.0, 1.0], texture_coordinates: [0.0, 1.0], normal: [ 0.0, -1.0, 0.0] },
Vertex { position: [1.0, 0.0, 0.0], texture_coordinates: [0.0, 0.5], normal: [ 0.0, -1.0, 0.0] },
// Top
Vertex { position: [0.0, 1.0, 0.0], texture_coordinates: [0.5, 0.0], normal: [ 0.0, 1.0, 0.0] },
Vertex { position: [0.0, 1.0, 1.0], texture_coordinates: [0.5, 0.5], normal: [ 0.0, 1.0, 0.0] },
Vertex { position: [1.0, 1.0, 1.0], texture_coordinates: [1.0, 0.5], normal: [ 0.0, 1.0, 0.0] },
Vertex { position: [1.0, 1.0, 0.0], texture_coordinates: [1.0, 0.0], normal: [ 0.0, 1.0, 0.0] },
];
#[rustfmt::skip]
pub const INDICES: &[u16] = &[
2, 0, 1,

View file

@ -1,3 +1,5 @@
use cgmath::Vector3;
#[repr(C)]
#[derive(Debug, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
pub struct Light {
@ -5,3 +7,13 @@ pub struct Light {
pub _padding: u32,
pub color: [f32; 3],
}
impl Light {
pub fn new(position: Vector3<f32>, color: Vector3<f32>) -> Self {
Self {
position: position.into(),
_padding: 0,
color: color.into(),
}
}
}

View file

@ -8,9 +8,10 @@ mod state;
mod texture;
mod uniforms;
mod vertex;
mod world;
mod world_state;
use std::time::Instant;
use std::time::{Duration, Instant};
use winit::{
dpi::{PhysicalSize, Size},
event::{ElementState, Event, KeyboardInput, MouseButton, VirtualKeyCode, WindowEvent},
@ -35,7 +36,11 @@ fn main() {
let mut state = futures::executor::block_on(State::new(&window));
let mut frames = 0;
let mut instant = Instant::now();
let mut frame_instant = Instant::now();
let mut elapsed = Duration::from_secs(0);
let mut frametime_min = Duration::from_secs(1000);
let mut frametime_max = Duration::from_secs(0);
let mut last_render_time = Instant::now();
@ -80,16 +85,29 @@ fn main() {
_ => {}
},
Event::RedrawRequested(_) => {
let frame_elapsed = frame_instant.elapsed();
frame_instant = Instant::now();
frametime_min = frametime_min.min(frame_elapsed);
frametime_max = frametime_max.max(frame_elapsed);
elapsed += frame_elapsed;
frames += 1;
if instant.elapsed().as_secs() >= 1 {
let frametime = instant.elapsed() / frames;
if elapsed.as_secs() >= 1 {
let frametime = elapsed / frames;
let fps = 1_000_000 / frametime.as_micros();
let fps_max = 1_000_000 / frametime_min.as_micros();
let fps_min = 1_000_000 / frametime_max.as_micros();
println!(
"{} frames | frametime {:?} | fps {}",
frames, frametime, fps
"{} frames | frametime avg={:?} min={:?} max={:?} | fps avg={} min={} max={}",
frames, frametime, frametime_min, frametime_max, fps, fps_min, fps_max,
);
instant = Instant::now();
elapsed = Duration::from_secs(0);
frames = 0;
frametime_min = Duration::from_secs(1000);
frametime_max = Duration::from_secs(0);
}
let now = Instant::now();

View file

@ -55,7 +55,7 @@ fn main(in: VertexOutput) -> [[location(0)]] vec4<f32> {
let object_color: vec4<f32> =
textureSample(texture, sampler_diffuse, in.texture_coordinates);
let ambient_strength = 0.2;
let ambient_strength = 0.1;
let ambient_color = light.color * ambient_strength;
let light_direction = normalize(light.position - in.world_position);

View file

@ -362,15 +362,15 @@ impl State {
}
fn update_aim(&mut self) {
let camera = &self.world_state.camera;
let chunk = &mut self.world_state.chunk;
let position = chunk
.raycast(camera.position.to_vec(), camera.direction())
.map(|(position, _)| position);
if position != chunk.highlighted {
chunk.highlighted = position;
self.world_state.update_chunk(&self.render_queue);
}
// let camera = &self.world_state.camera;
// let chunk = &mut self.world_state.chunk;
// let position = chunk
// .raycast(camera.position.to_vec(), camera.direction())
// .map(|(position, _)| position);
// if position != chunk.highlighted {
// chunk.highlighted = position;
// self.world_state.update_chunk(&self.render_queue);
// }
}
fn input_mouse(&mut self, dx: f64, dy: f64) {
@ -393,25 +393,25 @@ impl State {
} if self.mouse_grabbed => {
let camera = &self.world_state.camera;
if let Some((pos, axis)) = self
.world_state
.chunk
.raycast(camera.position.to_vec(), camera.direction())
{
if *button == 1 {
self.world_state.chunk.blocks[pos.y][pos.z][pos.x].take();
dbg!(&pos);
self.world_state.update_chunk(&self.render_queue);
} else if *button == 3 {
let new_pos = pos.map(|x| x as i32) - axis;
dbg!(&axis, &new_pos);
self.world_state.chunk.blocks[new_pos.y as usize][new_pos.z as usize]
[new_pos.x as usize] = Some(Block {
block_type: BlockType::Cobblestone,
});
self.world_state.update_chunk(&self.render_queue);
}
}
// if let Some((pos, axis)) = self
// .world_state
// .chunk
// .raycast(camera.position.to_vec(), camera.direction())
// {
// if *button == 1 {
// self.world_state.chunk.blocks[pos.y][pos.z][pos.x].take();
// dbg!(&pos);
// self.world_state.update_chunk(&self.render_queue);
// } else if *button == 3 {
// let new_pos = pos.map(|x| x as i32) - axis;
// dbg!(&axis, &new_pos);
// self.world_state.chunk.blocks[new_pos.y as usize][new_pos.z as usize]
// [new_pos.x as usize] = Some(Block {
// block_type: BlockType::Cobblestone,
// });
// self.world_state.update_chunk(&self.render_queue);
// }
// }
}
DeviceEvent::MouseMotion { delta: (dx, dy) } => self.input_mouse(*dx, *dy),
@ -425,13 +425,13 @@ impl State {
let (yaw_sin, yaw_cos) = self.world_state.camera.yaw.0.sin_cos();
let forward = cgmath::Vector3::new(yaw_cos, 0.0, yaw_sin).normalize();
self.world_state.camera.position += forward * self.forward_speed * 6.0 * dt_secs;
self.world_state.camera.position += forward * self.forward_speed * 15.0 * dt_secs;
let right = cgmath::Vector3::new(-yaw_sin, 0.0, yaw_cos).normalize();
self.world_state.camera.position += right * self.right_speed * 6.0 * dt_secs;
self.world_state.camera.position += right * self.right_speed * 15.0 * dt_secs;
let up = cgmath::Vector3::new(0.0, 1.0, 0.0).normalize();
self.world_state.camera.position += up * self.up_speed * 6.0 * dt_secs;
self.world_state.camera.position += up * self.up_speed * 15.0 * dt_secs;
self.update_aim();
@ -454,6 +454,7 @@ impl State {
label: Some("render_encoder"),
});
let mut triangle_count = 0;
{
let mut render_pass = render_encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: Some("render_pass"),
@ -462,9 +463,9 @@ impl State {
resolve_target: None,
ops: wgpu::Operations {
load: wgpu::LoadOp::Clear(wgpu::Color {
r: 0.05,
g: 0.05,
b: 0.05,
r: 0.502,
g: 0.663,
b: 0.965,
a: 1.0,
}),
store: true,
@ -485,24 +486,33 @@ impl State {
render_pass.set_bind_group(1, &self.world_state.uniform_bind_group, &[]);
render_pass.set_bind_group(2, &self.world_state.light_bind_group, &[]);
render_pass.set_vertex_buffer(0, self.world_state.vertex_buffer.slice(..));
render_pass.set_index_buffer(
self.world_state.index_buffer.slice(..),
wgpu::IndexFormat::Uint16,
);
for (block_type, instance_list) in &self.world_state.instance_lists {
let instance_buffer = &self.world_state.instance_buffers[block_type];
for (block_type, offset, instance_list) in &self.world_state.instance_lists {
// Set the texture
let texture_bind_group = &self.world_state.texture_bind_groups[block_type];
render_pass.set_bind_group(0, texture_bind_group, &[]);
// Set the vertex buffer
let vertex_buffer = match block_type {
BlockType::Grass => self.world_state.vertex_buffer_grass.slice(..),
_ => self.world_state.vertex_buffer.slice(..),
};
render_pass.set_vertex_buffer(0, vertex_buffer);
// Set the instance buffer
let instance_buffer = &self.world_state.instance_buffers[&(*block_type, *offset)];
render_pass.set_vertex_buffer(1, instance_buffer.slice(..));
render_pass.draw_indexed(
0..cube::INDICES.len() as u32,
0,
0..instance_list.len() as u32,
);
triangle_count += cube::INDICES.len() / 3 * instance_list.len();
}
}
@ -529,8 +539,11 @@ impl State {
render_pass.set_bind_group(0, &self.ui_texture_bind_group, &[]);
render_pass.draw_indexed(0..CROSSHAIR_INDICES.len() as u32, 0, 0..1);
triangle_count += CROSSHAIR_INDICES.len() / 3;
}
// dbg!(triangle_count);
self.render_queue
.submit(std::iter::once(render_encoder.finish()));

52
src/world.rs Normal file
View file

@ -0,0 +1,52 @@
use cgmath::Vector3;
use crate::{
chunk::{BlockType, Chunk},
instance::Instance,
};
pub struct World {
chunks: Vec<Vec<Vec<Chunk>>>,
}
impl World {
pub fn generate() -> Self {
let mut chunks = Vec::with_capacity(16);
for y in 0..16 {
let mut chunks_z = Vec::with_capacity(16);
for z in 0..16 {
let mut chunks_x = Vec::with_capacity(16);
for x in 0..16 {
let chunk = Chunk::generate(x, y, z);
chunks_x.push(chunk);
}
chunks_z.push(chunks_x);
}
chunks.push(chunks_z);
}
Self { chunks }
}
pub fn to_instances(&self) -> Vec<(BlockType, Vector3<i32>, Vec<Instance>)> {
let instant = std::time::Instant::now();
let mut instance_lists = Vec::new();
for (y, chunks_y) in self.chunks.iter().enumerate() {
for (z, chunks_z) in chunks_y.iter().enumerate() {
for (x, chunk) in chunks_z.iter().enumerate() {
let offset = Vector3::new(x as i32, y as i32, z as i32);
for (block_type, instances) in chunk.to_instances(offset) {
instance_lists.push((block_type, offset, instances));
}
}
}
}
let elapsed = instant.elapsed();
println!("generating world instances took {:?}", elapsed);
instance_lists
}
}

View file

@ -1,6 +1,7 @@
use std::{mem::size_of, time::Instant};
use ahash::AHashMap;
use cgmath::{Vector3, Zero};
use wgpu::{
util::{BufferInitDescriptor, DeviceExt},
BufferAddress, BufferDescriptor,
@ -16,6 +17,7 @@ use crate::{
texture::Texture,
uniforms::Uniforms,
vertex::Vertex,
world::World,
};
pub struct WorldState {
@ -26,13 +28,14 @@ pub struct WorldState {
pub texture_bind_groups: AHashMap<BlockType, wgpu::BindGroup>,
pub camera: Camera,
pub projection: Projection,
pub instance_lists: Vec<(BlockType, Vec<Instance>)>,
pub instance_lists: Vec<(BlockType, Vector3<i32>, Vec<Instance>)>,
pub vertex_buffer: wgpu::Buffer,
pub vertex_buffer_grass: wgpu::Buffer,
pub index_buffer: wgpu::Buffer,
pub instance_buffers: AHashMap<BlockType, wgpu::Buffer>,
pub instance_buffers: AHashMap<(BlockType, Vector3<i32>), wgpu::Buffer>,
pub depth_texture: Texture,
pub light_bind_group: wgpu::BindGroup,
pub chunk: Chunk,
pub world: World,
}
impl WorldState {
@ -40,22 +43,6 @@ impl WorldState {
render_device: &wgpu::Device,
render_queue: &wgpu::Queue,
) -> (wgpu::BindGroupLayout, AHashMap<BlockType, wgpu::BindGroup>) {
let dirt_texture = Texture::from_bytes(
render_device,
render_queue,
include_bytes!("../assets/block/dirt.png"),
"dirt",
)
.unwrap();
let cobblestone_texture = Texture::from_bytes(
render_device,
render_queue,
include_bytes!("../assets/block/cobblestone.png"),
"cobblestone",
)
.unwrap();
let sampler = render_device.create_sampler(&wgpu::SamplerDescriptor::default());
let bind_group_layout =
@ -85,15 +72,21 @@ impl WorldState {
});
let bind_groups: AHashMap<BlockType, wgpu::BindGroup> = [
(BlockType::Dirt, dirt_texture),
(BlockType::Cobblestone, cobblestone_texture),
(BlockType::Cobblestone, "assets/block/cobblestone.png"),
(BlockType::Dirt, "assets/block/dirt.png"),
(BlockType::Grass, "assets/block_temp/grass.png"),
(BlockType::Stone, "assets/block/stone.png"),
]
.iter()
.map(|(block_type, texture)| {
.map(|(block_type, texture_path)| {
let bytes = std::fs::read(texture_path).unwrap();
let texture =
Texture::from_bytes(render_device, render_queue, &bytes, "block texture").unwrap();
(
*block_type,
render_device.create_bind_group(&wgpu::BindGroupDescriptor {
label: Some("texture_bind_group"),
label: Some("block texture bind group"),
layout: &bind_group_layout,
entries: &[
wgpu::BindGroupEntry {
@ -125,7 +118,7 @@ impl WorldState {
swap_chain_descriptor.height,
cgmath::Deg(45.0),
0.1,
100.0,
500.0,
);
(camera, projection)
@ -185,11 +178,10 @@ impl WorldState {
fn create_light(
render_device: &wgpu::Device,
) -> (Light, wgpu::Buffer, wgpu::BindGroupLayout, wgpu::BindGroup) {
let light = Light {
position: [5.0, 5.0, 5.0],
_padding: 0,
color: [1.0, 1.0, 1.0],
};
let light = Light::new(
Vector3::new(256.0, 500.0, 200.0),
Vector3::new(1.0, 1.0, 1.0),
);
let light_buffer = render_device.create_buffer_init(&BufferInitDescriptor {
label: Some("light_buffer"),
@ -209,7 +201,7 @@ impl WorldState {
},
count: None,
}],
label: None,
label: Some("light_bind_group_layout"),
});
let light_bind_group = render_device.create_bind_group(&wgpu::BindGroupDescriptor {
@ -218,7 +210,7 @@ impl WorldState {
binding: 0,
resource: light_buffer.as_entire_binding(),
}],
label: None,
label: Some("light_bind_group"),
});
(
@ -249,6 +241,8 @@ impl WorldState {
push_constant_ranges: &[],
});
let wireframe = false;
render_device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some("Render Pipeline"),
layout: Some(&render_pipeline_layout),
@ -273,8 +267,16 @@ impl WorldState {
topology: wgpu::PrimitiveTopology::TriangleList,
strip_index_format: None,
front_face: wgpu::FrontFace::Ccw,
cull_mode: Some(wgpu::Face::Back),
polygon_mode: wgpu::PolygonMode::Fill,
cull_mode: if wireframe {
None
} else {
Some(wgpu::Face::Back)
},
polygon_mode: if wireframe {
wgpu::PolygonMode::Line
} else {
wgpu::PolygonMode::Fill
},
clamp_depth: false,
conservative: false,
},
@ -295,16 +297,16 @@ impl WorldState {
fn create_instances(
render_device: &wgpu::Device,
chunk: &Chunk,
world: &World,
) -> (
Vec<(BlockType, Vec<Instance>)>,
AHashMap<BlockType, wgpu::Buffer>,
Vec<(BlockType, Vector3<i32>, Vec<Instance>)>,
AHashMap<(BlockType, Vector3<i32>), wgpu::Buffer>,
) {
let instance_lists = chunk.to_instances();
let instance_lists = world.to_instances();
let instance_buffers = instance_lists
.iter()
.map(|(block_type, _)| {
.map(|(block_type, offset, _)| {
let buffer = render_device.create_buffer(&BufferDescriptor {
label: Some("instance_buffer"),
size: (size_of::<Instance>() * 16 * 16 * 16) as BufferAddress,
@ -312,7 +314,7 @@ impl WorldState {
mapped_at_creation: false,
});
(*block_type, buffer)
((*block_type, *offset), buffer)
})
.collect();
@ -322,10 +324,10 @@ impl WorldState {
pub fn update_chunk(&mut self, render_queue: &wgpu::Queue) {
let instant = Instant::now();
self.instance_lists = self.chunk.to_instances();
self.instance_lists = self.world.to_instances();
for (block_type, instance_list) in &self.instance_lists {
if let Some(instance_buffer) = self.instance_buffers.get_mut(&block_type) {
for (block_type, offset, instance_list) in &self.instance_lists {
if let Some(instance_buffer) = self.instance_buffers.get_mut(&(*block_type, *offset)) {
render_queue.write_buffer(instance_buffer, 0, bytemuck::cast_slice(&instance_list));
} else {
todo!();
@ -341,31 +343,8 @@ impl WorldState {
render_queue: &wgpu::Queue,
swap_chain_descriptor: &wgpu::SwapChainDescriptor,
) -> WorldState {
let chunk = Chunk {
blocks: [
[[Some(Block {
block_type: BlockType::Cobblestone,
}); 16]; 16],
[[Some(Block {
block_type: BlockType::Dirt,
}); 16]; 16],
[[None; 16]; 16],
[[None; 16]; 16],
[[None; 16]; 16],
[[None; 16]; 16],
[[None; 16]; 16],
[[None; 16]; 16],
[[None; 16]; 16],
[[None; 16]; 16],
[[None; 16]; 16],
[[None; 16]; 16],
[[None; 16]; 16],
[[None; 16]; 16],
[[None; 16]; 16],
[[None; 16]; 16],
],
highlighted: None,
};
// let chunk = Chunk::generate(0, 0, 0);
let world = World::generate();
let (world_texture_layout, texture_bind_groups) =
Self::create_textures(&render_device, &render_queue);
@ -392,6 +371,11 @@ impl WorldState {
contents: bytemuck::cast_slice(cube::VERTICES),
usage: wgpu::BufferUsage::VERTEX,
});
let grass_vertex_buffer = render_device.create_buffer_init(&BufferInitDescriptor {
label: Some("grass vertex buffer"),
contents: bytemuck::cast_slice(cube::VERTICES_GRASS),
usage: wgpu::BufferUsage::VERTEX,
});
let index_buffer = render_device.create_buffer_init(&BufferInitDescriptor {
label: Some("index_buffer"),
@ -399,7 +383,7 @@ impl WorldState {
usage: wgpu::BufferUsage::INDEX,
});
let (instance_lists, instance_buffers) = Self::create_instances(&render_device, &chunk);
let (instance_lists, instance_buffers) = Self::create_instances(&render_device, &world);
let depth_texture =
Texture::create_depth_texture(&render_device, &swap_chain_descriptor, "depth_texture");
@ -414,11 +398,12 @@ impl WorldState {
projection,
instance_lists,
vertex_buffer,
vertex_buffer_grass: grass_vertex_buffer,
index_buffer,
instance_buffers,
depth_texture,
light_bind_group,
chunk,
world,
};
world_state.update_chunk(&render_queue);