tangled
alpha
login
or
join now
j0.lol
/
bl0ck
0
fork
atom
WebGPU Voxel Game
0
fork
atom
overview
issues
4
pulls
pipelines
Various fixes/refactors
j0.lol
1 year ago
d7160fc4
038953f4
+128
-79
10 changed files
expand all
collapse all
unified
split
src
app.rs
gfx
camera.rs
light.rs
model.rs
gfx.rs
gui.rs
lib.rs
world
chunk.rs
map.rs
world.rs
+1
-1
src/app.rs
···
4
4
world::map::new,
5
5
world::World,
6
6
};
7
7
-
use glam::{dvec2, vec2};
7
7
+
use glam::dvec2;
8
8
use std::sync::Arc;
9
9
use winit::{
10
10
application::ApplicationHandler,
+89
-34
src/gfx.rs
···
4
4
mod resources;
5
5
mod texture;
6
6
7
7
-
use std::borrow::Borrow;
8
8
-
use std::f32::consts::{FRAC_PI_2, FRAC_PI_3};
9
9
-
use egui::text_selection::text_cursor_state::slice_char_range;
10
10
-
use egui::Key::A;
11
11
-
use egui_wgpu::ScreenDescriptor;
12
12
-
use glam::{uvec2, vec2, vec3, IVec3, Mat4, Quat, Vec3, Vec4, Vec4Swizzles};
13
13
-
use light::LightUniform;
14
14
-
use std::ops::Deref;
15
15
-
use std::{f32::consts::PI, path::Path, sync::Arc};
16
16
-
use wgpu::util::DeviceExt;
17
17
-
use wgpu::BindingResource;
18
18
-
use winit::dpi::PhysicalPosition;
19
19
-
use winit::keyboard::Key;
20
20
-
use winit::{
21
21
-
dpi::PhysicalSize,
22
22
-
event::{ElementState, KeyEvent, WindowEvent},
23
23
-
event_loop::EventLoopProxy,
24
24
-
keyboard::{KeyCode, PhysicalKey},
25
25
-
window::Window,
26
26
-
};
27
7
use crate::gfx::camera::CameraUniform;
28
8
use crate::gfx::model::DrawLight;
29
29
-
use crate::world::chunk::{sl3get, CHUNK_SIZE};
9
9
+
use crate::world::chunk::{sl3get, sl3get_opt, CHUNK_SIZE};
30
10
use crate::{
31
11
app::WASM_WIN_SIZE,
32
12
gfx::model::Vertex,
33
13
gui::EguiRenderer,
34
34
-
world::map::{Block, WorldMap},
14
14
+
world::map::{BlockKind, WorldMap},
35
15
world::World,
36
16
Instance, InstanceRaw,
37
17
};
18
18
+
use egui_wgpu::ScreenDescriptor;
19
19
+
use glam::{uvec2, vec3, IVec3, Quat, Vec3};
20
20
+
use std::f32::consts::{FRAC_PI_2, FRAC_PI_3};
21
21
+
use std::sync::Arc;
22
22
+
use wgpu::util::DeviceExt;
23
23
+
use wgpu::BindingResource;
24
24
+
use winit::{
25
25
+
dpi::PhysicalSize,
26
26
+
event::{KeyEvent, WindowEvent},
27
27
+
event_loop::EventLoopProxy,
28
28
+
keyboard::PhysicalKey,
29
29
+
window::Window,
30
30
+
};
38
31
39
32
pub struct CameraState {
40
33
pub object: camera::Camera,
···
325
318
label: Some("texture_bind_group_layout"),
326
319
});
327
320
328
328
-
let camera = camera::Camera::new(vec3(50., 20., 50.), -std::f32::consts::FRAC_PI_2, std::f32::consts::FRAC_PI_3);
321
321
+
let camera = camera::Camera::new(
322
322
+
vec3(50., 20., 50.),
323
323
+
-std::f32::consts::FRAC_PI_2,
324
324
+
std::f32::consts::FRAC_PI_3,
325
325
+
);
329
326
let projection = camera::Projection::new(
330
327
uvec2(surface_config.width, surface_config.height).as_vec2(),
331
328
FRAC_PI_2,
···
378
375
379
376
let mut light_uniform = camera::CameraUniform::new();
380
377
light_uniform.update_view_proj(&light, &light_projection);
381
381
-
382
382
-
383
378
384
379
let shadow_map = texture::Texture::create_depth_texture(
385
380
&device,
···
670
665
671
666
let mut i = _3diter
672
667
.filter_map(|(x, y, z)| {
673
673
-
if let Block::Air = sl3get(&chunk.blocks, x, y, z) {
668
668
+
if let BlockKind::Air = sl3get(&chunk.blocks, x, y, z) {
669
669
+
return None;
670
670
+
}
671
671
+
672
672
+
// lookup if node is surrounded by nodes
673
673
+
let mut do_not_occlude = false;
674
674
+
let mut sum = vec![];
675
675
+
676
676
+
for (x_, y_, z_) in [
677
677
+
(-1_i32, 0_i32, 0_i32),
678
678
+
(1, 0, 0),
679
679
+
(0, -1, 0),
680
680
+
(0, 1, 0),
681
681
+
(0, 0, -1),
682
682
+
(0, 0, 1),
683
683
+
] {
684
684
+
if x == 0
685
685
+
|| y == 0
686
686
+
|| z == 0
687
687
+
|| x == CHUNK_SIZE.0 - 1
688
688
+
|| y == CHUNK_SIZE.2 - 1
689
689
+
|| z == CHUNK_SIZE.1 - 1
690
690
+
{
691
691
+
do_not_occlude = true;
692
692
+
break;
693
693
+
}
694
694
+
695
695
+
let (x, y, z) = (x as i32 + x_, y as i32 + y_, z as i32 + z_);
696
696
+
if x < 0 || y < 0 || z < 0
697
697
+
// || x == CHUNK_SIZE.0 as i32 - 1
698
698
+
// || y == CHUNK_SIZE.2 as i32 - 1
699
699
+
// || z == CHUNK_SIZE.1 as i32 - 1
700
700
+
{
701
701
+
continue;
702
702
+
}
703
703
+
704
704
+
if let Some(block) =
705
705
+
sl3get_opt(&chunk.blocks, x as usize, y as usize, z as usize)
706
706
+
{
707
707
+
sum.push(block)
708
708
+
}
709
709
+
}
710
710
+
711
711
+
if !do_not_occlude && sum.iter().all(|b| *b == BlockKind::Brick) {
674
712
return None;
675
713
}
676
714
···
680
718
let mapping = |n| SPACE_BETWEEN * (n as f32 - CHUNK_SIZE.0 as f32 / 2.0);
681
719
let position = vec3(
682
720
mapping(x) + chunk_offset.x,
683
683
-
-(mapping(y) + chunk_offset.y),
721
721
+
(mapping(y) + chunk_offset.y),
684
722
mapping(z) + chunk_offset.z,
685
723
);
686
724
···
692
730
693
731
instances.append(&mut i);
694
732
}
733
733
+
734
734
+
// WGPU Crashes with an empty instance buffer, add a small item out of camera vfar
735
735
+
if instances.is_empty() {
736
736
+
instances.push(Instance {
737
737
+
position: Vec3::splat(9999.),
738
738
+
rotation: Quat::from_axis_angle(Vec3::Y, 0.0),
739
739
+
})
740
740
+
}
695
741
instances
696
742
}
697
743
···
716
762
egui: &mut Option<EguiRenderer>,
717
763
window: Arc<Window>,
718
764
world: &mut World,
719
719
-
dt: instant::Duration
765
765
+
dt: instant::Duration,
720
766
) -> Result<(), wgpu::SurfaceError> {
721
767
let output = self.surface.get_current_texture()?;
722
768
···
863
909
864
910
pub fn update(&mut self, world: &mut World, dt: instant::Duration) {
865
911
// Camera update
912
912
+
self.camera.controller.update_camera(
913
913
+
&mut self.camera.object,
914
914
+
dt,
915
915
+
world,
916
916
+
&mut self.object.remake,
917
917
+
);
866
918
self.camera
867
867
-
.controller
868
868
-
.update_camera(&mut self.camera.object, dt, world, &mut self.object.remake);
869
869
-
self.camera.uniform.update_view_proj(&self.camera.object, &self.camera.projection);
919
919
+
.uniform
920
920
+
.update_view_proj(&self.camera.object, &self.camera.projection);
870
921
871
922
self.queue.write_buffer(
872
923
&self.forward_pass.uniform_bufs[0],
···
875
926
);
876
927
877
928
// Light update
878
878
-
self.light.object.position = Quat::from_axis_angle(vec3(0.0, 0.0, 1.0), self.interact.sun_speed * dt.as_secs_f32())
879
879
-
* self.light.object.position;
880
880
-
self.light.uniform.update_view_proj(&self.light.object, &self.light.projection);
929
929
+
self.light.object.position = Quat::from_axis_angle(
930
930
+
vec3(0.0, 0.0, 1.0),
931
931
+
self.interact.sun_speed * dt.as_secs_f32(),
932
932
+
) * self.light.object.position;
933
933
+
self.light
934
934
+
.uniform
935
935
+
.update_view_proj(&self.light.object, &self.light.projection);
881
936
882
937
self.queue.write_buffer(
883
938
&self.forward_pass.uniform_bufs[1],
+5
-9
src/gfx/camera.rs
···
1
1
-
use glam::{ivec3, vec3, vec4, IVec3, Mat4, Vec2, Vec3, Vec4, Vec4Swizzles};
1
1
+
use glam::{ivec3, vec3, IVec3, Mat4, Vec2, Vec3, Vec4};
2
2
use instant::Duration;
3
3
use itertools::Itertools;
4
4
-
use rollgrid::math::Convert;
5
5
-
use std::f32::consts::FRAC_2_PI;
6
4
use winit::{
7
5
dpi::PhysicalPosition,
8
8
-
event::{ElementState, KeyEvent, MouseScrollDelta, WindowEvent},
6
6
+
event::{ElementState, MouseScrollDelta},
9
7
keyboard::KeyCode,
10
10
-
keyboard::PhysicalKey,
11
8
};
12
9
13
13
-
use crate::world::{chunk::Chunk, World};
10
10
+
use crate::world::{chunk::Chunk, map::RENDER_GRID_SIZE, World};
14
11
15
15
-
use super::Gfx;
16
12
17
13
const MAX_CAMERA_PITCH: f32 = (3.0 / std::f32::consts::PI) - 0.0001;
18
14
···
194
190
const BLOCK_UNIT_SIZE: i32 = 32;
195
191
let chunk_relative = IVec3::from(
196
192
(camera.position.x as i32 / BLOCK_UNIT_SIZE,
197
197
-
-(camera.position.y as i32 / BLOCK_UNIT_SIZE),
193
193
+
camera.position.y as i32 / BLOCK_UNIT_SIZE,
198
194
camera.position.z as i32 / BLOCK_UNIT_SIZE,
199
199
-
)) + IVec3::splat(-2);
195
195
+
)) + IVec3::splat(-(RENDER_GRID_SIZE as i32/2));
200
196
if chunk_relative != world.map.chunks.offset().into() {
201
197
world
202
198
.map
+1
-1
src/gfx/light.rs
···
1
1
use std::f32::consts::PI;
2
2
-
use glam::{vec3, Mat4, Vec3, Vec4};
2
2
+
use glam::{vec3, Mat4, Vec3};
3
3
4
4
#[repr(C)]
5
5
#[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)]
-1
src/gfx/model.rs
···
1
1
use super::texture;
2
2
use std::ops::Range;
3
3
-
use wasm_bindgen::__rt::__wbindgen_exn_store;
4
3
5
4
pub trait Vertex {
6
5
fn desc() -> wgpu::VertexBufferLayout<'static>;
+2
-2
src/gui.rs
···
1
1
-
use egui::{FontFamily, FontId, RichText};
1
1
+
use egui::{FontId, RichText};
2
2
use egui_winit::EventResponse;
3
3
-
use glam::{ivec2, ivec3, IVec2};
3
3
+
use glam::ivec3;
4
4
use winit::window::Window;
5
5
6
6
use crate::{
+1
-2
src/lib.rs
···
36
36
37
37
impl InstanceRaw {
38
38
fn desc() -> wgpu::VertexBufferLayout<'static> {
39
39
-
use std::mem;
39
39
+
40
40
41
41
wgpu::VertexBufferLayout {
42
42
array_stride: size_of::<InstanceRaw>() as wgpu::BufferAddress,
···
102
102
let event_loop = EventLoop::with_user_event().build().unwrap_throw();
103
103
104
104
let mut app = app::Application::new(&event_loop, "BL0CK");
105
105
-
// let mut app = DebugWinitApp::new();
106
105
event_loop.run_app(&mut app).unwrap();
107
106
}
-1
src/world.rs
···
1
1
pub(crate) mod map;
2
2
pub(crate) mod encoded;
3
3
pub(crate) mod chunk;
4
4
-
use std::fs::File;
5
4
6
5
use bincode::{Decode, Encode};
7
6
+15
-12
src/world/chunk.rs
···
1
1
-
use super::map::Block;
2
2
-
use base64::prelude::BASE64_STANDARD;
3
3
-
use base64::Engine;
1
1
+
use super::map::BlockKind;
4
2
use bincode::{Decode, Encode};
5
3
use glam::{ivec3, IVec3};
6
4
use itertools::Itertools;
···
21
19
pub(crate) const CHUNK_SIZE: (usize, usize, usize) = (16, 16, 16);
22
20
23
21
// A [Block; X*Y*Z] would be a much more efficient datatype, but, well...
24
24
-
pub type Slice3 = [Block; CHUNK_SIZE.0 * CHUNK_SIZE.1 * CHUNK_SIZE.2];
22
22
+
pub type Slice3 = [BlockKind; CHUNK_SIZE.0 * CHUNK_SIZE.1 * CHUNK_SIZE.2];
25
23
26
26
-
pub fn sl3get(sl3: &Slice3, x: usize, y: usize, z: usize) -> Block {
24
24
+
pub fn sl3get(sl3: &Slice3, x: usize, y: usize, z: usize) -> BlockKind {
27
25
sl3[y + CHUNK_SIZE.2 * (z + CHUNK_SIZE.1 * x)]
28
26
}
29
29
-
pub fn sl3set(sl3: &mut Slice3, x: usize, y: usize, z: usize, new: Block) {
27
27
+
pub fn sl3get_opt(sl3: &Slice3, x: usize, y: usize, z: usize) -> Option<BlockKind> {
28
28
+
sl3.get(y + CHUNK_SIZE.2 * (z + CHUNK_SIZE.1 * x)).copied()
29
29
+
}
30
30
+
pub fn sl3set(sl3: &mut Slice3, x: usize, y: usize, z: usize, new: BlockKind) {
30
31
sl3[y + CHUNK_SIZE.2 * (z + CHUNK_SIZE.1 * x)] = new;
31
32
}
32
33
···
53
54
54
55
// Pretty arbitrary numbers! Just trying to get something interesting
55
56
let n = (((sines / 4. + 0.5) * CHUNK_SIZE.2 as f32).round() as i32)
56
56
-
<= tile_pos_worldspace.y as _;
57
57
+
<= -tile_pos_worldspace.y as _;
57
58
58
59
if n {
59
59
-
Block::Brick
60
60
+
BlockKind::Brick
60
61
} else {
61
61
-
Block::Air
62
62
+
BlockKind::Air
62
63
}
63
64
})
64
65
.collect_array()
···
76
77
.blocks
77
78
.iter()
78
79
.map(|b| match b {
79
79
-
Block::Air => Block::Brick,
80
80
-
Block::Brick => Block::Air,
80
80
+
BlockKind::Air => BlockKind::Brick,
81
81
+
BlockKind::Brick => BlockKind::Air,
81
82
})
82
83
.collect_array()
83
84
.unwrap(),
···
115
116
// We are going to use LocalStorage for web. I don't like it either.
116
117
#[cfg(target_arch = "wasm32")]
117
118
{
119
119
+
use base64::prelude::{BASE64_STANDARD, Engine};
118
120
let encoded = bincode::encode_to_vec(self, config)?;
119
121
let encoded = BASE64_STANDARD.encode(encoded);
120
122
···
145
147
}
146
148
#[cfg(target_arch = "wasm32")]
147
149
{
150
150
+
use base64::prelude::{BASE64_STANDARD, Engine};
148
151
let store = web_sys::window().unwrap().local_storage().unwrap().unwrap();
149
152
if let Ok(Some(s)) = store.get(&file_name) {
150
153
let s = BASE64_STANDARD.decode(s)?;
···
200
203
#[cfg(not(target_arch = "wasm32"))]
201
204
{
202
205
// range
203
203
-
let r: i32 = 8;
206
206
+
let r: i32 = 8; // normally 8 or so
204
207
let _3diter = itertools::iproduct!(-r..r, -r..r, -r..r);
205
208
206
209
for (x, y, z) in _3diter {
+14
-16
src/world/map.rs
···
1
1
+
use super::chunk::Chunk;
1
2
use bincode::{Decode, Encode};
2
3
use glam::ivec3;
3
4
#[cfg(not(target_arch = "wasm32"))]
···
6
7
Rng,
7
8
};
8
9
use rollgrid::rollgrid3d::RollGrid3D;
9
9
-
use super::chunk::Chunk;
10
10
11
11
-
#[derive(Copy, Clone, Default, Encode, Decode)]
11
11
+
#[derive(Copy, Clone, Default, Encode, Decode, PartialEq)]
12
12
#[repr(u32)]
13
13
-
pub enum Block {
13
13
+
pub enum BlockKind {
14
14
#[default]
15
15
Air = 0,
16
16
Brick,
17
17
}
18
18
+
pub struct Block {
19
19
+
kind: BlockKind,
20
20
+
}
18
21
19
22
#[cfg(not(target_arch = "wasm32"))]
20
20
-
impl Distribution<Block> for StandardUniform {
21
21
-
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Block {
23
23
+
impl Distribution<BlockKind> for StandardUniform {
24
24
+
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> BlockKind {
22
25
match rng.random_range(0..=1) {
23
23
-
0 => Block::Air,
24
24
-
_ => Block::Brick,
26
26
+
0 => BlockKind::Air,
27
27
+
_ => BlockKind::Brick,
25
28
}
26
29
}
27
30
}
···
29
32
pub struct WorldMap {
30
33
pub chunks: RollGrid3D<Chunk>,
31
34
}
35
35
+
pub(crate) const RENDER_GRID_SIZE: usize = 15;
32
36
pub fn new() -> WorldMap {
33
33
-
const INITIAL_GENERATION_SIZE: usize = 5;
34
34
-
35
37
WorldMap {
36
38
chunks: RollGrid3D::new(
37
39
(
38
38
-
INITIAL_GENERATION_SIZE as _,
39
39
-
INITIAL_GENERATION_SIZE as _,
40
40
-
INITIAL_GENERATION_SIZE as _,
40
40
+
RENDER_GRID_SIZE as _,
41
41
+
RENDER_GRID_SIZE as _,
42
42
+
RENDER_GRID_SIZE as _,
41
43
),
42
44
(0, 0, 0),
43
45
|(x, y, z)| Chunk::load(ivec3(x, y, z)).unwrap(),
44
46
),
45
47
}
46
48
}
47
47
-
48
48
-
49
49
-
50
50
-