+10
-145
Cargo.lock
+10
-145
Cargo.lock
···
19
19
checksum = "c71b1793ee61086797f5c80b6efa2b8ffa6d5dd703f118545808a7f2e27f7046"
20
20
21
21
[[package]]
22
-
name = "addr2line"
23
-
version = "0.24.2"
24
-
source = "registry+https://github.com/rust-lang/crates.io-index"
25
-
checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1"
26
-
dependencies = [
27
-
"gimli",
28
-
]
29
-
30
-
[[package]]
31
22
name = "adler2"
32
23
version = "2.0.0"
33
24
source = "registry+https://github.com/rust-lang/crates.io-index"
···
137
128
checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
138
129
139
130
[[package]]
140
-
name = "backtrace"
141
-
version = "0.3.74"
142
-
source = "registry+https://github.com/rust-lang/crates.io-index"
143
-
checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a"
144
-
dependencies = [
145
-
"addr2line",
146
-
"cfg-if",
147
-
"libc",
148
-
"miniz_oxide",
149
-
"object",
150
-
"rustc-demangle",
151
-
"windows-targets 0.52.6",
152
-
]
153
-
154
-
[[package]]
155
-
name = "backtrace-ext"
156
-
version = "0.2.1"
157
-
source = "registry+https://github.com/rust-lang/crates.io-index"
158
-
checksum = "537beee3be4a18fb023b570f80e3ae28003db9167a751266b259926e25539d50"
159
-
dependencies = [
160
-
"backtrace",
161
-
]
162
-
163
-
[[package]]
164
131
name = "bit-set"
165
132
version = "0.6.0"
166
133
source = "registry+https://github.com/rust-lang/crates.io-index"
···
196
163
"console_error_panic_hook",
197
164
"console_log",
198
165
"env_logger",
166
+
"glam",
199
167
"image",
200
168
"log",
201
-
"miette",
202
169
"pollster",
203
170
"thiserror 2.0.11",
204
171
"wasm-bindgen",
···
605
572
]
606
573
607
574
[[package]]
608
-
name = "gimli"
609
-
version = "0.31.1"
610
-
source = "registry+https://github.com/rust-lang/crates.io-index"
611
-
checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
612
-
613
-
[[package]]
614
575
name = "gl_generator"
615
576
version = "0.14.0"
616
577
source = "registry+https://github.com/rust-lang/crates.io-index"
···
622
583
]
623
584
624
585
[[package]]
586
+
name = "glam"
587
+
version = "0.29.2"
588
+
source = "registry+https://github.com/rust-lang/crates.io-index"
589
+
checksum = "dc46dd3ec48fdd8e693a98d2b8bafae273a2d54c1de02a2a7e3d57d501f39677"
590
+
dependencies = [
591
+
"bytemuck",
592
+
]
593
+
594
+
[[package]]
625
595
name = "glow"
626
596
version = "0.13.1"
627
597
source = "registry+https://github.com/rust-lang/crates.io-index"
···
784
754
]
785
755
786
756
[[package]]
787
-
name = "is_ci"
788
-
version = "1.2.0"
789
-
source = "registry+https://github.com/rust-lang/crates.io-index"
790
-
checksum = "7655c9839580ee829dfacba1d1278c2b7883e50a277ff7541299489d6bdfdc45"
791
-
792
-
[[package]]
793
757
name = "jni"
794
758
version = "0.21.1"
795
759
source = "registry+https://github.com/rust-lang/crates.io-index"
···
941
905
]
942
906
943
907
[[package]]
944
-
name = "miette"
945
-
version = "7.4.0"
946
-
source = "registry+https://github.com/rust-lang/crates.io-index"
947
-
checksum = "317f146e2eb7021892722af37cf1b971f0a70c8406f487e24952667616192c64"
948
-
dependencies = [
949
-
"backtrace",
950
-
"backtrace-ext",
951
-
"cfg-if",
952
-
"miette-derive",
953
-
"owo-colors",
954
-
"supports-color",
955
-
"supports-hyperlinks",
956
-
"supports-unicode",
957
-
"terminal_size",
958
-
"textwrap",
959
-
"thiserror 1.0.64",
960
-
"unicode-width",
961
-
]
962
-
963
-
[[package]]
964
-
name = "miette-derive"
965
-
version = "7.4.0"
966
-
source = "registry+https://github.com/rust-lang/crates.io-index"
967
-
checksum = "23c9b935fbe1d6cbd1dac857b54a688145e2d93f48db36010514d0f612d0ad67"
968
-
dependencies = [
969
-
"proc-macro2",
970
-
"quote",
971
-
"syn 2.0.96",
972
-
]
973
-
974
-
[[package]]
975
908
name = "miniz_oxide"
976
909
version = "0.8.3"
977
910
source = "registry+https://github.com/rust-lang/crates.io-index"
···
1095
1028
checksum = "d079845b37af429bfe5dfa76e6d087d788031045b25cfc6fd898486fd9847666"
1096
1029
1097
1030
[[package]]
1098
-
name = "object"
1099
-
version = "0.36.5"
1100
-
source = "registry+https://github.com/rust-lang/crates.io-index"
1101
-
checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e"
1102
-
dependencies = [
1103
-
"memchr",
1104
-
]
1105
-
1106
-
[[package]]
1107
1031
name = "once_cell"
1108
1032
version = "1.19.0"
1109
1033
source = "registry+https://github.com/rust-lang/crates.io-index"
···
1128
1052
]
1129
1053
1130
1054
[[package]]
1131
-
name = "owo-colors"
1132
-
version = "4.1.0"
1133
-
source = "registry+https://github.com/rust-lang/crates.io-index"
1134
-
checksum = "fb37767f6569cd834a413442455e0f066d0d522de8630436e2a1761d9726ba56"
1135
-
1136
-
[[package]]
1137
1055
name = "parking_lot"
1138
1056
version = "0.12.3"
1139
1057
source = "registry+https://github.com/rust-lang/crates.io-index"
···
1343
1261
checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832"
1344
1262
1345
1263
[[package]]
1346
-
name = "rustc-demangle"
1347
-
version = "0.1.24"
1348
-
source = "registry+https://github.com/rust-lang/crates.io-index"
1349
-
checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
1350
-
1351
-
[[package]]
1352
1264
name = "rustc-hash"
1353
1265
version = "1.1.0"
1354
1266
source = "registry+https://github.com/rust-lang/crates.io-index"
···
1513
1425
checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731"
1514
1426
1515
1427
[[package]]
1516
-
name = "supports-color"
1517
-
version = "3.0.1"
1518
-
source = "registry+https://github.com/rust-lang/crates.io-index"
1519
-
checksum = "8775305acf21c96926c900ad056abeef436701108518cf890020387236ac5a77"
1520
-
dependencies = [
1521
-
"is_ci",
1522
-
]
1523
-
1524
-
[[package]]
1525
-
name = "supports-hyperlinks"
1526
-
version = "3.0.0"
1527
-
source = "registry+https://github.com/rust-lang/crates.io-index"
1528
-
checksum = "2c0a1e5168041f5f3ff68ff7d95dcb9c8749df29f6e7e89ada40dd4c9de404ee"
1529
-
1530
-
[[package]]
1531
-
name = "supports-unicode"
1532
-
version = "3.0.0"
1533
-
source = "registry+https://github.com/rust-lang/crates.io-index"
1534
-
checksum = "b7401a30af6cb5818bb64852270bb722533397edcfc7344954a38f420819ece2"
1535
-
1536
-
[[package]]
1537
1428
name = "syn"
1538
1429
version = "1.0.109"
1539
1430
source = "registry+https://github.com/rust-lang/crates.io-index"
···
1562
1453
checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755"
1563
1454
dependencies = [
1564
1455
"winapi-util",
1565
-
]
1566
-
1567
-
[[package]]
1568
-
name = "terminal_size"
1569
-
version = "0.4.0"
1570
-
source = "registry+https://github.com/rust-lang/crates.io-index"
1571
-
checksum = "4f599bd7ca042cfdf8f4512b277c02ba102247820f9d9d4a9f521f496751a6ef"
1572
-
dependencies = [
1573
-
"rustix",
1574
-
"windows-sys 0.59.0",
1575
-
]
1576
-
1577
-
[[package]]
1578
-
name = "textwrap"
1579
-
version = "0.16.1"
1580
-
source = "registry+https://github.com/rust-lang/crates.io-index"
1581
-
checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9"
1582
-
dependencies = [
1583
-
"unicode-linebreak",
1584
-
"unicode-width",
1585
1456
]
1586
1457
1587
1458
[[package]]
···
1693
1564
version = "1.0.13"
1694
1565
source = "registry+https://github.com/rust-lang/crates.io-index"
1695
1566
checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
1696
-
1697
-
[[package]]
1698
-
name = "unicode-linebreak"
1699
-
version = "0.1.5"
1700
-
source = "registry+https://github.com/rust-lang/crates.io-index"
1701
-
checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f"
1702
1567
1703
1568
[[package]]
1704
1569
name = "unicode-segmentation"
+1
-1
Cargo.toml
+1
-1
Cargo.toml
···
14
14
pollster = "0.3.0"
15
15
bytemuck = { version = "1.18.0", features = ["derive"] }
16
16
image = { version = "0.25.5", default-features = false, features = ["png", "jpeg"] }
17
-
miette = { version = "7.4.0", features = ["fancy"] }
18
17
thiserror = "2.0.11"
18
+
glam = { version = "0.29.2", features = ["bytemuck"] }
19
19
20
20
[lib]
21
21
crate-type = ["cdylib", "rlib"]
+121
src/camera.rs
+121
src/camera.rs
···
1
+
use glam::{Mat4, Vec3};
2
+
use winit::{
3
+
event::{ElementState, KeyEvent, WindowEvent},
4
+
keyboard::KeyCode,
5
+
keyboard::PhysicalKey,
6
+
};
7
+
8
+
pub struct Camera {
9
+
pub eye: Vec3,
10
+
pub target: Vec3,
11
+
pub up: Vec3,
12
+
pub aspect: f32,
13
+
pub fovy: f32,
14
+
pub znear: f32,
15
+
pub zfar: f32,
16
+
}
17
+
18
+
impl Camera {
19
+
pub fn build_view_projection_matrix(&self) -> Mat4 {
20
+
let view = Mat4::look_at_rh(self.eye, self.target, self.up);
21
+
let proj = Mat4::perspective_rh(self.fovy, self.aspect, self.znear, self.zfar);
22
+
23
+
return proj * view;
24
+
}
25
+
}
26
+
27
+
#[repr(C)]
28
+
#[derive(Debug, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
29
+
pub struct CameraUniform {
30
+
view_proj: Mat4,
31
+
}
32
+
33
+
impl CameraUniform {
34
+
pub fn new() -> Self {
35
+
Self {
36
+
view_proj: Mat4::IDENTITY,
37
+
}
38
+
}
39
+
40
+
pub fn update_view_proj(&mut self, camera: &Camera) {
41
+
self.view_proj = camera.build_view_projection_matrix();
42
+
}
43
+
}
44
+
45
+
pub struct CameraController {
46
+
speed: f32,
47
+
buttons: glam::BVec4, // fwd, bwd, lft, rht
48
+
}
49
+
50
+
impl CameraController {
51
+
pub fn new(speed: f32) -> Self {
52
+
Self {
53
+
speed,
54
+
buttons: glam::BVec4::FALSE,
55
+
}
56
+
}
57
+
58
+
pub fn process_events(&mut self, event: &WindowEvent) -> bool {
59
+
match event {
60
+
WindowEvent::KeyboardInput {
61
+
event:
62
+
KeyEvent {
63
+
state,
64
+
physical_key: PhysicalKey::Code(keycode),
65
+
..
66
+
},
67
+
..
68
+
} => {
69
+
let is_pressed = *state == ElementState::Pressed;
70
+
match keycode {
71
+
KeyCode::KeyW | KeyCode::ArrowUp => {
72
+
self.buttons.x = is_pressed;
73
+
true
74
+
}
75
+
KeyCode::KeyA | KeyCode::ArrowLeft => {
76
+
self.buttons.y = is_pressed;
77
+
true
78
+
}
79
+
KeyCode::KeyS | KeyCode::ArrowDown => {
80
+
self.buttons.z = is_pressed;
81
+
true
82
+
}
83
+
KeyCode::KeyD | KeyCode::ArrowRight => {
84
+
self.buttons.w = is_pressed;
85
+
true
86
+
}
87
+
_ => false,
88
+
}
89
+
}
90
+
_ => false,
91
+
}
92
+
}
93
+
94
+
pub fn update_camera(&self, camera: &mut Camera) {
95
+
let forward = camera.target - camera.eye;
96
+
let forward_norm = forward.normalize();
97
+
let forward_mag = forward.length();
98
+
99
+
// Prevents glitching when the camera gets too close to the
100
+
// center of the scene.
101
+
if self.buttons.x && forward_mag > self.speed {
102
+
camera.eye += forward_norm * self.speed;
103
+
}
104
+
if self.buttons.z {
105
+
camera.eye -= forward_norm * self.speed;
106
+
}
107
+
108
+
let right = forward_norm.cross(camera.up);
109
+
110
+
// Redo radius calc in case the forward/backward is pressed.
111
+
let forward = camera.target - camera.eye;
112
+
let forward_mag = forward.length();
113
+
114
+
if self.buttons.w {
115
+
camera.eye = camera.target - (forward + right * self.speed).normalize() * forward_mag;
116
+
}
117
+
if self.buttons.y {
118
+
camera.eye = camera.target - (forward - right * self.speed).normalize() * forward_mag;
119
+
}
120
+
}
121
+
}
+127
-46
src/lib.rs
+127
-46
src/lib.rs
···
1
+
#![allow(rust_analyzer::inactive_code)]
2
+
3
+
mod camera;
1
4
mod texture;
2
5
3
6
use wgpu::util::DeviceExt;
4
7
use winit::{
8
+
dpi::PhysicalSize,
5
9
event::*,
6
10
event_loop::EventLoop,
7
11
keyboard::{KeyCode, PhysicalKey},
···
40
44
}
41
45
42
46
const VERTICES: &[Vertex] = &[
43
-
Vertex { position: [-0.0868241, 0.49240386, 0.0], tex_coords: [0.4131759, 0.00759614], }, // A
44
-
Vertex { position: [-0.49513406, 0.06958647, 0.0], tex_coords: [0.0048659444, 0.43041354], }, // B
45
-
Vertex { position: [-0.21918549, -0.44939706, 0.0], tex_coords: [0.28081453, 0.949397], }, // C
46
-
Vertex { position: [0.35966998, -0.3473291, 0.0], tex_coords: [0.85967, 0.84732914], }, // D
47
-
Vertex { position: [0.44147372, 0.2347359, 0.0], tex_coords: [0.9414737, 0.2652641], }, // E
47
+
Vertex {
48
+
position: [-0.0868241, 0.49240386, 0.0],
49
+
tex_coords: [0.4131759, 0.00759614],
50
+
}, // A
51
+
Vertex {
52
+
position: [-0.49513406, 0.06958647, 0.0],
53
+
tex_coords: [0.0048659444, 0.43041354],
54
+
}, // B
55
+
Vertex {
56
+
position: [-0.21918549, -0.44939706, 0.0],
57
+
tex_coords: [0.28081453, 0.949397],
58
+
}, // C
59
+
Vertex {
60
+
position: [0.35966998, -0.3473291, 0.0],
61
+
tex_coords: [0.85967, 0.84732914],
62
+
}, // D
63
+
Vertex {
64
+
position: [0.44147372, 0.2347359, 0.0],
65
+
tex_coords: [0.9414737, 0.2652641],
66
+
}, // E
48
67
];
49
68
50
-
const INDICES: &[u16] = &[
51
-
0, 1, 4,
52
-
1, 2, 4,
53
-
2, 3, 4,
54
-
];
69
+
const INDICES: &[u16] = &[0, 1, 4, 1, 2, 4, 2, 3, 4];
70
+
71
+
use glam::{vec3, Vec3};
55
72
56
73
struct State<'srfc> {
57
74
surface: wgpu::Surface<'srfc>,
···
65
82
num_indices: u32,
66
83
diffuse_bind_group: wgpu::BindGroup,
67
84
diffuse_texture: texture::Texture,
85
+
camera: camera::Camera,
86
+
camera_controller: camera::CameraController,
87
+
camera_uniform: camera::CameraUniform,
88
+
camera_buffer: wgpu::Buffer,
89
+
camera_bind_group: wgpu::BindGroup,
68
90
69
91
// Window must be declared after surface
70
92
// so it gets dropped after it
···
78
100
79
101
impl<'a> State<'a> {
80
102
async fn new(window: &'a Window) -> State<'a> {
103
+
#[cfg(not(target_arch = "wasm32"))]
81
104
let size = window.inner_size();
105
+
#[cfg(target_arch = "wasm32")]
106
+
let size = PhysicalSize {
107
+
width: 100,
108
+
height: 100,
109
+
};
82
110
83
111
// 0 size can cause app to crash, better to enforce this maybe.
84
112
// crashes on webgl??
···
89
117
#[cfg(not(target_arch = "wasm32"))]
90
118
backends: wgpu::Backends::PRIMARY,
91
119
92
-
// WebGPU is sadly not supported in most browsers (yet!)
120
+
// WebGPU is sadly not supported in most browsers (yet!)
93
121
#[cfg(target_arch = "wasm32")]
94
-
backends: wgpu::Backends::GL,
122
+
backends: wgpu::Backends::BROWSER_WEBGPU | wgpu::Backends::GL,
95
123
96
124
..Default::default()
97
125
});
···
151
179
surface.configure(&device, &config);
152
180
153
181
let diffuse_bytes = include_bytes!("happy-tree.png");
154
-
let diffuse_texture = texture::Texture::from_bytes(&device, &queue, diffuse_bytes, "happy_tree.png").unwrap();
182
+
let diffuse_texture =
183
+
texture::Texture::from_bytes(&device, &queue, diffuse_bytes, "happy_tree.png").unwrap();
155
184
156
-
let texture_bind_group_layout = device.create_bind_group_layout(
157
-
&wgpu::BindGroupLayoutDescriptor {
185
+
let texture_bind_group_layout =
186
+
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
158
187
entries: &[
159
188
wgpu::BindGroupLayoutEntry {
160
189
binding: 0,
···
162
191
ty: wgpu::BindingType::Texture {
163
192
multisampled: false,
164
193
view_dimension: wgpu::TextureViewDimension::D2,
165
-
sample_type: wgpu::TextureSampleType::Float {
166
-
filterable: true
167
-
},
194
+
sample_type: wgpu::TextureSampleType::Float { filterable: true },
168
195
},
169
196
count: None,
170
197
},
···
173
200
visibility: wgpu::ShaderStages::FRAGMENT,
174
201
ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
175
202
count: None,
176
-
}
203
+
},
177
204
],
178
-
label: Some("texture_bind_group_layout")
179
-
}
180
-
);
205
+
label: Some("texture_bind_group_layout"),
206
+
});
207
+
208
+
let diffuse_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
209
+
layout: &texture_bind_group_layout,
210
+
entries: &[
211
+
wgpu::BindGroupEntry {
212
+
binding: 0,
213
+
resource: wgpu::BindingResource::TextureView(&diffuse_texture.view),
214
+
},
215
+
wgpu::BindGroupEntry {
216
+
binding: 1,
217
+
resource: wgpu::BindingResource::Sampler(&diffuse_texture.sampler),
218
+
},
219
+
],
220
+
label: Some("diffuse_bind_group"),
221
+
});
222
+
223
+
let camera = camera::Camera {
224
+
eye: vec3(0., 1., 2.),
225
+
target: Vec3::ZERO,
226
+
up: Vec3::Y,
227
+
aspect: config.width as f32 / config.height as f32,
228
+
fovy: 45.0,
229
+
znear: 0.1,
230
+
zfar: 100.0,
231
+
};
181
232
182
-
let diffuse_bind_group = device.create_bind_group(
183
-
&wgpu::BindGroupDescriptor {
184
-
layout: &texture_bind_group_layout,
185
-
entries: &[
186
-
wgpu::BindGroupEntry {
187
-
binding: 0,
188
-
resource: wgpu::BindingResource::TextureView(&diffuse_texture.view),
233
+
let camera_controller = camera::CameraController::new(0.2);
234
+
let mut camera_uniform = camera::CameraUniform::new();
235
+
camera_uniform.update_view_proj(&camera);
236
+
237
+
let camera_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
238
+
label: Some("Camera Buffer"),
239
+
contents: bytemuck::cast_slice(&[camera_uniform]),
240
+
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
241
+
});
242
+
243
+
let camera_bind_group_layout =
244
+
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
245
+
entries: &[wgpu::BindGroupLayoutEntry {
246
+
binding: 0,
247
+
visibility: wgpu::ShaderStages::VERTEX,
248
+
ty: wgpu::BindingType::Buffer {
249
+
ty: wgpu::BufferBindingType::Uniform,
250
+
has_dynamic_offset: false,
251
+
min_binding_size: None,
189
252
},
190
-
wgpu::BindGroupEntry {
191
-
binding: 1,
192
-
resource: wgpu::BindingResource::Sampler(&diffuse_texture.sampler),
193
-
}
194
-
],
195
-
label: Some("diffuse_bind_group"),
196
-
}
197
-
);
253
+
count: None,
254
+
}],
255
+
label: Some("camera_bind_group_layout"),
256
+
});
198
257
258
+
let camera_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
259
+
layout: &camera_bind_group_layout,
260
+
entries: &[wgpu::BindGroupEntry {
261
+
binding: 0,
262
+
resource: camera_buffer.as_entire_binding(),
263
+
}],
264
+
label: Some("camera_bind_group"),
265
+
});
199
266
200
267
let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
201
268
label: Some("Shader"),
···
205
272
let render_pipeline_layout =
206
273
device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
207
274
label: Some("Render Pipeline Layout"),
208
-
bind_group_layouts: &[&texture_bind_group_layout],
275
+
bind_group_layouts: &[&texture_bind_group_layout, &camera_bind_group_layout],
209
276
push_constant_ranges: &[],
210
277
});
211
278
···
253
320
usage: wgpu::BufferUsages::VERTEX,
254
321
});
255
322
256
-
let index_buffer = device.create_buffer_init(
257
-
&wgpu::util::BufferInitDescriptor {
258
-
label: Some("Index Buffer"),
259
-
contents: bytemuck::cast_slice(INDICES),
260
-
usage: wgpu::BufferUsages::INDEX,
261
-
}
262
-
);
323
+
let index_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
324
+
label: Some("Index Buffer"),
325
+
contents: bytemuck::cast_slice(INDICES),
326
+
usage: wgpu::BufferUsages::INDEX,
327
+
});
263
328
264
329
let num_indices = INDICES.len() as u32;
265
330
···
276
341
num_indices,
277
342
diffuse_bind_group,
278
343
diffuse_texture,
344
+
camera,
345
+
camera_controller,
346
+
camera_uniform,
347
+
camera_buffer,
348
+
camera_bind_group,
279
349
clear_color: wgpu::Color {
280
350
r: 0.1,
281
351
g: 0.2,
···
301
371
}
302
372
303
373
fn input(&mut self, event: &WindowEvent) -> bool {
374
+
self.camera_controller.process_events(event);
375
+
304
376
match event {
305
377
WindowEvent::CursorMoved {
306
378
device_id,
···
321
393
false
322
394
}
323
395
324
-
fn update(&mut self) {}
396
+
fn update(&mut self) {
397
+
self.camera_controller.update_camera(&mut self.camera);
398
+
self.camera_uniform.update_view_proj(&self.camera);
399
+
self.queue.write_buffer(
400
+
&self.camera_buffer,
401
+
0,
402
+
bytemuck::cast_slice(&[self.camera_uniform]),
403
+
);
404
+
}
325
405
326
406
fn render(&mut self) -> Result<(), wgpu::SurfaceError> {
327
407
let output = self.surface.get_current_texture()?;
···
353
433
354
434
render_pass.set_pipeline(&self.render_pipeline);
355
435
render_pass.set_bind_group(0, &self.diffuse_bind_group, &[]);
436
+
render_pass.set_bind_group(1, &self.camera_bind_group, &[]);
356
437
render_pass.set_vertex_buffer(0, self.vertex_buffer.slice(..));
357
438
render_pass.set_index_buffer(self.index_buffer.slice(..), wgpu::IndexFormat::Uint16);
358
439
+7
-1
src/shader.wgsl
+7
-1
src/shader.wgsl
···
1
1
// Vertex shader
2
2
3
+
struct CameraUniform {
4
+
view_proj: mat4x4<f32>
5
+
};
6
+
@group(1) @binding(0)
7
+
var<uniform> camera: CameraUniform;
8
+
3
9
struct VertexInput {
4
10
@location(0) position: vec3<f32>,
5
11
@location(1) tex_coords: vec2<f32>,
···
16
22
) -> VertexOutput {
17
23
var out: VertexOutput;
18
24
out.tex_coords = model.tex_coords;
19
-
out.clip_position = vec4<f32>(model.position, 1.0);
25
+
out.clip_position = camera.view_proj * vec4<f32>(model.position, 1.0);
20
26
return out;
21
27
}
22
28
+5
-6
src/texture.rs
+5
-6
src/texture.rs
···
1
1
use image::GenericImageView;
2
-
use miette::{IntoDiagnostic, Report, Result};
3
2
4
3
pub struct Texture {
5
4
#[allow(unused)]
···
14
13
queue: &wgpu::Queue,
15
14
bytes: &[u8],
16
15
label: &str,
17
-
) -> Result<Self> {
18
-
let img = image::load_from_memory(bytes).into_diagnostic()?;
19
-
Self::from_image(device, queue, &img, Some(label))
16
+
) -> Result<Self, image::ImageError> {
17
+
let img = image::load_from_memory(bytes)?;
18
+
Ok(Self::from_image(device, queue, &img, Some(label)))
20
19
}
21
20
22
21
fn from_image(
···
24
23
queue: &wgpu::Queue,
25
24
img: &image::DynamicImage,
26
25
label: Option<&str>,
27
-
) -> Result<Self> {
26
+
) -> Self {
28
27
let rgba = img.to_rgba8();
29
28
let dimensions = img.dimensions();
30
29
···
76
75
}
77
76
);
78
77
79
-
Ok(Self { texture, view, sampler })
78
+
Self { texture, view, sampler }
80
79
}
81
80
}