WIP generating chunks at player position
This commit is contained in:
Generated
+16
-25
@@ -506,18 +506,6 @@ version = "0.2.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "37ab347416e802de484e4d03c7316c48f1ecb56574dfd4a46a80f173ce1de04d"
|
checksum = "37ab347416e802de484e4d03c7316c48f1ecb56574dfd4a46a80f173ce1de04d"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "flate2"
|
|
||||||
version = "1.0.20"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "cd3aec53de10fe96d7d8c565eb17f2c687bb5518a2ec453b5b1252964526abe0"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if 1.0.0",
|
|
||||||
"crc32fast",
|
|
||||||
"libc",
|
|
||||||
"miniz_oxide 0.4.4",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fnv"
|
name = "fnv"
|
||||||
version = "1.0.7"
|
version = "1.0.7"
|
||||||
@@ -1809,6 +1797,20 @@ name = "serde"
|
|||||||
version = "1.0.125"
|
version = "1.0.125"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "558dc50e1a5a5fa7112ca2ce4effcb321b0300c0d4ccf0776a9f60cd89031171"
|
checksum = "558dc50e1a5a5fa7112ca2ce4effcb321b0300c0d4ccf0776a9f60cd89031171"
|
||||||
|
dependencies = [
|
||||||
|
"serde_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_derive"
|
||||||
|
version = "1.0.125"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b093b7a2bb58203b5da3056c05b4ec1fed827dcfdb37347a8841695263b3d06d"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "shaderc"
|
name = "shaderc"
|
||||||
@@ -2042,20 +2044,18 @@ dependencies = [
|
|||||||
"byteorder",
|
"byteorder",
|
||||||
"cgmath",
|
"cgmath",
|
||||||
"dirs",
|
"dirs",
|
||||||
"flate2",
|
|
||||||
"fs_extra",
|
"fs_extra",
|
||||||
"futures",
|
"futures",
|
||||||
"glob",
|
"glob",
|
||||||
"image",
|
|
||||||
"linked-hash-map",
|
|
||||||
"lzzzz",
|
"lzzzz",
|
||||||
"noise",
|
"noise",
|
||||||
"rand 0.8.3",
|
"rand 0.8.3",
|
||||||
|
"serde",
|
||||||
"shaderc",
|
"shaderc",
|
||||||
|
"toml",
|
||||||
"wgpu",
|
"wgpu",
|
||||||
"wgpu_glyph",
|
"wgpu_glyph",
|
||||||
"winit",
|
"winit",
|
||||||
"yaml-rust",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2438,12 +2438,3 @@ name = "xml-rs"
|
|||||||
version = "0.8.3"
|
version = "0.8.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b07db065a5cf61a7e4ba64f29e67db906fb1787316516c4e6e5ff0fea1efcd8a"
|
checksum = "b07db065a5cf61a7e4ba64f29e67db906fb1787316516c4e6e5ff0fea1efcd8a"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "yaml-rust"
|
|
||||||
version = "0.4.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85"
|
|
||||||
dependencies = [
|
|
||||||
"linked-hash-map",
|
|
||||||
]
|
|
||||||
|
|||||||
+22
-9
@@ -5,21 +5,34 @@ authors = ["Piotrek <hello@pbaja.me>"]
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
|
||||||
|
# Rendering and window management
|
||||||
winit = "0.24"
|
winit = "0.24"
|
||||||
wgpu = "0.7"
|
wgpu = "0.7"
|
||||||
wgpu_glyph = "0.11"
|
wgpu_glyph = "0.11"
|
||||||
futures = "0.3"
|
|
||||||
bytemuck = { version = "1.5", features = [ "derive" ] }
|
# Math
|
||||||
byteorder = "1.4"
|
|
||||||
image = "0.23.14"
|
|
||||||
cgmath = "0.18"
|
cgmath = "0.18"
|
||||||
rand = "0.8"
|
rand = "0.8"
|
||||||
noise = "0.7"
|
noise = "0.7"
|
||||||
dirs = "3.0"
|
|
||||||
flate2 = "1.0"
|
# Saving and loading to and from files
|
||||||
lzzzz = "0.8"
|
dirs = "3.0" # Retrieving common paths (%APPDATA%)
|
||||||
yaml-rust = "0.4"
|
serde = { version = "1.0", features = ["derive"] } # Serialization and deserialization (world.cfg)
|
||||||
linked-hash-map = "0.5"
|
toml = "0.5" # Toml file format (used with serde)
|
||||||
|
lzzzz = "0.8" # Lz4 compression
|
||||||
|
|
||||||
|
# Other
|
||||||
|
futures = "0.3"
|
||||||
|
bytemuck = { version = "1.5", features = [ "derive" ] }
|
||||||
|
byteorder = "1.4"
|
||||||
|
|
||||||
|
# Deprecated
|
||||||
|
#image = "0.23.14"
|
||||||
|
#flate2 = "1.0"
|
||||||
|
#yaml-rust = "0.4"
|
||||||
|
#linked-hash-map = "0.5"
|
||||||
|
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
anyhow = "1.0"
|
anyhow = "1.0"
|
||||||
|
|||||||
+17
-16
@@ -1,11 +1,9 @@
|
|||||||
mod camera_controller;
|
mod camera_controller;
|
||||||
mod player;
|
mod player;
|
||||||
pub mod world;
|
pub mod world;
|
||||||
use std::time::Instant;
|
use crate::renderer::renderer_view::RendererView;
|
||||||
use crate::renderer::content_view::ContentView;
|
|
||||||
use cgmath::Point3;
|
use cgmath::Point3;
|
||||||
use winit::event::Event;
|
use winit::event::Event;
|
||||||
use crate::renderer::{camera::CameraTransform};
|
|
||||||
use player::Player;
|
use player::Player;
|
||||||
use world::World;
|
use world::World;
|
||||||
|
|
||||||
@@ -18,19 +16,20 @@ pub enum GameState {
|
|||||||
pub struct Game {
|
pub struct Game {
|
||||||
state: GameState,
|
state: GameState,
|
||||||
player: Player,
|
player: Player,
|
||||||
|
#[allow(unused)]
|
||||||
world: World,
|
world: World,
|
||||||
|
|
||||||
prev_pos: Point3<i32>
|
prev_pos: Option<Point3<i32>>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Game {
|
impl Game {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let mut app = Self {
|
Self {
|
||||||
state: GameState::Paused,
|
state: GameState::Paused,
|
||||||
player: Player::new(),
|
player: Player::new(),
|
||||||
world: World::new("default".to_string()),
|
world: World::new("default".to_string()),
|
||||||
prev_pos: Point3{ x:0, y:0, z:0 }
|
prev_pos: None
|
||||||
};
|
}
|
||||||
|
|
||||||
// // Try to load world from file
|
// // Try to load world from file
|
||||||
// let timer = Instant::now();
|
// let timer = Instant::now();
|
||||||
@@ -56,24 +55,26 @@ impl Game {
|
|||||||
// app.world.save();
|
// app.world.save();
|
||||||
// println!("Saved in {}", timer.elapsed().as_secs_f32());
|
// println!("Saved in {}", timer.elapsed().as_secs_f32());
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
|
||||||
println!("App initialized");
|
|
||||||
app
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update(&mut self, delta: f32, content: &mut impl ContentView) {
|
pub fn update(&mut self, delta: f32, renderer: &mut impl RendererView) {
|
||||||
// Update camera controller
|
// Update camera controller
|
||||||
let camera = content.get_camera_transform();
|
let camera = renderer.get_camera_transform();
|
||||||
self.player.camera_controller.update(delta, camera);
|
self.player.camera_controller.update(delta, camera);
|
||||||
|
|
||||||
// Update chunks
|
// Update chunks
|
||||||
let pos = camera.get_position();
|
let pos = camera.get_position();
|
||||||
let pos = Point3{x: pos.x as i32, y: pos.y as i32, z: pos.z as i32};
|
let pos = Point3{x: pos.x as i32, y: pos.y as i32, z: pos.z as i32};
|
||||||
if pos != self.prev_pos {
|
if self.prev_pos == None || self.prev_pos != Some(pos) {
|
||||||
self.prev_pos = pos;
|
self.prev_pos = Some(pos);
|
||||||
|
renderer.get_ui().set_text("World", 0, format!("Position: {}, {}, {}", pos.x, pos.y, pos.z));
|
||||||
|
|
||||||
// Load sphere of chunks around player
|
// Load sphere of chunks around player (TODO)
|
||||||
|
let chunk_pos = Point3{x: pos.x / 32, y: pos.y / 32, z: pos.z / 32};
|
||||||
|
if self.world.load_chunk(chunk_pos) {
|
||||||
|
|
||||||
|
renderer.write(, block: &WorldBlock)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+12
-1
@@ -28,6 +28,7 @@ impl WorldChunk {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
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();
|
||||||
|
|
||||||
@@ -59,6 +60,7 @@ impl WorldChunk {
|
|||||||
instance
|
instance
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
pub fn to_bytes(&self) -> Vec<u8> {
|
pub fn to_bytes(&self) -> Vec<u8> {
|
||||||
|
|
||||||
// Header
|
// Header
|
||||||
@@ -82,6 +84,7 @@ impl WorldChunk {
|
|||||||
bytes
|
bytes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
pub fn all_blocks(&self) -> Vec<(Point3<u32>, &WorldBlock)> {
|
pub fn all_blocks(&self) -> Vec<(Point3<u32>, &WorldBlock)> {
|
||||||
self.nodes.iter().enumerate()
|
self.nodes.iter().enumerate()
|
||||||
.filter(|(_, n)| **n != 0)
|
.filter(|(_, n)| **n != 0)
|
||||||
@@ -101,7 +104,7 @@ impl WorldChunk {
|
|||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_block(&mut self, block_pos: &Point3<u32>) -> &mut WorldBlock {
|
pub fn get_block_mut(&mut self, block_pos: &Point3<u32>) -> &mut WorldBlock {
|
||||||
// Get block index
|
// Get block index
|
||||||
let index = (block_pos.x + SIZE as u32 * (block_pos.y + SIZE as u32 * block_pos.z)) as usize;
|
let index = (block_pos.x + SIZE as u32 * (block_pos.y + SIZE as u32 * block_pos.z)) as usize;
|
||||||
let mut value = self.nodes[index];
|
let mut value = self.nodes[index];
|
||||||
@@ -114,4 +117,12 @@ impl WorldChunk {
|
|||||||
// Return block reference
|
// Return block reference
|
||||||
&mut self.blocks[(value-1) as usize]
|
&mut self.blocks[(value-1) as usize]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_block(&self, block_pos: &Point3<u32>) -> &WorldBlock {
|
||||||
|
// Get block index
|
||||||
|
let index = (block_pos.x + SIZE as u32 * (block_pos.y + SIZE as u32 * block_pos.z)) as usize;
|
||||||
|
let value = self.nodes[index];
|
||||||
|
// Return block reference
|
||||||
|
&self.blocks[(value-1) as usize]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -39,7 +39,7 @@ impl WorldGen {
|
|||||||
/*
|
/*
|
||||||
* Generate block
|
* Generate block
|
||||||
*/
|
*/
|
||||||
pub fn generate(block_pos: &Point3<u32>, block: &mut WorldBlock) {
|
pub fn generate(block_pos: &Point3<i32>, block: &mut WorldBlock) {
|
||||||
let mut rng = rand::thread_rng();
|
let mut rng = rand::thread_rng();
|
||||||
let noise = Perlin::new();
|
let noise = Perlin::new();
|
||||||
|
|
||||||
|
|||||||
+69
-70
@@ -1,7 +1,6 @@
|
|||||||
mod generator;
|
mod generator;
|
||||||
pub mod chunk;
|
pub mod chunk;
|
||||||
pub mod block;
|
pub mod block;
|
||||||
use linked_hash_map::LinkedHashMap;
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
@@ -11,29 +10,37 @@ 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, YamlEmitter};
|
|
||||||
|
|
||||||
|
#[derive(serde::Serialize, serde::Deserialize, Debug)]
|
||||||
|
struct WorldData {
|
||||||
|
#[serde(default)]
|
||||||
|
pub name: String
|
||||||
|
}
|
||||||
|
|
||||||
pub struct World {
|
pub struct World {
|
||||||
name: String,
|
data: WorldData,
|
||||||
chunks: HashMap<Point3<u32>, WorldChunk>,
|
chunks: HashMap<Point3<i32>, WorldChunk>,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn point_abs(p: &Point3<i32>) -> Point3<u32> {
|
||||||
|
Point3 {x: p.x.abs() as u32, y: p.y.abs() as u32, z: p.z.abs() as u32 }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl World {
|
impl World {
|
||||||
|
|
||||||
pub fn new(name: String) -> Self {
|
pub fn new(name: String) -> Self {
|
||||||
Self {
|
Self {
|
||||||
name,
|
data: WorldData { name },
|
||||||
chunks: HashMap::new(),
|
chunks: HashMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn all_blocks(&self) -> Vec<(Point3<u32>, &WorldBlock)> {
|
pub fn all_blocks(&self) -> Vec<(Point3<i32>, &WorldBlock)> {
|
||||||
self.chunks.iter().map(|(chunk_pos, chunk)| {
|
self.chunks.iter().map(|(chunk_pos, chunk)| {
|
||||||
let off = chunk_pos * chunk::SIZE as u32;
|
let off = chunk_pos * chunk::SIZE as i32;
|
||||||
let result: Vec<(Point3<u32>, &WorldBlock)> = chunk.all_blocks().iter().map(|(pos, block)| {
|
let result: Vec<(Point3<i32>, &WorldBlock)> = chunk.all_blocks().iter().map(|(pos, block)| {
|
||||||
(
|
(
|
||||||
Point3{x: off.x+pos.x, y: off.y+pos.y, z: off.z+pos.z},
|
Point3{x: off.x+pos.x as i32, y: off.y+pos.y as i32, z: off.z+pos.z as i32},
|
||||||
*block
|
*block
|
||||||
)
|
)
|
||||||
}).collect();
|
}).collect();
|
||||||
@@ -58,77 +65,69 @@ impl World {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Save metadata
|
// Save metadata
|
||||||
let mut data: LinkedHashMap<Yaml, Yaml> = LinkedHashMap::new();
|
let data_str = toml::to_string(&self.data).unwrap();
|
||||||
data.insert(Yaml::String("name".to_string()), Yaml::String(self.name.clone()));
|
let data_path: PathBuf = [dir.to_str().unwrap(), "world.dat"].iter().collect();
|
||||||
|
|
||||||
let mut data_str = String::new();
|
|
||||||
let mut emit = YamlEmitter::new(&mut data_str);
|
|
||||||
emit.dump(&Yaml::Hash(data)).expect("Failed to encode yaml");
|
|
||||||
|
|
||||||
let data_path: PathBuf = [dir.to_str().unwrap(), "world.yml"].iter().collect();
|
|
||||||
let mut data_file = fs::File::create(data_path).unwrap();
|
let mut data_file = fs::File::create(data_path).unwrap();
|
||||||
data_file.write_all(data_str.as_bytes()).expect("Failed to write");
|
data_file.write_all(data_str.as_bytes()).expect("Failed to write world metadata");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Loads chunk and displays it in the world.
|
||||||
|
* It will try to load the chunk from file, and if that fails it will generate the chunk and save it.
|
||||||
|
*/
|
||||||
|
pub fn load_chunk(&mut self, pos: Point3<i32>) -> Option<&WorldChunk> {
|
||||||
|
// Abort if chunk is already loaded
|
||||||
|
if let Some(_) = self.chunks.get(&pos) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try loading chunk from file
|
||||||
|
let filename = format!("chunk_{}_{}_{}.dat", pos.x, pos.y, pos.z);
|
||||||
|
let filepath = dirs::data_local_dir().unwrap().join("Voxelgame").with_file_name(filename);
|
||||||
|
if filepath.is_file() {
|
||||||
|
let mut buff = Vec::new();
|
||||||
|
let mut file = fs::File::open(filepath).expect("Failed to open file");
|
||||||
|
file.read_to_end(&mut buff).expect("Failed to read file");
|
||||||
|
let chunk = WorldChunk::from_bytes(buff);
|
||||||
|
self.chunks.insert(pos, chunk);
|
||||||
|
println!("Chunk at {:?} loaded", pos);
|
||||||
|
return Some(&chunk);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try generating chunk
|
||||||
|
let mut chunk = WorldChunk::new();
|
||||||
|
for x in 0..32 {
|
||||||
|
for z in 0..32 {
|
||||||
|
let bpos = &Point3::<u32>{x,y:0,z};
|
||||||
|
let block = chunk.get_block_mut(&bpos);
|
||||||
|
let wpos = &Point3::<i32>{ x: pos.x+bpos.x as i32, y: pos.y+bpos.y as i32, z: pos.z+bpos.z as i32};
|
||||||
|
WorldGen::generate(wpos, block);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.chunks.insert(pos, chunk);
|
||||||
|
println!("Chunk at {:?} generated", pos);
|
||||||
|
Some(&chunk)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load(&mut self) -> bool {
|
pub fn load(&mut self) -> bool {
|
||||||
// Get directory
|
|
||||||
let mut dir = dirs::data_local_dir().unwrap();
|
|
||||||
dir.push("Voxelgame");
|
|
||||||
if !dir.is_dir() {
|
|
||||||
println!("Not exists: {:?}", dir);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load all chunks
|
|
||||||
let mut count = 0;
|
|
||||||
for entry in fs::read_dir(dir).unwrap() {
|
|
||||||
let path: PathBuf = entry.unwrap().path();
|
|
||||||
if path.extension().unwrap().to_str() != Some("dat") {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
let stem = path.file_stem().unwrap().to_str().unwrap();
|
|
||||||
if !stem.starts_with("chunk") {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let s: Vec<&str> = stem.split("_").collect();
|
|
||||||
let pos = Point3{x: s[1].parse::<u32>().unwrap(), y: s[2].parse::<u32>().unwrap(), z: s[3].parse::<u32>().unwrap()};
|
|
||||||
|
|
||||||
let mut bytes = Vec::new();
|
|
||||||
let mut file = fs::File::open(path).expect("Failed to open file");
|
|
||||||
file.read_to_end(&mut bytes).expect("Failed to read file");
|
|
||||||
let chunk = WorldChunk::from_bytes(bytes);
|
|
||||||
|
|
||||||
println!("Load: Chunk {}, {}, {}", pos.x, pos.y, pos.z);
|
|
||||||
self.chunks.insert(pos, chunk);
|
|
||||||
count += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load metadata
|
// Load metadata
|
||||||
return count > 0;
|
let filepath = dirs::data_local_dir().unwrap().join("Voxelgame").with_file_name("world.dat");
|
||||||
}
|
if let Ok(mut file) = fs::File::open(filepath) {
|
||||||
|
let mut buf = Vec::new();
|
||||||
pub fn gen_block(&mut self, block_wpos: &Point3<u32>) -> &WorldBlock {
|
file.read_to_end(&mut buf).unwrap();
|
||||||
// Split world space to chunk and block space
|
if let Ok(data) = toml::from_slice::<WorldData>(&buf[..]) {
|
||||||
let ch_pos = block_wpos / chunk::SIZE as u32;
|
self.data = data;
|
||||||
let bl_pos = block_wpos % chunk::SIZE as u32;
|
return true;
|
||||||
// Create chunk if does not exist
|
}
|
||||||
if let None = self.chunks.get(&ch_pos) {
|
|
||||||
self.chunks.insert(ch_pos.clone(), WorldChunk::new());
|
|
||||||
println!("Alloc: Chunk [{}, {}, {}]", ch_pos.x, ch_pos.y, ch_pos.z);
|
|
||||||
}
|
}
|
||||||
// Generate block for chunk
|
return false;
|
||||||
let chunk = self.chunks.get_mut(&ch_pos).unwrap();
|
|
||||||
let block = chunk.get_block(&bl_pos);
|
|
||||||
WorldGen::generate(&block_wpos, block);
|
|
||||||
block
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
pub fn get_block(&mut self, block_wpos: &Point3<u32>) -> Option<&WorldBlock> {
|
pub fn get_block(&mut self, block_wpos: &Point3<i32>) -> Option<&WorldBlock> {
|
||||||
// Split world space to chunk and block space
|
// Split world space to chunk and block space
|
||||||
let ch_pos = block_wpos / chunk::SIZE as u32;
|
let ch_pos = block_wpos / chunk::SIZE as i32;
|
||||||
let bl_pos = block_wpos % chunk::SIZE as u32;
|
let bl_pos = point_abs(block_wpos) % chunk::SIZE as u32;
|
||||||
// Return block if exists
|
// Return block if exists
|
||||||
if let Some(chunk) = self.chunks.get_mut(&ch_pos) {
|
if let Some(chunk) = self.chunks.get_mut(&ch_pos) {
|
||||||
return Some(chunk.get_block(&bl_pos));
|
return Some(chunk.get_block(&bl_pos));
|
||||||
|
|||||||
+1
-2
@@ -89,8 +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_text(0, format!("FPS: {}", fps));
|
renderer.ui.set_text("Performance", 0, format!("FPS: {}", fps));
|
||||||
|
|
||||||
fps_timer = std::time::Instant::now();
|
fps_timer = std::time::Instant::now();
|
||||||
fps_counter = 0;
|
fps_counter = 0;
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-7
@@ -6,7 +6,7 @@ mod passes;
|
|||||||
use passes::{RaytracePass, PostprocessPass};
|
use passes::{RaytracePass, PostprocessPass};
|
||||||
pub mod camera;
|
pub mod camera;
|
||||||
use camera::Camera;
|
use camera::Camera;
|
||||||
pub mod content_view;
|
pub mod renderer_view;
|
||||||
mod ui;
|
mod ui;
|
||||||
use ui::UserInterface;
|
use ui::UserInterface;
|
||||||
|
|
||||||
@@ -120,12 +120,12 @@ impl Renderer {
|
|||||||
// Update content
|
// Update content
|
||||||
let timer = Instant::now();
|
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));
|
self.ui.set_text("Performance", 1, 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 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));
|
self.ui.set_text("Performance", 2, 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 timer = Instant::now();
|
let timer = Instant::now();
|
||||||
@@ -133,18 +133,18 @@ impl Renderer {
|
|||||||
self.raytrace_pass.render(&mut encoder, &mut self.buffers, &self.texture);//&frame.view);
|
self.raytrace_pass.render(&mut encoder, &mut self.buffers, &self.texture);//&frame.view);
|
||||||
self.postprocess_pass.render(&mut encoder, &frame.view);
|
self.postprocess_pass.render(&mut encoder, &frame.view);
|
||||||
self.ui.render(&self.device, &mut encoder, &frame.view, 1280, 720);
|
self.ui.render(&self.device, &mut encoder, &frame.view, 1280, 720);
|
||||||
self.ui.set_text(4, format!("Build renderpass: {}ms", timer.elapsed().as_micros() as f64 / 1000.0));
|
self.ui.set_text("Performance", 3, format!("Build renderpass: {}ms", timer.elapsed().as_micros() as f64 / 1000.0));
|
||||||
|
|
||||||
// Submit encoder (command buffer)
|
// Submit encoder (command buffer)
|
||||||
let timer = Instant::now();
|
let timer = Instant::now();
|
||||||
self.queue.submit(std::iter::once(encoder.finish()));
|
self.queue.submit(std::iter::once(encoder.finish()));
|
||||||
self.ui.recall();
|
self.ui.recall();
|
||||||
self.ui.set_text(5, format!("Submit queue: {}ms", timer.elapsed().as_micros() as f64 / 1000.0));
|
self.ui.set_text("Performance", 4, format!("Submit queue: {}ms", timer.elapsed().as_micros() as f64 / 1000.0));
|
||||||
|
|
||||||
// Stats
|
// Stats
|
||||||
let content_stats = self.buffers.content.stats();
|
let content_stats = self.buffers.content.stats();
|
||||||
self.ui.set_text(7, format!("Nodes: {}MB", content_stats.node_tex_size));
|
self.ui.set_text("Renderer", 0, format!("Nodes: {}MB", content_stats.node_tex_size));
|
||||||
self.ui.set_text(8, format!("Blocks: {} / {} MB ({}/{})", content_stats.block_tex_used, content_stats.block_tex_size, content_stats.block_used, content_stats.block_count));
|
self.ui.set_text("Renderer", 1, format!("Blocks: {} / {} MB ({}/{})", content_stats.block_tex_used, content_stats.block_tex_size, content_stats.block_used, content_stats.block_count));
|
||||||
|
|
||||||
// Return ok
|
// Return ok
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -1,20 +1,26 @@
|
|||||||
|
use crate::renderer::UserInterface;
|
||||||
use crate::renderer::camera::CameraTransform;
|
use crate::renderer::camera::CameraTransform;
|
||||||
use crate::Renderer;
|
use crate::Renderer;
|
||||||
use crate::game::world::block::WorldBlock;
|
use crate::game::world::block::WorldBlock;
|
||||||
use cgmath::Point3;
|
use cgmath::Point3;
|
||||||
|
|
||||||
pub trait ContentView {
|
pub trait RendererView {
|
||||||
fn write(&mut self, block_pos: &Point3<u32>, block: &WorldBlock);
|
fn write(&mut self, block_pos: &Point3<u32>, block: &WorldBlock);
|
||||||
fn get_camera_transform(&mut self) -> &mut CameraTransform;
|
fn get_camera_transform(&mut self) -> &mut dyn CameraTransform;
|
||||||
|
fn get_ui(&mut self) -> &mut UserInterface;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ContentView for Renderer {
|
impl RendererView for Renderer {
|
||||||
|
|
||||||
fn write(&mut self, block_pos: &Point3<u32>, block: &WorldBlock) {
|
fn write(&mut self, block_pos: &Point3<u32>, block: &WorldBlock) {
|
||||||
self.buffers.content.write(&self.queue, block_pos, block)
|
self.buffers.content.write(&self.queue, block_pos, block)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_camera_transform(&mut self) -> &mut CameraTransform {
|
fn get_camera_transform(&mut self) -> &mut dyn CameraTransform {
|
||||||
&mut self.camera
|
&mut self.camera
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_ui(&mut self) -> &mut UserInterface {
|
||||||
|
&mut self.ui
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+31
-12
@@ -5,6 +5,9 @@ use futures::executor::LocalPool;
|
|||||||
use futures::task::SpawnExt;
|
use futures::task::SpawnExt;
|
||||||
|
|
||||||
const WHITE: [f32; 4] = [1.0, 1.0, 1.0, 1.0];
|
const WHITE: [f32; 4] = [1.0, 1.0, 1.0, 1.0];
|
||||||
|
const BLUE: [f32; 4] = [0.0, 0.2, 1.0, 1.0];
|
||||||
|
const GREEN: [f32; 4] = [0.1, 1.0, 0.0, 1.0];
|
||||||
|
|
||||||
|
|
||||||
pub struct UserInterface {
|
pub struct UserInterface {
|
||||||
// Glyph drawing
|
// Glyph drawing
|
||||||
@@ -12,7 +15,7 @@ pub struct UserInterface {
|
|||||||
local_pool: LocalPool,
|
local_pool: LocalPool,
|
||||||
brush: GlyphBrush<()>,
|
brush: GlyphBrush<()>,
|
||||||
// Texts
|
// Texts
|
||||||
texts: HashMap<u32, String>
|
texts: HashMap<String, Vec<String>>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UserInterface {
|
impl UserInterface {
|
||||||
@@ -27,20 +30,36 @@ impl UserInterface {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_text(&mut self, index: u32, text: String) {
|
fn print(brush: &mut GlyphBrush<()>, line: u32, text: &str, color: [f32; 4]) {
|
||||||
self.texts.insert(index, text);
|
let t = Text::new(text).with_color(color);
|
||||||
|
brush.queue(Section {
|
||||||
|
screen_position: (5 as f32, (5 + line*15) as f32),
|
||||||
|
bounds: (t.scale.x * t.text.len() as f32, t.scale.y),
|
||||||
|
text: vec![t],
|
||||||
|
..Section::default()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_text(&mut self, cat: &str, line: usize, text: String) {
|
||||||
|
// Category
|
||||||
|
let c = &cat.to_string();
|
||||||
|
if !self.texts.contains_key(c) {self.texts.insert(c.clone(), Vec::new());}
|
||||||
|
// Texts
|
||||||
|
let v = self.texts.get_mut(c).unwrap();
|
||||||
|
while v.len() < line+1 { v.push(String::new()); }
|
||||||
|
v[line] = text;
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
||||||
for (id, text) in self.texts.iter() {
|
let mut line = 0;
|
||||||
|
for (cat, texts) in self.texts.iter_mut() {
|
||||||
let text = Text::new(text).with_color(WHITE);
|
UserInterface::print(&mut self.brush, line, cat, GREEN);
|
||||||
self.brush.queue(Section {
|
line += 1;
|
||||||
screen_position: (5 as f32, (5 + id*15) as f32),
|
for text in texts.iter() {
|
||||||
bounds: (text.scale.x * text.text.len() as f32, text.scale.y),
|
UserInterface::print(&mut self.brush, line, text, WHITE);
|
||||||
text: vec![text],
|
line += 1;
|
||||||
..Section::default()
|
}
|
||||||
});
|
line += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw
|
// Draw
|
||||||
|
|||||||
Reference in New Issue
Block a user