1use std::sync::Arc;
2
3use nalgebra::{Matrix4, Point3, UnitQuaternion, Vector3};
4use wgpu::util::DeviceExt;
5use wgpu::{BindGroupLayoutEntry, BufferSlice};
6
7use crate::mipmapping::MipMapGen;
8use crate::PeterEngineApp;
9
10const DATA_TEXTURE_SIZE: usize = 2048;
11pub const MSAA_COUNT: u32 = 1;
12pub const MIP_LEVEL_COUNT: u32 = 4;
13
14pub const LINEAR_SAMPLER_DESCRIPTOR: wgpu::SamplerDescriptor = wgpu::SamplerDescriptor {
15 label: Some("linear_sampler"),
16 address_mode_u: wgpu::AddressMode::ClampToEdge,
17 address_mode_v: wgpu::AddressMode::ClampToEdge,
18 address_mode_w: wgpu::AddressMode::ClampToEdge,
19 mag_filter: wgpu::FilterMode::Linear,
20 min_filter: wgpu::FilterMode::Linear,
21 mipmap_filter: wgpu::FilterMode::Linear,
22 lod_min_clamp: 0.0,
23 lod_max_clamp: 32.0,
24 compare: None,
25 anisotropy_clamp: 1,
26 border_color: None,
27};
28
29pub const NEAREST_SAMPLER_DESCRIPTOR: wgpu::SamplerDescriptor = wgpu::SamplerDescriptor {
30 label: Some("nearest_sampler"),
31 address_mode_u: wgpu::AddressMode::ClampToEdge,
32 address_mode_v: wgpu::AddressMode::ClampToEdge,
33 address_mode_w: wgpu::AddressMode::ClampToEdge,
34 mag_filter: wgpu::FilterMode::Nearest,
35 min_filter: wgpu::FilterMode::Nearest,
36 mipmap_filter: wgpu::FilterMode::Nearest,
37 lod_min_clamp: 0.0,
38 lod_max_clamp: 32.0,
39 compare: None,
40 anisotropy_clamp: 1,
41 border_color: None,
42};
43
44pub struct Transform {
45 pub translation: Vector3<f32>,
46 pub rotation: UnitQuaternion<f32>,
47 pub scale: f32,
48}
49
50impl Default for Transform {
51 fn default() -> Self {
52 Self {
53 translation: Vector3::new(0.0, 0.0, 0.0),
54 rotation: UnitQuaternion::identity(),
55 scale: 1.0,
56 }
57 }
58}
59
60impl Transform {
61 pub fn apply(&self, point: Point3<f32>) -> Point3<f32> {
62 return self.scale * (self.rotation * point) + self.translation;
63 }
64}
65
66pub struct Projection {
67 pub clip_near: f32,
68 pub clip_far: f32,
69 pub model_matrix: Matrix4<f32>,
70 pub view_matrix: Matrix4<f32>,
71 pub projection_matrix: Matrix4<f32>,
72 pub derived_pvm: Matrix4<f32>,
73 pub derived_vm: Matrix4<f32>,
74}
75
76impl Default for Projection {
77 fn default() -> Self {
78 Self {
79 clip_near: 0.1,
80 clip_far: 100.0,
81 model_matrix: Matrix4::identity(),
82 view_matrix: Matrix4::identity(),
83 projection_matrix: Matrix4::identity(),
84 derived_vm: Matrix4::identity(),
85 derived_pvm: Matrix4::identity(),
86 }
87 }
88}
89
90impl Projection {
91 fn recompute_derived(&mut self) {
92 self.derived_vm = self.view_matrix * self.model_matrix;
93 self.derived_pvm = self.projection_matrix * self.derived_vm;
94 }
95
96 pub fn set_model_matrix(&mut self, model_matrix: Matrix4<f32>) {
97 self.model_matrix = model_matrix;
98 self.recompute_derived();
99 }
100
101 pub fn set_view_matrix(&mut self, view_matrix: Matrix4<f32>) {
102 self.view_matrix = view_matrix;
103 self.recompute_derived();
104 }
105
106 pub fn set_projection_matrix(&mut self, projection_matrix: Matrix4<f32>) {
107 self.projection_matrix = projection_matrix;
108 self.recompute_derived();
109 }
110
111 pub fn set_model_transform(&mut self, model_transform: Transform) {
112 let mut model_matrix = Matrix4::identity();
113 let rotation = model_transform.rotation.to_rotation_matrix();
114 model_matrix.fixed_view_mut::<3, 3>(0, 0).copy_from(&rotation.matrix());
115 model_matrix.fixed_view_mut::<3, 1>(0, 3).copy_from(&model_transform.translation);
116 model_matrix.m43 *= model_transform.scale;
117 self.set_model_matrix(model_matrix);
118 }
119
120 #[rustfmt::skip]
121 pub fn set_view_look_at(&mut self, eye: Point3<f32>, look_at: Point3<f32>) {
122 let view = (look_at - eye).normalize();
123 let right = Vector3::y().cross(&view).normalize();
124 let up = view.cross(&right);
125 #[rustfmt::skip]
126 let view_matrix = Matrix4::new(
127 right.x, right.y, right.z, -right.dot(&eye.coords),
128 up.x, up.y, up.z, -up.dot(&eye.coords),
129 view.x, view.y, view.z, -view.dot(&eye.coords),
130 0.0, 0.0, 0.0, 1.0,
131 );
132 self.set_view_matrix(view_matrix);
133 }
134
135 #[rustfmt::skip]
138 pub fn set_perspective_projection(&mut self, fov_deg: f32, aspect: f32, near: f32, far: f32) {
139 self.clip_near = near;
140 self.clip_far = far;
141 let fov_rad = fov_deg * std::f32::consts::PI / 180.0;
142 let height = 1.0 / (fov_rad / 2.0).tan();
143 let width = height * aspect;
144 let m22 = far / (far - near);
145 #[rustfmt::skip]
146 let projection_matrix = Matrix4::new(
147 width, 0.0, 0.0, 0.0,
148 0.0, height, 0.0, 0.0,
149 0.0, 0.0, m22, -near * m22,
150 0.0, 0.0, 1.0, 0.0,
151 );
152 self.set_projection_matrix(projection_matrix);
153 }
154
155 #[rustfmt::skip]
156 pub fn set_ortho_projection(
157 &mut self,
158 w: f32,
159 h: f32,
160 near: f32,
161 far: f32,
162 ) {
163 self.clip_near = near;
164 self.clip_far = far;
165 let n = near;
166 let f = far;
167 #[rustfmt::skip]
168 let projection_matrix = Matrix4::new(
169 2.0/w, 0.0, 0.0, -1.0,
170 0.0, -2.0/h, 0.0, 1.0,
171 0.0, 0.0, 1.0/(f-n), n/(f-n),
172 0.0, 0.0, 0.0, 1.0,
173 );
174 self.set_projection_matrix(projection_matrix);
175 }
176
177 pub fn update_uniforms(&mut self, uniforms: &mut Uniforms) {
178 uniforms.transform_m = self.model_matrix.into();
179 uniforms.transform_vm = self.derived_vm.into();
180 uniforms.transform_pvm = self.derived_pvm.into();
181 if let Some(inv) = self.derived_pvm.try_inverse() {
182 uniforms.transform_pvm_inv = inv.into();
183 }
184 uniforms.near = self.clip_near;
185 uniforms.far = self.clip_far;
186 }
187
188 pub fn screen_space_to_world_space(&self, screen_space: Point3<f32>) -> Point3<f32> {
189 let inv_pvm = self.derived_pvm.try_inverse().unwrap();
190 inv_pvm.transform_point(&screen_space)
191 }
192}
193
194#[repr(C, align(16))]
197#[derive(Debug, Clone, Copy, Default)]
198pub struct Vertex {
199 pub position: [f32; 3],
200 pub color: [f32; 4],
201 pub uv: [f32; 2],
202}
203
204impl Vertex {
205 const ATTRIBS: [wgpu::VertexAttribute; 3] =
206 wgpu::vertex_attr_array![0 => Float32x3, 1 => Float32x4, 2 => Float32x2];
207
208 pub fn desc() -> wgpu::VertexBufferLayout<'static> {
209 wgpu::VertexBufferLayout {
210 array_stride: std::mem::size_of::<Self>() as wgpu::BufferAddress,
211 step_mode: wgpu::VertexStepMode::Vertex,
212 attributes: &Self::ATTRIBS,
213 }
214 }
215}
216
217#[repr(C, align(16))]
218#[derive(Debug, Clone)]
219pub struct Uniforms {
220 pub transform_m: [[f32; 4]; 4],
221 pub transform_vm: [[f32; 4]; 4],
222 pub transform_pvm: [[f32; 4]; 4],
223 pub transform_pvm_inv: [[f32; 4]; 4],
224 pub near: f32,
225 pub far: f32,
226}
227
228impl Uniforms {
229 pub fn new() -> Self {
230 Self {
231 transform_m: Matrix4::identity().into(),
232 transform_vm: Matrix4::identity().into(),
233 transform_pvm: Matrix4::identity().into(),
234 transform_pvm_inv: Matrix4::identity().into(),
235 near: 0.1,
236 far: 1000.0,
237 }
238 }
239}
240
241pub unsafe fn ref_as_u8_slice<T: Sized>(p: &T) -> &[u8] {
242 std::slice::from_raw_parts((p as *const T) as *const u8, std::mem::size_of::<T>())
243}
244
245pub unsafe fn slice_as_u8_slice<T: Sized>(p: &[T]) -> &[u8] {
246 std::slice::from_raw_parts((&p[0] as *const T) as *const u8, std::mem::size_of::<T>() * p.len())
247}
248
249pub struct ImageTexture {
250 pub texture: wgpu::Texture,
251 pub texture_view: wgpu::TextureView,
252 pub bind_group: wgpu::BindGroup,
253}
254
255pub struct DataTexture {
256 pub texture: wgpu::Texture,
257 pub texture_view: wgpu::TextureView,
258 pub bind_group: wgpu::BindGroup,
259 pub cpu_buffer: GpuDataTextureBuffer,
260}
261
262impl DataTexture {
263 pub fn flush_data_texture(&self, queue: &wgpu::Queue) {
264 let (row_count, bytes) = self.cpu_buffer.get_write_info();
265 if row_count == 0 {
266 return;
267 }
268 queue.write_texture(
269 wgpu::ImageCopyTexture {
270 texture: &self.texture,
271 mip_level: 0,
272 origin: wgpu::Origin3d::ZERO,
273 aspect: wgpu::TextureAspect::All,
274 },
275 bytes,
276 wgpu::ImageDataLayout {
277 offset: 0,
278 bytes_per_row: Some(4 * DATA_TEXTURE_SIZE as u32),
279 rows_per_image: Some(row_count),
280 },
281 wgpu::Extent3d {
282 width: DATA_TEXTURE_SIZE as u32,
283 height: row_count,
284 depth_or_array_layers: 1,
285 },
286 );
287 }
288}
289
290pub struct ResizingBuffer<T: Copy> {
291 pub label: String,
292 pub usage: wgpu::BufferUsages,
293 pub buffer_and_len: Option<(wgpu::Buffer, usize)>,
295 pub contents: Vec<T>,
296}
297
298impl<T: Copy> ResizingBuffer<T> {
299 pub fn new(label: &str, usage: wgpu::BufferUsages) -> Self {
300 Self {
301 label: label.to_string(),
302 usage,
303 buffer_and_len: None,
304 contents: Vec::new(),
305 }
306 }
307
308 pub fn update<'a>(&'a mut self, device: &wgpu::Device, queue: &wgpu::Queue) -> usize {
309 let reallocate_length = match self.buffer_and_len.as_mut() {
310 Some((_, buffer_len)) if self.contents.len() <= *buffer_len => None,
311 Some((_, ref buffer_len)) => Some(self.contents.len().max(buffer_len + buffer_len / 2)),
312 None => Some(self.contents.len().max(1)),
313 };
314 match reallocate_length {
315 Some(reallocate_length) => {
316 match self.buffer_and_len.take() {
317 Some((buffer, _)) => buffer.destroy(),
318 None => {}
319 }
320 self.buffer_and_len = Some((
321 device.create_buffer(&wgpu::BufferDescriptor {
322 label: Some(&self.label),
323 size: (std::mem::size_of::<T>() * reallocate_length)
324 as wgpu::BufferAddress,
325 usage: self.usage,
326 mapped_at_creation: false,
327 }),
328 reallocate_length,
329 ));
330 }
331 None => {}
332 }
333 let buffer = &self.buffer_and_len.as_ref().unwrap().0;
334 if !self.contents.is_empty() {
335 let slice: &[u8] = unsafe { slice_as_u8_slice(&self.contents) };
336 queue.write_buffer(buffer, 0, slice);
337 slice.len()
338 } else {
339 0
340 }
341 }
342
343 pub fn get_slice<'a>(&'a self) -> Option<BufferSlice<'a>> {
344 match &self.buffer_and_len {
345 Some((buffer, _)) => Some(buffer.slice(..)),
346 None => None,
347 }
348 }
349
350 #[inline]
351 pub fn clear(&mut self) {
352 self.contents.clear();
353 }
354
355 #[inline]
356 pub fn push(&mut self, value: T) {
357 self.contents.push(value);
358 }
359
360 #[inline]
361 pub fn extend_from_slice(&mut self, values: &[T]) {
362 self.contents.extend_from_slice(values);
363 }
364
365 #[inline]
366 pub fn len(&self) -> usize {
367 self.contents.len()
368 }
369}
370
371#[derive(Clone)]
372pub struct RenderBufferOptions {
373 pub format: wgpu::TextureFormat,
374 pub sampler: Arc<wgpu::Sampler>,
375 pub textured_bind_group_layout: Arc<wgpu::BindGroupLayout>,
376 pub msaa_count: u32,
377 pub mipmap_count: u32,
378}
379
380pub struct RenderBufferContents {
381 pub size: (u32, u32),
382 pub msaa_intermediate: Option<wgpu::Texture>,
383 pub color: wgpu::Texture,
384 pub depth: wgpu::Texture,
385 pub bind_group: wgpu::BindGroup,
386}
387
388pub struct RenderBuffer {
389 pub label: String,
390 pub options: RenderBufferOptions,
391 pub contents: Option<RenderBufferContents>,
392}
393
394impl RenderBuffer {
395 pub fn new(label: String, options: RenderBufferOptions) -> Self {
396 Self {
397 label,
398 options,
399 contents: None,
400 }
401 }
402
403 pub fn get_buffers(
404 &mut self,
405 device: &wgpu::Device,
406 new_size: (u32, u32),
407 ) -> &RenderBufferContents {
408 let reallocate = match self.contents.as_ref() {
409 Some(RenderBufferContents { size, .. }) if *size == new_size => false,
410 _ => true,
411 };
412 if reallocate {
413 if let Some(contents) = self.contents.take() {
414 if let Some(msaa_intermediate) = contents.msaa_intermediate {
415 msaa_intermediate.destroy();
416 }
417 contents.color.destroy();
418 contents.depth.destroy();
419 }
420 let make_tex = |format, label, sample_count, mip_level_count| {
421 device.create_texture(&wgpu::TextureDescriptor {
422 label: Some(label),
423 size: wgpu::Extent3d {
424 width: new_size.0,
425 height: new_size.1,
426 depth_or_array_layers: 1,
427 },
428 mip_level_count,
429 sample_count,
430 dimension: wgpu::TextureDimension::D2,
431 format,
432 usage: wgpu::TextureUsages::RENDER_ATTACHMENT
433 | wgpu::TextureUsages::COPY_SRC
434 | wgpu::TextureUsages::COPY_DST
435 | wgpu::TextureUsages::TEXTURE_BINDING,
436 view_formats: &[], })
438 };
439 let label_color = format!("{}-color", self.label);
440 let label_depth = format!("{}-depth", self.label);
441 let msaa_intermediate = match self.options.msaa_count > 1 {
442 true => Some(make_tex(
443 self.options.format,
444 &label_color,
445 self.options.msaa_count,
446 self.options.mipmap_count,
447 )),
448 false => None,
449 };
450 let color = make_tex(
451 self.options.format,
452 &label_color,
453 self.options.msaa_count,
454 self.options.mipmap_count,
455 );
456 let depth =
457 make_tex(wgpu::TextureFormat::Depth32Float, &label_depth, self.options.msaa_count, 1);
458 let texture_view = color.create_view(&wgpu::TextureViewDescriptor::default());
459 let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
460 layout: &self.options.textured_bind_group_layout,
461 entries: &[
462 wgpu::BindGroupEntry {
463 binding: 0,
464 resource: wgpu::BindingResource::TextureView(&texture_view),
465 },
466 wgpu::BindGroupEntry {
467 binding: 1,
468 resource: wgpu::BindingResource::Sampler(&self.options.sampler),
469 },
470 ],
471 label: Some(&format!("{}-bind-group", self.label)),
472 });
473 self.contents = Some(RenderBufferContents {
474 size: new_size,
475 msaa_intermediate,
476 color,
477 depth,
478 bind_group,
479 });
480 }
481 &self.contents.as_ref().unwrap()
482 }
483}
484
485#[derive(Clone)]
486pub struct CameraSettings {
487 pub screen_size: (u32, u32),
488 pub position: Point3<f32>,
489 pub heading: f32,
490 pub pitch: f32,
491}
492
493impl CameraSettings {
494 pub fn new() -> Self {
495 Self {
496 screen_size: (800, 600),
497 position: Point3::origin(),
498 heading: 0.0,
499 pitch: 0.0,
500 }
501 }
502
503 pub fn aspect_ratio(&self) -> f32 {
504 self.screen_size.0 as f32 / self.screen_size.1 as f32
505 }
506
507 pub fn eye_vector(&self) -> Vector3<f32> {
508 let x = self.heading.cos() * self.pitch.cos();
509 let y = self.pitch.sin();
510 let z = self.heading.sin() * self.pitch.cos();
511 Vector3::new(x, y, z)
512 }
513
514 pub fn right_vector(&self) -> Vector3<f32> {
515 Vector3::new(self.heading.sin(), 0.0, -self.heading.cos())
516 }
517}
518
519pub struct UniformsBuffer {
520 pub uniforms: Uniforms,
521 pub uniforms_buffer: wgpu::Buffer,
522 pub bind_group_layout: wgpu::BindGroupLayout,
523 pub bind_group: wgpu::BindGroup,
524}
525
526impl UniformsBuffer {
527 pub fn new(label: &str, device: &wgpu::Device) -> Self {
528 let uniforms = Uniforms::new();
529 let uniforms_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
530 label: Some(label),
531 contents: unsafe { ref_as_u8_slice(&uniforms) },
532 usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
533 });
534 let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
535 entries: &[wgpu::BindGroupLayoutEntry {
536 binding: 0,
537 visibility: wgpu::ShaderStages::VERTEX | wgpu::ShaderStages::FRAGMENT,
538 ty: wgpu::BindingType::Buffer {
539 ty: wgpu::BufferBindingType::Uniform,
540 has_dynamic_offset: false,
541 min_binding_size: None,
542 },
543 count: None,
544 }],
545 label: Some(label),
546 });
547 let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
548 layout: &bind_group_layout,
549 entries: &[wgpu::BindGroupEntry {
550 binding: 0,
551 resource: uniforms_buffer.as_entire_binding(),
552 }],
553 label: Some(label),
554 });
555 Self {
556 uniforms,
557 uniforms_buffer,
558 bind_group_layout,
559 bind_group,
560 }
561 }
562
563 pub fn write_buffer(&self, queue: &wgpu::Queue) {
564 queue.write_buffer(&self.uniforms_buffer, 0, unsafe { ref_as_u8_slice(&self.uniforms) });
565 }
566}
567
568pub struct GeometryBuffer<V: Copy = Vertex> {
569 pub vertex_buffer: ResizingBuffer<V>,
570 pub index_buffer: ResizingBuffer<u32>,
571}
572
573impl<V: Copy> GeometryBuffer<V> {
574 pub fn new(name: &str) -> Self {
575 Self {
576 vertex_buffer: ResizingBuffer::new(
577 name,
578 wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST,
579 ),
580 index_buffer: ResizingBuffer::new(
581 name,
582 wgpu::BufferUsages::INDEX | wgpu::BufferUsages::COPY_DST,
583 ),
584 }
585 }
586
587 pub fn update(&mut self, device: &wgpu::Device, queue: &wgpu::Queue) -> usize {
588 self.vertex_buffer.update(device, queue) + self.index_buffer.update(device, queue)
589 }
590
591 pub fn clear(&mut self) {
592 self.vertex_buffer.clear();
593 self.index_buffer.clear();
594 }
595}
596
597impl GeometryBuffer<Vertex> {
598 pub fn add_line(&mut self, a: Point3<f32>, b: Point3<f32>, color: [f32; 4]) {
599 let index = self.vertex_buffer.len() as u32;
600 self.vertex_buffer.push(Vertex {
601 position: [a.x, a.y, a.z],
602 color,
603 uv: [0.0, 0.0],
604 });
605 self.vertex_buffer.push(Vertex {
606 position: [b.x, b.y, b.z],
607 color,
608 uv: [0.0, 0.0],
609 });
610 self.index_buffer.push(index);
611 self.index_buffer.push(index + 1);
612 }
613}
614
615pub struct GpuDataTextureBuffer {
616 pub data: Vec<u32>,
617 pub ptr: usize,
618}
619
620impl GpuDataTextureBuffer {
621 pub fn new() -> Self {
622 Self {
623 data: vec![0; DATA_TEXTURE_SIZE * DATA_TEXTURE_SIZE],
624 ptr: 0,
625 }
626 }
627
628 pub fn push(&mut self, value: u32) {
629 self.data[self.ptr] = value;
630 self.ptr += 1;
631 }
632
633 pub fn reset(&mut self) {
634 self.ptr = 0;
635 }
636
637 pub fn get_write_info(&self) -> (u32, &[u8]) {
639 let rows = (self.ptr + DATA_TEXTURE_SIZE - 1) / DATA_TEXTURE_SIZE;
641 let bytes = 4 * rows * DATA_TEXTURE_SIZE;
642 (rows as u32, unsafe {
643 std::slice::from_raw_parts(self.data.as_ptr() as *const u8, bytes as usize)
644 })
645 }
646}
647
648pub static SHADER_PRELUDE: &str = include_str!("shaders.wgsl");
649
650pub enum BindingDesc {
668 Uniforms,
669 Texture { filterable: bool },
674 Sampler { filterable: bool },
675 DataTexture,
676 Custom(wgpu::BindGroupLayoutEntry),
677}
678
679pub struct PipelineDesc {
680 pub layout: Vec<Vec<BindingDesc>>,
681 pub vertex_buffers: Vec<wgpu::VertexBufferLayout<'static>>,
682 pub vertex_shader: &'static str,
683 pub fragment_shader: &'static str,
684 pub topology: wgpu::PrimitiveTopology,
685 pub do_blend: bool,
686 pub depth_compare: bool,
687 pub depth_write: bool,
688}
689
690impl Default for PipelineDesc {
691 fn default() -> Self {
692 Self {
693 layout: Vec::new(),
694 vertex_buffers: Vec::new(),
695 vertex_shader: "vertex shader not specified!",
696 fragment_shader: "fragment shader not specified!",
697 topology: wgpu::PrimitiveTopology::TriangleList,
698 do_blend: false,
699 depth_compare: true,
700 depth_write: true,
701 }
702 }
703}
704
705pub struct RenderData {
729 pub target_format: wgpu::TextureFormat,
730 pub main_uniforms: UniformsBuffer,
731 pub device: Arc<wgpu::Device>,
732 pub queue: Arc<wgpu::Queue>,
733 pub shader: wgpu::ShaderModule,
734 pub linear_texture_sampler: wgpu::Sampler,
735 pub nearest_texture_sampler: wgpu::Sampler,
736 pub textured_bind_group_layout: wgpu::BindGroupLayout,
737 pub mipmap_gen: MipMapGen,
742 pub pixel_perfect_size: (u32, u32),
743 }
746
747impl RenderData {
751 pub fn new(cc: &eframe::CreationContext, shader_source: &str) -> Self {
774 let wgpu_render_state = cc.wgpu_render_state.as_ref().unwrap();
775 let device = Arc::clone(&wgpu_render_state.device);
776 let queue = Arc::clone(&wgpu_render_state.queue);
777
778 let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
779 label: None,
780 source: wgpu::ShaderSource::Wgsl(std::borrow::Cow::Borrowed(shader_source)),
781 });
782
783 let linear_texture_sampler = device.create_sampler(&LINEAR_SAMPLER_DESCRIPTOR);
784 let nearest_texture_sampler = device.create_sampler(&NEAREST_SAMPLER_DESCRIPTOR);
785 let textured_bind_group_layout =
786 device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
787 entries: &[
788 wgpu::BindGroupLayoutEntry {
789 binding: 0,
790 visibility: wgpu::ShaderStages::FRAGMENT,
791 ty: wgpu::BindingType::Texture {
792 multisampled: false,
793 view_dimension: wgpu::TextureViewDimension::D2,
794 sample_type: wgpu::TextureSampleType::Float { filterable: true },
795 },
796 count: None,
797 },
798 wgpu::BindGroupLayoutEntry {
799 binding: 1,
800 visibility: wgpu::ShaderStages::FRAGMENT,
801 ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
802 count: None,
803 },
804 ],
805 label: Some("textured_bind_group_layout"),
806 });
807
808 let main_uniforms = UniformsBuffer::new("main_uniforms", &device);
809
810 let mipmap_gen = MipMapGen::new(&device, wgpu::TextureFormat::Rgba8UnormSrgb);
822
823 Self {
834 target_format: wgpu_render_state.target_format,
835 main_uniforms,
836 device,
837 queue,
838 shader,
839 linear_texture_sampler,
840 nearest_texture_sampler,
841 textured_bind_group_layout,
842 mipmap_gen,
847 pixel_perfect_size: (1, 1),
848 }
853 }
854
855 pub fn create_pipeline(&self, desc: PipelineDesc) -> wgpu::RenderPipeline {
856 let mut target: wgpu::ColorTargetState = self.target_format.into();
857 if desc.do_blend {
858 target.blend = Some(wgpu::BlendState::ALPHA_BLENDING);
859 }
860 let mut bind_group_layouts = Vec::new();
861 for bind_group_desc in desc.layout {
862 let mut bindings = Vec::new();
863 for (binding_index, binding_desc) in bind_group_desc.iter().enumerate() {
864 bindings.push(match binding_desc {
865 BindingDesc::Uniforms => wgpu::BindGroupLayoutEntry {
866 binding: binding_index as u32,
867 visibility: wgpu::ShaderStages::VERTEX | wgpu::ShaderStages::FRAGMENT,
868 ty: wgpu::BindingType::Buffer {
869 ty: wgpu::BufferBindingType::Uniform,
870 has_dynamic_offset: false,
871 min_binding_size: None,
872 },
873 count: None,
874 },
875 BindingDesc::Texture { filterable } => wgpu::BindGroupLayoutEntry {
889 binding: binding_index as u32,
890 visibility: wgpu::ShaderStages::FRAGMENT,
891 ty: wgpu::BindingType::Texture {
892 multisampled: false,
893 view_dimension: wgpu::TextureViewDimension::D2,
894 sample_type: wgpu::TextureSampleType::Float {
895 filterable: *filterable,
896 },
897 },
898 count: None,
899 },
900 BindingDesc::DataTexture => wgpu::BindGroupLayoutEntry {
901 binding: binding_index as u32,
902 visibility: wgpu::ShaderStages::VERTEX | wgpu::ShaderStages::FRAGMENT,
903 ty: wgpu::BindingType::Texture {
904 multisampled: false,
905 view_dimension: wgpu::TextureViewDimension::D2,
906 sample_type: wgpu::TextureSampleType::Uint,
907 },
908 count: None,
909 },
910 BindingDesc::Sampler { filterable } => wgpu::BindGroupLayoutEntry {
911 binding: binding_index as u32,
912 visibility: wgpu::ShaderStages::FRAGMENT,
913 ty: wgpu::BindingType::Sampler(match *filterable {
914 true => wgpu::SamplerBindingType::Filtering,
915 false => wgpu::SamplerBindingType::NonFiltering,
916 }),
917 count: None,
918 },
919 BindingDesc::Custom(bind_group_layout_entry) => bind_group_layout_entry.clone(),
920 });
921 }
922 bind_group_layouts.push(self.device.create_bind_group_layout(
923 &wgpu::BindGroupLayoutDescriptor {
924 label: None,
925 entries: &bindings,
926 },
927 ));
928 }
929 let binding_group_layouts_by_ref =
930 bind_group_layouts.iter().map(|bgl| bgl as &wgpu::BindGroupLayout).collect::<Vec<_>>();
931 let pipeline_layout = self.device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
932 label: None,
933 bind_group_layouts: &binding_group_layouts_by_ref,
934 push_constant_ranges: &[],
935 });
936 self.device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
937 label: None,
938 layout: Some(&pipeline_layout),
939 vertex: wgpu::VertexState {
940 module: &self.shader,
941 entry_point: desc.vertex_shader,
942 buffers: &desc.vertex_buffers,
943 },
944 fragment: Some(wgpu::FragmentState {
945 module: &self.shader,
946 entry_point: desc.fragment_shader,
947 targets: &[Some(target)],
948 }),
949 primitive: wgpu::PrimitiveState {
950 topology: desc.topology,
951 strip_index_format: None,
952 front_face: wgpu::FrontFace::Ccw,
953 cull_mode: Some(wgpu::Face::Back),
954 polygon_mode: wgpu::PolygonMode::Fill,
955 unclipped_depth: false,
956 conservative: false,
957 },
958 depth_stencil: Some(wgpu::DepthStencilState {
959 format: wgpu::TextureFormat::Depth32Float,
960 depth_write_enabled: desc.depth_write,
961 depth_compare: match desc.depth_compare {
962 true => wgpu::CompareFunction::Less,
963 false => wgpu::CompareFunction::Always,
964 },
965 stencil: wgpu::StencilState::default(),
966 bias: wgpu::DepthBiasState::default(),
967 }),
968 multisample: wgpu::MultisampleState {
969 count: MSAA_COUNT,
970 mask: !0,
971 alpha_to_coverage_enabled: false,
972 },
973 multiview: None,
974 })
975 }
976
977 pub fn load_texture(&self, bytes: &[u8], filter: bool) -> ImageTexture {
978 let mip_level_count = if filter { MIP_LEVEL_COUNT } else { 1 };
979 let diffuse_image = image::load_from_memory(bytes).unwrap();
980 let diffuse_rgba = diffuse_image.to_rgba8();
981 let dimensions = diffuse_rgba.dimensions();
982 let texture_size = wgpu::Extent3d {
983 width: dimensions.0,
984 height: dimensions.1,
985 depth_or_array_layers: 1,
986 };
987 let diffuse_texture = self.device.create_texture(&wgpu::TextureDescriptor {
988 size: texture_size,
989 mip_level_count,
990 sample_count: 1,
991 dimension: wgpu::TextureDimension::D2,
992 format: wgpu::TextureFormat::Rgba8UnormSrgb,
993 usage: wgpu::TextureUsages::TEXTURE_BINDING
994 | wgpu::TextureUsages::COPY_DST
995 | wgpu::TextureUsages::RENDER_ATTACHMENT,
996 label: Some("font_texture"),
997 view_formats: &[],
998 });
999 self.queue.write_texture(
1000 wgpu::ImageCopyTexture {
1001 texture: &diffuse_texture,
1002 mip_level: 0,
1003 origin: wgpu::Origin3d::ZERO,
1004 aspect: wgpu::TextureAspect::All,
1005 },
1006 &diffuse_rgba,
1007 wgpu::ImageDataLayout {
1008 offset: 0,
1009 bytes_per_row: Some(4 * dimensions.0),
1010 rows_per_image: Some(dimensions.1),
1011 },
1012 texture_size,
1013 );
1014 if mip_level_count > 1 {
1015 let mut mipmap_encoder =
1016 self.device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
1017 label: Some("mipmap_gen"),
1018 });
1019 self.mipmap_gen.generate_mipmaps(
1020 &mut mipmap_encoder,
1021 &self.device,
1022 &diffuse_texture,
1023 mip_level_count,
1024 );
1025 self.queue.submit(Some(mipmap_encoder.finish()));
1026 }
1027 let texture_view = diffuse_texture.create_view(&wgpu::TextureViewDescriptor::default());
1028 let bind_group = self.device.create_bind_group(&wgpu::BindGroupDescriptor {
1029 layout: &self.textured_bind_group_layout,
1030 entries: &[
1031 wgpu::BindGroupEntry {
1032 binding: 0,
1033 resource: wgpu::BindingResource::TextureView(&texture_view),
1034 },
1035 wgpu::BindGroupEntry {
1036 binding: 1,
1037 resource: wgpu::BindingResource::Sampler(match filter {
1038 true => &self.linear_texture_sampler,
1039 false => &self.nearest_texture_sampler,
1040 }),
1041 },
1042 ],
1043 label: None,
1044 });
1045 ImageTexture {
1046 texture: diffuse_texture,
1047 texture_view,
1048 bind_group,
1049 }
1050 }
1051
1052 pub fn new_data_texture(&self) -> DataTexture {
1053 let data_texture = self.device.create_texture(&wgpu::TextureDescriptor {
1054 size: wgpu::Extent3d {
1055 width: DATA_TEXTURE_SIZE as u32,
1056 height: DATA_TEXTURE_SIZE as u32,
1057 depth_or_array_layers: 1,
1058 },
1059 mip_level_count: 1,
1060 sample_count: 1,
1061 dimension: wgpu::TextureDimension::D2,
1062 format: wgpu::TextureFormat::R32Uint,
1063 usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST,
1064 label: Some("data_texture"),
1065 view_formats: &[],
1066 });
1067 let data_texture_view = data_texture.create_view(&wgpu::TextureViewDescriptor {
1068 format: Some(wgpu::TextureFormat::R32Uint),
1069 ..Default::default()
1070 });
1071 let data_texture_bind_group_layout =
1072 self.device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
1073 entries: &[wgpu::BindGroupLayoutEntry {
1074 binding: 0,
1075 visibility: wgpu::ShaderStages::VERTEX | wgpu::ShaderStages::FRAGMENT,
1076 ty: wgpu::BindingType::Texture {
1077 multisampled: false,
1078 view_dimension: wgpu::TextureViewDimension::D2,
1079 sample_type: wgpu::TextureSampleType::Uint,
1080 },
1081 count: None,
1082 }],
1083 label: Some("data_texture_bind_group_layout"),
1084 });
1085 let data_texture_bind_group = self.device.create_bind_group(&wgpu::BindGroupDescriptor {
1086 layout: &data_texture_bind_group_layout,
1087 entries: &[wgpu::BindGroupEntry {
1088 binding: 0,
1089 resource: wgpu::BindingResource::TextureView(&data_texture_view),
1090 }],
1091 label: Some("data_texture_bind_group"),
1092 });
1093 DataTexture {
1094 texture: data_texture,
1095 texture_view: data_texture_view,
1096 bind_group: data_texture_bind_group,
1097 cpu_buffer: GpuDataTextureBuffer::new(),
1098 }
1099 }
1100}