Add world generation, better fps stats, multiple chunks, grass/stone blocks
This commit is contained in:
parent
248a634ecb
commit
61ec4c4da5
12 changed files with 415 additions and 127 deletions
89
Cargo.lock
generated
89
Cargo.lock
generated
|
@ -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"
|
||||
|
|
|
@ -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
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
BIN
assets/block_temp/grass.xcf
(Stored with Git LFS)
Normal file
Binary file not shown.
94
src/chunk.rs
94
src/chunk.rs
|
@ -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));
|
||||
}
|
||||
|
|
39
src/cube.rs
39
src/cube.rs
|
@ -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,
|
||||
|
|
12
src/light.rs
12
src/light.rs
|
@ -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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
32
src/main.rs
32
src/main.rs
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
89
src/state.rs
89
src/state.rs
|
@ -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
52
src/world.rs
Normal 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
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue