CHUNK GENERATION IS REAL
This commit is contained in:
124
Cargo.lock
generated
124
Cargo.lock
generated
@@ -24,7 +24,7 @@ version = "0.8.11"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
|
checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if 1.0.0",
|
||||||
"getrandom",
|
"getrandom",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"version_check",
|
"version_check",
|
||||||
@@ -319,6 +319,17 @@ version = "0.1.6"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a"
|
checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "block-mesh"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3c0345520b5aa77d7d154bd578a18e7a974350931b5f41f641a7844e951b978f"
|
||||||
|
dependencies = [
|
||||||
|
"ilattice",
|
||||||
|
"ndcopy",
|
||||||
|
"ndshape",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "block2"
|
name = "block2"
|
||||||
version = "0.5.1"
|
version = "0.5.1"
|
||||||
@@ -403,6 +414,12 @@ version = "1.1.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c"
|
checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-if"
|
||||||
|
version = "0.1.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cfg-if"
|
name = "cfg-if"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
@@ -713,7 +730,7 @@ version = "0.2.15"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
|
checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if 1.0.0",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"libc",
|
"libc",
|
||||||
"wasi",
|
"wasi",
|
||||||
@@ -731,6 +748,12 @@ dependencies = [
|
|||||||
"xml-rs",
|
"xml-rs",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "glam"
|
||||||
|
version = "0.19.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2b8509e6791516e81c1a630d0bd7fbac36d2fa8712a9da8662e716b52d5051ca"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "glow"
|
name = "glow"
|
||||||
version = "0.13.1"
|
version = "0.13.1"
|
||||||
@@ -842,6 +865,15 @@ version = "0.2.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df"
|
checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ilattice"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f3db9046391c0e0658a18e23877706d16e48cc8b4711702b9f703776410c2b84"
|
||||||
|
dependencies = [
|
||||||
|
"glam",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indexmap"
|
name = "indexmap"
|
||||||
version = "2.2.6"
|
version = "2.2.6"
|
||||||
@@ -859,7 +891,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97"
|
checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cesu8",
|
"cesu8",
|
||||||
"cfg-if",
|
"cfg-if 1.0.0",
|
||||||
"combine",
|
"combine",
|
||||||
"jni-sys",
|
"jni-sys",
|
||||||
"log",
|
"log",
|
||||||
@@ -921,7 +953,7 @@ version = "0.7.4"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f"
|
checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if 1.0.0",
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -931,7 +963,7 @@ 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 = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19"
|
checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if 1.0.0",
|
||||||
"windows-targets 0.52.5",
|
"windows-targets 0.52.5",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -1020,7 +1052,7 @@ dependencies = [
|
|||||||
"foreign-types",
|
"foreign-types",
|
||||||
"log",
|
"log",
|
||||||
"objc",
|
"objc",
|
||||||
"paste",
|
"paste 1.0.15",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1086,6 +1118,15 @@ dependencies = [
|
|||||||
"rawpointer",
|
"rawpointer",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ndcopy"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "24f4e41b81e3f7a4b742755be1bb368a6faafc43af555fe135c36b0efe095c59"
|
||||||
|
dependencies = [
|
||||||
|
"ndshape",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ndk"
|
name = "ndk"
|
||||||
version = "0.9.0"
|
version = "0.9.0"
|
||||||
@@ -1125,6 +1166,15 @@ dependencies = [
|
|||||||
"jni-sys",
|
"jni-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ndshape"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "975bce586ad637e27f6dc26ee907c07050686a588695bfd64b7873a9d48a700c"
|
||||||
|
dependencies = [
|
||||||
|
"static_assertions",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nonmax"
|
name = "nonmax"
|
||||||
version = "0.5.5"
|
version = "0.5.5"
|
||||||
@@ -1447,19 +1497,38 @@ version = "0.9.10"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
|
checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if 1.0.0",
|
||||||
"libc",
|
"libc",
|
||||||
"redox_syscall 0.5.1",
|
"redox_syscall 0.5.1",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"windows-targets 0.52.5",
|
"windows-targets 0.52.5",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "paste"
|
||||||
|
version = "0.1.18"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "45ca20c77d80be666aef2b45486da86238fabe33e38306bd3118fe4af33fa880"
|
||||||
|
dependencies = [
|
||||||
|
"paste-impl",
|
||||||
|
"proc-macro-hack",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "paste"
|
name = "paste"
|
||||||
version = "1.0.15"
|
version = "1.0.15"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
|
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "paste-impl"
|
||||||
|
version = "0.1.18"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d95a7db200b97ef370c8e6de0088252f7e0dfff7d047a28528e47456c0fc98b6"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro-hack",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "percent-encoding"
|
name = "percent-encoding"
|
||||||
version = "2.3.1"
|
version = "2.3.1"
|
||||||
@@ -1508,12 +1577,14 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"bevy_derive",
|
"bevy_derive",
|
||||||
"bevy_ecs",
|
"bevy_ecs",
|
||||||
|
"block-mesh",
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
"nalgebra",
|
"nalgebra",
|
||||||
"ndarray",
|
"ndarray",
|
||||||
"pollster",
|
"pollster",
|
||||||
"rand",
|
"rand",
|
||||||
"simba",
|
"simba",
|
||||||
|
"simdnoise",
|
||||||
"smaa",
|
"smaa",
|
||||||
"wgpu",
|
"wgpu",
|
||||||
"winit",
|
"winit",
|
||||||
@@ -1531,7 +1602,7 @@ version = "3.7.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "645493cf344456ef24219d02a768cf1fb92ddf8c92161679ae3d91b91a637be3"
|
checksum = "645493cf344456ef24219d02a768cf1fb92ddf8c92161679ae3d91b91a637be3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if 1.0.0",
|
||||||
"concurrent-queue",
|
"concurrent-queue",
|
||||||
"hermit-abi",
|
"hermit-abi",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
@@ -1576,6 +1647,12 @@ dependencies = [
|
|||||||
"toml_edit",
|
"toml_edit",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro-hack"
|
||||||
|
version = "0.5.20+deprecated"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.82"
|
version = "1.0.82"
|
||||||
@@ -1772,10 +1849,29 @@ dependencies = [
|
|||||||
"approx",
|
"approx",
|
||||||
"num-complex",
|
"num-complex",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
"paste",
|
"paste 1.0.15",
|
||||||
"wide",
|
"wide",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "simdeez"
|
||||||
|
version = "1.0.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f6ec898e1be717eee4b54a84ff2fc94ecb5a1b992d4ad148ce30575b45745662"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if 0.1.10",
|
||||||
|
"paste 0.1.18",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "simdnoise"
|
||||||
|
version = "3.1.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d9f69a3fa031fc2906ffe27aecc55bdd2c9cb95327c4695ea814a083145fa462"
|
||||||
|
dependencies = [
|
||||||
|
"simdeez",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "slab"
|
name = "slab"
|
||||||
version = "0.4.9"
|
version = "0.4.9"
|
||||||
@@ -1924,7 +2020,7 @@ version = "1.1.8"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c"
|
checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if 1.0.0",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -1937,7 +2033,7 @@ dependencies = [
|
|||||||
"arrayref",
|
"arrayref",
|
||||||
"arrayvec",
|
"arrayvec",
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
"cfg-if",
|
"cfg-if 1.0.0",
|
||||||
"log",
|
"log",
|
||||||
"tiny-skia-path",
|
"tiny-skia-path",
|
||||||
]
|
]
|
||||||
@@ -2069,7 +2165,7 @@ version = "0.2.92"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8"
|
checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if 1.0.0",
|
||||||
"wasm-bindgen-macro",
|
"wasm-bindgen-macro",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -2094,7 +2190,7 @@ version = "0.4.42"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0"
|
checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if 1.0.0",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
"web-sys",
|
"web-sys",
|
||||||
@@ -2275,7 +2371,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "90e37c7b9921b75dfd26dd973fdcbce36f13dfa6e2dc82aece584e0ed48c355c"
|
checksum = "90e37c7b9921b75dfd26dd973fdcbce36f13dfa6e2dc82aece584e0ed48c355c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrayvec",
|
"arrayvec",
|
||||||
"cfg-if",
|
"cfg-if 1.0.0",
|
||||||
"cfg_aliases 0.1.1",
|
"cfg_aliases 0.1.1",
|
||||||
"document-features",
|
"document-features",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
|
|||||||
@@ -15,8 +15,10 @@ ndarray = "0.15.6"
|
|||||||
pollster = "0.3"
|
pollster = "0.3"
|
||||||
rand = "0.8.5"
|
rand = "0.8.5"
|
||||||
simba = "0.8.1"
|
simba = "0.8.1"
|
||||||
|
simdnoise = "3.1.6"
|
||||||
smaa = "0.14.0"
|
smaa = "0.14.0"
|
||||||
wgpu = "0.20.1"
|
wgpu = "0.20.1"
|
||||||
bevy_ecs = "0.13.2"
|
bevy_ecs = "0.13.2"
|
||||||
bevy_derive = "0.13.2"
|
bevy_derive = "0.13.2"
|
||||||
winit = {version="0.30.1", features=["serde"]}
|
winit = {version="0.30.1", features=["serde"]}
|
||||||
|
block-mesh = "0.2.0"
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ use ndarray::Array3;
|
|||||||
use winit::{dpi::PhysicalPosition, keyboard::KeyCode as Key, window::CursorGrabMode};
|
use winit::{dpi::PhysicalPosition, keyboard::KeyCode as Key, window::CursorGrabMode};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
sync::ServerMessage,
|
common::ServerMessage,
|
||||||
world::component::{VoxelGrid, VoxelGridBundle},
|
common::component::{VoxelGrid, VoxelGridBundle},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{render::voxel::VoxelColor, Client};
|
use super::{render::voxel::VoxelColor, Client};
|
||||||
@@ -84,7 +84,7 @@ impl Client<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// camera position
|
// camera position
|
||||||
let move_dist = 10.0 * dt;
|
let move_dist = 2.0 * 16.0 * dt;
|
||||||
if input.pressed(Key::KeyW) {
|
if input.pressed(Key::KeyW) {
|
||||||
state.camera.pos += *state.camera.forward() * move_dist;
|
state.camera.pos += *state.camera.forward() * move_dist;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ use system::render::add_grid;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
server::Server,
|
server::Server,
|
||||||
sync::{ClientMessage, ServerHandle, ServerMessage},
|
common::{ClientMessage, ServerHandle, ServerMessage},
|
||||||
};
|
};
|
||||||
|
|
||||||
use self::{input::Input, render::Renderer, ClientState};
|
use self::{input::Input, render::Renderer, ClientState};
|
||||||
@@ -54,6 +54,7 @@ pub struct Client<'a> {
|
|||||||
pub struct ClientSystems {
|
pub struct ClientSystems {
|
||||||
render_add_grid: SystemId,
|
render_add_grid: SystemId,
|
||||||
render_update_transform: SystemId,
|
render_update_transform: SystemId,
|
||||||
|
render_add_chunk: SystemId,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Client<'_> {
|
impl Client<'_> {
|
||||||
@@ -70,7 +71,7 @@ impl Client<'_> {
|
|||||||
|
|
||||||
let state = ClientState::new();
|
let state = ClientState::new();
|
||||||
let server = ServerHandle::spawn(Server::start);
|
let server = ServerHandle::spawn(Server::start);
|
||||||
server.send(ServerMessage::LoadWorld);
|
server.send(ServerMessage::Join);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
window,
|
window,
|
||||||
@@ -85,6 +86,7 @@ impl Client<'_> {
|
|||||||
systems: ClientSystems {
|
systems: ClientSystems {
|
||||||
render_add_grid: world.register_system(add_grid),
|
render_add_grid: world.register_system(add_grid),
|
||||||
render_update_transform: world.register_system(system::render::update_transform),
|
render_update_transform: world.register_system(system::render::update_transform),
|
||||||
|
render_add_chunk: world.register_system(system::render::add_chunk),
|
||||||
},
|
},
|
||||||
world,
|
world,
|
||||||
server,
|
server,
|
||||||
@@ -110,6 +112,9 @@ impl Client<'_> {
|
|||||||
self.world
|
self.world
|
||||||
.run_system(self.systems.render_update_transform)
|
.run_system(self.systems.render_update_transform)
|
||||||
.expect("WHAT");
|
.expect("WHAT");
|
||||||
|
self.world
|
||||||
|
.run_system(self.systems.render_add_chunk)
|
||||||
|
.expect("WHAT v3");
|
||||||
self.world.clear_trackers();
|
self.world.clear_trackers();
|
||||||
|
|
||||||
if self.state.camera.pos.y < -10.0 {
|
if self.state.camera.pos.y < -10.0 {
|
||||||
@@ -129,8 +134,6 @@ impl Client<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if self.exit {
|
if self.exit {
|
||||||
self.server.send(ServerMessage::Stop);
|
|
||||||
self.server.join();
|
|
||||||
event_loop.exit();
|
event_loop.exit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -139,8 +142,12 @@ impl Client<'_> {
|
|||||||
for msg in self.server.recv() {
|
for msg in self.server.recv() {
|
||||||
match msg {
|
match msg {
|
||||||
ClientMessage::SpawnVoxelGrid(entity, grid) => {
|
ClientMessage::SpawnVoxelGrid(entity, grid) => {
|
||||||
let cid = self.world.spawn(grid).id();
|
let id = self.world.spawn(grid).id();
|
||||||
self.server_id_map.insert(entity, cid);
|
self.server_id_map.insert(entity, id);
|
||||||
|
}
|
||||||
|
ClientMessage::LoadChunk(entity, chunk) => {
|
||||||
|
let id = self.world.spawn(chunk).id();
|
||||||
|
self.server_id_map.insert(entity, id);
|
||||||
}
|
}
|
||||||
ClientMessage::PosUpdate(e, pos) => {
|
ClientMessage::PosUpdate(e, pos) => {
|
||||||
if let Some(id) = self.server_id_map.get(&e) {
|
if let Some(id) = self.server_id_map.get(&e) {
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
use crate::client::camera::Camera;
|
use crate::{
|
||||||
|
client::camera::Camera,
|
||||||
|
common::component::{ChunkMesh, ChunkPos},
|
||||||
|
};
|
||||||
|
|
||||||
use super::{voxel::VoxelColor, Renderer};
|
use super::{voxel::VoxelColor, Renderer};
|
||||||
use bevy_ecs::entity::Entity;
|
use bevy_ecs::entity::Entity;
|
||||||
@@ -10,6 +13,7 @@ use winit::window::Window;
|
|||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum RenderCommand {
|
pub enum RenderCommand {
|
||||||
CreateVoxelGrid(CreateVoxelGrid),
|
CreateVoxelGrid(CreateVoxelGrid),
|
||||||
|
AddChunk(AddChunk),
|
||||||
UpdateGridTransform(UpdateGridTransform),
|
UpdateGridTransform(UpdateGridTransform),
|
||||||
ViewUpdate(Camera),
|
ViewUpdate(Camera),
|
||||||
}
|
}
|
||||||
@@ -23,6 +27,13 @@ pub struct CreateVoxelGrid {
|
|||||||
pub grid: Array3<VoxelColor>,
|
pub grid: Array3<VoxelColor>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct AddChunk {
|
||||||
|
pub id: Entity,
|
||||||
|
pub pos: ChunkPos,
|
||||||
|
pub mesh: ChunkMesh,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct UpdateGridTransform {
|
pub struct UpdateGridTransform {
|
||||||
pub id: Entity,
|
pub id: Entity,
|
||||||
@@ -49,26 +60,28 @@ impl<'a> Renderer<'a> {
|
|||||||
let mut new_camera = false;
|
let mut new_camera = false;
|
||||||
for cmd in commands {
|
for cmd in commands {
|
||||||
match cmd {
|
match cmd {
|
||||||
RenderCommand::CreateVoxelGrid(desc) => {
|
RenderCommand::CreateVoxelGrid(desc) => self.voxel_pipeline.add_group(
|
||||||
self.voxel_pipeline.add_group(
|
|
||||||
&self.device,
|
&self.device,
|
||||||
&mut self.encoder,
|
&mut self.encoder,
|
||||||
&mut self.staging_belt,
|
&mut self.staging_belt,
|
||||||
desc,
|
desc,
|
||||||
);
|
),
|
||||||
}
|
|
||||||
RenderCommand::ViewUpdate(camera) => {
|
RenderCommand::ViewUpdate(camera) => {
|
||||||
new_camera = true;
|
new_camera = true;
|
||||||
self.camera = camera;
|
self.camera = camera;
|
||||||
}
|
}
|
||||||
RenderCommand::UpdateGridTransform(update) => {
|
RenderCommand::UpdateGridTransform(update) => self.voxel_pipeline.update_transform(
|
||||||
self.voxel_pipeline.update_transform(
|
|
||||||
&self.device,
|
&self.device,
|
||||||
&mut self.encoder,
|
&mut self.encoder,
|
||||||
&mut self.staging_belt,
|
&mut self.staging_belt,
|
||||||
update,
|
update,
|
||||||
);
|
),
|
||||||
}
|
RenderCommand::AddChunk(desc) => self.voxel_pipeline.add_chunk(
|
||||||
|
&self.device,
|
||||||
|
&mut self.encoder,
|
||||||
|
&mut self.staging_belt,
|
||||||
|
desc,
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if new_camera {
|
if new_camera {
|
||||||
|
|||||||
@@ -1,16 +1,14 @@
|
|||||||
mod command;
|
mod command;
|
||||||
mod util;
|
mod util;
|
||||||
pub mod voxel;
|
pub mod voxel;
|
||||||
pub mod voxel_poly;
|
|
||||||
|
|
||||||
pub use command::*;
|
pub use command::*;
|
||||||
use util::Texture;
|
|
||||||
|
|
||||||
use super::camera::Camera;
|
use super::camera::Camera;
|
||||||
use crate::client::rsc::CLEAR_COLOR;
|
use crate::client::rsc::CLEAR_COLOR;
|
||||||
use nalgebra::Vector2;
|
use nalgebra::Vector2;
|
||||||
use smaa::{SmaaMode, SmaaTarget};
|
use smaa::{SmaaMode, SmaaTarget};
|
||||||
use voxel_poly::VoxelPipeline;
|
use util::Texture;
|
||||||
|
use voxel::VoxelPipeline;
|
||||||
use winit::dpi::PhysicalSize;
|
use winit::dpi::PhysicalSize;
|
||||||
|
|
||||||
pub struct Renderer<'a> {
|
pub struct Renderer<'a> {
|
||||||
|
|||||||
@@ -1,239 +1,3 @@
|
|||||||
mod color;
|
mod poly;
|
||||||
mod grid;
|
// mod ray;
|
||||||
mod group;
|
pub use poly::*;
|
||||||
mod light;
|
|
||||||
mod view;
|
|
||||||
|
|
||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
use bevy_ecs::entity::Entity;
|
|
||||||
pub use color::*;
|
|
||||||
|
|
||||||
use light::GlobalLight;
|
|
||||||
use nalgebra::{Projective3, Transform3, Translation3, Vector2, Vector3};
|
|
||||||
|
|
||||||
use super::UpdateGridTransform;
|
|
||||||
use crate::client::{
|
|
||||||
camera::Camera,
|
|
||||||
render::{
|
|
||||||
util::{ArrBufUpdate, Storage, Uniform},
|
|
||||||
CreateVoxelGrid,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
use {group::VoxelGroup, view::View};
|
|
||||||
|
|
||||||
pub struct VoxelPipeline {
|
|
||||||
pipeline: wgpu::RenderPipeline,
|
|
||||||
view: Uniform<View>,
|
|
||||||
bind_group_layout: wgpu::BindGroupLayout,
|
|
||||||
bind_group: wgpu::BindGroup,
|
|
||||||
voxel_groups: Storage<VoxelGroup>,
|
|
||||||
voxels: Storage<VoxelColor>,
|
|
||||||
global_lights: Storage<GlobalLight>,
|
|
||||||
id_map: HashMap<Entity, (usize, VoxelGroup)>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl VoxelPipeline {
|
|
||||||
pub fn new(device: &wgpu::Device, format: &wgpu::TextureFormat) -> Self {
|
|
||||||
// shaders
|
|
||||||
let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
|
|
||||||
label: Some("Tile Shader"),
|
|
||||||
source: wgpu::ShaderSource::Wgsl(include_str!("shader.wgsl").into()),
|
|
||||||
});
|
|
||||||
|
|
||||||
let view = Uniform::init(device, "view", 0);
|
|
||||||
let voxels = Storage::init(device, "voxels", 1);
|
|
||||||
let voxel_groups = Storage::init(device, "voxel groups", 2);
|
|
||||||
let global_lights = Storage::init_with(
|
|
||||||
device,
|
|
||||||
"global lights",
|
|
||||||
3,
|
|
||||||
&[GlobalLight {
|
|
||||||
direction: Vector3::new(-0.5, -4.0, 2.0).normalize(),
|
|
||||||
}],
|
|
||||||
);
|
|
||||||
|
|
||||||
// bind groups
|
|
||||||
let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
|
||||||
entries: &[
|
|
||||||
view.bind_group_layout_entry(),
|
|
||||||
voxels.bind_group_layout_entry(),
|
|
||||||
voxel_groups.bind_group_layout_entry(),
|
|
||||||
global_lights.bind_group_layout_entry(),
|
|
||||||
],
|
|
||||||
label: Some("tile_bind_group_layout"),
|
|
||||||
});
|
|
||||||
|
|
||||||
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
|
|
||||||
layout: &bind_group_layout,
|
|
||||||
entries: &[
|
|
||||||
view.bind_group_entry(),
|
|
||||||
voxels.bind_group_entry(),
|
|
||||||
voxel_groups.bind_group_entry(),
|
|
||||||
global_lights.bind_group_entry(),
|
|
||||||
],
|
|
||||||
label: Some("tile_bind_group"),
|
|
||||||
});
|
|
||||||
|
|
||||||
// pipeline
|
|
||||||
let render_pipeline_layout =
|
|
||||||
device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
|
||||||
label: Some("Tile Pipeline Layout"),
|
|
||||||
bind_group_layouts: &[&bind_group_layout],
|
|
||||||
push_constant_ranges: &[],
|
|
||||||
});
|
|
||||||
|
|
||||||
let render_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
|
||||||
label: Some("Voxel Pipeline"),
|
|
||||||
layout: Some(&render_pipeline_layout),
|
|
||||||
vertex: wgpu::VertexState {
|
|
||||||
module: &shader,
|
|
||||||
entry_point: "vs_main",
|
|
||||||
buffers: &[],
|
|
||||||
compilation_options: wgpu::PipelineCompilationOptions::default(),
|
|
||||||
},
|
|
||||||
fragment: Some(wgpu::FragmentState {
|
|
||||||
module: &shader,
|
|
||||||
entry_point: "fs_main",
|
|
||||||
targets: &[Some(wgpu::ColorTargetState {
|
|
||||||
format: *format,
|
|
||||||
blend: Some(wgpu::BlendState::REPLACE),
|
|
||||||
write_mask: wgpu::ColorWrites::ALL,
|
|
||||||
})],
|
|
||||||
compilation_options: wgpu::PipelineCompilationOptions::default(),
|
|
||||||
}),
|
|
||||||
primitive: wgpu::PrimitiveState {
|
|
||||||
topology: wgpu::PrimitiveTopology::TriangleStrip,
|
|
||||||
strip_index_format: None,
|
|
||||||
front_face: wgpu::FrontFace::Ccw,
|
|
||||||
cull_mode: None,
|
|
||||||
polygon_mode: wgpu::PolygonMode::Fill,
|
|
||||||
unclipped_depth: false,
|
|
||||||
conservative: false,
|
|
||||||
},
|
|
||||||
depth_stencil: None,
|
|
||||||
multisample: wgpu::MultisampleState {
|
|
||||||
count: 1,
|
|
||||||
mask: !0,
|
|
||||||
alpha_to_coverage_enabled: true,
|
|
||||||
},
|
|
||||||
multiview: None,
|
|
||||||
});
|
|
||||||
|
|
||||||
Self {
|
|
||||||
pipeline: render_pipeline,
|
|
||||||
view,
|
|
||||||
bind_group,
|
|
||||||
bind_group_layout,
|
|
||||||
voxels,
|
|
||||||
voxel_groups,
|
|
||||||
global_lights,
|
|
||||||
id_map: HashMap::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_group(
|
|
||||||
&mut self,
|
|
||||||
device: &wgpu::Device,
|
|
||||||
encoder: &mut wgpu::CommandEncoder,
|
|
||||||
belt: &mut wgpu::util::StagingBelt,
|
|
||||||
CreateVoxelGrid {
|
|
||||||
id,
|
|
||||||
pos,
|
|
||||||
orientation,
|
|
||||||
dimensions,
|
|
||||||
grid,
|
|
||||||
}: CreateVoxelGrid,
|
|
||||||
) {
|
|
||||||
let offset = self.voxels.len();
|
|
||||||
|
|
||||||
let updates = [ArrBufUpdate {
|
|
||||||
offset,
|
|
||||||
data: &grid.as_slice().unwrap(),
|
|
||||||
}];
|
|
||||||
let size = offset + grid.len();
|
|
||||||
self.voxels.update(device, encoder, belt, size, &updates);
|
|
||||||
|
|
||||||
let proj = Projective3::identity()
|
|
||||||
* Translation3::from(pos)
|
|
||||||
* orientation
|
|
||||||
* Translation3::from(-dimensions.cast() / 2.0);
|
|
||||||
let group = VoxelGroup {
|
|
||||||
transform: proj,
|
|
||||||
transform_inv: proj.inverse(),
|
|
||||||
dimensions: dimensions.cast(),
|
|
||||||
offset: offset as u32,
|
|
||||||
};
|
|
||||||
let updates = [ArrBufUpdate {
|
|
||||||
offset: self.voxel_groups.len(),
|
|
||||||
data: &[group],
|
|
||||||
}];
|
|
||||||
let i = self.voxel_groups.len();
|
|
||||||
let size = i + 1;
|
|
||||||
self.voxel_groups
|
|
||||||
.update(device, encoder, belt, size, &updates);
|
|
||||||
|
|
||||||
self.id_map.insert(id, (i, group));
|
|
||||||
|
|
||||||
self.bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
|
|
||||||
layout: &self.bind_group_layout,
|
|
||||||
entries: &[
|
|
||||||
self.view.bind_group_entry(),
|
|
||||||
self.voxels.bind_group_entry(),
|
|
||||||
self.voxel_groups.bind_group_entry(),
|
|
||||||
self.global_lights.bind_group_entry(),
|
|
||||||
],
|
|
||||||
label: Some("tile_bind_group"),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn update_transform(
|
|
||||||
&mut self,
|
|
||||||
device: &wgpu::Device,
|
|
||||||
encoder: &mut wgpu::CommandEncoder,
|
|
||||||
belt: &mut wgpu::util::StagingBelt,
|
|
||||||
update: UpdateGridTransform,
|
|
||||||
) {
|
|
||||||
if let Some((i, group)) = self.id_map.get_mut(&update.id) {
|
|
||||||
let proj = Projective3::identity()
|
|
||||||
* Translation3::from(update.pos)
|
|
||||||
* update.orientation
|
|
||||||
* Translation3::from(-group.dimensions.cast() / 2.0);
|
|
||||||
group.transform = proj;
|
|
||||||
group.transform_inv = proj.inverse();
|
|
||||||
let updates = [ArrBufUpdate {
|
|
||||||
offset: *i,
|
|
||||||
data: &[*group],
|
|
||||||
}];
|
|
||||||
let size = self.voxel_groups.len();
|
|
||||||
self.voxel_groups
|
|
||||||
.update(device, encoder, belt, size, &updates);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn update_view(
|
|
||||||
&mut self,
|
|
||||||
device: &wgpu::Device,
|
|
||||||
encoder: &mut wgpu::CommandEncoder,
|
|
||||||
belt: &mut wgpu::util::StagingBelt,
|
|
||||||
size: Vector2<u32>,
|
|
||||||
camera: &Camera,
|
|
||||||
) {
|
|
||||||
let transform =
|
|
||||||
Transform3::identity() * Translation3::from(camera.pos) * camera.orientation;
|
|
||||||
let data = View {
|
|
||||||
width: size.x,
|
|
||||||
height: size.y,
|
|
||||||
zoom: camera.scale,
|
|
||||||
transform,
|
|
||||||
};
|
|
||||||
self.view.update(device, encoder, belt, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn draw<'a>(&'a self, render_pass: &mut wgpu::RenderPass<'a>) {
|
|
||||||
render_pass.set_pipeline(&self.pipeline);
|
|
||||||
render_pass.set_bind_group(0, &self.bind_group, &[]);
|
|
||||||
render_pass.draw(0..4, 0..1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
use block_mesh::Voxel;
|
||||||
use rand::distributions::{Distribution, Standard};
|
use rand::distributions::{Distribution, Standard};
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
@@ -46,3 +47,13 @@ impl Distribution<VoxelColor> for Standard {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl block_mesh::Voxel for VoxelColor {
|
||||||
|
fn get_visibility(&self) -> block_mesh::VoxelVisibility {
|
||||||
|
match self.a {
|
||||||
|
0 => block_mesh::VoxelVisibility::Empty,
|
||||||
|
255 => block_mesh::VoxelVisibility::Opaque,
|
||||||
|
_ => block_mesh::VoxelVisibility::Translucent,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
use bytemuck::Zeroable;
|
use bytemuck::Zeroable;
|
||||||
|
|
||||||
use crate::client::render::voxel::VoxelColor;
|
use super::VoxelColor;
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Copy, Clone, Debug, Zeroable)]
|
#[derive(Copy, Clone, Debug, Zeroable)]
|
||||||
@@ -1,21 +1,26 @@
|
|||||||
mod color;
|
mod color;
|
||||||
|
mod face;
|
||||||
mod group;
|
mod group;
|
||||||
mod instance;
|
mod light;
|
||||||
mod square;
|
|
||||||
mod view;
|
mod view;
|
||||||
|
|
||||||
use core::panic;
|
use block_mesh::{ndshape::RuntimeShape, UnitQuadBuffer, RIGHT_HANDED_Y_UP_CONFIG};
|
||||||
|
pub use color::*;
|
||||||
|
pub use face::*;
|
||||||
|
|
||||||
use group::FaceGroup;
|
use group::FaceGroup;
|
||||||
use instance::VoxelFace;
|
use light::GlobalLight;
|
||||||
use nalgebra::{Perspective3, Transform3, Translation3, Vector2, Vector3};
|
use nalgebra::{Perspective3, Transform3, Translation3, Vector2, Vector3};
|
||||||
use view::View;
|
use view::View;
|
||||||
use wgpu::{SurfaceConfiguration, VertexAttribute, VertexFormat};
|
use wgpu::{SurfaceConfiguration, VertexAttribute, VertexFormat};
|
||||||
|
|
||||||
use crate::client::camera::Camera;
|
use crate::{
|
||||||
|
client::{camera::Camera, render::AddChunk},
|
||||||
|
common::component::{chunk, ChunkData},
|
||||||
|
};
|
||||||
|
|
||||||
use super::{
|
use super::super::{
|
||||||
util::{Instances, Texture, Uniform},
|
util::{Instances, Storage, Texture, Uniform},
|
||||||
CreateVoxelGrid, UpdateGridTransform,
|
CreateVoxelGrid, UpdateGridTransform,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -25,6 +30,7 @@ pub struct VoxelPipeline {
|
|||||||
bind_group_layout: wgpu::BindGroupLayout,
|
bind_group_layout: wgpu::BindGroupLayout,
|
||||||
bind_groups: Vec<wgpu::BindGroup>,
|
bind_groups: Vec<wgpu::BindGroup>,
|
||||||
vertices: Vec<Instances<VoxelFace>>,
|
vertices: Vec<Instances<VoxelFace>>,
|
||||||
|
global_lights: Storage<GlobalLight>,
|
||||||
}
|
}
|
||||||
|
|
||||||
const INSTANCE_ATTRS: [wgpu::VertexAttribute; 2] = [
|
const INSTANCE_ATTRS: [wgpu::VertexAttribute; 2] = [
|
||||||
@@ -52,12 +58,21 @@ impl VoxelPipeline {
|
|||||||
let example_faces =
|
let example_faces =
|
||||||
Instances::<VoxelFace>::init(device, "voxel groups", 0, &INSTANCE_ATTRS);
|
Instances::<VoxelFace>::init(device, "voxel groups", 0, &INSTANCE_ATTRS);
|
||||||
let example_group = Uniform::<FaceGroup>::init(device, "voxel group", 1);
|
let example_group = Uniform::<FaceGroup>::init(device, "voxel group", 1);
|
||||||
|
let global_lights = Storage::init_with(
|
||||||
|
device,
|
||||||
|
"global lights",
|
||||||
|
3,
|
||||||
|
&[GlobalLight {
|
||||||
|
direction: Vector3::new(-0.5, -4.0, 2.0).normalize(),
|
||||||
|
}],
|
||||||
|
);
|
||||||
|
|
||||||
// bind groups
|
// bind groups
|
||||||
let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
||||||
entries: &[
|
entries: &[
|
||||||
view.bind_group_layout_entry(),
|
view.bind_group_layout_entry(),
|
||||||
example_group.bind_group_layout_entry(),
|
example_group.bind_group_layout_entry(),
|
||||||
|
global_lights.bind_group_layout_entry(),
|
||||||
],
|
],
|
||||||
label: Some("tile_bind_group_layout"),
|
label: Some("tile_bind_group_layout"),
|
||||||
});
|
});
|
||||||
@@ -84,7 +99,7 @@ impl VoxelPipeline {
|
|||||||
entry_point: "fs_main",
|
entry_point: "fs_main",
|
||||||
targets: &[Some(wgpu::ColorTargetState {
|
targets: &[Some(wgpu::ColorTargetState {
|
||||||
format: config.format,
|
format: config.format,
|
||||||
blend: Some(wgpu::BlendState::REPLACE),
|
blend: Some(wgpu::BlendState::ALPHA_BLENDING),
|
||||||
write_mask: wgpu::ColorWrites::ALL,
|
write_mask: wgpu::ColorWrites::ALL,
|
||||||
})],
|
})],
|
||||||
compilation_options: wgpu::PipelineCompilationOptions::default(),
|
compilation_options: wgpu::PipelineCompilationOptions::default(),
|
||||||
@@ -119,6 +134,7 @@ impl VoxelPipeline {
|
|||||||
bind_group_layout,
|
bind_group_layout,
|
||||||
bind_groups: Vec::new(),
|
bind_groups: Vec::new(),
|
||||||
vertices: Vec::new(),
|
vertices: Vec::new(),
|
||||||
|
global_lights,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,7 +154,7 @@ impl VoxelPipeline {
|
|||||||
size.x as f32 / size.y as f32,
|
size.x as f32 / size.y as f32,
|
||||||
std::f32::consts::PI / 2.0,
|
std::f32::consts::PI / 2.0,
|
||||||
0.1,
|
0.1,
|
||||||
1000.0,
|
10000.0,
|
||||||
);
|
);
|
||||||
transform = projection.as_matrix() * transform;
|
transform = projection.as_matrix() * transform;
|
||||||
let data = View {
|
let data = View {
|
||||||
@@ -177,46 +193,31 @@ impl VoxelPipeline {
|
|||||||
* Translation3::from(pos)
|
* Translation3::from(pos)
|
||||||
* orientation
|
* orientation
|
||||||
* Translation3::from(-dimensions.cast() / 2.0);
|
* Translation3::from(-dimensions.cast() / 2.0);
|
||||||
for face in 0..6 {
|
|
||||||
let group = FaceGroup {
|
|
||||||
dimensions: dimensions.cast(),
|
|
||||||
transform: proj,
|
|
||||||
face,
|
|
||||||
};
|
|
||||||
let uniform = Uniform::init_with(device, "voxel group", 1, &[group]);
|
|
||||||
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
|
|
||||||
layout: &self.bind_group_layout,
|
|
||||||
entries: &[self.view.bind_group_entry(), uniform.bind_group_entry()],
|
|
||||||
label: Some("voxel bind group"),
|
|
||||||
});
|
|
||||||
self.bind_groups.push(bind_group);
|
|
||||||
|
|
||||||
let mut data = Vec::new();
|
let mut buffer = UnitQuadBuffer::new();
|
||||||
let n_offset = match face % 3 {
|
let dim: Vector3<u32> = dimensions.cast();
|
||||||
0 => 1,
|
let dim = Vector3::new(dim.z, dim.y, dim.x);
|
||||||
1 => dimensions.z * dimensions.y,
|
let shape = RuntimeShape::<u32, 3>::new(dim.into());
|
||||||
2 => dimensions.z,
|
let slice = grid.as_slice().unwrap();
|
||||||
_ => 0,
|
block_mesh::visible_block_faces(
|
||||||
} as i32
|
slice,
|
||||||
* ((face as i32 / 3) * 2 - 1);
|
&shape,
|
||||||
let face_dir = (face as i32 / 3) * 2 - 1;
|
[0; 3],
|
||||||
for (i, ((x, y, z), color)) in grid.indexed_iter().enumerate() {
|
(dim - Vector3::new(1, 1, 1)).into(),
|
||||||
let neighbor = match face {
|
&RIGHT_HANDED_Y_UP_CONFIG.faces,
|
||||||
0 => if z > 0 {Some((x, y, z - 1))} else {None},
|
&mut buffer,
|
||||||
2 => if y > 0 {Some((x, y - 1, z))} else {None},
|
);
|
||||||
1 => if x > 0 {Some((x - 1, y, z))} else {None},
|
for (face, group) in buffer.groups.iter().enumerate() {
|
||||||
3 => if z < dimensions.z - 1 {Some((x, y, z + 1))} else {None},
|
let data: Vec<VoxelFace> = group
|
||||||
5 => if y < dimensions.y - 1 {Some((x, y + 1, z))} else {None},
|
.iter()
|
||||||
4 => if x < dimensions.x - 1 {Some((x + 1, y, z))} else {None},
|
.map(|a| {
|
||||||
_ => panic!("what"),
|
let i = a.minimum[0] + a.minimum[1] * dim.y + a.minimum[2] * dim.y * dim.x;
|
||||||
}.map(|p| grid.get(p).unwrap());
|
VoxelFace {
|
||||||
if color.a > 0 && !neighbor.is_some_and(|c| c.a == color.a) {
|
index: i,
|
||||||
data.push(VoxelFace {
|
color: slice[i as usize],
|
||||||
index: i as u32,
|
|
||||||
color: *color,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
self.vertices.push(Instances::init_with(
|
self.vertices.push(Instances::init_with(
|
||||||
device,
|
device,
|
||||||
"vvvvv",
|
"vvvvv",
|
||||||
@@ -224,6 +225,64 @@ impl VoxelPipeline {
|
|||||||
&INSTANCE_ATTRS,
|
&INSTANCE_ATTRS,
|
||||||
&data,
|
&data,
|
||||||
));
|
));
|
||||||
|
let group = FaceGroup {
|
||||||
|
dimensions: dimensions.cast(),
|
||||||
|
transform: proj,
|
||||||
|
face: ((8 - face) % 6) as u32,
|
||||||
|
};
|
||||||
|
let uniform = Uniform::init_with(device, "voxel group", 1, &[group]);
|
||||||
|
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||||
|
layout: &self.bind_group_layout,
|
||||||
|
entries: &[
|
||||||
|
self.view.bind_group_entry(),
|
||||||
|
uniform.bind_group_entry(),
|
||||||
|
self.global_lights.bind_group_entry(),
|
||||||
|
],
|
||||||
|
label: Some("voxel bind group"),
|
||||||
|
});
|
||||||
|
self.bind_groups.push(bind_group);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_chunk(
|
||||||
|
&mut self,
|
||||||
|
device: &wgpu::Device,
|
||||||
|
encoder: &mut wgpu::CommandEncoder,
|
||||||
|
belt: &mut wgpu::util::StagingBelt,
|
||||||
|
AddChunk { id, pos, mesh }: AddChunk,
|
||||||
|
) {
|
||||||
|
if mesh.faces.iter().all(|f| f.is_empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let proj = Transform3::identity()
|
||||||
|
* Translation3::from(pos.cast() * crate::common::component::chunk::SIDE_LENGTH as f32)
|
||||||
|
* Translation3::from(-chunk::DIMENSIONS.cast() / 2.0);
|
||||||
|
|
||||||
|
for (face, meshes) in mesh.faces.iter().enumerate() {
|
||||||
|
self.vertices.push(Instances::init_with(
|
||||||
|
device,
|
||||||
|
"vvvvv",
|
||||||
|
0,
|
||||||
|
&INSTANCE_ATTRS,
|
||||||
|
meshes,
|
||||||
|
));
|
||||||
|
let group = FaceGroup {
|
||||||
|
dimensions: chunk::DIMENSIONS.cast(),
|
||||||
|
transform: proj,
|
||||||
|
face: face as u32,
|
||||||
|
};
|
||||||
|
let uniform = Uniform::init_with(device, "voxel group", 1, &[group]);
|
||||||
|
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||||
|
layout: &self.bind_group_layout,
|
||||||
|
entries: &[
|
||||||
|
self.view.bind_group_entry(),
|
||||||
|
uniform.bind_group_entry(),
|
||||||
|
self.global_lights.bind_group_entry(),
|
||||||
|
],
|
||||||
|
label: Some("voxel bind group"),
|
||||||
|
});
|
||||||
|
self.bind_groups.push(bind_group);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -8,6 +8,7 @@ struct InstanceInput {
|
|||||||
struct VertexOutput {
|
struct VertexOutput {
|
||||||
@builtin(position) clip_position: vec4<f32>,
|
@builtin(position) clip_position: vec4<f32>,
|
||||||
@location(0) color: vec4<f32>,
|
@location(0) color: vec4<f32>,
|
||||||
|
@location(1) normal: vec3<f32>,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct VoxelFace {
|
struct VoxelFace {
|
||||||
@@ -28,16 +29,16 @@ struct VoxelGroup {
|
|||||||
face: u32,
|
face: u32,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct GlobalLight {
|
||||||
|
dir: vec3<f32>,
|
||||||
|
};
|
||||||
|
|
||||||
@group(0) @binding(0)
|
@group(0) @binding(0)
|
||||||
var<uniform> view: View;
|
var<uniform> view: View;
|
||||||
@group(0) @binding(1)
|
@group(0) @binding(1)
|
||||||
var<uniform> group: VoxelGroup;
|
var<uniform> group: VoxelGroup;
|
||||||
|
@group(0) @binding(3)
|
||||||
const DIRECTIONS = array(
|
var<storage, read> global_lights: array<GlobalLight>;
|
||||||
vec3<f32>(1.0, 1.0, 0.0),
|
|
||||||
vec3<f32>(0.0, 1.0, 1.0),
|
|
||||||
vec3<f32>(1.0, 0.0, 1.0),
|
|
||||||
);
|
|
||||||
|
|
||||||
@vertex
|
@vertex
|
||||||
fn vs_main(
|
fn vs_main(
|
||||||
@@ -48,14 +49,23 @@ fn vs_main(
|
|||||||
|
|
||||||
let invert = select(0.0, 1.0, group.face / 3 == 1);
|
let invert = select(0.0, 1.0, group.face / 3 == 1);
|
||||||
let invert_mult = 1.0 - invert * 2.0;
|
let invert_mult = 1.0 - invert * 2.0;
|
||||||
|
let face_axis = group.face % 3;
|
||||||
var square_pos = vec2<f32>(
|
var square_pos = vec2<f32>(
|
||||||
f32(vi % 2u),
|
f32(vi % 2u),
|
||||||
invert + invert_mult * f32(vi / 2u),
|
invert + invert_mult * f32(vi / 2u),
|
||||||
);
|
);
|
||||||
var cube_pos = vec3<f32>(invert);
|
var cube_pos = vec3<f32>(invert);
|
||||||
square_pos *= invert_mult;
|
square_pos *= invert_mult;
|
||||||
cube_pos[(group.face) % 3] += square_pos.x;
|
cube_pos[(group.face + 1) % 3] += square_pos.x;
|
||||||
cube_pos[(group.face + 1) % 3] += square_pos.y;
|
cube_pos[(group.face + 2) % 3] += square_pos.y;
|
||||||
|
|
||||||
|
let cube_normal = invert_mult * vec3<f32>(
|
||||||
|
f32(face_axis == 0),
|
||||||
|
f32(face_axis % 2),
|
||||||
|
f32(face_axis / 2),
|
||||||
|
);
|
||||||
|
out.normal = (group.transform * vec4<f32>(cube_normal, 0.0)).xyz;
|
||||||
|
|
||||||
var pos = vec4<f32>(
|
var pos = vec4<f32>(
|
||||||
cube_pos,
|
cube_pos,
|
||||||
1.0,
|
1.0,
|
||||||
@@ -78,5 +88,9 @@ fn vs_main(
|
|||||||
fn fs_main(
|
fn fs_main(
|
||||||
in: VertexOutput,
|
in: VertexOutput,
|
||||||
) -> @location(0) vec4<f32> {
|
) -> @location(0) vec4<f32> {
|
||||||
return in.color;
|
let diffuse = max(dot(global_lights[0].dir, in.normal) + 0.1, 0.0);
|
||||||
|
let ambient = 0.2;
|
||||||
|
let lighting = max(diffuse, ambient);
|
||||||
|
let new_rgb = min(in.color.xyz * lighting, vec3<f32>(1.0));
|
||||||
|
return vec4<f32>(new_rgb, in.color.a);
|
||||||
}
|
}
|
||||||
9
src/client/render/voxel/ray/light.rs
Normal file
9
src/client/render/voxel/ray/light.rs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
use nalgebra::Vector3;
|
||||||
|
|
||||||
|
#[repr(C, align(16))]
|
||||||
|
#[derive(Clone, Copy, PartialEq, bytemuck::Zeroable)]
|
||||||
|
pub struct GlobalLight {
|
||||||
|
pub direction: Vector3<f32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl bytemuck::Pod for GlobalLight {}
|
||||||
237
src/client/render/voxel/ray/mod.rs
Normal file
237
src/client/render/voxel/ray/mod.rs
Normal file
@@ -0,0 +1,237 @@
|
|||||||
|
mod color;
|
||||||
|
mod grid;
|
||||||
|
mod group;
|
||||||
|
mod light;
|
||||||
|
mod view;
|
||||||
|
|
||||||
|
pub use color::*;
|
||||||
|
|
||||||
|
use super::super::UpdateGridTransform;
|
||||||
|
use crate::client::{
|
||||||
|
camera::Camera,
|
||||||
|
render::{
|
||||||
|
util::{ArrBufUpdate, Storage, Uniform},
|
||||||
|
CreateVoxelGrid,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
use bevy_ecs::entity::Entity;
|
||||||
|
use light::GlobalLight;
|
||||||
|
use nalgebra::{Projective3, Transform3, Translation3, Vector2, Vector3};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use {group::VoxelGroup, view::View};
|
||||||
|
|
||||||
|
pub struct VoxelPipeline {
|
||||||
|
pipeline: wgpu::RenderPipeline,
|
||||||
|
view: Uniform<View>,
|
||||||
|
bind_group_layout: wgpu::BindGroupLayout,
|
||||||
|
bind_group: wgpu::BindGroup,
|
||||||
|
voxel_groups: Storage<VoxelGroup>,
|
||||||
|
voxels: Storage<VoxelColor>,
|
||||||
|
global_lights: Storage<GlobalLight>,
|
||||||
|
id_map: HashMap<Entity, (usize, VoxelGroup)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VoxelPipeline {
|
||||||
|
pub fn new(device: &wgpu::Device, format: &wgpu::TextureFormat) -> Self {
|
||||||
|
// shaders
|
||||||
|
let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
|
||||||
|
label: Some("Tile Shader"),
|
||||||
|
source: wgpu::ShaderSource::Wgsl(include_str!("shader.wgsl").into()),
|
||||||
|
});
|
||||||
|
|
||||||
|
let view = Uniform::init(device, "view", 0);
|
||||||
|
let voxels = Storage::init(device, "voxels", 1);
|
||||||
|
let voxel_groups = Storage::init(device, "voxel groups", 2);
|
||||||
|
let global_lights = Storage::init_with(
|
||||||
|
device,
|
||||||
|
"global lights",
|
||||||
|
3,
|
||||||
|
&[GlobalLight {
|
||||||
|
direction: Vector3::new(-0.5, -4.0, 2.0).normalize(),
|
||||||
|
}],
|
||||||
|
);
|
||||||
|
|
||||||
|
// bind groups
|
||||||
|
let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
||||||
|
entries: &[
|
||||||
|
view.bind_group_layout_entry(),
|
||||||
|
voxels.bind_group_layout_entry(),
|
||||||
|
voxel_groups.bind_group_layout_entry(),
|
||||||
|
global_lights.bind_group_layout_entry(),
|
||||||
|
],
|
||||||
|
label: Some("tile_bind_group_layout"),
|
||||||
|
});
|
||||||
|
|
||||||
|
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||||
|
layout: &bind_group_layout,
|
||||||
|
entries: &[
|
||||||
|
view.bind_group_entry(),
|
||||||
|
voxels.bind_group_entry(),
|
||||||
|
voxel_groups.bind_group_entry(),
|
||||||
|
global_lights.bind_group_entry(),
|
||||||
|
],
|
||||||
|
label: Some("tile_bind_group"),
|
||||||
|
});
|
||||||
|
|
||||||
|
// pipeline
|
||||||
|
let render_pipeline_layout =
|
||||||
|
device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
||||||
|
label: Some("Tile Pipeline Layout"),
|
||||||
|
bind_group_layouts: &[&bind_group_layout],
|
||||||
|
push_constant_ranges: &[],
|
||||||
|
});
|
||||||
|
|
||||||
|
let render_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
||||||
|
label: Some("Voxel Pipeline"),
|
||||||
|
layout: Some(&render_pipeline_layout),
|
||||||
|
vertex: wgpu::VertexState {
|
||||||
|
module: &shader,
|
||||||
|
entry_point: "vs_main",
|
||||||
|
buffers: &[],
|
||||||
|
compilation_options: wgpu::PipelineCompilationOptions::default(),
|
||||||
|
},
|
||||||
|
fragment: Some(wgpu::FragmentState {
|
||||||
|
module: &shader,
|
||||||
|
entry_point: "fs_main",
|
||||||
|
targets: &[Some(wgpu::ColorTargetState {
|
||||||
|
format: *format,
|
||||||
|
blend: Some(wgpu::BlendState::REPLACE),
|
||||||
|
write_mask: wgpu::ColorWrites::ALL,
|
||||||
|
})],
|
||||||
|
compilation_options: wgpu::PipelineCompilationOptions::default(),
|
||||||
|
}),
|
||||||
|
primitive: wgpu::PrimitiveState {
|
||||||
|
topology: wgpu::PrimitiveTopology::TriangleStrip,
|
||||||
|
strip_index_format: None,
|
||||||
|
front_face: wgpu::FrontFace::Ccw,
|
||||||
|
cull_mode: None,
|
||||||
|
polygon_mode: wgpu::PolygonMode::Fill,
|
||||||
|
unclipped_depth: false,
|
||||||
|
conservative: false,
|
||||||
|
},
|
||||||
|
depth_stencil: None,
|
||||||
|
multisample: wgpu::MultisampleState {
|
||||||
|
count: 1,
|
||||||
|
mask: !0,
|
||||||
|
alpha_to_coverage_enabled: true,
|
||||||
|
},
|
||||||
|
multiview: None,
|
||||||
|
});
|
||||||
|
|
||||||
|
Self {
|
||||||
|
pipeline: render_pipeline,
|
||||||
|
view,
|
||||||
|
bind_group,
|
||||||
|
bind_group_layout,
|
||||||
|
voxels,
|
||||||
|
voxel_groups,
|
||||||
|
global_lights,
|
||||||
|
id_map: HashMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_group(
|
||||||
|
&mut self,
|
||||||
|
device: &wgpu::Device,
|
||||||
|
encoder: &mut wgpu::CommandEncoder,
|
||||||
|
belt: &mut wgpu::util::StagingBelt,
|
||||||
|
CreateVoxelGrid {
|
||||||
|
id,
|
||||||
|
pos,
|
||||||
|
orientation,
|
||||||
|
dimensions,
|
||||||
|
grid,
|
||||||
|
}: CreateVoxelGrid,
|
||||||
|
) {
|
||||||
|
let offset = self.voxels.len();
|
||||||
|
|
||||||
|
let updates = [ArrBufUpdate {
|
||||||
|
offset,
|
||||||
|
data: &grid.as_slice().unwrap(),
|
||||||
|
}];
|
||||||
|
let size = offset + grid.len();
|
||||||
|
self.voxels.update(device, encoder, belt, size, &updates);
|
||||||
|
|
||||||
|
let proj = Projective3::identity()
|
||||||
|
* Translation3::from(pos)
|
||||||
|
* orientation
|
||||||
|
* Translation3::from(-dimensions.cast() / 2.0);
|
||||||
|
let group = VoxelGroup {
|
||||||
|
transform: proj,
|
||||||
|
transform_inv: proj.inverse(),
|
||||||
|
dimensions: dimensions.cast(),
|
||||||
|
offset: offset as u32,
|
||||||
|
};
|
||||||
|
let updates = [ArrBufUpdate {
|
||||||
|
offset: self.voxel_groups.len(),
|
||||||
|
data: &[group],
|
||||||
|
}];
|
||||||
|
let i = self.voxel_groups.len();
|
||||||
|
let size = i + 1;
|
||||||
|
self.voxel_groups
|
||||||
|
.update(device, encoder, belt, size, &updates);
|
||||||
|
|
||||||
|
self.id_map.insert(id, (i, group));
|
||||||
|
|
||||||
|
self.bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||||
|
layout: &self.bind_group_layout,
|
||||||
|
entries: &[
|
||||||
|
self.view.bind_group_entry(),
|
||||||
|
self.voxels.bind_group_entry(),
|
||||||
|
self.voxel_groups.bind_group_entry(),
|
||||||
|
self.global_lights.bind_group_entry(),
|
||||||
|
],
|
||||||
|
label: Some("tile_bind_group"),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update_transform(
|
||||||
|
&mut self,
|
||||||
|
device: &wgpu::Device,
|
||||||
|
encoder: &mut wgpu::CommandEncoder,
|
||||||
|
belt: &mut wgpu::util::StagingBelt,
|
||||||
|
update: UpdateGridTransform,
|
||||||
|
) {
|
||||||
|
if let Some((i, group)) = self.id_map.get_mut(&update.id) {
|
||||||
|
let proj = Projective3::identity()
|
||||||
|
* Translation3::from(update.pos)
|
||||||
|
* update.orientation
|
||||||
|
* Translation3::from(-group.dimensions.cast() / 2.0);
|
||||||
|
group.transform = proj;
|
||||||
|
group.transform_inv = proj.inverse();
|
||||||
|
let updates = [ArrBufUpdate {
|
||||||
|
offset: *i,
|
||||||
|
data: &[*group],
|
||||||
|
}];
|
||||||
|
let size = self.voxel_groups.len();
|
||||||
|
self.voxel_groups
|
||||||
|
.update(device, encoder, belt, size, &updates);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update_view(
|
||||||
|
&mut self,
|
||||||
|
device: &wgpu::Device,
|
||||||
|
encoder: &mut wgpu::CommandEncoder,
|
||||||
|
belt: &mut wgpu::util::StagingBelt,
|
||||||
|
size: Vector2<u32>,
|
||||||
|
camera: &Camera,
|
||||||
|
) {
|
||||||
|
let transform =
|
||||||
|
Transform3::identity() * Translation3::from(camera.pos) * camera.orientation;
|
||||||
|
let data = View {
|
||||||
|
width: size.x,
|
||||||
|
height: size.y,
|
||||||
|
zoom: camera.scale,
|
||||||
|
transform,
|
||||||
|
};
|
||||||
|
self.view.update(device, encoder, belt, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn draw<'a>(&'a self, render_pass: &mut wgpu::RenderPass<'a>) {
|
||||||
|
render_pass.set_pipeline(&self.pipeline);
|
||||||
|
render_pass.set_bind_group(0, &self.bind_group, &[]);
|
||||||
|
render_pass.draw(0..4, 0..1);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,9 +4,9 @@ pub const FPS: u32 = 60;
|
|||||||
pub const FRAME_TIME: Duration = Duration::from_millis(1000 / FPS as u64);
|
pub const FRAME_TIME: Duration = Duration::from_millis(1000 / FPS as u64);
|
||||||
|
|
||||||
pub const CLEAR_COLOR: wgpu::Color = wgpu::Color {
|
pub const CLEAR_COLOR: wgpu::Color = wgpu::Color {
|
||||||
r: 0.1,
|
r: 0.5,
|
||||||
g: 0.1,
|
g: 0.8,
|
||||||
b: 0.1,
|
b: 1.0,
|
||||||
a: 1.0,
|
a: 1.0,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -5,15 +5,15 @@ use bevy_ecs::{
|
|||||||
query::{Added, Changed, Or},
|
query::{Added, Changed, Or},
|
||||||
system::{Query, ResMut},
|
system::{Query, ResMut},
|
||||||
};
|
};
|
||||||
use nalgebra::Vector3;
|
use nalgebra::{AbstractRotation, Rotation3, Vector3};
|
||||||
use ndarray::Axis;
|
use ndarray::{Array3, Axis};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
client::{
|
client::{
|
||||||
component::RenderCommands,
|
component::RenderCommands,
|
||||||
render::{CreateVoxelGrid, RenderCommand, UpdateGridTransform},
|
render::{voxel::VoxelColor, AddChunk, CreateVoxelGrid, RenderCommand, UpdateGridTransform},
|
||||||
},
|
},
|
||||||
world::component::{Orientation, Pos, VoxelGrid},
|
common::component::{ChunkData, ChunkMesh, ChunkPos, Orientation, Pos, VoxelGrid},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn add_grid(
|
pub fn add_grid(
|
||||||
@@ -24,16 +24,21 @@ pub fn add_grid(
|
|||||||
mut renderer: ResMut<RenderCommands>,
|
mut renderer: ResMut<RenderCommands>,
|
||||||
) {
|
) {
|
||||||
for (id, pos, orientation, grid) in query.iter() {
|
for (id, pos, orientation, grid) in query.iter() {
|
||||||
|
let dims = Vector3::new(
|
||||||
|
grid.len_of(Axis(0)) + 2,
|
||||||
|
grid.len_of(Axis(1)) + 2,
|
||||||
|
grid.len_of(Axis(2)) + 2,
|
||||||
|
);
|
||||||
|
let mut padded = Array3::from_elem((dims.x, dims.y, dims.z), VoxelColor::none());
|
||||||
|
padded
|
||||||
|
.slice_mut(ndarray::s![1..dims.x - 1, 1..dims.y - 1, 1..dims.z - 1])
|
||||||
|
.assign(grid);
|
||||||
renderer.push(RenderCommand::CreateVoxelGrid(CreateVoxelGrid {
|
renderer.push(RenderCommand::CreateVoxelGrid(CreateVoxelGrid {
|
||||||
id,
|
id,
|
||||||
pos: **pos,
|
pos: **pos,
|
||||||
orientation: **orientation,
|
orientation: **orientation,
|
||||||
dimensions: Vector3::new(
|
dimensions: dims,
|
||||||
grid.len_of(Axis(0)),
|
grid: padded,
|
||||||
grid.len_of(Axis(1)),
|
|
||||||
grid.len_of(Axis(2)),
|
|
||||||
),
|
|
||||||
grid: grid.deref().clone(),
|
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -50,3 +55,16 @@ pub fn update_transform(
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn add_chunk(
|
||||||
|
query: Query<(Entity, &ChunkPos, &ChunkMesh), Or<(Added<ChunkPos>, Added<ChunkMesh>)>>,
|
||||||
|
mut renderer: ResMut<RenderCommands>,
|
||||||
|
) {
|
||||||
|
for (id, pos, mesh) in query.iter() {
|
||||||
|
renderer.push(RenderCommand::AddChunk(AddChunk {
|
||||||
|
id,
|
||||||
|
pos: *pos,
|
||||||
|
mesh: mesh.clone()
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
124
src/common/component/chunk.rs
Normal file
124
src/common/component/chunk.rs
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
use std::collections::{HashMap, HashSet};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
client::render::voxel::{VoxelColor, VoxelFace},
|
||||||
|
util::oct_tree::OctTree,
|
||||||
|
};
|
||||||
|
use bevy_derive::{Deref, DerefMut};
|
||||||
|
use bevy_ecs::{bundle::Bundle, component::Component, entity::Entity, system::Resource};
|
||||||
|
use block_mesh::{ndshape::RuntimeShape, UnitQuadBuffer, RIGHT_HANDED_Y_UP_CONFIG};
|
||||||
|
use nalgebra::Vector3;
|
||||||
|
use ndarray::{s, Array3, Axis};
|
||||||
|
|
||||||
|
pub const SIDE_LENGTH: usize = 16 * 16;
|
||||||
|
pub const SHAPE: (usize, usize, usize) = (SIDE_LENGTH, SIDE_LENGTH, SIDE_LENGTH);
|
||||||
|
pub const DIMENSIONS: Vector3<usize> = Vector3::new(SIDE_LENGTH, SIDE_LENGTH, SIDE_LENGTH);
|
||||||
|
pub const LEN: usize = SHAPE.0 * SHAPE.1 * SHAPE.2;
|
||||||
|
|
||||||
|
#[derive(Debug, Component, Clone, Deref, DerefMut)]
|
||||||
|
pub struct ChunkData {
|
||||||
|
#[deref]
|
||||||
|
data: OctTree<VoxelColor>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ChunkData {
|
||||||
|
pub fn empty() -> Self {
|
||||||
|
Self {
|
||||||
|
data: OctTree::Leaf(VoxelColor::none()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_tree(t: OctTree<VoxelColor>) -> Self {
|
||||||
|
Self { data: t }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Component, Default, Deref, DerefMut)]
|
||||||
|
pub struct ChunkPos(pub Vector3<i32>);
|
||||||
|
impl ChunkPos {
|
||||||
|
pub fn new(x: i32, y: i32, z: i32) -> Self {
|
||||||
|
Self(Vector3::new(x, y, z))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl From<Vector3<i32>> for ChunkPos {
|
||||||
|
fn from(val: Vector3<i32>) -> Self {
|
||||||
|
ChunkPos(val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Component)]
|
||||||
|
pub struct ChunkMesh {
|
||||||
|
pub faces: [Vec<VoxelFace>; 6],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ChunkMesh {
|
||||||
|
pub fn from_data(data: &Array3<VoxelColor>) -> Self {
|
||||||
|
let dim_pad = Vector3::new(
|
||||||
|
data.len_of(Axis(0)) as u32,
|
||||||
|
data.len_of(Axis(1)) as u32,
|
||||||
|
data.len_of(Axis(2)) as u32,
|
||||||
|
);
|
||||||
|
let dim = dim_pad - Vector3::from_element(2);
|
||||||
|
let mut buffer = UnitQuadBuffer::new();
|
||||||
|
let shape = RuntimeShape::<u32, 3>::new(dim_pad.into());
|
||||||
|
let slice = data.as_slice().unwrap();
|
||||||
|
block_mesh::visible_block_faces(
|
||||||
|
slice,
|
||||||
|
&shape,
|
||||||
|
[0; 3],
|
||||||
|
(dim_pad - Vector3::new(1, 1, 1)).into(),
|
||||||
|
&RIGHT_HANDED_Y_UP_CONFIG.faces,
|
||||||
|
&mut buffer,
|
||||||
|
);
|
||||||
|
let faces = [2, 1, 0, 5, 4, 3].map(|f| {
|
||||||
|
buffer.groups[f]
|
||||||
|
.iter()
|
||||||
|
.map(|a| {
|
||||||
|
let i = (a.minimum[0]-1) + (a.minimum[1]-1) * dim.y + (a.minimum[2]-1) * dim.y * dim.x;
|
||||||
|
let i_pad = a.minimum[0] + a.minimum[1] * dim_pad.y + a.minimum[2] * dim_pad.y * dim_pad.x;
|
||||||
|
VoxelFace {
|
||||||
|
index: i,
|
||||||
|
color: slice[i_pad as usize],
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
});
|
||||||
|
Self { faces }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Component, Deref, DerefMut)]
|
||||||
|
pub struct LoadedChunks {
|
||||||
|
loaded: HashSet<ChunkPos>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LoadedChunks {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
loaded: HashSet::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Resource, Deref, DerefMut)]
|
||||||
|
pub struct ChunkMap {
|
||||||
|
#[deref]
|
||||||
|
map: HashMap<ChunkPos, Entity>,
|
||||||
|
pub generating: HashSet<ChunkPos>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ChunkMap {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
map: HashMap::new(),
|
||||||
|
generating: HashSet::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Bundle, Clone)]
|
||||||
|
pub struct ChunkBundle {
|
||||||
|
pub pos: ChunkPos,
|
||||||
|
pub data: ChunkData,
|
||||||
|
pub mesh: ChunkMesh,
|
||||||
|
}
|
||||||
@@ -1,19 +1,9 @@
|
|||||||
|
use crate::client::render::voxel::VoxelColor;
|
||||||
|
use bevy_ecs::{bundle::Bundle, component::Component};
|
||||||
|
use ndarray::{Array3, ArrayBase, Dim, SliceArg};
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
|
|
||||||
use bevy_derive::{Deref, DerefMut};
|
use super::{Orientation, Pos};
|
||||||
use bevy_ecs::{bundle::Bundle, component::Component};
|
|
||||||
use nalgebra::{Rotation3, Vector3};
|
|
||||||
use ndarray::{Array3, ArrayBase, Dim, SliceArg};
|
|
||||||
|
|
||||||
use crate::client::render::voxel::VoxelColor;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Component, Default)]
|
|
||||||
pub struct Synced;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Component, Default, Deref, DerefMut)]
|
|
||||||
pub struct Pos(pub Vector3<f32>);
|
|
||||||
#[derive(Debug, Clone, Copy, Component, Default, Deref, DerefMut)]
|
|
||||||
pub struct Orientation(pub Rotation3<f32>);
|
|
||||||
|
|
||||||
pub type VoxelGrid = TrackedGrid<VoxelColor>;
|
pub type VoxelGrid = TrackedGrid<VoxelColor>;
|
||||||
pub type GridRegion = (Range<usize>, Range<usize>, Range<usize>);
|
pub type GridRegion = (Range<usize>, Range<usize>, Range<usize>);
|
||||||
@@ -41,27 +31,10 @@ impl<T> TrackedGrid<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Pos {
|
impl<T> std::ops::Deref for TrackedGrid<T> {
|
||||||
pub fn new(x: f32, y: f32, z: f32) -> Self {
|
type Target = Array3<T>;
|
||||||
Self(Vector3::new(x, y, z))
|
fn deref(&self) -> &Self::Target {
|
||||||
}
|
&self.data
|
||||||
}
|
|
||||||
impl Orientation {
|
|
||||||
pub fn from_axis_angle<SB: nalgebra::Storage<f32, nalgebra::Const<3>>>(
|
|
||||||
axis: &nalgebra::Unit<nalgebra::Matrix<f32, nalgebra::Const<3>, nalgebra::Const<1>, SB>>,
|
|
||||||
angle: f32,
|
|
||||||
) -> Self {
|
|
||||||
Self(Rotation3::from_axis_angle(axis, angle))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl From<Vector3<f32>> for Pos {
|
|
||||||
fn from(val: Vector3<f32>) -> Self {
|
|
||||||
Pos(val)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl From<Rotation3<f32>> for Orientation {
|
|
||||||
fn from(val: Rotation3<f32>) -> Self {
|
|
||||||
Orientation(val)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,10 +44,3 @@ pub struct VoxelGridBundle {
|
|||||||
pub orientation: Orientation,
|
pub orientation: Orientation,
|
||||||
pub grid: VoxelGrid,
|
pub grid: VoxelGrid,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> std::ops::Deref for TrackedGrid<T> {
|
|
||||||
type Target = Array3<T>;
|
|
||||||
fn deref(&self) -> &Self::Target {
|
|
||||||
&self.data
|
|
||||||
}
|
|
||||||
}
|
|
||||||
62
src/common/component/mod.rs
Normal file
62
src/common/component/mod.rs
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
pub mod chunk;
|
||||||
|
mod grid;
|
||||||
|
|
||||||
|
use chunk::LoadedChunks;
|
||||||
|
pub use chunk::{ChunkBundle, ChunkData, ChunkMap, ChunkMesh, ChunkPos};
|
||||||
|
pub use grid::*;
|
||||||
|
|
||||||
|
use bevy_derive::{Deref, DerefMut};
|
||||||
|
use bevy_ecs::{bundle::Bundle, component::Component};
|
||||||
|
use nalgebra::{Rotation3, Vector3};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, Component, Default, Deref, DerefMut)]
|
||||||
|
pub struct Pos(pub Vector3<f32>);
|
||||||
|
|
||||||
|
impl Pos {
|
||||||
|
pub fn new(x: f32, y: f32, z: f32) -> Self {
|
||||||
|
Self(Vector3::new(x, y, z))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl From<Vector3<f32>> for Pos {
|
||||||
|
fn from(val: Vector3<f32>) -> Self {
|
||||||
|
Pos(val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, Component, Default, Deref, DerefMut)]
|
||||||
|
pub struct Orientation(pub Rotation3<f32>);
|
||||||
|
impl Orientation {
|
||||||
|
pub fn from_axis_angle<SB: nalgebra::Storage<f32, nalgebra::Const<3>>>(
|
||||||
|
axis: &nalgebra::Unit<nalgebra::Matrix<f32, nalgebra::Const<3>, nalgebra::Const<1>, SB>>,
|
||||||
|
angle: f32,
|
||||||
|
) -> Self {
|
||||||
|
Self(Rotation3::from_axis_angle(axis, angle))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl From<Rotation3<f32>> for Orientation {
|
||||||
|
fn from(val: Rotation3<f32>) -> Self {
|
||||||
|
Orientation(val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, Component)]
|
||||||
|
pub struct Player;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Bundle)]
|
||||||
|
pub struct PlayerBundle {
|
||||||
|
pub player: Player,
|
||||||
|
pub loaded_chunks: LoadedChunks,
|
||||||
|
pub pos: Pos,
|
||||||
|
pub orientation: Orientation,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PlayerBundle {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
player: Player,
|
||||||
|
loaded_chunks: LoadedChunks::new(),
|
||||||
|
pos: Pos::default(),
|
||||||
|
orientation: Orientation::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
28
src/common/message.rs
Normal file
28
src/common/message.rs
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
use crate::{
|
||||||
|
common::component::{ChunkBundle, Pos, VoxelGridBundle},
|
||||||
|
util::thread::{ExitType, ThreadChannel, ThreadHandle},
|
||||||
|
};
|
||||||
|
use bevy_ecs::entity::Entity;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub enum ServerMessage {
|
||||||
|
Stop,
|
||||||
|
Join,
|
||||||
|
SpawnVoxelGrid(VoxelGridBundle),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ExitType for ServerMessage {
|
||||||
|
fn exit() -> Self {
|
||||||
|
ServerMessage::Stop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub enum ClientMessage {
|
||||||
|
SpawnVoxelGrid(Entity, VoxelGridBundle),
|
||||||
|
LoadChunk(Entity, ChunkBundle),
|
||||||
|
PosUpdate(Entity, Pos),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type ClientChannel = ThreadChannel<ClientMessage, ServerMessage>;
|
||||||
|
pub type ServerHandle = ThreadHandle<ServerMessage, ClientMessage>;
|
||||||
4
src/common/mod.rs
Normal file
4
src/common/mod.rs
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
pub mod component;
|
||||||
|
mod message;
|
||||||
|
|
||||||
|
pub use message::*;
|
||||||
@@ -4,9 +4,9 @@ use client::ClientApp;
|
|||||||
use winit::event_loop::EventLoop;
|
use winit::event_loop::EventLoop;
|
||||||
|
|
||||||
mod client;
|
mod client;
|
||||||
mod world;
|
mod common;
|
||||||
mod server;
|
mod server;
|
||||||
mod sync;
|
mod util;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let event_loop = EventLoop::new().expect("Failed to create event loop");
|
let event_loop = EventLoop::new().expect("Failed to create event loop");
|
||||||
|
|||||||
182
src/server/chunk/load.rs
Normal file
182
src/server/chunk/load.rs
Normal file
@@ -0,0 +1,182 @@
|
|||||||
|
use std::collections::{HashMap, HashSet, VecDeque};
|
||||||
|
|
||||||
|
use bevy_ecs::{entity::Entity, system::Commands};
|
||||||
|
use nalgebra::Vector3;
|
||||||
|
use ndarray::{s, Array3, Axis};
|
||||||
|
use simdnoise::NoiseBuilder;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
client::render::voxel::VoxelColor,
|
||||||
|
common::component::{chunk, ChunkBundle, ChunkData, ChunkMesh, ChunkPos},
|
||||||
|
util::{
|
||||||
|
oct_tree::OctTree,
|
||||||
|
thread::{ExitType, ThreadChannel, ThreadHandle},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct ChunkManager {
|
||||||
|
handles: Vec<ThreadHandle<ChunkLoaderMsg, ServerChunkMsg>>,
|
||||||
|
i: usize,
|
||||||
|
n: usize,
|
||||||
|
map: HashMap<ChunkPos, Entity>,
|
||||||
|
generating: HashSet<ChunkPos>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ChunkManager {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
let n = 4;
|
||||||
|
Self {
|
||||||
|
handles: std::iter::repeat_with(|| ThreadHandle::spawn(chunk_loader_main))
|
||||||
|
.take(n)
|
||||||
|
.collect(),
|
||||||
|
i: 0,
|
||||||
|
n,
|
||||||
|
map: HashMap::new(),
|
||||||
|
generating: HashSet::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn entity_at(&self, pos: &ChunkPos) -> Option<&Entity> {
|
||||||
|
self.map.get(pos)
|
||||||
|
}
|
||||||
|
pub fn is_generating(&self, pos: &ChunkPos) -> bool {
|
||||||
|
self.generating.contains(pos)
|
||||||
|
}
|
||||||
|
pub fn queue(&mut self, pos: ChunkPos) {
|
||||||
|
if !self.is_generating(&pos) {
|
||||||
|
self.handles[self.i].send(ChunkLoaderMsg::Generate(pos));
|
||||||
|
self.i = (self.i + 1) % self.n;
|
||||||
|
self.generating.insert(pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn update(&mut self, commands: &mut Commands) {
|
||||||
|
for msg in self.handles.iter_mut().flat_map(|h| h.recv()) {
|
||||||
|
match msg {
|
||||||
|
ServerChunkMsg::ChunkGenerated(chunk) => {
|
||||||
|
let id = commands
|
||||||
|
.spawn(ChunkBundle {
|
||||||
|
pos: chunk.pos,
|
||||||
|
data: chunk.data,
|
||||||
|
mesh: chunk.mesh,
|
||||||
|
})
|
||||||
|
.id();
|
||||||
|
self.map.insert(chunk.pos, id);
|
||||||
|
self.generating.remove(&chunk.pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct GeneratedChunk {
|
||||||
|
pub pos: ChunkPos,
|
||||||
|
pub data: ChunkData,
|
||||||
|
pub mesh: ChunkMesh,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for ChunkManager {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
for h in &mut self.handles {
|
||||||
|
h.send(ChunkLoaderMsg::Exit);
|
||||||
|
h.join();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ServerChunkMsg {
|
||||||
|
ChunkGenerated(GeneratedChunk),
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ChunkLoaderMsg {
|
||||||
|
Generate(ChunkPos),
|
||||||
|
Exit,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ExitType for ChunkLoaderMsg {
|
||||||
|
fn exit() -> Self {
|
||||||
|
Self::Exit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn chunk_loader_main(channel: ThreadChannel<ServerChunkMsg, ChunkLoaderMsg>) {
|
||||||
|
let mut to_generate = VecDeque::new();
|
||||||
|
'outer: loop {
|
||||||
|
let msg = channel.recv_wait();
|
||||||
|
match msg {
|
||||||
|
ChunkLoaderMsg::Generate(pos) => {
|
||||||
|
to_generate.push_back(pos);
|
||||||
|
}
|
||||||
|
ChunkLoaderMsg::Exit => {
|
||||||
|
break 'outer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(pos) = to_generate.pop_front() {
|
||||||
|
let data = generate(pos);
|
||||||
|
let mesh = ChunkMesh::from_data(&data);
|
||||||
|
let data = if pos.y > 0 || pos.y < -1 {
|
||||||
|
ChunkData::empty()
|
||||||
|
} else {
|
||||||
|
ChunkData::from_tree(OctTree::from_arr(data.slice(s![
|
||||||
|
1..data.len_of(Axis(0)) - 1,
|
||||||
|
1..data.len_of(Axis(1)) - 1,
|
||||||
|
1..data.len_of(Axis(2)) - 1
|
||||||
|
])))
|
||||||
|
};
|
||||||
|
channel.send(ServerChunkMsg::ChunkGenerated(GeneratedChunk {
|
||||||
|
pos,
|
||||||
|
data,
|
||||||
|
mesh,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate(pos: ChunkPos) -> Array3<VoxelColor> {
|
||||||
|
let shape = [chunk::SIDE_LENGTH + 2; 3];
|
||||||
|
if pos.y > 0 {
|
||||||
|
return Array3::from_elem(shape, VoxelColor::none());
|
||||||
|
}
|
||||||
|
if pos.y < -1 {
|
||||||
|
return Array3::from_elem(shape, VoxelColor::none());
|
||||||
|
}
|
||||||
|
let posf: Vector3<f32> = (pos.cast() * chunk::SIDE_LENGTH as f32) - Vector3::from_element(1.0);
|
||||||
|
let (a, b, c, d) = (0.0, 50.0, 100.0, 127.0);
|
||||||
|
let (noise, ..) = NoiseBuilder::gradient_2d_offset(
|
||||||
|
posf.x,
|
||||||
|
chunk::SIDE_LENGTH + 2,
|
||||||
|
posf.z,
|
||||||
|
chunk::SIDE_LENGTH + 2,
|
||||||
|
)
|
||||||
|
.with_seed(0)
|
||||||
|
.with_freq(0.005)
|
||||||
|
.generate();
|
||||||
|
Array3::from_shape_fn(shape, |(x, y, z)| {
|
||||||
|
let y = y as f32 + posf.y;
|
||||||
|
let n = (noise[x + z * (chunk::SIDE_LENGTH + 2)] + 0.022) * (1.0 / 0.044) * d;
|
||||||
|
if y < n.max(b) {
|
||||||
|
if y < b {
|
||||||
|
VoxelColor {
|
||||||
|
r: 100,
|
||||||
|
g: 100,
|
||||||
|
b: 255,
|
||||||
|
a: 255,
|
||||||
|
}
|
||||||
|
} else if y < c {
|
||||||
|
VoxelColor {
|
||||||
|
r: 100,
|
||||||
|
g: 255,
|
||||||
|
b: 100,
|
||||||
|
a: 255,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
VoxelColor {
|
||||||
|
r: 150,
|
||||||
|
g: 150,
|
||||||
|
b: 150,
|
||||||
|
a: 255,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
VoxelColor::none()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
2
src/server/chunk/mod.rs
Normal file
2
src/server/chunk/mod.rs
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
mod load;
|
||||||
|
pub use load::*;
|
||||||
80
src/server/client.rs
Normal file
80
src/server/client.rs
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
use std::collections::{hash_map, HashMap};
|
||||||
|
|
||||||
|
use bevy_derive::{Deref, DerefMut};
|
||||||
|
use bevy_ecs::{component::Component, entity::Entity, system::Resource};
|
||||||
|
|
||||||
|
use crate::common::{ClientChannel, ClientMessage, ServerMessage};
|
||||||
|
|
||||||
|
pub enum ServerClient {
|
||||||
|
Local(ClientChannel),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ServerClient {
|
||||||
|
pub fn recv(&mut self) -> Vec<ServerMessage> {
|
||||||
|
match self {
|
||||||
|
Self::Local(ch) => ch.recv().collect(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn send(&self, msg: ClientMessage) {
|
||||||
|
match self {
|
||||||
|
Self::Local(ch) => ch.send(msg),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deref, DerefMut)]
|
||||||
|
pub struct ServerClients {
|
||||||
|
map: HashMap<Entity, ServerClient>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ServerClients {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
map: HashMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn add(&mut self, id: Entity, client: ServerClient) {
|
||||||
|
self.map.insert(id, client);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> IntoIterator for &'a mut ServerClients {
|
||||||
|
type Item = (&'a Entity, &'a mut ServerClient);
|
||||||
|
type IntoIter = hash_map::IterMut<'a, Entity, ServerClient>;
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
self.map.iter_mut()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// I don't think it's worth putting a reciever in here rn
|
||||||
|
// and moving that stuff into the ecs but we'll see
|
||||||
|
#[derive(Component)]
|
||||||
|
pub struct ClientComponent {
|
||||||
|
send: Vec<ClientMessage>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ClientComponent {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self { send: Vec::new() }
|
||||||
|
}
|
||||||
|
pub fn send(&mut self, msg: ClientMessage) {
|
||||||
|
self.send.push(msg);
|
||||||
|
}
|
||||||
|
pub fn take(&mut self) -> Vec<ClientMessage> {
|
||||||
|
std::mem::take(&mut self.send)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Resource)]
|
||||||
|
pub struct ClientBroadcast(Vec<ClientMessage>);
|
||||||
|
impl ClientBroadcast {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self(Vec::new())
|
||||||
|
}
|
||||||
|
pub fn send(&mut self, msg: ClientMessage) {
|
||||||
|
self.0.push(msg);
|
||||||
|
}
|
||||||
|
pub fn take(&mut self) -> Vec<ClientMessage> {
|
||||||
|
std::mem::take(&mut self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,21 +1,29 @@
|
|||||||
|
mod chunk;
|
||||||
|
mod client;
|
||||||
mod rsc;
|
mod rsc;
|
||||||
mod system;
|
mod system;
|
||||||
|
mod test;
|
||||||
|
|
||||||
use crate::{
|
pub use client::*;
|
||||||
sync::{ClientChannel, ClientMessage, ClientSender, ServerMessage},
|
|
||||||
world::{
|
use crate::common::{
|
||||||
component::{Orientation, Pos, Synced, VoxelGrid, VoxelGridBundle},
|
component::{
|
||||||
generation::generate,
|
ChunkBundle, ChunkData, ChunkMap, ChunkMesh, ChunkPos, Orientation, PlayerBundle, Pos,
|
||||||
|
VoxelGrid, VoxelGridBundle,
|
||||||
},
|
},
|
||||||
|
ClientChannel, ClientMessage, ServerMessage,
|
||||||
};
|
};
|
||||||
use bevy_ecs::{entity::Entity, query::With, system::SystemId, world::World};
|
use bevy_ecs::{entity::Entity, system::SystemId, world::World};
|
||||||
|
use chunk::ChunkManager;
|
||||||
|
use client::{ClientBroadcast, ServerClient, ServerClients};
|
||||||
use rsc::UPDATE_TIME;
|
use rsc::UPDATE_TIME;
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
|
use test::spawn_test_stuff;
|
||||||
|
|
||||||
pub struct Server {
|
pub struct Server {
|
||||||
update_time: Duration,
|
update_time: Duration,
|
||||||
target: Instant,
|
target: Instant,
|
||||||
client: ClientChannel,
|
clients: ServerClients,
|
||||||
world: World,
|
world: World,
|
||||||
systems: ServerSystems,
|
systems: ServerSystems,
|
||||||
mov: Vec<Entity>,
|
mov: Vec<Entity>,
|
||||||
@@ -24,23 +32,27 @@ pub struct Server {
|
|||||||
|
|
||||||
pub struct ServerSystems {
|
pub struct ServerSystems {
|
||||||
sync_pos: SystemId,
|
sync_pos: SystemId,
|
||||||
|
sync_chunks: SystemId,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ServerSystems {
|
impl ServerSystems {
|
||||||
pub fn new(world: &mut World) -> Self {
|
pub fn new(world: &mut World) -> Self {
|
||||||
Self {
|
Self {
|
||||||
sync_pos: world.register_system(system::sync::pos),
|
sync_pos: world.register_system(system::sync::pos),
|
||||||
|
sync_chunks: world.register_system(system::sync::chunks),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Server {
|
impl Server {
|
||||||
pub fn new(client: ClientChannel) -> Self {
|
pub fn new() -> Self {
|
||||||
let mut world = World::new();
|
let mut world = World::new();
|
||||||
world.insert_resource(ClientSender(client.sender()));
|
world.insert_resource(ClientBroadcast::new());
|
||||||
|
world.insert_resource(ChunkMap::new());
|
||||||
|
world.insert_non_send_resource(ChunkManager::new());
|
||||||
let systems = ServerSystems::new(&mut world);
|
let systems = ServerSystems::new(&mut world);
|
||||||
Self {
|
Self {
|
||||||
client,
|
clients: ServerClients::new(),
|
||||||
world,
|
world,
|
||||||
systems,
|
systems,
|
||||||
target: Instant::now(),
|
target: Instant::now(),
|
||||||
@@ -50,17 +62,38 @@ impl Server {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn from_client(client: ClientChannel) -> Self {
|
||||||
|
let mut s = Self::new();
|
||||||
|
s.add_client(ServerClient::Local(client));
|
||||||
|
s
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_client(&mut self, client: ServerClient) {
|
||||||
|
let id = self.world.spawn(ClientComponent::new()).id();
|
||||||
|
self.clients.add(id, client);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn start(ch: ClientChannel) {
|
pub fn start(ch: ClientChannel) {
|
||||||
Self::new(ch).run();
|
Self::from_client(ch).run();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run(&mut self) {
|
pub fn run(&mut self) {
|
||||||
generate(&mut self.world);
|
spawn_test_stuff(&mut self.world);
|
||||||
loop {
|
loop {
|
||||||
self.recv();
|
self.recv();
|
||||||
let now = Instant::now();
|
let now = Instant::now();
|
||||||
if now >= self.target {
|
if now >= self.target {
|
||||||
self.target += self.update_time;
|
self.target += self.update_time;
|
||||||
|
self.tick();
|
||||||
|
}
|
||||||
|
if self.stop {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
self.send();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn tick(&mut self) {
|
||||||
let mut q = self.world.query::<(Entity, &mut Pos)>();
|
let mut q = self.world.query::<(Entity, &mut Pos)>();
|
||||||
for (e, mut p) in q.iter_mut(&mut self.world) {
|
for (e, mut p) in q.iter_mut(&mut self.world) {
|
||||||
if self.mov.contains(&e) {
|
if self.mov.contains(&e) {
|
||||||
@@ -68,24 +101,21 @@ impl Server {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.world.run_system(self.systems.sync_pos).unwrap();
|
self.world.run_system(self.systems.sync_pos).unwrap();
|
||||||
|
self.world.run_system(self.systems.sync_chunks).unwrap();
|
||||||
self.world.clear_trackers();
|
self.world.clear_trackers();
|
||||||
}
|
}
|
||||||
if self.stop {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn recv(&mut self) {
|
pub fn recv(&mut self) {
|
||||||
for msg in self.client.recv() {
|
for (id, client) in &mut self.clients {
|
||||||
|
for msg in client.recv() {
|
||||||
match msg {
|
match msg {
|
||||||
ServerMessage::LoadWorld => {
|
ServerMessage::Join => {
|
||||||
let mut q = self
|
let mut q = self
|
||||||
.world
|
.world
|
||||||
.query_filtered::<(Entity, &Pos, &Orientation, &VoxelGrid), With<Synced>>();
|
.query::<(Entity, &Pos, &Orientation, &VoxelGrid)>();
|
||||||
// ePOG
|
// ePOG
|
||||||
for (e, p, o, g) in q.iter(&self.world) {
|
for (e, p, o, g) in q.iter(&self.world) {
|
||||||
self.client.send(ClientMessage::SpawnVoxelGrid(
|
client.send(ClientMessage::SpawnVoxelGrid(
|
||||||
e,
|
e,
|
||||||
VoxelGridBundle {
|
VoxelGridBundle {
|
||||||
pos: *p,
|
pos: *p,
|
||||||
@@ -94,11 +124,27 @@ impl Server {
|
|||||||
},
|
},
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
let mut q = self
|
||||||
|
.world
|
||||||
|
.query::<(Entity, &ChunkPos, &ChunkData, &ChunkMesh)>();
|
||||||
|
for (e, p, c, m) in q.iter(&self.world) {
|
||||||
|
client.send(ClientMessage::LoadChunk(
|
||||||
|
e,
|
||||||
|
ChunkBundle {
|
||||||
|
pos: *p,
|
||||||
|
data: c.clone(),
|
||||||
|
mesh: m.clone(),
|
||||||
|
},
|
||||||
|
))
|
||||||
|
}
|
||||||
|
self.world.entity_mut(*id).insert(PlayerBundle::new());
|
||||||
}
|
}
|
||||||
ServerMessage::SpawnVoxelGrid(grid) => {
|
ServerMessage::SpawnVoxelGrid(grid) => {
|
||||||
let e = self.world.spawn((grid.clone(), Synced)).id();
|
let e = self.world.spawn(grid.clone()).id();
|
||||||
self.mov.push(e);
|
self.mov.push(e);
|
||||||
self.client.send(ClientMessage::SpawnVoxelGrid(e, grid));
|
self.world
|
||||||
|
.resource_mut::<ClientBroadcast>()
|
||||||
|
.send(ClientMessage::SpawnVoxelGrid(e, grid));
|
||||||
}
|
}
|
||||||
ServerMessage::Stop => {
|
ServerMessage::Stop => {
|
||||||
self.stop = true;
|
self.stop = true;
|
||||||
@@ -107,3 +153,21 @@ impl Server {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn send(&mut self) {
|
||||||
|
let msgs = self.world.resource_mut::<ClientBroadcast>().take();
|
||||||
|
for msg in &msgs {
|
||||||
|
for (_, client) in &mut self.clients {
|
||||||
|
client.send(msg.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut q = self.world.query::<(Entity, &mut ClientComponent)>();
|
||||||
|
for (e, mut c) in q.iter_mut(&mut self.world) {
|
||||||
|
if let Some(sc) = self.clients.get(&e) {
|
||||||
|
for msg in c.take() {
|
||||||
|
sc.send(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,9 +1,72 @@
|
|||||||
use bevy_ecs::{entity::Entity, query::Changed, system::{Query, Res}};
|
use bevy_ecs::{
|
||||||
|
entity::Entity,
|
||||||
|
query::{Changed, With},
|
||||||
|
system::{Commands, NonSendMut, Query, ResMut},
|
||||||
|
};
|
||||||
|
use nalgebra::Vector3;
|
||||||
|
|
||||||
use crate::{sync::{ClientMessage, ClientSender}, world::component::{Pos, Synced}};
|
use crate::{
|
||||||
|
common::{
|
||||||
|
component::{
|
||||||
|
chunk::{self, ChunkBundle, LoadedChunks},
|
||||||
|
ChunkData, ChunkMesh, ChunkPos, Player, Pos,
|
||||||
|
},
|
||||||
|
ClientMessage,
|
||||||
|
},
|
||||||
|
server::{chunk::ChunkManager, client::ClientBroadcast, ClientComponent},
|
||||||
|
};
|
||||||
|
|
||||||
pub fn pos(query: Query<(Entity, &Synced, &Pos), Changed<Pos>>, client: Res<ClientSender>) {
|
pub fn pos(query: Query<(Entity, &Pos), Changed<Pos>>, mut clients: ResMut<ClientBroadcast>) {
|
||||||
for (e, _, pos) in query.iter() {
|
for (e, pos) in query.iter() {
|
||||||
client.send(ClientMessage::PosUpdate(e, *pos));
|
clients.send(ClientMessage::PosUpdate(e, *pos));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn chunks(
|
||||||
|
mut players: Query<(&Pos, &mut LoadedChunks, &mut ClientComponent), With<Player>>,
|
||||||
|
chunks: Query<(&ChunkPos, &ChunkData, &ChunkMesh)>,
|
||||||
|
mut loader: NonSendMut<ChunkManager>,
|
||||||
|
mut commands: Commands,
|
||||||
|
) {
|
||||||
|
for (pos, mut loaded, mut client) in &mut players {
|
||||||
|
let fp = **pos / chunk::SIDE_LENGTH as f32;
|
||||||
|
let player_chunk = Vector3::new(
|
||||||
|
fp.x.floor() as i32,
|
||||||
|
fp.y.floor() as i32,
|
||||||
|
fp.z.floor() as i32,
|
||||||
|
);
|
||||||
|
let radius: i32 = 5;
|
||||||
|
let width = radius * 2 - 1;
|
||||||
|
let mut desired = Vec::new();
|
||||||
|
for i in 0..width.pow(3) {
|
||||||
|
let pos = Vector3::new(i % width, (i / width) % width, i / (width.pow(2)))
|
||||||
|
- Vector3::from_element(radius - 1);
|
||||||
|
let dist = pos.cast::<f32>().norm();
|
||||||
|
if dist < radius as f32 {
|
||||||
|
desired.push((dist, pos));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
desired.sort_by(|(da, ..), (db, ..)| da.total_cmp(db));
|
||||||
|
for (_, pos) in desired {
|
||||||
|
let coords = pos - player_chunk;
|
||||||
|
let pos = ChunkPos(coords);
|
||||||
|
if !loaded.contains(&pos) {
|
||||||
|
if let Some(id) = loader.entity_at(&pos) {
|
||||||
|
let (pos, data, mesh) = chunks.get(*id).unwrap();
|
||||||
|
client.send(ClientMessage::LoadChunk(
|
||||||
|
*id,
|
||||||
|
ChunkBundle {
|
||||||
|
pos: *pos,
|
||||||
|
data: data.clone(),
|
||||||
|
mesh: mesh.clone(),
|
||||||
|
},
|
||||||
|
));
|
||||||
|
loaded.insert(*pos);
|
||||||
|
} else {
|
||||||
|
loader.queue(pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
loader.update(&mut commands);
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,15 +1,12 @@
|
|||||||
use crate::world::component::VoxelGrid;
|
use crate::client::render::voxel::VoxelColor;
|
||||||
|
use crate::common::component::{VoxelGrid, VoxelGridBundle};
|
||||||
use bevy_ecs::world::World;
|
use bevy_ecs::world::World;
|
||||||
use nalgebra::{Rotation3, UnitVector3, Vector3};
|
use nalgebra::{Rotation3, UnitVector3, Vector3};
|
||||||
use ndarray::Array3;
|
use ndarray::Array3;
|
||||||
|
|
||||||
use crate::client::render::voxel::VoxelColor;
|
pub fn spawn_test_stuff(world: &mut World) {
|
||||||
|
|
||||||
use super::component::{Synced, VoxelGridBundle};
|
|
||||||
|
|
||||||
pub fn generate(world: &mut World) {
|
|
||||||
let dim = (15, 10, 10);
|
let dim = (15, 10, 10);
|
||||||
world.spawn((VoxelGridBundle {
|
world.spawn(VoxelGridBundle {
|
||||||
pos: Vector3::new(0.0, 0.0, 20.0).into(),
|
pos: Vector3::new(0.0, 0.0, 20.0).into(),
|
||||||
orientation: Rotation3::from_axis_angle(&Vector3::y_axis(), 0.5).into(),
|
orientation: Rotation3::from_axis_angle(&Vector3::y_axis(), 0.5).into(),
|
||||||
grid: VoxelGrid::new(Array3::from_shape_fn(dim, |(x, y, z)| {
|
grid: VoxelGrid::new(Array3::from_shape_fn(dim, |(x, y, z)| {
|
||||||
@@ -33,30 +30,34 @@ pub fn generate(world: &mut World) {
|
|||||||
VoxelColor::none()
|
VoxelColor::none()
|
||||||
}
|
}
|
||||||
})),
|
})),
|
||||||
}, Synced));
|
});
|
||||||
|
|
||||||
let dim = (1000, 2, 1000);
|
// let dim = (1000, 2, 1000);
|
||||||
world.spawn((VoxelGridBundle {
|
// world.spawn((
|
||||||
pos: Vector3::new(0.0, -2.1, 0.0).into(),
|
// VoxelGridBundle {
|
||||||
orientation: Rotation3::identity().into(),
|
// pos: Vector3::new(0.0, -2.1, 0.0).into(),
|
||||||
grid: VoxelGrid::new(Array3::from_shape_fn(dim, |(x, y, z)| {
|
// orientation: Rotation3::identity().into(),
|
||||||
if y == 0 {
|
// grid: VoxelGrid::new(Array3::from_shape_fn(dim, |(x, y, z)| {
|
||||||
VoxelColor::random()
|
// if y == 0 {
|
||||||
} else if (y == dim.1 - 1) && (x == 0 || x == dim.0 - 1 || z == 0 || z == dim.2 - 1) {
|
// VoxelColor::random()
|
||||||
VoxelColor {
|
// } else if (y == dim.1 - 1) && (x == 0 || x == dim.0 - 1 || z == 0 || z == dim.2 - 1)
|
||||||
r: 255,
|
// {
|
||||||
g: 0,
|
// VoxelColor {
|
||||||
b: 255,
|
// r: 255,
|
||||||
a: 255,
|
// g: 0,
|
||||||
}
|
// b: 255,
|
||||||
} else {
|
// a: 255,
|
||||||
VoxelColor::none()
|
// }
|
||||||
}
|
// } else {
|
||||||
})),
|
// VoxelColor::none()
|
||||||
}, Synced));
|
// }
|
||||||
|
// })),
|
||||||
|
// },
|
||||||
|
// Synced,
|
||||||
|
// ));
|
||||||
|
|
||||||
let dim = (3, 3, 3);
|
let dim = (3, 3, 3);
|
||||||
world.spawn((VoxelGridBundle {
|
world.spawn(VoxelGridBundle {
|
||||||
pos: Vector3::new(0.0, 0.0, 16.5).into(),
|
pos: Vector3::new(0.0, 0.0, 16.5).into(),
|
||||||
orientation: (Rotation3::from_axis_angle(&Vector3::y_axis(), std::f32::consts::PI / 4.0)
|
orientation: (Rotation3::from_axis_angle(&Vector3::y_axis(), std::f32::consts::PI / 4.0)
|
||||||
* Rotation3::from_axis_angle(
|
* Rotation3::from_axis_angle(
|
||||||
@@ -70,5 +71,5 @@ pub fn generate(world: &mut World) {
|
|||||||
b: 255,
|
b: 255,
|
||||||
a: 255,
|
a: 255,
|
||||||
})),
|
})),
|
||||||
}, Synced));
|
});
|
||||||
}
|
}
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
pub mod thread;
|
|
||||||
|
|
||||||
use crate::world::component::{Pos, VoxelGridBundle};
|
|
||||||
use bevy_ecs::{entity::Entity, system::Resource};
|
|
||||||
use std::sync::mpsc::Sender;
|
|
||||||
use thread::{ThreadChannel, ThreadHandle};
|
|
||||||
|
|
||||||
pub enum ServerMessage {
|
|
||||||
Stop,
|
|
||||||
LoadWorld,
|
|
||||||
SpawnVoxelGrid(VoxelGridBundle),
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum ClientMessage {
|
|
||||||
SpawnVoxelGrid(Entity, VoxelGridBundle),
|
|
||||||
PosUpdate(Entity, Pos),
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type ClientChannel = ThreadChannel<ClientMessage, ServerMessage>;
|
|
||||||
pub type ServerHandle = ThreadHandle<ServerMessage, ClientMessage>;
|
|
||||||
|
|
||||||
#[derive(Resource, Clone)]
|
|
||||||
pub struct ClientSender(pub Sender<ClientMessage>);
|
|
||||||
impl ClientSender {
|
|
||||||
pub fn send(&self, msg: ClientMessage) {
|
|
||||||
self.0.send(msg).expect("YOU HAVE FAILED THE MISSION");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
2
src/util/mod.rs
Normal file
2
src/util/mod.rs
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
pub mod thread;
|
||||||
|
pub mod oct_tree;
|
||||||
42
src/util/oct_tree.rs
Normal file
42
src/util/oct_tree.rs
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
use std::fmt::Debug;
|
||||||
|
|
||||||
|
use nalgebra::Vector3;
|
||||||
|
use ndarray::{Array3, ArrayView3, Axis};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum OctTree<T> {
|
||||||
|
Leaf(T),
|
||||||
|
Node(Box<[OctTree<T>; 8]>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: PartialEq + Clone + Debug> OctTree<T> {
|
||||||
|
pub fn from_arr(arr: ArrayView3<T>) -> OctTree<T> {
|
||||||
|
let mut node_arr = arr.map(|x| OctTree::Leaf(x.clone()));
|
||||||
|
while node_arr.len() > 1 {
|
||||||
|
let new_data = node_arr.exact_chunks([2; 3]).into_iter().map(|chunk| {
|
||||||
|
let vec: Vec<OctTree<T>> = chunk.iter().cloned().collect();
|
||||||
|
let vec: [OctTree<T>; 8] = vec.try_into().unwrap();
|
||||||
|
if let OctTree::Leaf(first) = &chunk[[0; 3]] {
|
||||||
|
if vec.iter().all(|n| {
|
||||||
|
if let OctTree::Leaf(d) = n {
|
||||||
|
*d == *first
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
return OctTree::Leaf(first.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
OctTree::Node(Box::new(vec))
|
||||||
|
}).collect();
|
||||||
|
node_arr = Array3::from_shape_vec([node_arr.len_of(Axis(0)) / 2; 3], new_data).unwrap();
|
||||||
|
}
|
||||||
|
node_arr[[0; 3]].clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> OctTree<T> {
|
||||||
|
fn get(i: Vector3<usize>) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,12 +3,16 @@ use std::{
|
|||||||
thread::JoinHandle,
|
thread::JoinHandle,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct ThreadHandle<SendMsg, RecvMsg> {
|
pub trait ExitType {
|
||||||
pub channel: ThreadChannel<SendMsg, RecvMsg>,
|
fn exit() -> Self;
|
||||||
pub handle: Option<JoinHandle<()>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<SendMsg: Send + 'static, RecvMsg: Send + 'static> ThreadHandle<SendMsg, RecvMsg> {
|
pub struct ThreadHandle<SendMsg: Send + 'static + ExitType, RecvMsg: Send + 'static> {
|
||||||
|
channel: ThreadChannel<SendMsg, RecvMsg>,
|
||||||
|
handle: Option<JoinHandle<()>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<SendMsg: Send + 'static + ExitType, RecvMsg: Send + 'static> ThreadHandle<SendMsg, RecvMsg> {
|
||||||
pub fn send(&self, msg: SendMsg) {
|
pub fn send(&self, msg: SendMsg) {
|
||||||
self.channel.send(msg);
|
self.channel.send(msg);
|
||||||
}
|
}
|
||||||
@@ -34,6 +38,13 @@ impl<SendMsg: Send + 'static, RecvMsg: Send + 'static> ThreadHandle<SendMsg, Rec
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<SendMsg: ExitType + Send, RecvMsg: Send + 'static> Drop for ThreadHandle<SendMsg, RecvMsg> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
let _ = self.channel.send.send(SendMsg::exit());
|
||||||
|
self.join();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct ThreadChannel<SendMsg, RecvMsg> {
|
pub struct ThreadChannel<SendMsg, RecvMsg> {
|
||||||
send: Sender<SendMsg>,
|
send: Sender<SendMsg>,
|
||||||
recv: Receiver<RecvMsg>,
|
recv: Receiver<RecvMsg>,
|
||||||
@@ -50,4 +61,7 @@ impl<SendMsg, RecvMsg> ThreadChannel<SendMsg, RecvMsg> {
|
|||||||
pub fn recv(&self) -> TryIter<RecvMsg> {
|
pub fn recv(&self) -> TryIter<RecvMsg> {
|
||||||
self.recv.try_iter()
|
self.recv.try_iter()
|
||||||
}
|
}
|
||||||
|
pub fn recv_wait(&self) -> RecvMsg {
|
||||||
|
self.recv.recv().expect("OOOAAAAAAA")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
use crate::client::render::voxel::VoxelColor;
|
|
||||||
|
|
||||||
use super::component::TrackedGrid;
|
|
||||||
|
|
||||||
pub struct Chunk {
|
|
||||||
grid: TrackedGrid<VoxelColor>
|
|
||||||
}
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
pub mod component;
|
|
||||||
pub mod generation;
|
|
||||||
pub mod chunk;
|
|
||||||
Reference in New Issue
Block a user