]> git.lizzy.rs Git - mt_client.git/blob - src/gfx/map.rs
Mesh data queue
[mt_client.git] / src / gfx / map.rs
1 mod atlas;
2 mod mesh;
3
4 use super::{media::MediaMgr, state::State, util::MatrixUniform};
5 use atlas::create_atlas;
6 use cgmath::{prelude::*, Matrix4, Point3, Vector3};
7 use mesh::{create_mesh, MeshData};
8 use mt_net::{MapBlock, NodeDef};
9 use serde::{Deserialize, Serialize};
10 use std::{
11     collections::HashMap,
12     ops::DerefMut,
13     sync::{Arc, Mutex},
14 };
15 use wgpu::util::DeviceExt;
16
17 #[derive(Serialize, Deserialize, PartialEq, Eq, Copy, Clone, Debug)]
18 #[serde(rename_all = "snake_case")]
19 pub enum LeavesMode {
20     Opaque,
21     Simple,
22     Fancy,
23 }
24
25 #[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
26 pub struct MapRenderSettings {
27     pub leaves: LeavesMode,
28     pub opaque_liquids: bool,
29 }
30
31 impl Default for MapRenderSettings {
32     fn default() -> Self {
33         Self {
34             leaves: LeavesMode::Fancy,
35             opaque_liquids: false,
36         }
37     }
38 }
39
40 struct AtlasSlice {
41     cube_tex_coords: [[[f32; 2]; 6]; 6],
42 }
43
44 struct MeshMakeInfo {
45     // i optimized the shit out of these
46     textures: Vec<AtlasSlice>,
47     nodes: [Option<Box<NodeDef>>; u16::MAX as usize + 1],
48 }
49
50 type MeshQueue = HashMap<Point3<i16>, MeshData>;
51
52 pub struct MapRender {
53     pipeline: wgpu::RenderPipeline,
54     atlas: wgpu::BindGroup,
55     model: wgpu::BindGroupLayout,
56     blocks: HashMap<[i16; 3], BlockModel>,
57     mesh_make_info: Arc<MeshMakeInfo>,
58     mesh_data_buffer: Mutex<usize>,
59     queue_consume: MeshQueue,
60     queue_produce: Arc<Mutex<MeshQueue>>,
61 }
62
63 #[repr(C)]
64 #[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)]
65 struct Vertex {
66     pos: [f32; 3],
67     tex_coords: [f32; 2],
68     light: f32,
69 }
70
71 impl Vertex {
72     const ATTRIBS: [wgpu::VertexAttribute; 3] =
73         wgpu::vertex_attr_array![0 => Float32x3, 1 => Float32x2, 2 => Float32];
74
75     fn desc<'a>() -> wgpu::VertexBufferLayout<'a> {
76         wgpu::VertexBufferLayout {
77             array_stride: std::mem::size_of::<Self>() as wgpu::BufferAddress,
78             step_mode: wgpu::VertexStepMode::Vertex,
79             attributes: &Self::ATTRIBS,
80         }
81     }
82 }
83
84 struct BlockMesh {
85     vertex_buffer: wgpu::Buffer,
86     num_vertices: u32,
87 }
88
89 impl BlockMesh {
90     fn new(state: &State, vertices: &[Vertex]) -> Option<Self> {
91         if vertices.is_empty() {
92             return None;
93         }
94
95         Some(BlockMesh {
96             vertex_buffer: state
97                 .device
98                 .create_buffer_init(&wgpu::util::BufferInitDescriptor {
99                     label: Some("mapblock.vertex_buffer"),
100                     contents: bytemuck::cast_slice(vertices),
101                     usage: wgpu::BufferUsages::VERTEX,
102                 }),
103             num_vertices: vertices.len() as u32,
104         })
105     }
106
107     fn render<'a>(&'a self, pass: &mut wgpu::RenderPass<'a>, transform: &'a MatrixUniform) {
108         pass.set_bind_group(2, &transform.bind_group, &[]);
109         pass.set_vertex_buffer(0, self.vertex_buffer.slice(..));
110         pass.draw(0..self.num_vertices, 0..1);
111     }
112 }
113
114 struct BlockModel {
115     mesh: Option<BlockMesh>,
116     mesh_blend: Option<BlockMesh>,
117     transform: MatrixUniform,
118 }
119
120 fn block_float_pos(pos: Vector3<i16>) -> Vector3<f32> {
121     pos.cast::<f32>().unwrap() * 16.0
122 }
123
124 impl MapRender {
125     pub fn render<'a>(&'a self, state: &'a State, pass: &mut wgpu::RenderPass<'a>) {
126         pass.set_pipeline(&self.pipeline);
127         pass.set_bind_group(0, &self.atlas, &[]);
128         pass.set_bind_group(1, &state.camera_uniform.bind_group, &[]);
129
130         struct BlendEntry<'a> {
131             dist: f32,
132             index: usize,
133             mesh: &'a BlockMesh,
134             transform: &'a MatrixUniform,
135         }
136
137         let mut blend = Vec::new();
138
139         for (index, (pos, model)) in self.blocks.iter().enumerate() {
140             if let Some(mesh) = &model.mesh {
141                 mesh.render(pass, &model.transform);
142             }
143
144             if let Some(mesh) = &model.mesh_blend {
145                 blend.push(BlendEntry {
146                     index,
147                     dist: (block_float_pos(Vector3::from(*pos))
148                         - Vector3::from(state.camera.position))
149                     .magnitude(),
150                     mesh,
151                     transform: &model.transform,
152                 });
153             }
154         }
155
156         blend.sort_unstable_by(|a, b| {
157             a.dist
158                 .partial_cmp(&b.dist)
159                 .unwrap_or(std::cmp::Ordering::Equal)
160                 .then_with(|| a.index.cmp(&b.index))
161         });
162
163         for entry in blend {
164             entry.mesh.render(pass, entry.transform);
165         }
166     }
167
168     pub fn update(&mut self, state: &mut State) {
169         std::mem::swap(
170             self.queue_produce.lock().unwrap().deref_mut(),
171             &mut self.queue_consume,
172         );
173         for (pos, data) in self.queue_consume.drain() {
174             self.blocks.insert(
175                 pos.into(),
176                 BlockModel {
177                     mesh: BlockMesh::new(state, &data.vertices),
178                     mesh_blend: BlockMesh::new(state, &data.vertices_blend),
179                     transform: MatrixUniform::new(
180                         &state.device,
181                         &self.model,
182                         Matrix4::from_translation(
183                             block_float_pos(pos.to_vec()) + Vector3::new(8.5, 8.5, 8.5),
184                         ),
185                         "mapblock",
186                         false,
187                     ),
188                 },
189             );
190         }
191     }
192
193     pub fn add_block(&self, pos: Point3<i16>, block: Box<MapBlock>) {
194         let (pos, data) = create_mesh(
195             &mut self.mesh_data_buffer.lock().unwrap(),
196             self.mesh_make_info.clone(),
197             &Default::default(),
198             pos,
199             block,
200         );
201
202         self.queue_produce.lock().unwrap().insert(pos, data);
203     }
204
205     pub fn new(state: &mut State, media: &MediaMgr, mut nodes: HashMap<u16, NodeDef>) -> Self {
206         let (atlas_img, atlas_slices) = create_atlas(&mut nodes, media);
207
208         let atlas_size = wgpu::Extent3d {
209             width: atlas_img.width(),
210             height: atlas_img.height(),
211             depth_or_array_layers: 1,
212         };
213
214         let atlas_texture = state.device.create_texture(&wgpu::TextureDescriptor {
215             size: atlas_size,
216             mip_level_count: 1,
217             sample_count: 1,
218             dimension: wgpu::TextureDimension::D2,
219             format: wgpu::TextureFormat::Rgba8UnormSrgb,
220             usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST,
221             label: Some("tile_atlas"),
222             view_formats: &[],
223         });
224
225         state.queue.write_texture(
226             wgpu::ImageCopyTexture {
227                 texture: &atlas_texture,
228                 mip_level: 0,
229                 origin: wgpu::Origin3d::ZERO,
230                 aspect: wgpu::TextureAspect::All,
231             },
232             &atlas_img,
233             wgpu::ImageDataLayout {
234                 offset: 0,
235                 bytes_per_row: std::num::NonZeroU32::new(4 * atlas_img.width()),
236                 rows_per_image: std::num::NonZeroU32::new(atlas_img.height()),
237             },
238             atlas_size,
239         );
240
241         let atlas_view = atlas_texture.create_view(&wgpu::TextureViewDescriptor::default());
242
243         let atlas_sampler = state.device.create_sampler(&wgpu::SamplerDescriptor {
244             address_mode_u: wgpu::AddressMode::ClampToEdge,
245             address_mode_v: wgpu::AddressMode::ClampToEdge,
246             address_mode_w: wgpu::AddressMode::ClampToEdge,
247             // "We've got you surrounded, stop using Nearest filter"
248             // - "I hate bilinear filtering I hate bilinear filtering I hate bilinear filtering"
249             mag_filter: wgpu::FilterMode::Nearest,
250             min_filter: wgpu::FilterMode::Nearest,
251             mipmap_filter: wgpu::FilterMode::Nearest,
252             ..Default::default()
253         });
254
255         let atlas_bind_group_layout =
256             state
257                 .device
258                 .create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
259                     entries: &[
260                         wgpu::BindGroupLayoutEntry {
261                             binding: 0,
262                             visibility: wgpu::ShaderStages::FRAGMENT,
263                             ty: wgpu::BindingType::Texture {
264                                 multisampled: false,
265                                 view_dimension: wgpu::TextureViewDimension::D2,
266                                 sample_type: wgpu::TextureSampleType::Float { filterable: true },
267                             },
268                             count: None,
269                         },
270                         wgpu::BindGroupLayoutEntry {
271                             binding: 1,
272                             visibility: wgpu::ShaderStages::FRAGMENT,
273                             ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
274                             count: None,
275                         },
276                     ],
277                     label: Some("atlas.bind_group_layout"),
278                 });
279
280         let atlas_bind_group = state.device.create_bind_group(&wgpu::BindGroupDescriptor {
281             layout: &atlas_bind_group_layout,
282             entries: &[
283                 wgpu::BindGroupEntry {
284                     binding: 0,
285                     resource: wgpu::BindingResource::TextureView(&atlas_view),
286                 },
287                 wgpu::BindGroupEntry {
288                     binding: 1,
289                     resource: wgpu::BindingResource::Sampler(&atlas_sampler),
290                 },
291             ],
292             label: Some("atlas.bind_group"),
293         });
294
295         let model_bind_group_layout = MatrixUniform::layout(&state.device, "mapblock");
296
297         let shader = state
298             .device
299             .create_shader_module(wgpu::include_wgsl!("../../assets/shaders/map.wgsl"));
300
301         let pipeline_layout =
302             state
303                 .device
304                 .create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
305                     label: None,
306                     bind_group_layouts: &[
307                         &atlas_bind_group_layout,
308                         &model_bind_group_layout,
309                         &state.camera_bind_group_layout,
310                     ],
311                     push_constant_ranges: &[],
312                 });
313
314         let pipeline = state
315             .device
316             .create_render_pipeline(&wgpu::RenderPipelineDescriptor {
317                 label: None,
318                 layout: Some(&pipeline_layout),
319                 vertex: wgpu::VertexState {
320                     module: &shader,
321                     entry_point: "vs_main",
322                     buffers: &[Vertex::desc()],
323                 },
324                 fragment: Some(wgpu::FragmentState {
325                     module: &shader,
326                     entry_point: "fs_main",
327                     targets: &[Some(wgpu::ColorTargetState {
328                         format: state.config.format,
329                         blend: Some(wgpu::BlendState::REPLACE),
330                         write_mask: wgpu::ColorWrites::ALL,
331                     })],
332                 }),
333                 primitive: wgpu::PrimitiveState {
334                     topology: wgpu::PrimitiveTopology::TriangleList,
335                     strip_index_format: None,
336                     front_face: wgpu::FrontFace::Ccw,
337                     cull_mode: Some(wgpu::Face::Back),
338                     polygon_mode: wgpu::PolygonMode::Fill,
339                     unclipped_depth: false,
340                     conservative: false,
341                 },
342                 depth_stencil: Some(wgpu::DepthStencilState {
343                     format: wgpu::TextureFormat::Depth32Float,
344                     depth_write_enabled: true,
345                     depth_compare: wgpu::CompareFunction::Less,
346                     stencil: wgpu::StencilState::default(),
347                     bias: wgpu::DepthBiasState::default(),
348                 }),
349                 multisample: wgpu::MultisampleState {
350                     count: 1,
351                     mask: !0,
352                     alpha_to_coverage_enabled: false,
353                 },
354                 multiview: None,
355             });
356
357         Self {
358             pipeline,
359             mesh_make_info: Arc::new(MeshMakeInfo {
360                 nodes: std::array::from_fn(|i| nodes.get(&(i as u16)).cloned().map(Box::new)),
361                 textures: atlas_slices,
362             }),
363             mesh_data_buffer: Mutex::new(0),
364             atlas: atlas_bind_group,
365             model: model_bind_group_layout,
366             blocks: HashMap::new(),
367             queue_consume: HashMap::new(),
368             queue_produce: Arc::new(Mutex::new(HashMap::new())),
369         }
370     }
371 }
372
373 #[rustfmt::skip]
374 const CUBE: [[([f32; 3], [f32; 2]); 6]; 6] = [
375         [
376                 ([-0.5,  0.5, -0.5], [ 0.0,  1.0]),
377                 ([ 0.5,  0.5,  0.5], [ 1.0,  0.0]),
378                 ([ 0.5,  0.5, -0.5], [ 1.0,  1.0]),
379                 ([ 0.5,  0.5,  0.5], [ 1.0,  0.0]),
380                 ([-0.5,  0.5, -0.5], [ 0.0,  1.0]),
381                 ([-0.5,  0.5,  0.5], [ 0.0,  0.0]),
382         ],
383         [
384                 ([-0.5, -0.5, -0.5], [ 0.0,  1.0]),
385                 ([ 0.5, -0.5, -0.5], [ 1.0,  1.0]),
386                 ([ 0.5, -0.5,  0.5], [ 1.0,  0.0]),
387                 ([ 0.5, -0.5,  0.5], [ 1.0,  0.0]),
388                 ([-0.5, -0.5,  0.5], [ 0.0,  0.0]),
389                 ([-0.5, -0.5, -0.5], [ 0.0,  1.0]),
390         ],
391         [
392                 ([ 0.5,  0.5,  0.5], [ 1.0,  1.0]),
393                 ([ 0.5, -0.5, -0.5], [ 0.0,  0.0]),
394                 ([ 0.5,  0.5, -0.5], [ 0.0,  1.0]),
395                 ([ 0.5, -0.5, -0.5], [ 0.0,  0.0]),
396                 ([ 0.5,  0.5,  0.5], [ 1.0,  1.0]),
397                 ([ 0.5, -0.5,  0.5], [ 1.0,  0.0]),
398         ],
399         [
400                 ([-0.5,  0.5,  0.5], [ 1.0,  1.0]),
401                 ([-0.5,  0.5, -0.5], [ 0.0,  1.0]),
402                 ([-0.5, -0.5, -0.5], [ 0.0,  0.0]),
403                 ([-0.5, -0.5, -0.5], [ 0.0,  0.0]),
404                 ([-0.5, -0.5,  0.5], [ 1.0,  0.0]),
405                 ([-0.5,  0.5,  0.5], [ 1.0,  1.0]),
406         ],
407         [
408                 ([-0.5, -0.5,  0.5], [ 0.0,  0.0]),
409                 ([ 0.5, -0.5,  0.5], [ 1.0,  0.0]),
410                 ([ 0.5,  0.5,  0.5], [ 1.0,  1.0]),
411                 ([ 0.5,  0.5,  0.5], [ 1.0,  1.0]),
412                 ([-0.5,  0.5,  0.5], [ 0.0,  1.0]),
413                 ([-0.5, -0.5,  0.5], [ 0.0,  0.0]),
414         ],
415         [
416                 ([-0.5, -0.5, -0.5], [ 0.0,  0.0]),
417                 ([ 0.5,  0.5, -0.5], [ 1.0,  1.0]),
418                 ([ 0.5, -0.5, -0.5], [ 1.0,  0.0]),
419                 ([ 0.5,  0.5, -0.5], [ 1.0,  1.0]),
420                 ([-0.5, -0.5, -0.5], [ 0.0,  0.0]),
421                 ([-0.5,  0.5, -0.5], [ 0.0,  1.0]),
422         ],
423 ];