Pausing rendering, warnings cleanup, more statistics

This commit is contained in:
Piotrek
2021-05-10 15:36:11 +02:00
parent 4eaa0fab56
commit a09f446ecd
10 changed files with 84 additions and 79 deletions
Generated
+25 -25
View File
@@ -1,30 +1,5 @@
# This file is automatically @generated by Cargo. # This file is automatically @generated by Cargo.
# It is not intended for manual editing. # It is not intended for manual editing.
[[package]]
name = "VoxelGame"
version = "0.1.0"
dependencies = [
"anyhow",
"bytemuck",
"byteorder",
"cgmath",
"dirs",
"flate2",
"fs_extra",
"futures",
"glob",
"image",
"linked-hash-map",
"lzzzz",
"noise",
"rand 0.8.3",
"shaderc",
"wgpu",
"wgpu_glyph",
"winit",
"yaml-rust",
]
[[package]] [[package]]
name = "ab_glyph" name = "ab_glyph"
version = "0.2.10" version = "0.2.10"
@@ -2058,6 +2033,31 @@ version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
[[package]]
name = "voxel_game"
version = "0.1.0"
dependencies = [
"anyhow",
"bytemuck",
"byteorder",
"cgmath",
"dirs",
"flate2",
"fs_extra",
"futures",
"glob",
"image",
"linked-hash-map",
"lzzzz",
"noise",
"rand 0.8.3",
"shaderc",
"wgpu",
"wgpu_glyph",
"winit",
"yaml-rust",
]
[[package]] [[package]]
name = "walkdir" name = "walkdir"
version = "2.3.2" version = "2.3.2"
+1 -1
View File
@@ -1,5 +1,5 @@
[package] [package]
name = "VoxelGame" name = "voxel_game"
version = "0.1.0" version = "0.1.0"
authors = ["Piotrek <hello@pbaja.me>"] authors = ["Piotrek <hello@pbaja.me>"]
edition = "2018" edition = "2018"
+10 -3
View File
@@ -3,7 +3,7 @@ mod player;
pub mod world; pub mod world;
use std::time::Instant; use std::time::Instant;
use crate::renderer::content_view::ContentView; use crate::renderer::content_view::ContentView;
use cgmath::{SquareMatrix, Point3, InnerSpace}; use cgmath::Point3;
use winit::event::Event; use winit::event::Event;
use crate::renderer::{camera::CameraTransform}; use crate::renderer::{camera::CameraTransform};
use player::Player; use player::Player;
@@ -16,6 +16,7 @@ pub enum GameState {
} }
pub struct Game { pub struct Game {
state: GameState,
player: Player, player: Player,
world: World world: World
} }
@@ -23,6 +24,7 @@ pub struct Game {
impl Game { impl Game {
pub fn new(content: &mut dyn ContentView) -> Self { pub fn new(content: &mut dyn ContentView) -> Self {
let mut app = Self { let mut app = Self {
state: GameState::Paused,
player: Player::new(), player: Player::new(),
world: World::new("default".to_string()) world: World::new("default".to_string())
}; };
@@ -62,7 +64,7 @@ impl Game {
self.player.camera_controller.handle_input(event); self.player.camera_controller.handle_input(event);
} }
pub fn update_state(&mut self, requested_state: GameState) -> GameState { pub fn update_state(&mut self, requested_state: GameState) -> &GameState {
match requested_state { match requested_state {
GameState::Paused => { GameState::Paused => {
self.player.camera_controller.set_enabled(false); self.player.camera_controller.set_enabled(false);
@@ -73,7 +75,12 @@ impl Game {
}; };
// Currently we are not preventing any state changes, just return requested state // Currently we are not preventing any state changes, just return requested state
requested_state self.state = requested_state;
&self.state
}
pub fn get_state(&self) -> &GameState {
&self.state
} }
pub fn update_camera(&mut self, delta: f32, camera_transform: &mut dyn CameraTransform) { pub fn update_camera(&mut self, delta: f32, camera_transform: &mut dyn CameraTransform) {
-3
View File
@@ -1,7 +1,4 @@
use cgmath::Point3; use cgmath::Point3;
use std::iter::FromIterator;
use std::io::Write;
use flate2::{write::DeflateEncoder, Compression};
pub const SIZE: usize = 32; pub const SIZE: usize = 32;
pub const SIZE_QB: usize = SIZE*SIZE*SIZE; pub const SIZE_QB: usize = SIZE*SIZE*SIZE;
+9 -15
View File
@@ -1,20 +1,20 @@
use std::time::Instant;
use flate2::Compression;
use flate2::write::DeflateEncoder;
use flate2::read::DeflateDecoder;
use byteorder::LittleEndian; use byteorder::LittleEndian;
use byteorder::ByteOrder; use byteorder::ByteOrder;
use cgmath::Point3; use cgmath::Point3;
use std::io::Write;
use std::convert::TryInto;
use lzzzz::lz4; use lzzzz::lz4;
use std::io::Read;
use crate::game::world::{WorldBlock, block}; use crate::game::world::{WorldBlock, block};
pub const SIZE: usize = 32; pub const SIZE: usize = 32;
const SIZE_SQ: usize = SIZE*SIZE; const SIZE_SQ: usize = SIZE*SIZE;
const SIZE_QB: usize = SIZE*SIZE*SIZE; const SIZE_QB: usize = SIZE*SIZE*SIZE;
// 1 chunk times on i7-5930K
// alg | size | compr | decom
// raw 32.89kB 0.06s 1.19s
// deflate fast 1.23kB 1.22s 5.46s
// lz4 1.6kB 0.07s 1.23s
pub struct WorldChunk { pub struct WorldChunk {
nodes: Box<[u32]>, nodes: Box<[u32]>,
blocks: Vec<WorldBlock> blocks: Vec<WorldBlock>
@@ -30,15 +30,15 @@ impl WorldChunk {
pub fn from_bytes(bytes: Vec<u8>) -> Self { pub fn from_bytes(bytes: Vec<u8>) -> Self {
let mut instance = Self::new(); let mut instance = Self::new();
let (header_bytes, bytes) = bytes.split_at(128);
let (node_bytes, block_bytes_compressed) = bytes.split_at((SIZE_QB*4) as usize);
// Header // Header
let (header_bytes, bytes) = bytes.split_at(128);
let file_ver = header_bytes[0]; let file_ver = header_bytes[0];
let num_blocks = LittleEndian::read_u32(&header_bytes[1..5]) as usize; let num_blocks = LittleEndian::read_u32(&header_bytes[1..5]) as usize;
assert_eq!(file_ver, 1); assert_eq!(file_ver, 1);
// Nodes // Nodes
let (node_bytes, block_bytes_compressed) = bytes.split_at((SIZE_QB*4) as usize);
for i in 0..SIZE_QB { for i in 0..SIZE_QB {
let idx = (i*4) as usize; let idx = (i*4) as usize;
let val = u32::from_le_bytes([node_bytes[idx], node_bytes[idx+1], node_bytes[idx+2], node_bytes[idx+3]]); let val = u32::from_le_bytes([node_bytes[idx], node_bytes[idx+1], node_bytes[idx+2], node_bytes[idx+3]]);
@@ -79,12 +79,6 @@ impl WorldChunk {
} }
lz4::compress_to_vec(&buf, &mut bytes, lz4::ACC_LEVEL_DEFAULT).unwrap(); lz4::compress_to_vec(&buf, &mut bytes, lz4::ACC_LEVEL_DEFAULT).unwrap();
// alg | size | compr | decom
// raw 32.89kB 0.06s 1.19s
// deflate fast 1.23kB 1.22s 5.46s
// lz4 1.6kB 0.07s 1.23s
bytes bytes
} }
+1 -1
View File
@@ -44,7 +44,7 @@ impl WorldGen {
let noise = Perlin::new(); let noise = Perlin::new();
// Generate height map // Generate height map
let (map, max) = WorldGen::gen_height_map(block_pos.x as usize, block_pos.z as usize, &mut rng, &noise); let (map, _max) = WorldGen::gen_height_map(block_pos.x as usize, block_pos.z as usize, &mut rng, &noise);
// Fill // Fill
for x in 0..block::SIZE { for x in 0..block::SIZE {
+4 -6
View File
@@ -1,19 +1,17 @@
mod generator; mod generator;
pub mod chunk; pub mod chunk;
pub mod block; pub mod block;
use std::time::Instant;
use linked_hash_map::LinkedHashMap; use linked_hash_map::LinkedHashMap;
use std::path::PathBuf; use std::path::PathBuf;
use std::path::Path;
use std::io::Write; use std::io::Write;
use std::io::Read; use std::io::Read;
use std::fs; use std::fs;
use cgmath::{Point3, InnerSpace}; use cgmath::Point3;
use std::collections::HashMap; use std::collections::HashMap;
use generator::WorldGen; use generator::WorldGen;
use chunk::WorldChunk; use chunk::WorldChunk;
use block::WorldBlock; use block::WorldBlock;
use yaml_rust::{Yaml, YamlLoader, YamlEmitter}; use yaml_rust::{Yaml, YamlEmitter};
pub struct World { pub struct World {
@@ -101,7 +99,7 @@ impl World {
file.read_to_end(&mut bytes).expect("Failed to read file"); file.read_to_end(&mut bytes).expect("Failed to read file");
let chunk = WorldChunk::from_bytes(bytes); let chunk = WorldChunk::from_bytes(bytes);
println!("loaded {:?}", pos); println!("Load: Chunk {}, {}, {}", pos.x, pos.y, pos.z);
self.chunks.insert(pos, chunk); self.chunks.insert(pos, chunk);
count += 1; count += 1;
} }
@@ -117,7 +115,7 @@ impl World {
// Create chunk if does not exist // Create chunk if does not exist
if let None = self.chunks.get(&ch_pos) { if let None = self.chunks.get(&ch_pos) {
self.chunks.insert(ch_pos.clone(), WorldChunk::new()); self.chunks.insert(ch_pos.clone(), WorldChunk::new());
println!("Alloc chunk [{}, {}, {}]", ch_pos.x, ch_pos.y, ch_pos.z); println!("Alloc: Chunk [{}, {}, {}]", ch_pos.x, ch_pos.y, ch_pos.z);
} }
// Generate block for chunk // Generate block for chunk
let chunk = self.chunks.get_mut(&ch_pos).unwrap(); let chunk = self.chunks.get_mut(&ch_pos).unwrap();
+10 -8
View File
@@ -24,7 +24,7 @@ fn main() {
.expect("Failed to create window"); .expect("Failed to create window");
let mut renderer = Renderer::new(&window); let mut renderer = Renderer::new(&window);
let mut app = Game::new(&mut renderer); let mut game = Game::new(&mut renderer);
// Stats // Stats
let mut fps_timer = std::time::Instant::now(); let mut fps_timer = std::time::Instant::now();
@@ -34,7 +34,7 @@ fn main() {
// Run event loop // Run event loop
events.run(move |ev, _, c| { events.run(move |ev, _, c| {
// App input // App input
app.input(&ev); game.input(&ev);
// Other // Other
match ev { match ev {
@@ -46,7 +46,7 @@ fn main() {
// Escape key // Escape key
WindowEvent::KeyboardInput { input: KeyboardInput { state: ElementState::Pressed, virtual_keycode: Some(VirtualKeyCode::Escape), .. }, .. } => { WindowEvent::KeyboardInput { input: KeyboardInput { state: ElementState::Pressed, virtual_keycode: Some(VirtualKeyCode::Escape), .. }, .. } => {
// Request pause // Request pause
if let GameState::Paused = app.update_state(GameState::Paused) { if let GameState::Paused = game.update_state(GameState::Paused) {
window.set_cursor_grab(false).unwrap(); window.set_cursor_grab(false).unwrap();
window.set_cursor_visible(true); window.set_cursor_visible(true);
} }
@@ -54,7 +54,7 @@ fn main() {
// Window clicked // Window clicked
WindowEvent::MouseInput { state: ElementState::Pressed, button: MouseButton::Left, .. } => { WindowEvent::MouseInput { state: ElementState::Pressed, button: MouseButton::Left, .. } => {
// Request unpause // Request unpause
if let GameState::Running = app.update_state(GameState::Running) { if let GameState::Running = game.update_state(GameState::Running) {
window.set_cursor_grab(true).unwrap(); window.set_cursor_grab(true).unwrap();
window.set_cursor_visible(false); window.set_cursor_visible(false);
} }
@@ -73,11 +73,13 @@ fn main() {
Event::MainEventsCleared => { Event::MainEventsCleared => {
// Update // Update
let delta = delta_timer.elapsed().as_secs_f32(); let delta = delta_timer.elapsed().as_secs_f32();
app.update_camera(delta, &mut renderer.camera); game.update_camera(delta, &mut renderer.camera);
delta_timer = std::time::Instant::now(); delta_timer = std::time::Instant::now();
// Redraw // Redraw if running
window.request_redraw(); if let GameState::Running = game.get_state() {
window.request_redraw();
}
} }
// Draw // Draw
Event::RedrawRequested(_) => { Event::RedrawRequested(_) => {
@@ -87,7 +89,7 @@ fn main() {
if elapsed >= 0.5 { if elapsed >= 0.5 {
let mut fps = (fps_counter as f64) / elapsed; let mut fps = (fps_counter as f64) / elapsed;
fps = (fps*100.0_f64).floor() / 100.0; fps = (fps*100.0_f64).floor() / 100.0;
renderer.ui.set_fps(fps as f32); renderer.ui.set_text(0, format!("FPS: {}", fps));
fps_timer = std::time::Instant::now(); fps_timer = std::time::Instant::now();
fps_counter = 0; fps_counter = 0;
+8 -1
View File
@@ -1,4 +1,4 @@
use wgpu_glyph::Text; use std::time::Instant;
use winit::{window::Window, dpi::PhysicalSize}; use winit::{window::Window, dpi::PhysicalSize};
pub mod buffers; pub mod buffers;
use buffers::Buffers; use buffers::Buffers;
@@ -118,10 +118,14 @@ impl Renderer {
self.queue.write_buffer(&self.buffers.uniforms.buffer, 0, bytemuck::cast_slice(&[self.buffers.uniforms.values])); self.queue.write_buffer(&self.buffers.uniforms.buffer, 0, bytemuck::cast_slice(&[self.buffers.uniforms.values]));
// Update content // Update content
let timer = Instant::now();
self.buffers.content.update(&self.queue); self.buffers.content.update(&self.queue);
self.ui.set_text(2, format!("Update content: {}ms", timer.elapsed().as_micros() as f64 / 1000.0));
// Get next frame to render to // Get next frame to render to
let timer = Instant::now();
let frame = self.swapchain.get_current_frame()?.output; let frame = self.swapchain.get_current_frame()?.output;
self.ui.set_text(3, format!("Swapchain get frame: {}ms", timer.elapsed().as_micros() as f64 / 1000.0));
// Create encoder that will build command buffer for us // Create encoder that will build command buffer for us
let mut encoder = self.device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: Some("Render Encoder"),}); let mut encoder = self.device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: Some("Render Encoder"),});
@@ -130,7 +134,10 @@ impl Renderer {
self.ui.render(&self.device, &mut encoder, &frame.view, 1280, 720); self.ui.render(&self.device, &mut encoder, &frame.view, 1280, 720);
// Submit encoder (command buffer) // Submit encoder (command buffer)
let timer = Instant::now();
self.queue.submit(std::iter::once(encoder.finish())); self.queue.submit(std::iter::once(encoder.finish()));
self.ui.set_text(4, format!("Submit queue: {}ms", timer.elapsed().as_micros() as f64 / 1000.0));
self.ui.recall(); self.ui.recall();
// Return ok // Return ok
+16 -16
View File
@@ -1,3 +1,4 @@
use std::collections::HashMap;
use wgpu_glyph::{GlyphBrush, ab_glyph::FontArc, GlyphBrushBuilder, Section, Text}; use wgpu_glyph::{GlyphBrush, ab_glyph::FontArc, GlyphBrushBuilder, Section, Text};
use wgpu::util::StagingBelt; use wgpu::util::StagingBelt;
use futures::executor::LocalPool; use futures::executor::LocalPool;
@@ -11,7 +12,7 @@ pub struct UserInterface {
local_pool: LocalPool, local_pool: LocalPool,
brush: GlyphBrush<()>, brush: GlyphBrush<()>,
// Texts // Texts
fps_text: String texts: HashMap<u32, String>
} }
impl UserInterface { impl UserInterface {
@@ -22,27 +23,26 @@ impl UserInterface {
staging_belt: StagingBelt::new(1024), staging_belt: StagingBelt::new(1024),
local_pool: LocalPool::new(), local_pool: LocalPool::new(),
brush: GlyphBrushBuilder::using_font(font).build(device, render_format), brush: GlyphBrushBuilder::using_font(font).build(device, render_format),
fps_text: "-".to_string() texts: HashMap::new()
} }
} }
fn print(&mut self, x: u32, y: u32, msg: &str) { pub fn set_text(&mut self, index: u32, text: String) {
let text = Text::new(msg).with_color(WHITE); self.texts.insert(index, text);
self.brush.queue(Section {
screen_position: (x as f32, y as f32),
bounds: (text.scale.x * text.text.len() as f32, text.scale.y),
text: vec![text],
..Section::default()
});
}
pub fn set_fps(&mut self, fps: f32) {
self.fps_text = format!("FPS: {}", fps);
} }
pub fn render(&mut self, device: &wgpu::Device, encoder: &mut wgpu::CommandEncoder, target: &wgpu::TextureView, width: u32, height: u32) { pub fn render(&mut self, device: &wgpu::Device, encoder: &mut wgpu::CommandEncoder, target: &wgpu::TextureView, width: u32, height: u32) {
// Print texts for (id, text) in self.texts.iter() {
self.print(5, 5, &self.fps_text.clone());
let text = Text::new(text).with_color(WHITE);
self.brush.queue(Section {
screen_position: (5 as f32, (5 + id*15) as f32),
bounds: (text.scale.x * text.text.len() as f32, text.scale.y),
text: vec![text],
..Section::default()
});
}
// Draw // Draw
self.brush.draw_queued(&device, &mut self.staging_belt, encoder, target, width, height).expect("Draw queued"); self.brush.draw_queued(&device, &mut self.staging_belt, encoder, target, width, height).expect("Draw queued");
self.staging_belt.finish(); self.staging_belt.finish();